Now as the fold_stmt re-org is merged from trunk this moves the
simplify dispatch first before doing the legacy stuff.  It also
adds dumping to this place and removes dumping from
tree-ssa-forwprop.c (as there it catches all fold_stmt transforms
done).  I now also dump the associated sequence which makes
two match testcases fail (I've yet to investigate how to best
write multi-line matching regexps in tcl...).

The patch also adds more foldings from builtins.c and splits
the match-1.c testcase.

Committed.

Richard.

2014-08-28  Richard Biener  <rguent...@suse.de>

        * gimple-fold.c (fold_stmt_1): Move gimple_simplify dispatch
        first, add dumping here.
        * tree-ssa-forwprop.c (pass_forwprop::execute): Remove dumping.
        * match-builtin.pd: Implement more patterns and fix existing ones.

        testsuite/
        * gcc.dg/tree-ssa/match-1.c: Split into ...
        * gcc.dg/tree-ssa/match-builtins.c: ... this ...
        * tree-ssa/match-builtins-fast-math.c: ... and this.

Index: gcc/gimple-fold.c
===================================================================
--- gcc/gimple-fold.c   (revision 214676)
+++ gcc/gimple-fold.c   (working copy)
@@ -2876,6 +2876,71 @@ fold_stmt_1 (gimple_stmt_iterator *gsi,
     default:;
     }
 
+  /* Dispatch to pattern-based folding.  */
+  /* ???  Change "inplace" semantics to allow replacing a stmt if
+     no further stmts need to be inserted (basically disallow
+     creating of new SSA names).  */
+  if (!inplace
+      || is_gimple_assign (stmt))
+    {
+      gimple_seq seq = NULL;
+      code_helper rcode;
+      tree ops[3] = {};
+      if (gimple_simplify (stmt, &rcode, ops, inplace ? NULL : &seq, valueize))
+       {
+         if (is_gimple_assign (stmt)
+             && rcode.is_tree_code ())
+           {
+             if ((!inplace
+                  || gimple_num_ops (stmt) <= get_gimple_rhs_num_ops (rcode))
+                 /* Play safe and do not allow abnormals to be mentioned in
+                    newly created statements.  */
+                 && !((TREE_CODE (ops[0]) == SSA_NAME
+                       && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[0]))
+                      || (ops[1]
+                          && TREE_CODE (ops[1]) == SSA_NAME
+                          && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[1]))
+                      || (ops[2]
+                          && TREE_CODE (ops[2]) == SSA_NAME
+                          && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[2]))))
+               {
+                 gimple_assign_set_rhs_with_ops_1 (gsi, rcode,
+                                                   ops[0], ops[1], ops[2]);
+                 if (dump_file && (dump_flags & TDF_DETAILS))
+                   {
+                     fprintf (dump_file, "gimple_simplified to ");
+                     if (!gimple_seq_empty_p (seq))
+                       print_gimple_seq (dump_file, seq, 0, TDF_SLIM);
+                     print_gimple_stmt (dump_file, gsi_stmt (*gsi),
+                                        0, TDF_SLIM);
+                   }
+                 gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
+                 changed = true;
+               }
+           }
+         else if (!inplace)
+           {
+             if (gimple_has_lhs (stmt))
+               {
+                 tree lhs = gimple_get_lhs (stmt);
+                 maybe_push_res_to_seq (rcode, TREE_TYPE (lhs),
+                                        ops, &seq, lhs);
+                 if (dump_file && (dump_flags & TDF_DETAILS))
+                   {
+                     fprintf (dump_file, "gimple_simplified to ");
+                     print_gimple_seq (dump_file, seq, 0, TDF_SLIM);
+                   }
+                 gsi_replace_with_seq_vops (gsi, seq);
+                 changed = true;
+               }
+             else
+               gcc_unreachable ();
+           }
+       }
+    }
+
+  stmt = gsi_stmt (*gsi);
+
   /* Fold the main computation performed by the statement.  */
   switch (gimple_code (stmt))
     {
@@ -3012,58 +3077,7 @@ fold_stmt_1 (gimple_stmt_iterator *gsi,
        }
     }
 
