On Tue, 2011-05-24 at 14:26 +0200, Richard Guenther wrote:

<snip>

> > +/* Recursive subroutine of powi_as_mults.  This function takes the
> > +   array, CACHE, of already calculated exponents and an exponent N and
> > +   returns a tree that corresponds to CACHE[1]**N, with type TYPE.  */
> > +
> > +static tree
> > +powi_as_mults_1 (gimple_stmt_iterator *gsi, location_t loc, tree type,
> > +                HOST_WIDE_INT n, tree *cache, tree target)
> > +{
> > +  tree op0, op1, ssa_target;
> > +  unsigned HOST_WIDE_INT digit;
> > +  gimple mult_stmt;
> > +
> > +  if (n < POWI_TABLE_SIZE)
> > +    {
> > +      if (cache[n])
> > +       return cache[n];
> > +
> > +      ssa_target = make_ssa_name (target, NULL);
> 
> You can hoist the ssa_target creation before the if instead of
> replicating it ...

OK.  The time spent in make_ssa_name will be wasted in the common case
where the value is found in the cache.  But I can restructure the logic
to avoid that.

> 
> > +      cache[n] = ssa_target;
> > +
> > +      op0 = powi_as_mults_1 (gsi, loc, type, n - powi_table[n], cache, 
> > target);
> > +      op1 = powi_as_mults_1 (gsi, loc, type, powi_table[n], cache, target);
> > +    }
> > +  else if (n & 1)
> > +    {
> > +      digit = n & ((1 << POWI_WINDOW_SIZE) - 1);
> > +      op0 = powi_as_mults_1 (gsi, loc, type, n - digit, cache, target);
> > +      op1 = powi_as_mults_1 (gsi, loc, type, digit, cache, target);
> > +      ssa_target = make_ssa_name (target, NULL);
> 
> here and
> 
> > +    }
> > +  else
> > +    {
> > +      op0 = powi_as_mults_1 (gsi, loc, type, n >> 1, cache, target);
> > +      op1 = op0;
> > +      ssa_target = make_ssa_name (target, NULL);
> 
> here.
> 
> > +    }
> > +
> > +  mult_stmt = gimple_build_assign_with_ops (MULT_EXPR, ssa_target, op0, 
> > op1);
> > +  gsi_insert_before (gsi, mult_stmt, GSI_SAME_STMT);
> > +
> > +  return ssa_target;
> > +}
> > +
> > +/* Convert ARG0**N to a tree of multiplications of ARG0 with itself.
> > +   This function needs to be kept in sync with powi_cost above.  */
> > +
> > +static tree
> > +powi_as_mults (gimple_stmt_iterator *gsi, location_t loc,
> > +              tree arg0, HOST_WIDE_INT n)
> > +{
> > +  tree cache[POWI_TABLE_SIZE], result, type = TREE_TYPE (arg0), target;
> > +  gimple div_stmt;
> > +
> > +  if (n == 0)
> > +    return build_real (type, dconst1);
> > +
> > +  memset (cache, 0,  sizeof (cache));
> > +  cache[1] = arg0;
> > +
> > +  target = create_tmp_var (type, "powmult");
> > +  add_referenced_var (target);
> > +
> > +  result = powi_as_mults_1 (gsi, loc, type, (n < 0) ? -n : n, cache, 
> > target);
> > +
> > +  if (n >= 0)
> > +    return result;
> > +
> > +  /* If the original exponent was negative, reciprocate the result.  */
> > +  target = create_tmp_var (type, "powmult");
> > +  add_referenced_var (target);
> 
> re-use target from above.
> 

Oops, sorry, that was sloppy.

> > +  target = make_ssa_name (target, NULL);
> > +
> > +  div_stmt = gimple_build_assign_with_ops (RDIV_EXPR, target,
> > +                                          build_real (type, dconst1),
> > +                                          result);
> > +  gsi_insert_before (gsi, div_stmt, GSI_SAME_STMT);
> > +
> > +  return target;
> > +}
> > +
> > +/* ARG0 and N are the two arguments to a powi builtin in GSI with
> > +   location info LOC.  If the arguments are appropriate, create an
> > +   equivalent sequence of statements prior to GSI using an optimal
> > +   number of multiplications, and return an expession holding the
> > +   result.  */
> > +
> > +static tree
> > +gimple_expand_builtin_powi (gimple_stmt_iterator *gsi, location_t loc,
> > +                           tree arg0, HOST_WIDE_INT n)
> > +{
> > +  /* Avoid largest negative number.  */
> > +  if (n != -n
> > +      && ((n >= -1 && n <= 2)
> > +         || (optimize_function_for_speed_p (cfun)
> > +             && powi_cost (n) <= POWI_MAX_MULTS)))
> > +    return powi_as_mults (gsi, loc, arg0, n);
> > +
> > +  return NULL_TREE;
> > +}
> > +
> >  /* Go through all calls to sin, cos and cexpi and call execute_cse_sincos_1
> > -   on the SSA_NAME argument of each of them.  */
> > +   on the SSA_NAME argument of each of them.  Also expand powi(x,n) into
> > +   an optimal number of multiplies, when n is a constant.  */
> >
> >  static unsigned int
> >  execute_cse_sincos (void)
> > @@ -821,7 +1056,9 @@ execute_cse_sincos (void)
> >              && (fndecl = gimple_call_fndecl (stmt))
> >              && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
> >            {
> > -             tree arg;
> > +             tree arg, arg0, arg1, result;
> > +             HOST_WIDE_INT n, n_hi;
> > +             location_t loc;
> >
> >              switch (DECL_FUNCTION_CODE (fndecl))
> >                {
> > @@ -833,6 +1070,29 @@ execute_cse_sincos (void)
> >                    cfg_changed |= execute_cse_sincos_1 (arg);
> >                  break;
> >
> > +               CASE_FLT_FN (BUILT_IN_POWI):
> > +                 arg0 = gimple_call_arg (stmt, 0);
> > +                 arg1 = gimple_call_arg (stmt, 1);
> > +                 if (!host_integerp (arg1, 0))
> > +                   break;
> > +
> > +                 n = TREE_INT_CST_LOW (arg1);
> > +                 n_hi = TREE_INT_CST_HIGH (arg1);
> > +                 if (n_hi != 0 && n_hi != -1)
> > +                   break;
> 
> The n_hi query and check isn't necessary as host_integerp already
> ensures this.
> 

Ah, OK.  Thanks.

> > +
> > +                 loc = gimple_location (stmt);
> > +                 result = gimple_expand_builtin_powi (&gsi, loc, arg0, n);
> > +
> > +                 if (result)
> > +                   {
> > +                     tree lhs = gimple_get_lhs (stmt);
> > +                     gimple new_stmt = gimple_build_assign (lhs, result);
> > +                     gimple_set_location (new_stmt, loc);
> > +                     gsi_replace (&gsi, new_stmt, true);
> > +                   }
> > +                 break;
> > +
> >                default:;
> >                }
> >            }
> > @@ -849,10 +1109,9 @@ execute_cse_sincos (void)
> >  static bool
> >  gate_cse_sincos (void)
> >  {
> > -  /* Make sure we have either sincos or cexp.  */
> > -  return (TARGET_HAS_SINCOS
> > -         || TARGET_C99_FUNCTIONS)
> > -        && optimize;
> > +  /* We no longer require either sincos or cexp, since powi expansion
> > +     piggybacks on this pass.  */
> > +  return optimize;
> >  }
> >
> >  struct gimple_opt_pass pass_cse_sincos =
> 
> With the above changes the patch is ok for trunk, possibly after we
> resolved the gsi_replace virtual operand case (you probably
> can reproduce it with -funsafe-math-optimizations -ferrno-math).

OK, just saw your other note.  I'll copy the logic from
update_call_from-tree ().

Thanks,
Bill

> 
> Thanks,
> Richard.

Reply via email to