[PATCH] fold ((X & N) + B) & M to (X + B) & M (PR tree-optimization/31261)

Jakub Jelinek jakub@redhat.com
Wed Mar 21 17:07:00 GMT 2007


Hi!

This is an simplify_binary_operation_1 optimization reimplemented
in fold, so that such expressions can be simplified even earlier than
in the combiner.
Bootstrapped/regtested on x86_64-linux, ok for trunk?

2007-03-21  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/31261
	* fold-const.c (fold_binary): Optimize ((A & N) + B) & M
	for constants M and N, M == (1LL << cst) - 1 && (N & M) == M.

	* gcc.dg/tree-ssa/pr31261.c: New test.

--- gcc/fold-const.c.jj	2007-03-12 17:18:17.000000000 +0100
+++ gcc/fold-const.c	2007-03-21 13:55:16.000000000 +0100
@@ -10349,6 +10349,117 @@ fold_binary (enum tree_code code, tree t
 			      fold_convert (type, arg0));
 	}
 
+      /* For constants M and N, if M == (1LL << cst) - 1 && (N & M) == M,
+	 ((A & N) + B) & M -> (A + B) & M
+	 Similarly if (N & M) == 0,
+	 ((A | N) + B) & M -> (A + B) & M
+	 and for - instead of + (or unary - instead of +)
+	 and/or ^ instead of |.
+	 If B is constant and (B & M) == 0, fold into A & M.  */
+      if (host_integerp (arg1, 1))
+	{
+	  unsigned HOST_WIDE_INT cst1 = tree_low_cst (arg1, 1);
+	  if (~cst1 && (cst1 & (cst1 + 1)) == 0
+	      && INTEGRAL_TYPE_P (TREE_TYPE (arg0))
+	      && (TREE_CODE (arg0) == PLUS_EXPR
+		  || TREE_CODE (arg0) == MINUS_EXPR
+		  || TREE_CODE (arg0) == NEGATE_EXPR)
+	      && (TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0))
+		  || TREE_CODE (TREE_TYPE (arg0)) == INTEGER_TYPE))
+	    {
+	      tree pmop[2];
+	      int which = 0;
+	      unsigned HOST_WIDE_INT cst0;
+
+	      pmop[0] = TREE_OPERAND (arg0, 0);
+	      pmop[1] = NULL;
+	      if (TREE_CODE (arg0) != NEGATE_EXPR)
+		{
+		  pmop[1] = TREE_OPERAND (arg0, 1);
+		  which = 1;
+		}
+
+	      if (!host_integerp (TYPE_MAX_VALUE (TREE_TYPE (arg0)), 1)
+		  || (tree_low_cst (TYPE_MAX_VALUE (TREE_TYPE (arg0)), 1)
+		      & cst1) != cst1)
+		which = -1;
+
+	      for (; which >= 0; which--)
+		switch (TREE_CODE (pmop[which]))
+		  {
+		  case BIT_AND_EXPR:
+		  case BIT_IOR_EXPR:
+		  case BIT_XOR_EXPR:
+		    if (TREE_CODE (TREE_OPERAND (pmop[which], 1))
+			!= INTEGER_CST)
+		      break;
+		    /* tree_low_cst not used, because we don't care about
+		       the upper bits.  */
+		    cst0 = TREE_INT_CST_LOW (TREE_OPERAND (pmop[which], 1));
+		    cst0 &= cst1;
+		    if (TREE_CODE (pmop[which]) == BIT_AND_EXPR)
+		      {
+			if (cst0 != cst1)
+			  break;
+		      }
+		    else if (cst0 != 0)
+		      break;
+		    pmop[which] = TREE_OPERAND (pmop[which], 0);
+		    break;
+		  case INTEGER_CST:
+		    if ((TREE_CODE (arg0) == PLUS_EXPR
+			 || (TREE_CODE (arg0) == MINUS_EXPR && which == 0))
+			&& (TREE_INT_CST_LOW (pmop[which]) & cst1) == 0)
+		      pmop[which] = NULL;
+		    break;
+		  default:
+		    break;
+		  }
+
+	      if (pmop[0] != TREE_OPERAND (arg0, 0)
+		  || (TREE_CODE (arg0) != NEGATE_EXPR
+		      && pmop[1] != TREE_OPERAND (arg0, 1)))
+		{
+		  tree utype = type;
+		  if (! TYPE_OVERFLOW_WRAPS (TREE_TYPE (arg0)))
+		    {
+		      utype = lang_hooks.types.unsigned_type (type);
+		      if (pmop[0] != NULL)
+			pmop[0] = fold_convert (utype, pmop[0]);
+		      if (pmop[1] != NULL)
+			pmop[1] = fold_convert (utype, pmop[1]);
+		    }
+
+		  if (TREE_CODE (arg0) == NEGATE_EXPR)
+		    tem = fold_build1 (NEGATE_EXPR, utype, pmop[0]);
+		  else if (TREE_CODE (arg0) == PLUS_EXPR)
+		    {
+		      if (pmop[0] != NULL && pmop[1] != NULL)
+			tem = fold_build2 (PLUS_EXPR, utype, pmop[0],
+					   pmop[1]);
+		      else if (pmop[0] != NULL)
+			tem = pmop[0];
+		      else if (pmop[1] != NULL)
+			tem = pmop[1];
+		      else
+			return build_int_cst (type, 0);
+		    }
+		  else if (pmop[0] == NULL)
+		    tem = fold_build1 (NEGATE_EXPR, utype, pmop[1]);
+		  else
+		    tem = fold_build2 (MINUS_EXPR, utype, pmop[0], pmop[1]);
+		  if (utype == type)
+		    return fold_build2 (BIT_AND_EXPR, type, tem, arg1);
+		  else
+		    return fold_convert (type,
+					 fold_build2 (BIT_AND_EXPR, utype,
+						      tem,
+						      fold_convert (utype,
+								    arg1)));
+		}
+	    }
+	}
+
       t1 = distribute_bit_expr (code, type, arg0, arg1);
       if (t1 != NULL_TREE)
 	return t1;
--- gcc/testsuite/gcc.dg/tree-ssa/pr31261.c.jj	2007-03-21 15:20:39.000000000 +0100
+++ gcc/testsuite/gcc.dg/tree-ssa/pr31261.c	2007-03-21 15:23:55.000000000 +0100
@@ -0,0 +1,40 @@
+/* PR tree-optimization/31261 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-original" } */
+
+unsigned int
+f1 (unsigned int a)
+{
+  return (8 - (a & 7)) & 7;
+}
+
+long int
+f2 (long int b)
+{
+  return (16 + (b & 7)) & 15;
+}
+
+char
+f3 (char c)
+{
+  return -(c & 63) & 31;
+}
+
+int
+f4 (int d)
+{
+  return (12 - (d & 15)) & 7;
+}
+
+int
+f5 (int e)
+{
+  return (12 - (e & 7)) & 15;
+}
+
+/* { dg-final { scan-tree-dump-times "return -a \& 7;" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "return b \& 7;" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "return \\(int\\) \\(char\\) -\\(unsigned char\\) c \& 31;" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "return \\(int\\) \\(12 - \\(unsigned int\\) d\\) \& 7;" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "return 12 - \\(e \& 7\\) \& 15;" 1 "original" } } */
+/* { dg-final { cleanup-tree-dump "original" } } */

	Jakub



More information about the Gcc-patches mailing list