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.  */
