https://gcc.gnu.org/g:96292bfbef1913981df899b792a8e784363c9a43

commit 96292bfbef1913981df899b792a8e784363c9a43
Author: Alexandre Oliva <ol...@adacore.com>
Date:   Thu Jan 23 02:51:41 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-extended from that sign bit, and conclude
    that the compare fails if it isn't.
    
    When the signed variable is masked without getting the 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 zero- rather than
    sign-extended from the narrow variable's precision, so 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 cd9d35034918..13541fe1ef74 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -8552,12 +8552,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;
@@ -8583,7 +8592,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();
+}

Reply via email to