Index: gcc/tree-ssa-math-opts.c
===================================================================
--- gcc/tree-ssa-math-opts.c	(revision 174708)
+++ gcc/tree-ssa-math-opts.c	(working copy)
@@ -1172,13 +1172,7 @@ gimple_expand_builtin_pow (gimple_stmt_iterator *g
 
   if (flag_unsafe_math_optimizations
       && cbrtfn
-      /* FIXME: The following line was originally
-	 && (tree_expr_nonnegative_p (arg0) || !HONOR_NANS (mode)),
-	 but since arg0 is a gimple value, the first predicate
-	 will always return false.  It needs to be replaced with a
-	 call to a similar gimple_val_nonnegative_p function to be
-         added in gimple-fold.c.  */
-      && !HONOR_NANS (mode)
+      && (gimple_val_nonnegative_real_p (arg0) || !HONOR_NANS (mode))
       && REAL_VALUES_EQUAL (c, dconst1_3))
     return build_and_insert_call (gsi, loc, &target, cbrtfn, arg0);
   
@@ -1190,13 +1184,7 @@ gimple_expand_builtin_pow (gimple_stmt_iterator *g
   if (flag_unsafe_math_optimizations
       && sqrtfn
       && cbrtfn
-      /* FIXME: The following line was originally
-	 && (tree_expr_nonnegative_p (arg0) || !HONOR_NANS (mode)),
-	 but since arg0 is a gimple value, the first predicate
-	 will always return false.  It needs to be replaced with a
-	 call to a similar gimple_val_nonnegative_p function to be
-         added in gimple-fold.c.  */
-      && !HONOR_NANS (mode)
+      && (gimple_val_nonnegative_real_p (arg0) || !HONOR_NANS (mode))
       && optimize_function_for_speed_p (cfun)
       && hw_sqrt_exists
       && REAL_VALUES_EQUAL (c, dconst1_6))
@@ -1270,13 +1258,7 @@ gimple_expand_builtin_pow (gimple_stmt_iterator *g
 
   if (flag_unsafe_math_optimizations
       && cbrtfn
-      /* FIXME: The following line was originally
-	 && (tree_expr_nonnegative_p (arg0) || !HONOR_NANS (mode)),
-	 but since arg0 is a gimple value, the first predicate
-	 will always return false.  It needs to be replaced with a
-	 call to a similar gimple_val_nonnegative_p function to be
-         added in gimple-fold.c.  */
-      && !HONOR_NANS (mode)
+      && (gimple_val_nonnegative_real_p (arg0) || !HONOR_NANS (mode))
       && real_identical (&c2, &c)
       && optimize_function_for_speed_p (cfun)
       && powi_cost (n / 3) <= POWI_MAX_MULTS)
Index: gcc/gimple-fold.c
===================================================================
--- gcc/gimple-fold.c	(revision 174708)
+++ gcc/gimple-fold.c	(working copy)
@@ -3433,3 +3433,134 @@ fold_const_aggregate_ref (tree t)
 {
   return fold_const_aggregate_ref_1 (t, NULL);
 }
+
+/* Return true iff VAL is a gimple expression that is known to be
+   non-negative.  Restricted to floating-point inputs.  */
+
+bool
+gimple_val_nonnegative_real_p (tree val)
+{
+  gimple def_stmt;
+
+  gcc_assert (val && (TREE_CODE (TREE_TYPE (val)) == REAL_TYPE));
+
+  /* Use existing logic for non-gimple trees.  */
+  if (tree_expr_nonnegative_p (val))
+    return true;
+
+  if (TREE_CODE (val) != SSA_NAME)
+    return false;
+
+  /* Currently we look only at the immediately defining statement
+     to make this determination, since recursion on defining 
+     statements of operands can lead to quadratic behavior in the
+     worst case.  This is expected to catch almost all occurrences
+     in practice.  It would be possible to implement limited-depth
+     recursion if important cases are lost.  Alternatively, passes
+     that need this information (such as the pow/powi lowering code
+     in the cse_sincos pass) could be revised to provide it through
+     dataflow propagation.  */
+
+  def_stmt = SSA_NAME_DEF_STMT (val);
+
+  if (is_gimple_assign (def_stmt))
+    {
+      tree op0, op1;
+
+      /* See fold-const.c:tree_expr_nonnegative_p for additional
+	 cases that could be handled with recursion.  */
+
+      switch (gimple_assign_rhs_code (def_stmt))
+	{
+	case ABS_EXPR:
+	  /* Always true for floating-point operands.  */
+	  return true;
+
+	case MULT_EXPR:
+	  /* True if the two operands are identical (since we are
+	     restricted to floating-point inputs).  */
+	  op0 = gimple_assign_rhs1 (def_stmt);
+	  op1 = gimple_assign_rhs2 (def_stmt);
+
+	  if (op0 == op1
+	      || operand_equal_p (op0, op1, 0))
+	    return true;
+
+	default:
+	  return false;
+	}
+    }
+  else if (is_gimple_call (def_stmt))
+    {
+      tree fndecl = gimple_call_fndecl (def_stmt);
+      if (fndecl
+	  && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+	{
+	  tree arg1;
+
+	  switch (DECL_FUNCTION_CODE (fndecl))
+	    {
+	    CASE_FLT_FN (BUILT_IN_ACOS):
+	    CASE_FLT_FN (BUILT_IN_ACOSH):
+	    CASE_FLT_FN (BUILT_IN_CABS):
+	    CASE_FLT_FN (BUILT_IN_COSH):
+	    CASE_FLT_FN (BUILT_IN_ERFC):
+	    CASE_FLT_FN (BUILT_IN_EXP):
+	    CASE_FLT_FN (BUILT_IN_EXP10):
+	    CASE_FLT_FN (BUILT_IN_EXP2):
+	    CASE_FLT_FN (BUILT_IN_FABS):
+	    CASE_FLT_FN (BUILT_IN_FDIM):
+	    CASE_FLT_FN (BUILT_IN_HYPOT):
+	    CASE_FLT_FN (BUILT_IN_POW10):
+	      return true;
+
+	    CASE_FLT_FN (BUILT_IN_SQRT):
+	      /* sqrt(-0.0) is -0.0, and sqrt is not defined over other
+		 nonnegative inputs.  */
+	      if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (val))))
+		return true;
+
+	      break;
+
+	    CASE_FLT_FN (BUILT_IN_POWI):
+	      /* True if the second argument is an even integer.  */
+	      arg1 = gimple_call_arg (def_stmt, 1);
+
+	      if (TREE_CODE (arg1) == INTEGER_CST
+		  && (TREE_INT_CST_LOW (arg1) & 1) == 0)
+		return true;
+
+	      break;
+	      
+	    CASE_FLT_FN (BUILT_IN_POW):
+	      /* True if the second argument is an even integer-valued
+		 real.  */
+	      arg1 = gimple_call_arg (def_stmt, 1);
+
+	      if (TREE_CODE (arg1) == REAL_CST)
+		{
+		  REAL_VALUE_TYPE c;
+		  HOST_WIDE_INT n;
+
+		  c = TREE_REAL_CST (arg1);
+		  n = real_to_integer (&c);
+
+		  if ((n & 1) == 0)
+		    {
+		      REAL_VALUE_TYPE cint;
+		      real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
+		      if (real_identical (&c, &cint))
+			return true;
+		    }
+		}
+
+	      break;
+
+	    default:
+	      return false;
+	    }
+	}
+    }
+
+  return false;
+}
Index: gcc/gimple.h
===================================================================
--- gcc/gimple.h	(revision 174708)
+++ gcc/gimple.h	(working copy)
@@ -4988,4 +4988,5 @@ extern tree maybe_fold_and_comparisons (enum tree_
 extern tree maybe_fold_or_comparisons (enum tree_code, tree, tree,
 				       enum tree_code, tree, tree);
 
+bool gimple_val_nonnegative_real_p (tree);
 #endif  /* GCC_GIMPLE_H */
