On Fri, Sep 25, 2026 at 11:30:07AM +0200, Richard Biener wrote:
> On Fri, Sep 25, 2026 at 10:31 AM Stefan Schulze Frielinghaus
> <[email protected]> wrote:
> >
> > From: Stefan Schulze Frielinghaus <[email protected]>
> >
> > As a first step I went for implementing this during simplify RTX.
> > However, in the end this works only partly. For example, a candidate
> > insn created during a 3-insn combine resulting from the simplification
> > has a vector constant as an operand, now, which may have been previously
> > a register operand. This may lead to fail predicate general_operand in
> > case the constant is not a legitimate one which leads to rejecting the
> > insn instead of fixing it up during LRA. This was the motivation for
> > also doing the same on tree level. Then we end up prior expand with a
> > PLUS and MULT which in turn means after expand we do so, too, and
> > combine can merge both (independent of the vector constant which may
> > have been pushed into the constant pool at this particular time).
> >
> > Note, the RTX simplification still works for vector constants which are
> > accepted by TARGET_LEGITIMATE_CONSTANT_P. For s390, the different code
> > paths are demonstrated in the subsequent patch where
> > test_<mode>_minus_vrepi profits already from the rtx canonicalization,
> > and test_<mode>_minus_constpool profits from the tree canonicalization.
> >
> > Of course, this is not uncontroversial. In case the multiplication is
> > used in more than one place, the combination might be undesired. The
> > same holds true in case the constant vector is used in multiple places
> > but the negated version is not. The former is partly addressed by
> > match.pd requiring a single use for mult. Of course, there still might
> > be cases where this may prohibit CSE optimizations later on.
> >
> > If this is about to being accepted, then one could also introduce a
> > mach.pd rule for A-((-B)*C) -> (B*C)+A which is already taken care of in
> > simplify RTX due to the recursive call.
> >
> > This is motivated by the fact that on s390 we only have vector
> > multiply-and-add but no subtract variant over the integers.
> >
> > Note, w.r.t. the SPEC CPU 2017 suite, the results are underwhelming in
> > the sense that only two times the canonicalization helps for emitting a
> > VMAL instead of VML+VS. On the other hand the results are also a
> > relieve in the sense that they show that no extra multiplications were
> > introduced due to pulling in the minus.
> >
> > Side remark: We generously accept all scalar constants during
> > TARGET_LEGITIMATE_CONSTANT_P, since those which do not end up as
> > immediates, RA does a very nice job by reloading and sharing those
> > reloads among insns. In contrast, vector constants can never end up as
> > immediates which is why putting those early into the constant pool leads
> > generally to better code. Only in those few cases where a constant can
> > be constructed via a single instruction, we do not utilize the constant
> > pool.
> > ---
> > Bootstrapped and regtested on
> > - aarch64-unknown-linux-gnu
> > - powerpc64le-unknown-linux-gnu
> > - s390x-ibm-linux-gnu
> > - x86_64-pc-linux-gnu
> > If there is consensus to commit this, I would add A-((-B)*C) -> (B*C)+A
> > and give this another round of testing.
> >
> > gcc/match.pd | 12 ++++++++++++
> > gcc/simplify-rtx.cc | 17 ++++++++++++++++-
> > 2 files changed, 28 insertions(+), 1 deletion(-)
> >
> > diff --git a/gcc/match.pd b/gcc/match.pd
> > index 268bf3f11e5..a5a476e17a3 100644
> > --- a/gcc/match.pd
> > +++ b/gcc/match.pd
> > @@ -2532,6 +2532,18 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
> > (if (!FIXED_POINT_TYPE_P (type))
> > (plus @0 (negate @1))))
> >
> > +/* A - (B * C) -> (B * (-C)) + A if C is a constant vector. */
>
> This should be catched by A - B -> A + (-B) when B can be easily
> negated via negate_expr_p. match.pd does not implement
> the fold-const MULT_EXPR case and I remember Kyrylo messing
> with negating of vectors, so CCed.
That sounds interesting. @Kyrylo if you have any pointers for me, I am
certainly interested.
>
> The negate_expr_p match will have the issue of single-uses as you
> say. So I'm not entirely convinced this is a good idea as this
> "canonicalization" doesn't really help much, unlike for example
> knowing that A - INTEGER_CST will never appear (besides for INT_MIN),
> but it will be A + INTEGER_CST always.
Yea it is a special case with a potential harmful effect which is why I
was also uncertain. In light of the underwhelming results for SPEC,
let's drop this patch. Thanks for considering!
Cheers,
Stefan
>
> > +/* Perform this only in case the multiplication has a single use. */
> > +(simplify
> > + (minus @0 (mult:cs @1 VECTOR_CST@2))
> > + (if (VECTOR_INTEGER_TYPE_P (type))
> > + (with { tree neg_const_vec = const_unop (NEGATE_EXPR, type, @2); }
> > + /* Be defensive here and check that the negation of a constant
> > + vector can be represented which may not be the case for
> > + scalable vectors. */
> > + (if (neg_const_vec)
> > + (plus (mult @1 { neg_const_vec; }) @0)))))
> > +
> > /* A - MIN (B, C) -> A + MAX (-B, -C)
> > A - MAX (B, C) -> A + MIN (-B, -C) if B and C are easily negatable. */
> > (for minmax (min max)
> > diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc
> > index 38c8abfe3e7..ce3e5469812 100644
> > --- a/gcc/simplify-rtx.cc
> > +++ b/gcc/simplify-rtx.cc
> > @@ -3690,12 +3690,27 @@ simplify_context::simplify_binary_operation_1
> > (rtx_code code,
> > && (tem = simplify_plus_minus (code, mode, op0, op1)) != 0)
> > return tem;
> >
> > - /* Handle vector series. */
> > + /* Handle integer vector operations. */
> > if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT)
> > {
> > tem = simplify_binary_operation_series (code, mode, op0, op1);
> > if (tem)
> > return tem;
> > +
> > + /* Canonicalize A-(B*C) into (B*(-C))+A if C is a constant
> > vector. */
> > + rtx neg_const_vec;
> > + if (GET_CODE (op1) == MULT
> > + && CONST_VECTOR_P (XEXP (op1, 1))
> > + /* Be defensive here and check that the negation of a constant
> > + vector can be represented which may not be the case for
> > + scalable vectors. */
> > + && (neg_const_vec
> > + = simplify_unary_operation (NEG, mode, XEXP (op1, 1),
> > mode)))
> > + {
> > + rtx new_mult = simplify_gen_binary (MULT, mode, XEXP (op1, 0),
> > + neg_const_vec);
> > + return simplify_gen_binary (PLUS, mode, new_mult, op0);
> > + }
> > }
> > break;
> >
> > --
> > 2.55.0
> >