On Wed, Oct 14, 2015 at 6:50 PM, Richard Sandiford
<[email protected]> wrote:
> This patch fixes some fallout from my patch to move the sqrt and cbrt
> folding rules to match.pd. The rules included canonicalisations like:
>
> sqrt(sqrt(x))->pow(x,1/4)
>
> which in the original code was only ever done at the generic level.
> My patch meant that we'd do it whenever we tried to fold a gimple
> statement, and eventually it would win over the sincos optimisation
> that replaces pow(x,1/4) with sqrt(sqrt(x)).
>
> Following a suggestion from Richard B, the patch adds a new
> PROP_gimple_* flag to say whether fp routines have been optimised
> for the target. If so, match.pd should only transform calls to math
> functions if the result is actually an optimisation, not just an
> IL simplification or canonicalisation. The question then of course
> is: which rules are which? I've added block comments that describe
> the criteria I was using.
>
> A slight wart is that we need to use the cfun global to access
> the PROP_gimple_* flag; there's no local function pointer available.
>
> Bootstrapped & regression-tested on x86_64-linux-gnu. Also tested
> on powerc64-linux-gnu. OK to install?
Ok with the typo below fixed.
Thanks,
Richard.
> Thanks,
> Richard
>
>
> gcc/
> PR tree-optimization/67945
> * tree-pass.h (PROP_gimple_opt_math): New property flag.
> * generic-match-head.c (canonicalize_math_p): New function.
> * gimple-match-head.c: Include tree-pass.h.
> (canonicalize_math_p): New function.
> * match.pd: Group math built-in rules into simplifications
> and canonicalizations. Guard the latter with canonicalize_math_p.
> * tree-ssa-math-opts.c (pass_data_cse_sincos): Provide the
> PROP_gimple_opt_math property.
>
> diff --git a/gcc/generic-match-head.c b/gcc/generic-match-head.c
> index 0a7038d..94135b3 100644
> --- a/gcc/generic-match-head.c
> +++ b/gcc/generic-match-head.c
> @@ -73,3 +73,12 @@ single_use (tree t ATTRIBUTE_UNUSED)
> {
> return true;
> }
> +
> +/* Return true if math operations should be canonicalized,
> + e.g. sqrt(sqrt(x)) -> pow(x, 0.25). */
> +
> +static inline bool
> +canonicalize_math_p ()
> +{
> + return true;
> +}
> diff --git a/gcc/gimple-match-head.c b/gcc/gimple-match-head.c
> index cab77a4..f29e97f 100644
> --- a/gcc/gimple-match-head.c
> +++ b/gcc/gimple-match-head.c
> @@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see
> #include "target.h"
> #include "cgraph.h"
> #include "gimple-match.h"
> +#include "tree-pass.h"
>
>
> /* Forward declarations of the private auto-generated matchers.
> @@ -827,3 +828,12 @@ single_use (tree t)
> {
> return TREE_CODE (t) != SSA_NAME || has_zero_uses (t) || has_single_use
> (t);
> }
> +
> +/* Return true if math operations should be canonicalized,
> + e.g. sqrt(sqrt(x)) -> pow(x, 0.25). */
> +
> +static inline bool
> +canonicalize_math_p ()
> +{
> + return !cfun || (cfun->curr_properties & PROP_gimple_opt_math) == 0;
> +}
> diff --git a/gcc/match.pd b/gcc/match.pd
> index 655c9ff..d319441 100644
> --- a/gcc/match.pd
> +++ b/gcc/match.pd
> @@ -2134,11 +2134,25 @@ along with GCC; see the file COPYING3. If not see
> clearly less optimal and which we'll transform again in forwprop. */
>
>
> -/* Simplification of math builtins. */
> +/* Simplification of math builtins. These rules must all be optimizations
> + as well as IL simplifications. If there is a possibility that the new
> + form could be a pessimization, the rule should go in the canonicalization
> + section that follows this one.
>
> -/* fold_builtin_logarithm */
> -(if (flag_unsafe_math_optimizations)
> + Rules can generally go in this section if they satisfy one of
> + the following:
> +
> + - the rule describes an identity
> +
> + - the rule replaces calls with something as simple as addition or
> + multiplication
> +
> + - the rule contains unary calls only and simplifies the surrounding
> + arithmetic. (The idea here is to exclude non-unary calls in which
> + one operand is constant and in which the call is known to be cheap
> + when the operand has that value.) */
>
> +(if (flag_unsafe_math_optimizations)
> /* Simplify sqrt(x) * sqrt(x) -> x. */
> (simplify
> (mult (SQRT@1 @0) @1)
> @@ -2151,63 +2165,12 @@ along with GCC; see the file COPYING3. If not see
> (mult (root:s @0) (root:s @1))
> (root (mult @0 @1))))
>
> - /* Simplify pow(x,y) * pow(x,z) -> pow(x,y+z). */
> - (simplify
> - (mult (POW:s @0 @1) (POW:s @0 @2))
> - (POW @0 (plus @1 @2)))
> -
> - /* Simplify pow(x,y) * pow(z,y) -> pow(x*z,y). */
> - (simplify
> - (mult (POW:s @0 @1) (POW:s @2 @1))
> - (POW (mult @0 @2) @1))
> -
> /* Simplify expN(x) * expN(y) -> expN(x+y). */
> (for exps (EXP EXP2 EXP10 POW10)
> (simplify
> (mult (exps:s @0) (exps:s @1))
> (exps (plus @0 @1))))
>
> - /* Simplify tan(x) * cos(x) -> sin(x). */
> - (simplify
> - (mult:c (TAN:s @0) (COS:s @0))
> - (SIN @0))
> -
> - /* Simplify x * pow(x,c) -> pow(x,c+1). */
> - (simplify
> - (mult @0 (POW:s @0 REAL_CST@1))
> - (if (!TREE_OVERFLOW (@1))
> - (POW @0 (plus @1 { build_one_cst (type); }))))
> -
> - /* Simplify sin(x) / cos(x) -> tan(x). */
> - (simplify
> - (rdiv (SIN:s @0) (COS:s @0))
> - (TAN @0))
> -
> - /* Simplify cos(x) / sin(x) -> 1 / tan(x). */
> - (simplify
> - (rdiv (COS:s @0) (SIN:s @0))
> - (rdiv { build_one_cst (type); } (TAN @0)))
> -
> - /* Simplify sin(x) / tan(x) -> cos(x). */
> - (simplify
> - (rdiv (SIN:s @0) (TAN:s @0))
> - (if (! HONOR_NANS (@0)
> - && ! HONOR_INFINITIES (@0))
> - (cos @0)))
> -
> - /* Simplify tan(x) / sin(x) -> 1.0 / cos(x). */
> - (simplify
> - (rdiv (TAN:s @0) (SIN:s @0))
> - (if (! HONOR_NANS (@0)
> - && ! HONOR_INFINITIES (@0))
> - (rdiv { build_one_cst (type); } (COS @0))))
> -
> - /* Simplify pow(x,c) / x -> pow(x,c-1). */
> - (simplify
> - (rdiv (POW:s @0 REAL_CST@1) @0)
> - (if (!TREE_OVERFLOW (@1))
> - (POW @0 (minus @1 { build_one_cst (type); }))))
> -
> /* Simplify a/root(b/c) into a*root(c/b). */
> (for root (SQRT CBRT)
> (simplify
> @@ -2220,17 +2183,13 @@ along with GCC; see the file COPYING3. If not see
> (rdiv @0 (exps:s @1))
> (mult @0 (exps (negate @1)))))
>
> - /* Simplify x / pow (y,z) -> x * pow(y,-z). */
> - (simplify
> - (rdiv @0 (POW:s @1 @2))
> - (mult @0 (POW @1 (negate @2))))
> -
> /* Special case, optimize logN(expN(x)) = x. */
> (for logs (LOG LOG2 LOG10 LOG10)
> exps (EXP EXP2 EXP10 POW10)
> (simplify
> (logs (exps @0))
> @0))
> +
> /* Optimize logN(func()) for various exponential functions. We
> want to determine the value "x" and the power "exponent" in
> order to transform logN(x**exponent) into exponent*logN(x). */
> @@ -2243,16 +2202,16 @@ along with GCC; see the file COPYING3. If not see
> switch (exps)
> {
> CASE_FLT_FN (BUILT_IN_EXP):
> - /* Prepare to do logN(exp(exponent) -> exponent*logN(e). */
> + /* Prepare to do logN(exp(exponent)) -> exponent*logN(e). */
> x = build_real_truncate (type, dconst_e ());
> break;
> CASE_FLT_FN (BUILT_IN_EXP2):
> - /* Prepare to do logN(exp2(exponent) -> exponent*logN(2). */
> + /* Prepare to do logN(exp2(exponent)) -> exponent*logN(2). */
> x = build_real (type, dconst2);
> break;
> CASE_FLT_FN (BUILT_IN_EXP10):
> CASE_FLT_FN (BUILT_IN_POW10):
> - /* Prepare to do logN(exp10(exponent) -> exponent*logN(10). */
> + /* Prepare to do logN(exp10(exponent)) -> exponent*logN(10). */
> {
> REAL_VALUE_TYPE dconst10;
> real_from_integer (&dconst10, VOIDmode, 10, SIGNED);
> @@ -2264,6 +2223,7 @@ along with GCC; see the file COPYING3. If not see
> }
> }
> (mult (logs { x; }) @0))))
> +
> (for logs (LOG LOG
> LOG2 LOG2
> LOG10 LOG10)
> @@ -2275,11 +2235,11 @@ along with GCC; see the file COPYING3. If not see
> switch (exps)
> {
> CASE_FLT_FN (BUILT_IN_SQRT):
> - /* Prepare to do logN(sqrt(x) -> 0.5*logN(x). */
> + /* Prepare to do logN(sqrt(x)) -> 0.5*logN(x). */
> x = build_real (type, dconsthalf);
> break;
> CASE_FLT_FN (BUILT_IN_CBRT):
> - /* Prepare to do logN(cbrt(x) -> (1/3)*logN(x). */
> + /* Prepare to do logN(cbrt(x)) -> (1/3)*logN(x). */
> x = build_real_truncate (type, dconst_third ());
> break;
> default:
> @@ -2287,12 +2247,118 @@ along with GCC; see the file COPYING3. If not see
> }
> }
> (mult { x; } (logs @0)))))
> - /* logN(pow(x,exponent) -> exponent*logN(x). */
> +
> + /* logN(pow(x,exponent)) -> exponent*logN(x). */
> (for logs (LOG LOG2 LOG10)
> pows (POW)
> (simplify
> (logs (pows @0 @1))
> - (mult @1 (logs @0)))))
> + (mult @1 (logs @0))))
> +
> + (for sqrts (SQRT)
> + cbrts (CBRT)
> + exps (EXP EXP2 EXP10 POW10)
> + /* sqrt(expN(x)) -> expN(x*0.5). */
> + (simplify
> + (sqrts (exps @0))
> + (exps (mult @0 { build_real (type, dconsthalf); })))
> + /* cbrt(expN(x)) -> expN(x/3). */
> + (simplify
> + (cbrts (exps @0))
> + (exps (mult @0 { build_real_truncate (type, dconst_third ()); })))))
> +
> +/* Canonicalization of sequences of math builtins. These rules represent
> + IL simplifications but are not necessarily optimizations.
> +
> + The sincos pass is responsible for picking "optimal" implementations
> + ef math builtins, which may be more complicated and can sometimes go
of math builtins
> + the other way, e.g. converting pow into a sequence of sqrts.
> + We only want to do these canonicalizations before the pass has run. */
> +
> +(if (flag_unsafe_math_optimizations && canonicalize_math_p ())
> + /* Simplify tan(x) * cos(x) -> sin(x). */
> + (simplify
> + (mult:c (TAN:s @0) (COS:s @0))
> + (SIN @0))
> +
> + /* Simplify x * pow(x,c) -> pow(x,c+1). */
> + (simplify
> + (mult @0 (POW:s @0 REAL_CST@1))
> + (if (!TREE_OVERFLOW (@1))
> + (POW @0 (plus @1 { build_one_cst (type); }))))
> +
> + /* Simplify sin(x) / cos(x) -> tan(x). */
> + (simplify
> + (rdiv (SIN:s @0) (COS:s @0))
> + (TAN @0))
> +
> + /* Simplify cos(x) / sin(x) -> 1 / tan(x). */
> + (simplify
> + (rdiv (COS:s @0) (SIN:s @0))
> + (rdiv { build_one_cst (type); } (TAN @0)))
> +
> + /* Simplify sin(x) / tan(x) -> cos(x). */
> + (simplify
> + (rdiv (SIN:s @0) (TAN:s @0))
> + (if (! HONOR_NANS (@0)
> + && ! HONOR_INFINITIES (@0))
> + (cos @0)))
> +
> + /* Simplify tan(x) / sin(x) -> 1.0 / cos(x). */
> + (simplify
> + (rdiv (TAN:s @0) (SIN:s @0))
> + (if (! HONOR_NANS (@0)
> + && ! HONOR_INFINITIES (@0))
> + (rdiv { build_one_cst (type); } (COS @0))))
> +
> + /* Simplify pow(x,y) * pow(x,z) -> pow(x,y+z). */
> + (simplify
> + (mult (POW:s @0 @1) (POW:s @0 @2))
> + (POW @0 (plus @1 @2)))
> +
> + /* Simplify pow(x,y) * pow(z,y) -> pow(x*z,y). */
> + (simplify
> + (mult (POW:s @0 @1) (POW:s @2 @1))
> + (POW (mult @0 @2) @1))
> +
> + /* Simplify pow(x,c) / x -> pow(x,c-1). */
> + (simplify
> + (rdiv (POW:s @0 REAL_CST@1) @0)
> + (if (!TREE_OVERFLOW (@1))
> + (POW @0 (minus @1 { build_one_cst (type); }))))
> +
> + /* Simplify x / pow (y,z) -> x * pow(y,-z). */
> + (simplify
> + (rdiv @0 (POW:s @1 @2))
> + (mult @0 (POW @1 (negate @2))))
> +
> + (for sqrts (SQRT)
> + cbrts (CBRT)
> + pows (POW)
> + /* sqrt(sqrt(x)) -> pow(x,1/4). */
> + (simplify
> + (sqrts (sqrts @0))
> + (pows @0 { build_real (type, dconst_quarter ()); }))
> + /* sqrt(cbrt(x)) -> pow(x,1/6). */
> + (simplify
> + (sqrts (cbrts @0))
> + (pows @0 { build_real_truncate (type, dconst_sixth ()); }))
> + /* cbrt(sqrt(x)) -> pow(x,1/6). */
> + (simplify
> + (cbrts (sqrts @0))
> + (pows @0 { build_real_truncate (type, dconst_sixth ()); }))
> + /* cbrt(cbrt(x)) -> pow(x,1/9), iff x is nonnegative. */
> + (simplify
> + (cbrts (cbrts tree_expr_nonnegative_p@0))
> + (pows @0 { build_real_truncate (type, dconst_ninth ()); }))
> + /* sqrt(pow(x,y)) -> pow(|x|,y*0.5). */
> + (simplify
> + (sqrts (pows @0 @1))
> + (pows (abs @0) (mult @1 { build_real (type, dconsthalf); })))
> + /* cbrt(pow(x,y)) -> pow(x,y/3), iff x is nonnegative. */
> + (simplify
> + (cbrts (pows tree_expr_nonnegative_p@0 @1))
> + (pows @0 (mult @1 { build_real_truncate (type, dconst_third ()); })))))
>
> /* Narrowing of arithmetic and logical operations.
>
> @@ -2364,44 +2430,3 @@ along with GCC; see the file COPYING3. If not see
> (with { tree utype = unsigned_type_for (TREE_TYPE (@0)); }
> (convert (bit_and (op (convert:utype @0) (convert:utype @1))
> (convert:utype @4))))))))
> -
> -(if (flag_unsafe_math_optimizations)
> - (for sqrts (SQRT)
> - cbrts (CBRT)
> - exps (EXP EXP2 EXP10 POW10)
> - /* sqrt(expN(x)) -> expN(x*0.5). */
> - (simplify
> - (sqrts (exps @0))
> - (exps (mult @0 { build_real (type, dconsthalf); })))
> - /* cbrt(expN(x)) -> expN(x/3). */
> - (simplify
> - (cbrts (exps @0))
> - (exps (mult @0 { build_real_truncate (type, dconst_third ()); }))))
> -
> - (for sqrts (SQRT)
> - cbrts (CBRT)
> - pows (POW)
> - /* sqrt(sqrt(x)) -> pow(x,1/4). */
> - (simplify
> - (sqrts (sqrts @0))
> - (pows @0 { build_real (type, dconst_quarter ()); }))
> - /* sqrt(cbrt(x)) -> pow(x,1/6). */
> - (simplify
> - (sqrts (cbrts @0))
> - (pows @0 { build_real_truncate (type, dconst_sixth ()); }))
> - /* cbrt(sqrt(x)) -> pow(x,1/6). */
> - (simplify
> - (cbrts (sqrts @0))
> - (pows @0 { build_real_truncate (type, dconst_sixth ()); }))
> - /* cbrt(cbrt(x)) -> pow(x,1/9), iff x is nonnegative. */
> - (simplify
> - (cbrts (cbrts tree_expr_nonnegative_p@0))
> - (pows @0 { build_real_truncate (type, dconst_ninth ()); }))
> - /* sqrt(pow(x,y)) -> pow(|x|,y*0.5). */
> - (simplify
> - (sqrts (pows @0 @1))
> - (pows (abs @0) (mult @1 { build_real (type, dconsthalf); })))
> - /* cbrt(pow(x,y)) -> pow(x,y/3), iff x is nonnegative. */
> - (simplify
> - (cbrts (pows tree_expr_nonnegative_p@0 @1))
> - (pows @0 (mult @1 { build_real_truncate (type, dconst_third ()); })))))
> diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
> index 91f63a8..c37e4b2 100644
> --- a/gcc/tree-pass.h
> +++ b/gcc/tree-pass.h
> @@ -222,6 +222,10 @@ protected:
> #define PROP_gimple_lvec (1 << 12) /* lowered vector */
> #define PROP_gimple_eomp (1 << 13) /* no OpenMP directives */
> #define PROP_gimple_lva (1 << 14) /* No va_arg internal
> function. */
> +#define PROP_gimple_opt_math (1 << 15) /* Disable canonicalization
> + of math functions; the
> + current choices have
> + been optimized. */
>
> #define PROP_trees \
> (PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh | PROP_gimple_lomp)
> diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c
> index 39c027c..42fe312 100644
> --- a/gcc/tree-ssa-math-opts.c
> +++ b/gcc/tree-ssa-math-opts.c
> @@ -1689,7 +1689,7 @@ const pass_data pass_data_cse_sincos =
> OPTGROUP_NONE, /* optinfo_flags */
> TV_NONE, /* tv_id */
> PROP_ssa, /* properties_required */
> - 0, /* properties_provided */
> + PROP_gimple_opt_math, /* properties_provided */
> 0, /* properties_destroyed */
> 0, /* todo_flags_start */
> TODO_update_ssa, /* todo_flags_finish */
>