PR67945: Fix oscillation between pow representations
authorRichard Sandiford <richard.sandiford@arm.com>
Thu, 15 Oct 2015 09:50:07 +0000 (09:50 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Thu, 15 Oct 2015 09:50:07 +0000 (09:50 +0000)
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.

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.

From-SVN: r228840

gcc/ChangeLog
gcc/generic-match-head.c
gcc/gimple-match-head.c
gcc/match.pd
gcc/tree-pass.h
gcc/tree-ssa-math-opts.c

index 6dec962d2839dd417ccce656dfea9ecbd1826e7b..75c4c17dd35d9751f1366fb2726bc76de5e773ec 100644 (file)
@@ -1,3 +1,15 @@
+2015-10-15  Richard Sandiford  <richard.sandiford@arm.com>
+
+       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.
+
 2015-10-15  Marek Polacek  <polacek@redhat.com>
 
        PR tree-optimization/67953
index 0a7038dfc864e28ba1f1ca04a0c810638cff8f6e..94135b36555fbdd8765782843c8e064cefb096d6 100644 (file)
@@ -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;
+}
index 16d8c5b7eb1ae62e7c4fb6ca1e0c9417ef601926..8f7291912c7a79ed06356773c55895cc31d6ee9e 100644 (file)
@@ -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.
@@ -825,3 +826,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;
+}
index 24e19a9647268598d5f26429257294b233c400c0..e0ecbe2e776587a3e08cb85e222987525b7ac647 100644 (file)
@@ -2135,11 +2135,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)
@@ -2152,63 +2166,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
@@ -2221,17 +2184,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).  */
@@ -2244,16 +2203,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);
@@ -2265,6 +2224,7 @@ along with GCC; see the file COPYING3.  If not see
        }
      }
     (mult (logs { x; }) @0))))
+
  (for logs (LOG LOG
             LOG2 LOG2
            LOG10 LOG10)
@@ -2276,11 +2236,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:
@@ -2288,12 +2248,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
+   of math builtins, which may be more complicated and can sometimes go
+   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. 
 
@@ -2365,44 +2431,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 ()); })))))
index 91f63a8d4a64341528139168ffc7fb08a09c1bcc..c37e4b2c2e9b8e485a0ed55e0c87db664293b8b7 100644 (file)
@@ -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)
index 21604f592ede83ae1e9572f8f8e1d1c01575e93d..92236422f2a7af05ef89b14099b77324944982ef 100644 (file)
@@ -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 */