Thank you for reviewing this patch!
On Fri, 2025-08-29 at 13:14 -0500, Segher Boessenkool wrote:
> > This leads to having 2 instructions for the simple
> > case of left shift by one.
> > vspltisw 0,1
> > vsld 2,2,0
> > This could have been performed simply with one add instruction
> > vaddudm 2,2,2
> > This patch fixes this issue. During the expansion of vashl op
> > check if the operand number 2 is a constant and its value is 1,
> > if yes then generate plus op, otherwise materialize the result
> > of operand 2 into a register and generate ashift op.
>
> Please don't do this. Just do a define_insn that recognises a shift
> by
> const int 1, and emits an vaddudm machine insn for that. The RTL as
> we
> currently create is just fine, and if we would want a canonical
> representation for this the shift is probably the best idea!
>
I did try this approach, and encountered several issues.
1. The pattern
[(set (match_operand:VEC_I 0 "vint_operand")
(ashift:VEC_I (match_operand:VEC_I 1 "vint_operand")
(match_operand:VEC_I 2 "vint_operand")))]
makes sure that operand #2 must be vint_operand, thus if it is a
constant, then the function 'maybe_legitimize_operands' which is called
under 'maybe_gen_insn', materialized the constant into a register after
which the pattern matches successfully.
2. Due to the above problem, I could not create a define insn, that can
look at the operand 2 as a constant and generate vaddudm. I try
something like following:
(define_insn
[(set (match_operand:VEC_I 0 "vint_operand")
(ashift:VEC_I (match_operand:VEC_I 1 "vint_operand")
(const_vector:V2DI [(const_int 1) (const_int
1)])))]
"<VI_unit>"
{
return "vaddu<VI_char>m %0,%1,%1";
}
)
But the problem is again, operand 2 is always materialized into a
register. If possible, could you please suggest how I can recognize
operand #2 as a constant when it is already in a register.
> > PR target/119702
> > gcc:
> > * config/rs6000/vector.md (vashl<mode>3): Generate add
> > when
> > operand 2 is a constant with value 1.
>
> Changelog lines are 80 character positions wide. Please do not wrap
> early.
>
> There should be no indent for continuation lines after the * line.
> So:
>
> * wherever/that/is: Something and something more more more
> more more
> more more more and some more.
>
> > diff --git a/gcc/config/rs6000/vector.md
> > b/gcc/config/rs6000/vector.md
> > index f5797387ca7..02e2361e4a3 100644
> > --- a/gcc/config/rs6000/vector.md
> > +++ b/gcc/config/rs6000/vector.md
> > @@ -1391,9 +1391,29 @@
> > (define_expand "vashl<mode>3"
> > [(set (match_operand:VEC_I 0 "vint_operand")
> > (ashift:VEC_I (match_operand:VEC_I 1 "vint_operand")
> > - (match_operand:VEC_I 2 "vint_operand")))]
> > + (match_operand:VEC_I 2 "general_operand")))]
> > "VECTOR_UNIT_ALTIVEC_OR_VSX_P (<MODE>mode)"
> > - "")
> > +{
> > + rtx op2 = operands[2];
> > + if (CONSTANT_P(op2)) {
> > + HOST_WIDE_INT shift = INTVAL(const_vector_elt (op2, 0));
> > +
> > + if (shift == 1)
> > + {
> > + emit_insn (gen_rtx_SET (operands[0],
> > + gen_rtx_PLUS (<MODE>mode,
> > + operands[1],
> > + operands[1])));
> > + DONE;
> > + }
> > + }
> > + operands[2] = copy_to_mode_reg (<MODE>mode, op2);
> > + emit_insn (gen_rtx_SET (operands[0],
> > + gen_rtx_ASHIFT (<MODE>mode,
> > + operands[1],
> > + operands[2])));
> > + DONE;
> > +})
>
> You shouldn't ever do things this way: if what you want to generate
> is
> just the pattern of the define_*, just fall throough (without calling
> DONE (or FAIL). This is much more usual in a define_insn, but it
> works
> fine in a define_expand as well, see our add<mode>3_carry_in for
> example
> (this pattern is generated by name from other things in the backend,
> many of those things will finally end up in define_insn
> *add<mode>3_carry_in_internal, the next pattern, doing "adde").
>
Just adding this comment, in case the above mentioned approach does not
work. Would this be ok? Make the operand #2 constraint as
general_operand (so that it is not materialized into a register). Then
if operand #2 is a constant int 1, pass through, else copy it to mode
reg and generate emit ASHIFT insn.
diff --git a/gcc/config/rs6000/vector.md b/gcc/config/rs6000/vector.md
index f5797387ca7..cba57a7319e 100644
--- a/gcc/config/rs6000/vector.md
+++ b/gcc/config/rs6000/vector.md
@@ -1387,13 +1387,24 @@
DONE;
})
+
;; Expanders for arithmetic shift left on each vector element
(define_expand "vashl<mode>3"
[(set (match_operand:VEC_I 0 "vint_operand")
(ashift:VEC_I (match_operand:VEC_I 1 "vint_operand")
- (match_operand:VEC_I 2 "vint_operand")))]
+ (match_operand:VEC_I 2 "general_operand")))]
"VECTOR_UNIT_ALTIVEC_OR_VSX_P (<MODE>mode)"
- "")
+{
+ rtx op2 = operands[2];
+ if (CONSTANT_P(op2) && INTVAL(const_vector_elt (op2, 0)) != 1) {
+ operands[2] = copy_to_mode_reg (<MODE>mode, op2);
+ emit_insn (gen_rtx_SET (operands[0],
+ gen_rtx_ASHIFT (<MODE>mode,
+ operands[1],
+ operands[2])));
+ DONE;
+ }
+})
This way it is easy to recognize in define_insn as follows
diff --git a/gcc/config/rs6000/altivec.md
b/gcc/config/rs6000/altivec.md
index 7edc288a656..3f678f2e666 100644
--- a/gcc/config/rs6000/altivec.md
+++ b/gcc/config/rs6000/altivec.md
@@ -2107,6 +2107,17 @@
"vsrv %0,%1,%2"
[(set_attr "type" "vecsimple")])
+
+(define_insn ""
+ [(set (match_operand:VI2 0 "register_operand" "=v")
+ (ashift:VI2 (match_operand:VI2 1 "register_operand" "v")
+ (const_vector:V2DI [(const_int 1) (const_int
1)])))]
+ "<VI_unit>"
+ {
+ return "vaddu<VI_char>m %0,%1,%1";
+ }
+)
+
As you mentioned I will have to add patterns for various sizes as well.
Regards,
Avinash Jayakar