OSDN Git Service

2005-11-19 Richard Guenther <rguenther@suse.de>
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 19 Nov 2005 11:29:10 +0000 (11:29 +0000)
committerrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 19 Nov 2005 11:29:10 +0000 (11:29 +0000)
        PR middle-end/23294
* fold-const.c (fold_plusminus_mult_expr): New function.
(fold_binary): Use to canonicalize PLUS_EXPR and MINUS_EXPR
cases, remove now unnecessary code.

* gcc.dg/tree-ssa/pr23294.c: New testcase.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@107218 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/fold-const.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/pr23294.c [new file with mode: 0644]

index 8f1604f..1200433 100644 (file)
@@ -1,3 +1,10 @@
+2005-11-19  Richard Guenther  <rguenther@suse.de>
+
+       PR middle-end/23294
+       * fold-const.c (fold_plusminus_mult_expr): New function.
+       (fold_binary): Use to canonicalize PLUS_EXPR and MINUS_EXPR
+       cases, remove now unnecessary code.
+
 2005-11-19  Paolo Bonzini  <bonzini@gcc.gnu.org>
 
        * gensupport.c (old_preds): Rename to std_preds, add special field.
index abaac75..b8576fc 100644 (file)
@@ -6556,6 +6556,104 @@ fold_to_nonsharp_ineq_using_bound (tree ineq, tree bound)
   return fold_build2 (GE_EXPR, type, a, y);
 }
 
+/* Fold a sum or difference of at least one multiplication.
+   Returns the folded tree or NULL if no simplification could be made.  */
+
+static tree
+fold_plusminus_mult_expr (enum tree_code code, tree type, tree arg0, tree arg1)
+{
+  tree arg00, arg01, arg10, arg11;
+  tree alt0 = NULL_TREE, alt1 = NULL_TREE, same;
+
+  /* (A * C) +- (B * C) -> (A+-B) * C.
+     (A * C) +- A -> A * (C+-1).
+     We are most concerned about the case where C is a constant,
+     but other combinations show up during loop reduction.  Since
+     it is not difficult, try all four possibilities.  */
+
+  if (TREE_CODE (arg0) == MULT_EXPR)
+    {
+      arg00 = TREE_OPERAND (arg0, 0);
+      arg01 = TREE_OPERAND (arg0, 1);
+    }
+  else
+    {
+      arg00 = arg0;
+      if (!FLOAT_TYPE_P (type))
+       arg01 = build_int_cst (type, 1);
+      else
+       arg01 = build_real (type, dconst1);
+    }
+  if (TREE_CODE (arg1) == MULT_EXPR)
+    {
+      arg10 = TREE_OPERAND (arg1, 0);
+      arg11 = TREE_OPERAND (arg1, 1);
+    }
+  else
+    {
+      arg10 = arg1;
+      if (!FLOAT_TYPE_P (type))
+       arg11 = build_int_cst (type, 1);
+      else
+       arg11 = build_real (type, dconst1);
+    }
+  same = NULL_TREE;
+
+  if (operand_equal_p (arg01, arg11, 0))
+    same = arg01, alt0 = arg00, alt1 = arg10;
+  else if (operand_equal_p (arg00, arg10, 0))
+    same = arg00, alt0 = arg01, alt1 = arg11;
+  else if (operand_equal_p (arg00, arg11, 0))
+    same = arg00, alt0 = arg01, alt1 = arg10;
+  else if (operand_equal_p (arg01, arg10, 0))
+    same = arg01, alt0 = arg00, alt1 = arg11;
+
+  /* No identical multiplicands; see if we can find a common
+     power-of-two factor in non-power-of-two multiplies.  This
+     can help in multi-dimensional array access.  */
+  else if (host_integerp (arg01, 0)
+          && host_integerp (arg11, 0))
+    {
+      HOST_WIDE_INT int01, int11, tmp;
+      bool swap = false;
+      tree maybe_same;
+      int01 = TREE_INT_CST_LOW (arg01);
+      int11 = TREE_INT_CST_LOW (arg11);
+
+      /* Move min of absolute values to int11.  */
+      if ((int01 >= 0 ? int01 : -int01)
+         < (int11 >= 0 ? int11 : -int11))
+        {
+         tmp = int01, int01 = int11, int11 = tmp;
+         alt0 = arg00, arg00 = arg10, arg10 = alt0;
+         maybe_same = arg01;
+         swap = true;
+       }
+      else
+       maybe_same = arg11;
+
+      if (exact_log2 (int11) > 0 && int01 % int11 == 0)
+        {
+         alt0 = fold_build2 (MULT_EXPR, TREE_TYPE (arg00), arg00,
+                             build_int_cst (TREE_TYPE (arg00),
+                                            int01 / int11));
+         alt1 = arg10;
+         same = maybe_same;
+         if (swap)
+           maybe_same = alt0, alt0 = alt1, alt1 = maybe_same;
+       }
+    }
+
+  if (same)
+    return fold_build2 (MULT_EXPR, type,
+                       fold_build2 (code, type,
+                                    fold_convert (type, alt0),
+                                    fold_convert (type, alt1)),
+                       fold_convert (type, same));
+
+  return NULL_TREE;
+}
+
 /* Fold a unary expression of code CODE and type TYPE with operand
    OP0.  Return the folded expression if folding is successful.
    Otherwise, return NULL_TREE.  */
