Hi,
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.
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)))))
#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))))
This is just a proposal, has not been implemented. Hope your comments
on this.
Best Regards,
Feng