-  /* Dispatch to pattern-based folding.
-     ???  Do this after the previous stuff as fold_stmt is used to make
-     stmts valid gimple again via maybe_fold_reference of ops.  */
-  /* ???  Change "inplace" semantics to allow replacing a stmt if
-     no further stmts need to be inserted (basically disallow
-     creating of new SSA names).  */
-  if (inplace
-      && !is_gimple_assign (stmt))
-    return changed;
-
-  gimple_seq seq = NULL;
-  code_helper rcode;
-  tree ops[3] = {};
-  if (!gimple_simplify (stmt, &rcode, ops, inplace ? NULL : &seq, valueize))
-    return changed;
-
-  if (is_gimple_assign (stmt)
-      && rcode.is_tree_code ())
-    {
-      if (inplace
-         && gimple_num_ops (stmt) <= get_gimple_rhs_num_ops (rcode))
-       return changed;
-      /* Play safe and do not allow abnormals to be mentioned in
-         newly created statements.  */
-      if ((TREE_CODE (ops[0]) == SSA_NAME
-          && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[0]))
-         || (ops[1]
-             && TREE_CODE (ops[1]) == SSA_NAME
-             && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[1]))
-         || (ops[2]
-             && TREE_CODE (ops[2]) == SSA_NAME
-             && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ops[2])))
-       return changed;
-      gimple_assign_set_rhs_with_ops_1 (gsi, rcode, ops[0], ops[1], ops[2]);
-      gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
-    }
-  else
-    {
-      if (inplace)
-       return changed;
-      if (gimple_has_lhs (stmt))
-       {
-         tree lhs = gimple_get_lhs (stmt);
-         maybe_push_res_to_seq (rcode, TREE_TYPE (lhs),
-                                ops, &seq, lhs);
-         gsi_replace_with_seq_vops (gsi, seq);
-       }
-      else
-       gcc_unreachable ();
-    }
-
-  return true;
+  return changed;
 }
 
 /* Fold the statement pointed to by GSI.  In some cases, this function may
Index: gcc/match-builtin.pd
===================================================================
--- gcc/match-builtin.pd        (revision 214675)
+++ gcc/match-builtin.pd        (working copy)
@@ -18,27 +18,103 @@ along with GCC; see the file COPYING3.
 <http://www.gnu.org/licenses/>.  */
 
 
-/* One builtin function to atom.  */
-(simplify
-  (BUILT_IN_SQRT (mult @0 @0))
-  @0)
+/* ???  For math builtins we fail to properly repeat patterns for
+   all FP type kinds (sqrtf, sqrt, sqrtl).  And we fail to provide
+   a mechanism to iterate two ops in lock-step like
+   (for fn1 in sqrt sqrtf sqrtl and fn2 in pow powf powl ...)
+   if we were to do that repetition semi-manually.
+   We could also automagically use the type of the expr to
+   always do mathfn_built_in at code-gen time and always
+   automagically iterate over kinds (but that's bogus for
+   things like (convert (BUILT_IN_SQRT @0)) -> (BUILT_IN_SQRTF @0).  */
+
+
 /* One builtin function to builtin function.  */
 (simplify
   (BUILT_IN_CABS (complex:c @0 real_zerop))
-  (BUILT_IN_FABS @0))
+  (abs @0))
 /* One builtin function to expr.  */
 (simplify
   (BUILT_IN_CABS (complex @0 @0))
-  (mult (BUILT_IN_FABS @0) { build_real (TREE_TYPE (@0), real_value_truncate 
(TYPE_MODE (TREE_TYPE (@0)), dconst_sqrt2 ())); }))
+  (mult (abs @0) { build_real (TREE_TYPE (@0), real_value_truncate (TYPE_MODE 
(TREE_TYPE (@0)), dconst_sqrt2 ())); }))
 /* One nested fn.  */
 (simplify
   (mult:c (BUILT_IN_POW @0 @1) @0)
   (BUILT_IN_POW @0 (PLUS_EXPR @1 { build_one_cst (TREE_TYPE (@1)); })))
