Index: gcc/tree-ssa-math-opts.c
===================================================================
--- gcc/tree-ssa-math-opts.c	(revision 174199)
+++ gcc/tree-ssa-math-opts.c	(working copy)
@@ -965,6 +965,7 @@ powi_as_mults_1 (gimple_stmt_iterator *gsi, locati
     }
 
   mult_stmt = gimple_build_assign_with_ops (MULT_EXPR, ssa_target, op0, op1);
+  gimple_set_location (mult_stmt, loc);
   gsi_insert_before (gsi, mult_stmt, GSI_SAME_STMT);
 
   return ssa_target;
@@ -999,6 +1000,7 @@ powi_as_mults (gimple_stmt_iterator *gsi, location
   div_stmt = gimple_build_assign_with_ops (RDIV_EXPR, target, 
 					   build_real (type, dconst1),
 					   result);
+  gimple_set_location (div_stmt, loc);
   gsi_insert_before (gsi, div_stmt, GSI_SAME_STMT);
 
   return target;
@@ -1024,6 +1026,34 @@ gimple_expand_builtin_powi (gimple_stmt_iterator *
   return NULL_TREE;
 }
 
+/* Build a gimple call statement that calls FN with argument ARG.
+   Set the lhs of the call statement to a fresh SSA name for
+   variable VAR.  If VAR is NULL, first allocate it.  Insert the
+   statement prior to GSI's current position, and return the fresh
+   SSA name.  */
+
+static tree
+build_and_insert_call (gimple_stmt_iterator *gsi, tree fn, tree arg,
+		       tree *var, location_t loc)
+{
+  gimple call_stmt;
+  tree ssa_target;
+
+  if (!*var)
+    {
+      *var = create_tmp_var (TREE_TYPE (arg), "powroot");
+      add_referenced_var (*var);
+    }
+
+  call_stmt = gimple_build_call (fn, 1, arg);
+  ssa_target = make_ssa_name (*var, NULL);
+  gimple_set_lhs (call_stmt, ssa_target);
+  gimple_set_location (call_stmt, loc);
+  gsi_insert_before (gsi, call_stmt, GSI_SAME_STMT);
+
+  return ssa_target;
+}
+
 /* ARG0 and ARG1 are the two arguments to a pow builtin call in GSI
    with location info LOC.  If possible, create an equivalent and
    less expensive sequence of statements prior to GSI, and return an
@@ -1035,6 +1065,8 @@ gimple_expand_builtin_pow (gimple_stmt_iterator *g
 {
   REAL_VALUE_TYPE c, cint;
   HOST_WIDE_INT n;
+  tree type, sqrtfn, target = NULL_TREE;
+  enum machine_mode mode;
 
   /* If the exponent isn't a constant, there's nothing of interest
      to be done.  */
@@ -1054,6 +1086,108 @@ gimple_expand_builtin_pow (gimple_stmt_iterator *g
 	      && powi_cost (n) <= POWI_MAX_MULTS)))
     return gimple_expand_builtin_powi (gsi, loc, arg0, n);
 
