Richard Sandiford <[email protected]> writes:
> I suppose it would be more constructive to sketch what I'm actually
> suggesting.  I still think your original idea of having a vec_select
> pattern and a scalar pattern is the way to go.  Due to the vec_select-to-
> subreg simplificaton rule that you mentioned (and contributed), the
> vec_select will always be for the high part.  In other words, it will
> always be for architectural lane 1.  So for your suggestion:
>
> (define_insn "@aarch64_simd_vec_copy_lane<mode>"
>   [(set (match_operand:VP_2E 0 "register_operand" "=w,w")
>       (vec_merge:VP_2E
>           (vec_duplicate:VP_2E
>             (vec_select:<VEL>
>               (match_operand:VP_2E 3 "register_operand" "w,0")
>               (parallel
>                 [(match_operand:SI 4 "immediate_operand" "i,i")])))
>           (match_operand:VP_2E 1 "register_operand" "0,w")
>           (match_operand:SI 2 "immediate_operand" "i,i")))]
>   "TARGET_SIMD
>    && exact_log2 (INTVAL (operands[2])) >= 0
>    && INTVAL (operands[4]) == exact_log2 (INTVAL (operands[2]))"
>   {
>
> operand 4 should in practice always be 0 for big-endian and 1 for
> little-endian.  The other case should be folded away.  We could test
> for that using:
>
>   "TARGET_SIMD
>    && exact_log2 (INTVAL (operands[2])) >= 0
>    && ENDIAN_LANE_N (2, INTVAL (operands[4])) == 1"
>
> (i.e. just changing the last line).
>
> This is then (as you say) a replacement for the existing VP_2E
> subset of the aarch64_simd_vec_copy_lane<mode> pattern.

Sigh.  But of course that drops the bit about making sure that lane 1
of the result comes from lane 1 of operand 3.  I had that in an earlier
version but somehow convinced myself that it wasn't necessary.

So we do still need the equivalent of:

   && INTVAL (operands[4]) == exact_log2 (INTVAL (operands[2]))

In this context, the full condition could be:

   "TARGET_SIMD
    && ENDIAN_LANE_N (2, INTVAL (operands[4])) == 1
    && INTVAL (operands[2]) == (BYTES_BIG_ENDIAN ? 1 : 2)"

for better contrast with the suggestion below.

Then alternative 0, which ties operands 0 and 1, would be:

   ins\t%0[1], %3[1]

for both endiannesses.  Alternative 1 would similarly be:

   ins\t%0[0], %1[0]

for both endiannesses.

Maybe there's an argument that simplify-rtx.cc should simplify this
to the vec_set form.  I.e., for little-endian:

  (vec_merge:V2X
    (vec_duplicate:V2X (vec_select:X V1 [(const_int 1)]))
    V2
    (const_int 2))

should become:

  (vec_merge:V2X
    (vec_duplicate:V2X (lowpart V2))
    V1
    (const_int 1))

and similarly for big-endian with the constants adjusted appropriately.

We would then use the vec_set form for both endiannesses.  That also has
the advantage of coping better with spilling, since vec_set has the GPR
and memory alternatives to fall back on.

Maybe that's a bit target-specific?  But it is simpler in rtl terms too.

> The scalar pattern will always be for the low part.  In other words,
> it will always be for architectural lane 0.  So for your suggestion:
>
> (define_insn "*aarch64_simd_vec_copy_lane_same<mode>_subreg"
>   [(set (match_operand:VP_2E 0 "register_operand" "=w,w")
>       (vec_merge:VP_2E
>           (vec_duplicate:VP_2E
>             (match_operand:<VEL> 2 "register_operand" "w,0"))
>           (match_operand:VP_2E 1 "register_operand" "0,w")
>           (match_operand:SI 3 "immediate_operand" "i,i")))]
>   "TARGET_SIMD
>    && INTVAL (operands[3]) == 2
>    && SUBREG_P (operands[2])
>    && known_eq (SUBREG_BYTE (operands[2]), GET_MODE_SIZE (<VEL>mode))"
>   {
>
> I think we should replace the condition with:
>
>   "TARGET_SIMD && exact_log2 (INTVAL (operands[2])) >= 0"
>
> This pattern is then a replacement for the VP_2E subset of the existing
> @aarch64_simd_vec_set<mode> pattern.  Because of that, it would be good
> to include the existing ?r and Utv alternatives too.  The thing that
> we're adding is alternative 1 above.

Similarly here, we'd need:

   "TARGET_SIMD && INTVAL (operands[2]) == (BYTES_BIG_ENDIAN ? 2 : 1)"

And the alternative that ties operands 0 and 2 would be:

   ins\t%0[1], %1[1]

for both endiannesses.  The other alternatives would insert operand 2
into %0[0].

Adding the condition means that we'd need to retain the existing vec_set
for inserting operand 2 into %0[1].

Richard

Reply via email to