summaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-math-opts.c
diff options
context:
space:
mode:
authorwschmidt <wschmidt@138bc75d-0d04-0410-961f-82ee72b054a4>2011-05-27 19:11:19 +0000
committerwschmidt <wschmidt@138bc75d-0d04-0410-961f-82ee72b054a4>2011-05-27 19:11:19 +0000
commitae43b05e18d3e6498309b0a1cce4fbef7ff73098 (patch)
tree55dafe7cac0581d42b0e70b4b8848b51d77f7d6a /gcc/tree-ssa-math-opts.c
parentb3a2ccd79bdb6fc553e882d03398e989e963a939 (diff)
downloadgcc-ae43b05e18d3e6498309b0a1cce4fbef7ff73098.tar.gz
2011-05-27 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
PR tree-optimization/46728 * tree-ssa-math-opts.c (powi_as_mults_1): Add gimple_set_location. (powi_as_mults): Add gimple_set_location. (build_and_insert_call): New. (gimple_expand_builtin_pow): Add handling for pow(x,y) when y is 0.5, 0.25, 0.75, 1./3., or 1./6. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@174349 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-ssa-math-opts.c')
-rw-r--r--gcc/tree-ssa-math-opts.c149
1 files changed, 146 insertions, 3 deletions
diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c
index 975ce9b1e5f..0e3f738b4cc 100644
--- a/gcc/tree-ssa-math-opts.c
+++ b/gcc/tree-ssa-math-opts.c
@@ -965,6 +965,7 @@ powi_as_mults_1 (gimple_stmt_iterator *gsi, location_t loc, tree type,
}
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_t loc,
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 *gsi, location_t loc,
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
@@ -1033,16 +1063,21 @@ static tree
gimple_expand_builtin_pow (gimple_stmt_iterator *gsi, location_t loc,
tree arg0, tree arg1)
{
- REAL_VALUE_TYPE c, cint;
+ REAL_VALUE_TYPE c, cint, dconst1_4, dconst3_4, dconst1_3, dconst1_6;
HOST_WIDE_INT n;
+ tree type, sqrtfn, cbrtfn, sqrt_arg0, sqrt_sqrt, ssa_target;
+ tree target = NULL_TREE;
+ enum machine_mode mode;
+ bool hw_sqrt_exists;
+ gimple mult_stmt;
/* If the exponent isn't a constant, there's nothing of interest
to be done. */
if (TREE_CODE (arg1) != REAL_CST)
return NULL_TREE;
- /* If the exponent is equivalent to an integer, expand it into
- multiplies when profitable. */
+ /* If the exponent is equivalent to an integer, expand to an optimal
+ multiplication sequence when profitable. */
c = TREE_REAL_CST (arg1);
n = real_to_integer (&c);
real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
@@ -1054,6 +1089,114 @@ gimple_expand_builtin_pow (gimple_stmt_iterator *gsi, location_t loc,
&& 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);
+
+ /* Optimize pow(x,0.5) = sqrt(x). This replacement is always safe
+ unless signed zeros must be maintained. pow(-0,0.5) = +0, while
+ sqrt(-0) = -0. */
+ if (sqrtfn
+ && REAL_VALUES_EQUAL (c, dconsthalf)
+ && !HONOR_SIGNED_ZEROS (mode))
+ return build_and_insert_call (gsi, sqrtfn, arg0, &target, loc);
+
+ /* Optimize pow(x,0.25) = sqrt(sqrt(x)). Assume on most machines that
+ a builtin sqrt instruction is smaller than a call to pow with 0.25,
+ so do this optimization even if -Os. Don't do this optimization
+ if we don't have a hardware sqrt insn. */
+ 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 (flag_unsafe_math_optimizations
+ && sqrtfn
+ && REAL_VALUES_EQUAL (c, dconst1_4)
+ && hw_sqrt_exists)
+ {
+ /* 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)) unless we are
+ optimizing for space. Don't do this optimization if we don't have
+ a hardware sqrt insn. */
+ real_from_integer (&dconst3_4, VOIDmode, 3, 0, 0);
+ SET_REAL_EXP (&dconst3_4, REAL_EXP (&dconst3_4) - 2);
+
+ if (flag_unsafe_math_optimizations
+ && sqrtfn
+ && optimize_function_for_speed_p (cfun)
+ && REAL_VALUES_EQUAL (c, dconst3_4)
+ && hw_sqrt_exists)
+ {
+ /* 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). This requires unsafe math
+ optimizations since 1./3. is not exactly representable. If x
+ is negative and finite, the correct value of pow(x,1./3.) is
+ a NaN with the "invalid" exception raised, because the value
+ of 1./3. actually has an even denominator. The correct value
+ of cbrt(x) is a negative real value. */
+ cbrtfn = mathfn_built_in (type, BUILT_IN_CBRT);
+ dconst1_3 = real_value_truncate (mode, dconst_third ());
+
+ 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)
+ && REAL_VALUES_EQUAL (c, dconst1_3))
+ return build_and_insert_call (gsi, cbrtfn, arg0, &target, loc);
+
+ /* Optimize pow(x,1./6.) = cbrt(sqrt(x)). Don't do this optimization
+ if we don't have a hardware sqrt insn. */
+ dconst1_6 = dconst1_3;
+ SET_REAL_EXP (&dconst1_6, REAL_EXP (&dconst1_6) - 1);
+
+ 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)
+ && optimize_function_for_speed_p (cfun)
+ && hw_sqrt_exists
+ && REAL_VALUES_EQUAL (c, dconst1_6))
+ {
+ /* 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);
+ }
+
return NULL_TREE;
}