+
+/* From fold_builtin_fabs and fold_builtin_abs.  */
+/* Fold a call to fabs, fabsf or fabsl, to abs, labs, llabs or imaxabs.  */
+(for fn in BUILT_IN_FABS BUILT_IN_FABSF BUILT_IN_FABSL BUILT_IN_ABS 
BUILT_IN_LABS BUILT_IN_LLABS BUILT_IN_IMAXABS
+ (simplify
+  (fn @0)
+  (abs @0)))
+
+/* From fold_builtin_pow.  */
+/* Optimize pow(1.0,y) = 1.0.  */
+(simplify
+ (BUILT_IN_POW real_onep@0 @1)
+ @0)
 (simplify
-  (BUILT_IN_POW @0 REAL_CST@1)
-  /* This needs to be conditionalized on flag_unsafe_math_optimizations,
-     but we keep it for now to exercise function re-optimization.
-     It makes gcc.dg/pr43419.c FAIL execution though.  */
-  (if (REAL_VALUES_EQUAL (TREE_REAL_CST (@1), dconsthalf))
-      (BUILT_IN_SQRT @0)))
+ (BUILT_IN_POW @0 REAL_CST@1)
+ (with { REAL_VALUE_TYPE c = TREE_REAL_CST (@1); }
+  /* Optimize pow(x,0.0) = 1.0.  */
+  (if (REAL_VALUES_EQUAL (c, dconst0))
+   { build_real (type, dconst1); })
+  /* Optimize pow(x,1.0) = x.  */
+  (if (REAL_VALUES_EQUAL (c, dconst1))
+   @0)
+  /* Optimize pow(x,-1.0) = 1.0/x.  */
+  (if (REAL_VALUES_EQUAL (c, dconstm1))
+   (rdiv { build_real (type, dconst1); } @0))
+  /* Optimize pow(x,0.5) = sqrt(x).  */
+  (if (flag_unsafe_math_optimizations
+       && REAL_VALUES_EQUAL (c, dconsthalf))
+   (BUILT_IN_SQRT @0))
+  /* Optimize pow(x,1.0/3.0) = cbrt(x).  */
+  (with
+    { const REAL_VALUE_TYPE dconstroot
+        = real_value_truncate (TYPE_MODE (type), dconst_third ()); }
+    (if (flag_unsafe_math_optimizations
+        && REAL_VALUES_EQUAL (c, dconstroot))
+     (BUILT_IN_CBRT @0)))))
+/* Strip sign ops from even integer powers.
+   ???  The code in builtins.c manages to perform this recursively
+   through the whole expression in arg0 of pow.  */
+(for sgnop in abs negate
+  (simplify
+    (BUILT_IN_POW (sgnop @0) REAL_CST@1)
+    (with
+      { 
+       REAL_VALUE_TYPE c = TREE_REAL_CST (@1);
+        HOST_WIDE_INT n = real_to_integer (&c);
+        REAL_VALUE_TYPE cint;
+        real_from_integer (&cint, VOIDmode, n, SIGNED);
+      }
+      (if (real_identical (&c, &cint)
+          && (n & 1) == 0
+          && flag_unsafe_math_optimizations)
+       (BUILT_IN_POW @0 @1)))))
 
