On Fri, 21 Aug 2020, Feng Xue OS via Gcc 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...

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).

#Form 2:
 (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))))))
     (mult:v{ !single_use (@3) && !single_use (@4 } (plusminus @1 @2) @0))))

Indeed, something more flexible than '!' would be nice, but I am not so sure about this version. If we are going to allow inserting code after resimplification and before validation, maybe we should go even further and let people insert arbitrary code there...

--
Marc Glisse

Reply via email to