https://gcc.gnu.org/g:91fa9c15cc4fb9947e7e2f7990f7d5a58845d5cf
commit r15-7173-g91fa9c15cc4fb9947e7e2f7990f7d5a58845d5cf Author: Alexandre Oliva <ol...@adacore.com> Date: Thu Jan 23 23:23:16 2025 -0300 [ifcombine] check for more zero-extension cases [PR118572] When comparing a signed narrow variable with a wider constant that has the bit corresponding to the variable's sign bit set, we would check that the constant is a sign-extension from that sign bit, and conclude that the compare fails if it isn't. When the signed variable is masked without getting the [lr]l_signbit variable set, or when the sign bit itself is masked out, we know the sign-extension bits from the extended variable are going to be zero, so the constant will only compare equal if it is a zero- rather than sign-extension from the narrow variable's precision, therefore, check that it satisfies this property, and yield a false compare result otherwise. for gcc/ChangeLog PR tree-optimization/118572 * gimple-fold.cc (fold_truth_andor_for_ifcombine): Compare as unsigned the variables whose extension bits are masked out. for gcc/testsuite/ChangeLog PR tree-optimization/118572 * gcc.dg/field-merge-24.c: New. Diff: --- gcc/gimple-fold.cc | 20 ++++++++++++++++--- gcc/testsuite/gcc.dg/field-merge-24.c | 36 +++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc index 5f2fe56ea383..45485782cdf9 100644 --- a/gcc/gimple-fold.cc +++ b/gcc/gimple-fold.cc @@ -8542,12 +8542,21 @@ fold_truth_andor_for_ifcombine (enum tree_code code, tree truth_type, { /* Before clipping upper bits of the right-hand operand of the compare, check that they're sign or zero extensions, depending on how the - left-hand operand would be extended. */ + left-hand operand would be extended. If it is unsigned, or if there's + a mask that zeroes out extension bits, whether because we've checked + for upper bits in the mask and did not set ll_signbit, or because the + sign bit itself is masked out, check that the right-hand operand is + zero-extended. */ bool l_non_ext_bits = false; if (ll_bitsize < lr_bitsize) { wide_int zext = wi::zext (l_const, ll_bitsize); - if ((ll_unsignedp ? zext : wi::sext (l_const, ll_bitsize)) == l_const) + if ((ll_unsignedp + || (ll_and_mask.get_precision () + && (!ll_signbit + || ((ll_and_mask & wi::mask (ll_bitsize - 1, true, ll_bitsize)) + == 0))) + ? zext : wi::sext (l_const, ll_bitsize)) == l_const) l_const = zext; else l_non_ext_bits = true; @@ -8573,7 +8582,12 @@ fold_truth_andor_for_ifcombine (enum tree_code code, tree truth_type, if (rl_bitsize < rr_bitsize) { wide_int zext = wi::zext (r_const, rl_bitsize); - if ((rl_unsignedp ? zext : wi::sext (r_const, rl_bitsize)) == r_const) + if ((rl_unsignedp + || (rl_and_mask.get_precision () + && (!rl_signbit + || ((rl_and_mask & wi::mask (rl_bitsize - 1, true, rl_bitsize)) + == 0))) + ? zext : wi::sext (r_const, rl_bitsize)) == r_const) r_const = zext; else r_non_ext_bits = true; diff --git a/gcc/testsuite/gcc.dg/field-merge-24.c b/gcc/testsuite/gcc.dg/field-merge-24.c new file mode 100644 index 000000000000..ce5bce7d0b49 --- /dev/null +++ b/gcc/testsuite/gcc.dg/field-merge-24.c @@ -0,0 +1,36 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +/* PR tree-optimization/118572 */ +/* Check that signed compares with constants that seem signed in the other + compare operand's width get treated as unsigned if its upper bits are masked + out. */ + +__attribute__((noipa)) +int test(signed char c) +{ + return (((0x80 & (c&0xff)) != 0) && ((0xc0 & (c&0xff)) == 0x80)); +} + +__attribute__((noipa)) +int test2(signed char c) +{ + return (((-128 & (c&-1)) != 0) && ((-64 & (c&-1)) == -128)); +} + +__attribute__((noipa)) +int test3(signed char c) +{ + return (((0x80 & (c&-1)) != 0) && ((0x1248c0 & (c&-1)) == 0x124880)); +} + +__attribute__((noipa)) +int test4(signed char c) +{ + return (((0x400 & (c&-1)) == 0) && ((0x40 & (c&-1)) == 0x40)); +} + +int main() { + if (test(0x80) == 0 || test2(-128) == 0 || test3(-128) == 0 || test4(64) == 0) + __builtin_abort(); +}