+/* From fold_builtin_sqrt.  */
+(if (flag_unsafe_math_optimizations)
+ /* Optimize sqrt(expN(x)) = expN(x*0.5).  */
+ (for expfn in BUILT_IN_EXP10 BUILT_IN_POW10 BUILT_IN_EXP BUILT_IN_EXP2
+  (simplify
+   (BUILT_IN_SQRT (expfn @0))
+   (expfn (mult @0 { build_real (type, dconsthalf); }))))
+ /* Optimize sqrt(Nroot(x)) -> pow(x,1/(2*N)).  */
+ (for rootfn in BUILT_IN_SQRT BUILT_IN_CBRT
+  (simplify
+   (BUILT_IN_SQRT (rootfn @0))
+   (with
+    { REAL_VALUE_TYPE dconstroot;
+      if (BUILTIN_SQRT_P (rootfn)) dconstroot = dconsthalf;
+      else dconstroot = dconst_third ();
+      /* Adjust for the outer root.  */
+      SET_REAL_EXP (&dconstroot, REAL_EXP (&dconstroot) - 1);
+      dconstroot = real_value_truncate (TYPE_MODE (type), dconstroot); }
+    (BUILT_IN_POW @0 { build_real (type, dconstroot); }))))
+ /* Optimize sqrt(pow(x,y)) = pow(|x|,y*0.5).  */
+ (simplify
+  (BUILT_IN_SQRT (BUILT_IN_POW @0 @1))
+  (BUILT_IN_POW (abs @0) (mult @1 { build_real (TREE_TYPE (@1), dconsthalf); 
}))))
Index: gcc/testsuite/gcc.dg/tree-ssa/match-1.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/match-1.c     (revision 214675)
+++ gcc/testsuite/gcc.dg/tree-ssa/match-1.c     (working copy)
@@ -1,38 +0,0 @@
-/* { dg-do compile } */
-/* { dg-options "-O -fdump-tree-forwprop1-details" }  */
-
-double test1 (_Complex double z)
-{
-  __imag z = 0.;
-  return __builtin_cabs (z);
-}
-
-/* { dg-final { scan-tree-dump "gimple_simplified to \[^\n\r\]*fabs" 
"forwprop1" } } */
-
-double test2 (double x)
-{
-  _Complex z = x;
-  __imag z = x;
-  return __builtin_cabs (z);
-}
-
-/* { dg-final { scan-tree-dump "gimple_simplified to \[^\n\r\]*= _\\d\+ \\* 
1.41" "forwprop1" } } */
-
-double test3 (double x)
-{
-  double y = __builtin_pow (x, 5.);
-  return y * x;
-}
-
-/* { dg-final { scan-tree-dump "gimple_simplified to \[^\n\r\]*pow 
\\(x_\\d\+\\(D\\), 6" "forwprop1" } } */
-
-double test4 (double w)
-{
-  double x = w * w;
-  double y = __builtin_pow (x, -0.5);
-  return y * x;
-}
-
-/* { dg-final { scan-tree-dump "gimple_simplified to \[^\n\r\]*= 
w_\\d\+\\(D\\)" "forwprop1" } } */
-
-/* { dg-final { cleanup-tree-dump "forwprop1" } } */
Index: gcc/testsuite/gcc.dg/tree-ssa/match-builtins.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/match-builtins.c      (revision 214675)
+++ gcc/testsuite/gcc.dg/tree-ssa/match-builtins.c      (working copy)
@@ -26,13 +26,4 @@ double test3 (double x)
 
 /* { dg-final { scan-tree-dump "gimple_simplified to \[^\n\r\]*pow 
\\(x_\\d\+\\(D\\), 6" "forwprop1" } } */
 
-double test4 (double w)
-{
-  double x = w * w;
-  double y = __builtin_pow (x, -0.5);
-  return y * x;
-}
-
-/* { dg-final { scan-tree-dump "gimple_simplified to \[^\n\r\]*= 
w_\\d\+\\(D\\)" "forwprop1" } } */
-
 /* { dg-final { cleanup-tree-dump "forwprop1" } } */
Index: gcc/testsuite/gcc.dg/tree-ssa/match-builtins-fast-math.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/match-builtins-fast-math.c    (revision 0)
+++ gcc/testsuite/gcc.dg/tree-ssa/match-builtins-fast-math.c    (working copy)
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O -ffast-math -fdump-tree-forwprop1-details" }  */
+
+double test4 (double w)
+{
+  double x = w * w;
+  double y = __builtin_pow (x, -0.5);
+  return y * x;
+}
+
+/* { dg-final { scan-tree-dump "gimple_simplified to _\\d\+ = ABS_EXPR 
<w_\\d\+\\(D\\)" "forwprop1" } } */
+
+/* { dg-final { cleanup-tree-dump "forwprop1" } } */
Index: gcc/tree-ssa-forwprop.c
===================================================================
--- gcc/tree-ssa-forwprop.c     (revision 214675)
+++ gcc/tree-ssa-forwprop.c     (working copy)
@@ -3672,11 +3672,6 @@ pass_forwprop::execute (function *fun)
                  && gimple_purge_dead_eh_edges (bb))
                cfg_changed = true;
              update_stmt (stmt);
-             if (dump_file && (dump_flags & TDF_DETAILS))
-               {
-                 fprintf (dump_file, "gimple_simplified to ");
-                 print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
-               }
            }
 
          /* Fill up the lattice.  */

Reply via email to