On Wed, Oct 14, 2015 at 6:50 PM, Richard Sandiford <richard.sandif...@arm.com> 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 */ >