{
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 && SCALAR_FLOAT_TYPE_P (TREE_TYPE (val)));
+
+ /* 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;
+}
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);
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))
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)