[PATCH] Avoid mutual recursion between BIT_{IOR,AND}_EXPR optimizations (PR middle-end/34337)

Jakub Jelinek jakub@redhat.com
Wed Dec 5 09:06:00 GMT 2007


Hi!

The (X << C3) & C1 optimization I've recently added apparently can mutually
recurse with (X & C1) | C2 optimization Roger added almost two years ago.
While the justification for the other PR23670 transformations is obvious, I
wonder what the rationale is for trying to remove some bits from a constant
when it won't be optimized into 0 anyway.
The following patch just fixes the mutual recursion, but I wonder if we in
case fold_binary doesn't simplify it (or, to avoid mutual recursion, doesn't
simplify it back to the original X & C1) at least shouldn't decide which
of the two constants (C1 vs. C1 & ~C2) is better for further optimizations.
Say on:
int foo (int x) { return (x & 65535) | 255; }
with -Os on x86_64-linux we now generate:
        andl    $65280, %edi
        orb     $-1, %dil
        movl    %edi, %eax
        ret
while without this transformation we would generate:
        movzwl  %di,%eax
        orb     $-1, %al
        ret
which is shorter.  But I'm not exactly sure what criteria for better should
we use.  We can certainly just don't do this transformation at all if
fold_binary has not simplified it, or e.g. (C1 & (C1 + 1)) == 0 constants
can be considered better, or those which additionally have 8, 16, 32, 64
bits set, something else?

In any case, is the following patch ok for trunk, so that the regression is
gone (and leave further improvements for a followup)?

2007-12-05  Jakub Jelinek  <jakub@redhat.com>

	PR middle-end/34337
	* fold-const.c (fold_binary) <case BIT_IOR_EXPR>: Avoid mutual
	recursion with BIT_AND_EXPR shift optimization.

	* gcc.c-torture/execute/20071205-1.c: New test.

--- gcc/fold-const.c.jj	2007-12-03 21:45:00.000000000 +0100
+++ gcc/fold-const.c	2007-12-05 09:46:10.000000000 +0100
@@ -10603,13 +10603,25 @@ fold_binary (enum tree_code code, tree t
 	  hi1 &= mhi;
 	  lo1 &= mlo;
 	  if ((hi1 & ~hi2) != hi1 || (lo1 & ~lo2) != lo1)
-	    return fold_build2 (BIT_IOR_EXPR, type,
-				fold_build2 (BIT_AND_EXPR, type,
-					     TREE_OPERAND (arg0, 0),
-					     build_int_cst_wide (type,
-								 lo1 & ~lo2,
-								 hi1 & ~hi2)),
-				arg1);
+	    {
+	      tree new_c1 = build_int_cst_wide (type, lo1 & ~lo2, hi1 & ~hi2);
+
+	      tem = fold_binary (BIT_AND_EXPR, type,
+				 TREE_OPERAND (arg0, 0), new_c1);
+	      /* Avoid mutual recursion where this removes some bits from C1
+		 and ((Y >> N) & C1) or ((Y << N) & C1) optimization
+		 adds them back again.  */
+	      if (tem
+		  && TREE_CODE (tem) == BIT_AND_EXPR
+		  && tree_int_cst_equal (TREE_OPERAND (tem, 1),
+					 TREE_OPERAND (arg0, 1)))
+		tem = NULL;
+	      else
+		tem = build2_stat (BIT_AND_EXPR, type,
+				   TREE_OPERAND (arg0, 0), new_c1);
+	      if (tem)
+		return fold_build2 (BIT_IOR_EXPR, type, tem, arg1);
+	    }
 	}
 
       /* (X & Y) | Y is (X, Y).  */
--- gcc/testsuite/gcc.c-torture/execute/20071205-1.c.jj	2007-12-05 09:27:47.000000000 +0100
+++ gcc/testsuite/gcc.c-torture/execute/20071205-1.c	2007-12-05 09:27:25.000000000 +0100
@@ -0,0 +1,17 @@
+/* PR middle-end/34337 */
+
+extern void abort (void);
+
+int
+foo (int x)
+{
+  return ((x << 8) & 65535) | 255;
+}
+
+int
+main (void)
+{
+  if (foo (0x32) != 0x32ff || foo (0x174) != 0x74ff)
+    abort ();
+  return 0;
+}

	Jakub



More information about the Gcc-patches mailing list