@@ -7205,6 +7303,17 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          && integer_onep (arg1))
        return fold_build1 (NEGATE_EXPR, type, TREE_OPERAND (arg0, 0));
 
+      /* Handle (A1 * C1) + (A2 * C2) with A1, A2 or C1, C2 being the
+        same or one.  */
+      if ((TREE_CODE (arg0) == MULT_EXPR
+          || TREE_CODE (arg1) == MULT_EXPR)
+         && (!FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations))
+        {
+         tree tem = fold_plusminus_mult_expr (code, type, arg0, arg1);
+         if (tem)
+           return tem;
+       }
+
       if (! FLOAT_TYPE_P (type))
        {
          if (integer_zerop (arg1))
@@ -7266,70 +7375,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
                                                               parg1)));
            }
 
-         if (TREE_CODE (arg0) == MULT_EXPR && TREE_CODE (arg1) == MULT_EXPR)
-           {
-             tree arg00, arg01, arg10, arg11;
-             tree alt0 = NULL_TREE, alt1 = NULL_TREE, same;
-
-             /* (A * C) + (B * C) -> (A+B) * C.
-                We are most concerned about the case where C is a constant,
-                but other combinations show up during loop reduction.  Since
-                it is not difficult, try all four possibilities.  */
-
-             arg00 = TREE_OPERAND (arg0, 0);
-             arg01 = TREE_OPERAND (arg0, 1);
-             arg10 = TREE_OPERAND (arg1, 0);
-             arg11 = TREE_OPERAND (arg1, 1);
-             same = NULL_TREE;
-
-             if (operand_equal_p (arg01, arg11, 0))
-               same = arg01, alt0 = arg00, alt1 = arg10;
-             else if (operand_equal_p (arg00, arg10, 0))
-               same = arg00, alt0 = arg01, alt1 = arg11;
-             else if (operand_equal_p (arg00, arg11, 0))
-               same = arg00, alt0 = arg01, alt1 = arg10;
-             else if (operand_equal_p (arg01, arg10, 0))
-               same = arg01, alt0 = arg00, alt1 = arg11;
-
-             /* No identical multiplicands; see if we can find a common
-                power-of-two factor in non-power-of-two multiplies.  This
-                can help in multi-dimensional array access.  */
-             else if (TREE_CODE (arg01) == INTEGER_CST
-                      && TREE_CODE (arg11) == INTEGER_CST
-                      && TREE_INT_CST_HIGH (arg01) == 0
-                      && TREE_INT_CST_HIGH (arg11) == 0)
-               {
-                 HOST_WIDE_INT int01, int11, tmp;
-                 int01 = TREE_INT_CST_LOW (arg01);
-                 int11 = TREE_INT_CST_LOW (arg11);
-
-                 /* Move min of absolute values to int11.  */
-                 if ((int01 >= 0 ? int01 : -int01)
-                     < (int11 >= 0 ? int11 : -int11))
-                   {
-                     tmp = int01, int01 = int11, int11 = tmp;
-                     alt0 = arg00, arg00 = arg10, arg10 = alt0;
-                     alt0 = arg01, arg01 = arg11, arg11 = alt0;
-                   }
-
-                 if (exact_log2 (int11) > 0 && int01 % int11 == 0)
-                   {
-                     alt0 = fold_build2 (MULT_EXPR, type, arg00,
-                                         build_int_cst (NULL_TREE,
-                                                        int01 / int11));
-                     alt1 = arg10;
-                     same = arg11;
-                   }
-               }
-
-             if (same)
-               return fold_build2 (MULT_EXPR, type,
-                                   fold_build2 (PLUS_EXPR, type,
-                                                fold_convert (type, alt0),
-                                                fold_convert (type, alt1)),
-                                   fold_convert (type, same));
-           }
-
          /* Try replacing &a[i1] + c * i2 with &a[i1 + i2], if c is step
             of the array.  Loop optimizer sometimes produce this type of
             expressions.  */
@@ -7379,56 +7424,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
            return fold_build2 (MULT_EXPR, type, arg0,
                                build_real (type, dconst2));
 
