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

Reply via email to