https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127447
Richard Biener <rguenth at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Status|NEW |ASSIGNED
Assignee|unassigned at gcc dot gnu.org |rguenth at gcc dot
gnu.org
--- Comment #5 from Richard Biener <rguenth at gcc dot gnu.org> ---
✦ Root Cause Analysis
The miscompilation of obj/gcc/t.c at -O2 is caused by a bug in the
GIMPLE-level ifcombine optimization pass, specifically during the decoding of
field references in decode_field_reference (gcc/gcc/gimple-fold.cc).
1. Comparison Structure:
The code inside b() contains a conditional block equivalent to:
1 _6 = (unsigned char) _2; // where _2 = a.1_1 ^ -8
2 _3 = (short int) _2;
3 if (_6 != 0) goto return_block;
4 if (_3 != 0) goto return_block;
5 else marker_32();
To reach the marker_32() block, both _6 == 0 and _3 == 0 must hold,
forming
an OR/AND combination pattern that ifcombine attempts to optimize into a
single 16-bit comparison.
2. Constant Decoding Mismatch:
During fold_truth_andor_for_ifcombine (and through
decode_field_reference),
the XOR binary operation a.1_1 ^ -8 != 0 is rewritten to compare a.1_1
against
-8.
- The left comparison's target constant is -8 (an INTEGER_CST of type
int,
32-bit), but the outer cast is unsigned char (8-bit).
- In decode_field_reference, when the outer cast is stripped, the outer
type (unsigned char, 8-bit) is saved in outer_type. However, the
constant operand -8 is returned with its original 32-bit precision
without being truncated/cast to outer_type.
- Consequently, ll_bitsize is determined to be 8, and the right-hand
constant bitsize lr_bitsize is also 8. Because ll_bitsize < lr_bitsize
(8 < 8) evaluates to false, the constant -8 (which has set bits outside
the lowest 8 bits) is never truncated to 8 bits (248).
3. Tautological Check Failure:
During comparison combination, thePass checks if the constant (-8
represented as 0xfff8 in 16-bit) has set bits outside the mask for the
compared field (ll_mask = 0x00ff). Since 0xfff8 & ~0x00ff != 0, ifcombine
incorrectly concludes that the comparison is tautological (always false),
causing the entire conditional check to fold into constant 0 (false), which
optimizes away the call to marker_32().