Hi!

The function comment says:
   *XOR_P is to be FALSE if EXP might be a XOR used in a compare, in which
   case, if XOR_CMP_OP is a zero constant, it will be overridden with *PEXP,
   *XOR_P will be set to TRUE, and the left-hand operand of the XOR will be
   decoded.  If *XOR_P is TRUE, XOR_CMP_OP is supposed to be NULL, and then the
   right-hand operand of the XOR will be decoded.
and the comment right above the xor_p handling says
  /* Turn (a ^ b) [!]= 0 into a [!]= b.  */
but I don't see anything that would actually check that the other operand is
0, in the testcase below it happily optimizes (a ^ 1) == 8 into a == 1.

The following patch adds that check.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

Note, there are various other parts of the function I'm worried about, but
haven't had time to construct counterexamples yet.

One worrying thing is the
  /* Drop casts, only save the outermost type.  We need not worry about
     narrowing then widening casts, or vice-versa, for those that are not
     essential for the compare have already been optimized out at this
     point.  */
comment, while obviously there are various optimizations which do optimize
nested casts and the like, I'm not really sure it is safe to rely on them
happening always before this optimization, there are various options to
disable certain optimizations and some IL could appear right before
ifcombine without being optimized yet the way this routine expects.
Plus, the 3 casts are looked through in between various optimizations which
might make those narrowing/widening or vice versa cases necessary.

Also, e.g. for the xor optimization, I think there is a difference between
int a and
  (a ^ 0x23) == 0
and
  ((int) (((unsigned char) a) ^ (unsigned char) 0x23)) == 0
etc.

Another thing I'm worrying about are mixing up the different patterns
together, there is the BIT_AND_EXPR handling, BIT_XOR_EXPR handling,
RSHIFT_EXPR handling and then load handling.
What if all 4 appear together, or 3 of them, 2 of them?
Is the xor optimization still valid if there is BIT_AND_EXPR in between?
I.e. instead of
  (a ^ 123) == 0
there is
  ((a ^ 123) & 234) == 0
?

2024-12-18  Jakub Jelinek  <ja...@redhat.com>

        PR tree-optimization/118081
        * gimple-fold.cc (decode_field_reference): Only set *xor_p to true
        if *xor_cmp_op is integer_zerop.

        * gcc.dg/pr118081.c: New test.

--- gcc/gimple-fold.cc.jj       2024-12-14 11:28:08.000000000 +0100
+++ gcc/gimple-fold.cc  2024-12-17 17:27:31.294874825 +0100
@@ -7572,7 +7572,7 @@ decode_field_reference (tree *pexp, HOST
        /* Not much we can do when xor appears in the right-hand compare
           operand.  */
        return NULL_TREE;
-      else
+      else if (integer_zerop (*xor_cmp_op))
        {
          *xor_p = true;
          exp = res_ops[0];
--- gcc/testsuite/gcc.dg/pr118081.c.jj  2024-12-17 17:31:07.522860128 +0100
+++ gcc/testsuite/gcc.dg/pr118081.c     2024-12-17 17:29:59.131813646 +0100
@@ -0,0 +1,28 @@
+/* PR tree-optimization/118081 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fno-tree-vrp -fno-expensive-optimizations" } */
+
+int a, b;
+
+int
+foo (int f)
+{
+  return f ? f || 0 : f;
+}
+
+void
+bar (void)
+{
+  b = a ? a : 1;
+  int i = foo (1 ^ b);
+  signed char h = i - 8;
+  if (h)
+    return;
+  __builtin_abort ();
+}
+
+int
+main ()
+{
+  bar ();
+}

        Jakub

Reply via email to