From ba869341b42aefb6c58d513c0cabeaed22091bf2 Mon Sep 17 00:00:00 2001 From: Bill Schmidt Date: Fri, 27 May 2011 19:11:19 +0000 Subject: [PATCH] re PR tree-optimization/46728 (GCC does not generate fmadd for pow (x, 0.75)+y on powerpc) 2011-05-27 Bill Schmidt 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. From-SVN: r174349 --- gcc/ChangeLog | 9 +++ gcc/tree-ssa-math-opts.c | 149 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 155 insertions(+), 3 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 53f0b1c3a20..a1ae80c59eb 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2011-05-27 Bill Schmidt + + 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. + 2011-05-27 Alexander Monakov * doc/contrib.texi: Update copyright years. 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; } -- 2.30.2