-         /* Convert x*c+x into x*(c+1).  */
-         if (flag_unsafe_math_optimizations
-             && TREE_CODE (arg0) == MULT_EXPR
-             && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
-             && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg0, 1))
-             && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
-           {
-             REAL_VALUE_TYPE c;
-
-             c = TREE_REAL_CST (TREE_OPERAND (arg0, 1));
-             real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
-             return fold_build2 (MULT_EXPR, type, arg1,
-                                 build_real (type, c));
-           }
-
-         /* Convert x+x*c into x*(c+1).  */
-         if (flag_unsafe_math_optimizations
-             && TREE_CODE (arg1) == MULT_EXPR
-             && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST
-             && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg1, 1))
-             && operand_equal_p (TREE_OPERAND (arg1, 0), arg0, 0))
-           {
-             REAL_VALUE_TYPE c;
-
-             c = TREE_REAL_CST (TREE_OPERAND (arg1, 1));
-             real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
-             return fold_build2 (MULT_EXPR, type, arg0,
-                                 build_real (type, c));
-           }
-
-         /* Convert x*c1+x*c2 into x*(c1+c2).  */
-         if (flag_unsafe_math_optimizations
-             && TREE_CODE (arg0) == MULT_EXPR
-             && TREE_CODE (arg1) == MULT_EXPR
-             && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
-             && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg0, 1))
-             && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST
-             && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg1, 1))
-             && operand_equal_p (TREE_OPERAND (arg0, 0),
-                                 TREE_OPERAND (arg1, 0), 0))
-           {
-             REAL_VALUE_TYPE c1, c2;
-
-             c1 = TREE_REAL_CST (TREE_OPERAND (arg0, 1));
-             c2 = TREE_REAL_CST (TREE_OPERAND (arg1, 1));
-             real_arithmetic (&c1, PLUS_EXPR, &c1, &c2);
-             return fold_build2 (MULT_EXPR, type,
-                                 TREE_OPERAND (arg0, 0),
-                                 build_real (type, c1));
-           }
           /* Convert a + (b*c + d*e) into (a + b*c) + d*e.  */
           if (flag_unsafe_math_optimizations
               && TREE_CODE (arg1) == PLUS_EXPR
@@ -7771,26 +7766,15 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
          && (tem = distribute_real_division (code, type, arg0, arg1)))
        return tem;
 
-      if (TREE_CODE (arg0) == MULT_EXPR
-         && TREE_CODE (arg1) == MULT_EXPR
+      /* Handle (A1 * C1) - (A2 * C2) with A1, A2 or C1, C2 being the
+        same or one.  */
+      if ((TREE_CODE (arg0) == MULT_EXPR
+          || TREE_CODE (arg1) == MULT_EXPR)
          && (!FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations))
-       {
-          /* (A * C) - (B * C) -> (A-B) * C.  */
-         if (operand_equal_p (TREE_OPERAND (arg0, 1),
-                              TREE_OPERAND (arg1, 1), 0))
-           return fold_build2 (MULT_EXPR, type,
-                               fold_build2 (MINUS_EXPR, type,
-                                            TREE_OPERAND (arg0, 0),
-                                            TREE_OPERAND (arg1, 0)),
-                               TREE_OPERAND (arg0, 1));
-          /* (A * C1) - (A * C2) -> A * (C1-C2).  */
-         if (operand_equal_p (TREE_OPERAND (arg0, 0),
-                              TREE_OPERAND (arg1, 0), 0))
-           return fold_build2 (MULT_EXPR, type,
-                               TREE_OPERAND (arg0, 0),
-                               fold_build2 (MINUS_EXPR, type,
-                                            TREE_OPERAND (arg0, 1),
-                                            TREE_OPERAND (arg1, 1)));
+        {
+         tree tem = fold_plusminus_mult_expr (code, type, arg0, arg1);
+         if (tem)
+           return tem;
        }
 
       goto associate;
index 4d7c750..3c79b1e 100644 (file)
@@ -1,3 +1,8 @@
+2005-11-19  Richard Guenther  <rguenther@suse.de>
+
+       PR middle-end/23294
+       * gcc.dg/tree-ssa/pr23294.c: New testcase.
+
 2005-11-19  Hans-Peter Nilsson  <hp@bitrange.com>
 
        * gcc.dg/fold-overflow-1.c: Adjust for float output for mmix-*-*.
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr23294.c b/gcc/testsuite/gcc.dg/tree-ssa/pr23294.c
new file mode 100644 (file)
index 0000000..0ab4ed2
--- /dev/null
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-vars" } */
+
+int f1(int a)
+{
+  return a*6-a;
+}
+
+int f2(int a)
+{
+  return a*4+a;
+}
+
+int f3(int a)
+{
+  return 2*a + 3*a;
+}
+
+int f4(int a, int b)
+{
+  return 2*a + 6*b;
+}
+
+int f5(int a, int b)
+{
+  return 2*a - 6*b;
+}
+
+int f6(int a, int b)
+{
+  return 6*a - 2*b;
+}
+
+/* { dg-final { scan-tree-dump-times "a \\\* 5" 3 "vars" } } */
+/* { dg-final { scan-tree-dump "\\\(b \\\* 3 \\\+ a\\\) \\\* 2" "vars" } } */
+/* { dg-final { scan-tree-dump "\\\(a - b \\\* 3\\\) \\\* 2" "vars" } } */
+/* { dg-final { scan-tree-dump "\\\(a \\\* 3 - b\\\) \\\* 2" "vars" } } */
+/* { dg-final { cleanup-tree-dump "vars" } } */