The following testcase is miscompiled, because byte 0x20000000
is bit 0x100000000 and ifcombine incorrectly combines the two loads
into a BIT_FIELD_REF even when they are very far away.
The problem is that gimple-fold.cc ifcombine uses get_best_mode heavily,
and that function has just int bitsize and int bitpos arguments, so
when called e.g. with
if (get_best_mode (end_bit - first_bit, first_bit, 0, ll_end_region,
ll_align, BITS_PER_WORD, volatilep, &lnmode))
where end_bit - first_bit doesn't fit into int, it is silently truncated.
If there was just a single problematic get_best_mode call, I would probably
just check for overflows in the caller, but there are many.
And the two arguments are used solely as arguments to
bit_field_mode_iterator constructor which has HOST_WIDE_INT arguments,
so I think the easiest fix is just make the get_best_mode arguments
also HOST_WIDE_INT.
2025-07-31 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/121264
* machmode.h (get_best_mode): Change type of first 2 arguments
from int to HOST_WIDE_INT.
* stor-layout.cc (get_best_mode): Likewise.
* gcc.dg/tree-ssa/pr121264.c: New test.
/* Find the best mode to use to access a bit field. */
-extern bool get_best_mode (int, int, poly_uint64, poly_uint64, unsigned int,
+extern bool get_best_mode (HOST_WIDE_INT, HOST_WIDE_INT,
+ poly_uint64, poly_uint64, unsigned int,
unsigned HOST_WIDE_INT, bool, scalar_int_mode *);
/* Determine alignment, 1<=result<=BIGGEST_ALIGNMENT. */
decide which of the above modes should be used. */
bool
-get_best_mode (int bitsize, int bitpos,
+get_best_mode (HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
poly_uint64 bitregion_start, poly_uint64 bitregion_end,
unsigned int align,
unsigned HOST_WIDE_INT largest_mode_bitsize, bool volatilep,
--- /dev/null
+/* PR tree-optimization/121264 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump " \\\| " "optimized" } } */
+
+struct A { char b; char c[0x20000010]; } a;
+
+int
+foo ()
+{
+ return a.c[0x20000000] || a.c[1];
+}