OSDN Git Service

2011-05-27 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
authorwschmidt <wschmidt@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 27 May 2011 19:11:19 +0000 (19:11 +0000)
committerwschmidt <wschmidt@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 27 May 2011 19:11:19 +0000 (19:11 +0000)
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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@174349 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/tree-ssa-math-opts.c

index 53f0b1c..a1ae80c 100644 (file)
@@ -1,3 +1,12 @@
+2011-05-27  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
+
+       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  <amonakov@ispras.ru>
 
        * doc/contrib.texi: Update copyright years.
index 975ce9b..0e3f738 100644 (file)
@@ -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;
 }