On Wed, Sep 2, 2020 at 9:27 AM Marc Glisse <marc.gli...@inria.fr> wrote:
>
> On Wed, 2 Sep 2020, Richard Biener via Gcc wrote:
>
> > On Mon, Aug 24, 2020 at 8:20 AM Feng Xue OS via Gcc <gcc@gcc.gnu.org> wrote:
> >>
> >>>>   There is a match-folding issue derived from pr94234.  A piece of code 
> >>>> like:
> >>>>
> >>>>   int foo (int n)
> >>>>   {
> >>>>      int t1 = 8 * n;
> >>>>      int t2 = 8 * (n - 1);
> >>>>
> >>>>      return t1 - t2;
> >>>>   }
> >>>>
> >>>>  It can be perfectly caught by the rule "(A * C) +- (B * C) -> (A +- B) 
> >>>> * C", and
> >>>>  be folded to constant "8". But this folding will fail if both v1 and v2 
> >>>> have
> >>>>  multiple uses, as the following code.
> >>>>
> >>>>   int foo (int n)
> >>>>   {
> >>>>      int t1 = 8 * n;
> >>>>      int t2 = 8 * (n - 1);
> >>>>
> >>>>      use_fn (t1, t2);
> >>>>      return t1 - t2;
> >>>>   }
> >>>>
> >>>>  Given an expression with non-single-use operands, folding it will 
> >>>> introduce
> >>>>  duplicated computation in most situations, and is deemed to be 
> >>>> unprofitable.
> >>>>  But it is always beneficial if final result is a constant or existing 
> >>>> SSA value.
> >>>>
> >>>>  And the rule is:
> >>>>   (simplify
> >>>>    (plusminus (mult:cs@3 @0 @1) (mult:cs@4 @0 @2))
> >>>>    (if ((!ANY_INTEGRAL_TYPE_P (type)
> >>>>         || TYPE_OVERFLOW_WRAPS (type)
> >>>>         || (INTEGRAL_TYPE_P (type)
> >>>>             && tree_expr_nonzero_p (@0)
> >>>>             && expr_not_equal_to (@0, wi::minus_one (TYPE_PRECISION 
> >>>> (type)))))
> >>>>        /* If @1 +- @2 is constant require a hard single-use on either
> >>>>           original operand (but not on both).  */
> >>>>        && (single_use (@3) || single_use (@4)))   <----- control whether 
> >>>> match or not
> >>>>     (mult (plusminus @1 @2) @0)))
> >>>>
> >>>>  Current matcher only provides a way to check something before folding,
> >>>>  but no mechanism to affect decision after folding. If has, for the above
> >>>>  case, we can let it go when we find result is a constant.
> >>>
> >>> :s already has a counter-measure where it still folds if the output is at
> >>> most one operation. So this transformation has a counter-counter-measure
> >>> of checking single_use explicitly. And now we want a counter^3-measure...
> >>>
> >> Counter-measure is key factor to matching-cost.  ":s" seems to be somewhat
> >> coarse-grained. And here we do need more control over it.
> >>
> >> But ideally, we could decouple these counter-measures from definitions of
> >> match-rule, and let gimple-matcher get a more reasonable match-or-not
> >> decision based on these counters. Anyway, it is another story.
> >>
> >>>>  Like the way to describe input operand using flags, we could also add
> >>>>  a new flag to specify this kind of constraint on output that we expect
> >>>>  it is a simple gimple value.
> >>>>
> >>>>  Proposed syntax is
> >>>>
> >>>>   (opcode:v{ condition } ....)
> >>>>
> >>>>  The char "v" stands for gimple value, if more descriptive, other char is
> >>>>  preferred. "condition" enclosed by { } is an optional c-syntax condition
> >>>>  expression. If present, only when "condition" is met, matcher will check
> >>>>  whether folding result is a gimple value using
> >>>>  gimple_simplified_result_is_gimple_val ().
> >>>>
> >>>>  Since there is no SSA concept in GENERIC, this is only for GIMPLE-match,
> >>>>  not GENERIC-match.
> >>>>
> >>>>  With this syntax, the rule is changed to
> >>>>
> >>>>  #Form 1:
> >>>>   (simplify
> >>>>    (plusminus (mult:cs@3 @0 @1) (mult:cs@4 @0 @2))
> >>>>    (if ((!ANY_INTEGRAL_TYPE_P (type)
> >>>>         || TYPE_OVERFLOW_WRAPS (type)
> >>>>         || (INTEGRAL_TYPE_P (type)
> >>>>             && tree_expr_nonzero_p (@0)
> >>>>             && expr_not_equal_to (@0, wi::minus_one (TYPE_PRECISION 
> >>>> (type))))))
> >>>>        ( if (!single_use (@3) && !single_use (@4))
> >>>>           (mult:v (plusminus @1 @2) @0)))
> >>>>           (mult (plusminus @1 @2) @0)))))
> >>>
> >>> That seems to match what you can do with '!' now (that's very recent).
> >
> > It's also what :s does but a slight bit more "local".  When any operand is
> > marked :s and it has more than a single-use we only allow simplifications
> > that do not require insertion of extra stmts.  So basically the above 
> > pattern
> > doesn't behave any different than if you omit your :v.  Only if you'd
> > place :v on an inner expression there would be a difference.  Correlating
> > the inner expression we'd not want to insert new expressions for with
> > a specific :s (or multiple ones) would be a more natural extension of what
> > :s provides.
> >
> > Thus, for the above case (Form 1), you do not need :v at all and :s works.
>
> Let's consider that multiplication is expensive. We have code like
> 5*X-3*X, which can be simplified to 2*X. However, if both 5*X and 3*X have
> other uses, that would increase the number of multiplications. :s would
> not block a simplification to 2*X, which is a single stmt. So the existing
> transformation has extra explicit checks for single_use. And those extra
> checks block the transformation even for 5*X-4*X -> X which does not
> increase the number of multiplications. Which is where '!' (or :v here)
> comes in.

Yeah, I guess the existing :s cannot capture the fact that in case one
multiplication is single-use only the transform is still clearly profitable,
saving the subtraction.

Well, as you said it will allow simplification to 2*X anyway.

> Or we could decide that the extra multiplication is not that bad if it
> saves an addition, simplifies the expression, possibly gains more insn
> parallelism, etc, in which case we could just drop the existing hard
> single_use check...

;)

it's all going to be heuristics because the decision is made
locally.  If you consider the other two uses might be
5*X + 3*X then converting both to 2*X and 8*X should be
a win because we save one addition and one subtraction.
But that would require folding everything tentatively and
then applying some global costing ...

Richard.

> --
> Marc Glisse

Reply via email to