https://gcc.gnu.org/g:cc2aaa9ac0d31f8f4098c4276e0695afb7f63fcf

commit cc2aaa9ac0d31f8f4098c4276e0695afb7f63fcf
Author: Alexandre Oliva <ol...@gnu.org>
Date:   Sun Jan 12 22:16:21 2025 -0300

    [ifcombine] propagate signbit mask to xor right-hand operand

Diff:
---
 gcc/gimple-fold.cc                    | 20 ++++++++++++++++
 gcc/testsuite/gcc.dg/field-merge-20.c | 44 +++++++++++++++++++++++++++++++++++
 2 files changed, 64 insertions(+)

diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index a3987c4590ae..93ed8b3abb05 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -8270,6 +8270,16 @@ fold_truth_andor_for_ifcombine (enum tree_code code, 
tree truth_type,
        ll_and_mask = sign;
       else
        ll_and_mask &= sign;
+      if (l_xor)
+       {
+         if (!lr_and_mask.get_precision ())
+           lr_and_mask = sign;
+         else
+           lr_and_mask &= sign;
+         if (l_const.get_precision ())
+           l_const &= wide_int::from (lr_and_mask,
+                                      l_const.get_precision (), UNSIGNED);
+       }
     }
 
   if (rsignbit)
@@ -8279,6 +8289,16 @@ fold_truth_andor_for_ifcombine (enum tree_code code, 
tree truth_type,
        rl_and_mask = sign;
       else
        rl_and_mask &= sign;
+      if (r_xor)
+       {
+         if (!rr_and_mask.get_precision ())
+           rr_and_mask = sign;
+         else
+           rr_and_mask &= sign;
+         if (r_const.get_precision ())
+           r_const &= wide_int::from (rr_and_mask,
+                                      r_const.get_precision (), UNSIGNED);
+       }
     }
 
   /* If either comparison code is not correct for our logical operation,
diff --git a/gcc/testsuite/gcc.dg/field-merge-20.c 
b/gcc/testsuite/gcc.dg/field-merge-20.c
new file mode 100644
index 000000000000..3c1ec0cbd80f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/field-merge-20.c
@@ -0,0 +1,44 @@
+/* { dg-do run } */
+/* { dg-options "-O1" } */
+
+/* tree-optimization/118409 */
+
+/* Check that tests involving a sign bit of a storage unit are handled
+   correctly.  The compares are turned into xor tests by earlier passes, and 
ifcombine has to propagate the sign bit mask to the right hand of the compare 
extracted from the */
+
+typedef struct {
+    int p : __CHAR_BIT__;
+    int d : 1;
+    int b : __CHAR_BIT__ - 2;
+    int e : 1;
+    int f;
+} g;
+
+g a = {.d = 1, .e = 1}, c = {.b = 1, .d = 1, .e = 1};
+
+__attribute__((noipa))
+int f1 ()
+{
+  if (a.d == c.d
+      && a.e == c.e
+      && a.f == 0)
+    return 0;
+  return -1;
+}
+
+__attribute__((noipa))
+int f2 ()
+{
+  if (a.d != c.d
+      || a.e != c.e
+      || a.f != 0)
+    return -1;
+  return 0;
+}
+
+int main() {
+  if (f1 () < 0
+      || f2 () < 0)
+    __builtin_abort();
+  return 0;
+}

Reply via email to