+  /* Attempt various optimizations using sqrt and cbrt.  */
+  type = TREE_TYPE (arg0);
+  mode = TYPE_MODE (type);
+  sqrtfn = mathfn_built_in (type, BUILT_IN_SQRT);
+
+  if (flag_unsafe_math_optimizations && sqrtfn != NULL_TREE)
+    {
+      REAL_VALUE_TYPE dconst1_4, dconst3_4;
+      tree cbrtfn;
+      bool hw_sqrt_exists;
+
+      /* Optimize pow(x,0.5) = sqrt(x).  */
+      if (REAL_VALUES_EQUAL (c, dconsthalf))
+	return build_and_insert_call (gsi, sqrtfn, arg0, &target, loc);
+
+      /* Optimize pow(x,0.25) = sqrt(sqrt(x)).  */
+      dconst1_4 = dconst1;
+      SET_REAL_EXP (&dconst1_4, REAL_EXP (&dconst1_4) - 2);
+      hw_sqrt_exists = optab_handler(sqrt_optab, mode) != CODE_FOR_nothing;
+
+      if (REAL_VALUES_EQUAL (c, dconst1_4) && hw_sqrt_exists)
+	{
+	  tree sqrt_arg0;
+
+	  /* sqrt(x)  */
+	  sqrt_arg0 = build_and_insert_call (gsi, sqrtfn, arg0, &target, loc);
+
+	  /* sqrt(sqrt(x))  */
+	  return build_and_insert_call (gsi, sqrtfn, sqrt_arg0,	&target, loc);
+	}
+      
+      /* Optimize pow(x,0.75) = sqrt(x) * sqrt(sqrt(x)).  */
+      real_from_integer (&dconst3_4, VOIDmode, 3, 0, 0);
+      SET_REAL_EXP (&dconst3_4, REAL_EXP (&dconst3_4) - 2);
+
+      if (optimize_function_for_speed_p (cfun)
+	  && !TREE_SIDE_EFFECTS (arg0) /* TODO: is this needed?  */
+	  && REAL_VALUES_EQUAL (c, dconst3_4)
+	  && hw_sqrt_exists)
+	{
+	  tree sqrt_arg0, sqrt_sqrt, ssa_target;
+	  gimple mult_stmt;
+
+	  /* sqrt(x)  */
+	  sqrt_arg0 = build_and_insert_call (gsi, sqrtfn, arg0, &target, loc);
+
+	  /* sqrt(sqrt(x))  */
+	  sqrt_sqrt = build_and_insert_call (gsi, sqrtfn, sqrt_arg0,
+					     &target, loc);
+	  /* sqrt(x) * sqrt(sqrt(x))  */
+	  ssa_target = make_ssa_name (target, NULL);
+	  mult_stmt = gimple_build_assign_with_ops (MULT_EXPR, ssa_target,
+						    sqrt_arg0, sqrt_sqrt);
+	  gimple_set_location (mult_stmt, loc);
+	  gsi_insert_before (gsi, mult_stmt, GSI_SAME_STMT);
+
+	  return ssa_target;
+	}
+
+      /* Optimize pow(x,1./3.) = cbrt(x), and pow(x,1./6.) = cbrt(sqrt(x)).  */
+      cbrtfn = mathfn_built_in (type, BUILT_IN_CBRT);
+
+      if (cbrtfn != NULL_TREE)
+	{
+	  /* pow(x,1./3.) => cbrt(x).  */
+	  const REAL_VALUE_TYPE dconst1_3
+	    = real_value_truncate (mode, dconst_third ());
+
+	  if (REAL_VALUES_EQUAL (c, dconst1_3))
+	    return build_and_insert_call (gsi, cbrtfn, arg0, &target, loc);
+
+	  /* pow(x,1./6.) => cbrt(sqrt(x)).  */
+	  if (optimize_function_for_speed_p (cfun) && hw_sqrt_exists)
+	    {
+	      REAL_VALUE_TYPE dconst1_6 = dconst1_3;
+	      SET_REAL_EXP (&dconst1_6, REAL_EXP (&dconst1_6) - 1);
+
+	      if (REAL_VALUES_EQUAL (c, dconst1_6))
+		{
+		  tree sqrt_arg0;
+
+		  /* sqrt(x)  */
+		  sqrt_arg0 = build_and_insert_call (gsi, sqrtfn, arg0,
+						     &target, loc);
+		  /* cbrt(sqrt(x))  */
+		  return build_and_insert_call (gsi, cbrtfn, sqrt_arg0,
+						&target, loc);
+		}
+	    }
+	}
+    }
+
+  /* We allow one transformation when flag_unsafe_math_optimizations is
+     false.  Replacing pow(x,0.5) with sqrt(x) is safe, provided signed
+     zeros must not be maintained.  For x = -0, the former produces +0,
+     and the latter produces -0.  */
+  else if (sqrtfn != NULL_TREE
+	   && !HONOR_SIGNED_ZEROS (mode)
+	   && REAL_VALUES_EQUAL (c, dconsthalf))
+
+    return build_and_insert_call (gsi, sqrtfn, arg0, &target, loc);
+
   return NULL_TREE;
 }
 
