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 */
>

Reply via email to