On 13/11/2026 13:32, Richard Biener wrote:
> On Fri, Nov 13, 2026 at 12:45 PM Richard Earnshaw via Sourceware Forge
> <[email protected]> wrote:
>>
>> From: Richard Earnshaw <[email protected]>
>>
>> If a vec_perm selects the same element from the source for every
>> element in the destination, eg with
>>   __builtin_shuffle (v1, v2, { N, N,... N });
>> then this can be simplified to
>>   vec_duplicate (v[N'])
>> where v and N' are picked from the first vector or the second depending
>> on the value of N.
> 
> ISTR we sofar refrained from using VEC_DUPLICATE for non-VLA vectors
> for reasons that escape me.  Is this to have vec_same_elem_p handle
> the permute case?  Can we instead handle a canonical vec_permute
> form there (and in uniform_vector_p)?
> 

The original motivation for this was a test I was running on Arm (aarch32).  For

#include <arm_neon.h>
#include <stdint.h>

int16x8_t be_dupq_lane (int16x8_t v)
{
  return (int16x8_t) __builtin_shuffle (v, v,
                                        (uint16x8_t) { 0, 0, 0, 0,
                                                       0, 0, 0, 0 });
}

The compiler was producing better code when compiling for big-endian 

be_dupq_lane:
        vdup.16 q0, d1[3]
        bx      lr
 
compared to the code for little-endian:

be_dupq_lane:
        vmov.i16        q8, #256  @ v16qi
        vmov    q9, q0  @ v16qi
        vtbl.8  d0, {d0, d1}, d16
        vtbl.8  d1, {d18, d19}, d17
        bx      lr

Investigation showed that this was because we have a vec_perm pattern for 
little-endian, but not for big-endian.  As a result, the gimple generated 
becomes

int16x8_t be_dupq_lane (int16x8_t v)
{
  int16x8_t _2;

  <bb 2> [local count: 1073741824]:
  _2 = VEC_PERM_EXPR <v_1(D), v_1(D), { 0, 0, 0, 0, 0, 0, 0, 0 }>;
  return _2;
}


while on big-endian it's just

int16x8_t be_dupq_lane (int16x8_t v)
{
  int16x8_t _2;
  short int _4;

  <bb 2> [local count: 1073741824]:
  _4 = BIT_FIELD_REF <v_1(D), 16, 0>;
  _2 = {_4, _4, _4, _4, _4, _4, _4, _4};
  return _2;
}

and at this point I was then faced with the question: do I try to recognize 
this idiom directly in the expansion code in the back end, or do I try to find 
a generic way of expressing this that can be done in the mid-end?  I thought 
the latter would be the more sensible approach in that it would then 
potentially apply to all targets saving the need to recognize specific idioms 
in every vec_perm implementation.
 

R.

>> gcc/ChangeLog:
>>
>>         * match.pd: Simplify vec_perm to vec_duplicate when all outputs
>>         come from the same input lane.
>> ---
>>  gcc/match.pd | 24 +++++++++++++++++++++++-
>>  1 file changed, 23 insertions(+), 1 deletion(-)
>>
>> diff --git a/gcc/match.pd b/gcc/match.pd
>> index 3912f9f7d5438..52ebf642677e8 100644
>> --- a/gcc/match.pd
>> +++ b/gcc/match.pd
>> @@ -12910,6 +12910,28 @@ and,
>>       (view_convert @0)
>>       (if (known_eq (nelts, nelts_in) && sel.series_p (0, 1, nelts_in, 1))
>>        (view_convert @1)
>> +      (if (canonicalize_math_after_vectorization_p ()
>> +          && known_eq (nelts, nelts_in) && sel.series_p (0, 1, sel[0], 0)
>> +          && (known_lt ((poly_uint64) sel[0], nelts)
>> +              || known_ge ((poly_uint64) sel[0], nelts)))
>> +       (with
>> +       {
>> +         poly_uint64 index = sel[0];
>> +         tree vec = op0;
>> +         poly_uint64 lane = index;
>> +         if (known_ge (index, nelts))
>> +           {
>> +             vec = op1;
>> +             lane -= nelts;
>> +           }
>> +         tree elem_type = TREE_TYPE (TREE_TYPE (vec));
>> +         unsigned HOST_WIDE_INT bits = tree_to_uhwi (TYPE_SIZE (elem_type));
>> +       }
>> +       (
>> +         vec_duplicate
>> +          (BIT_FIELD_REF:elem_type { vec; }
>> +                                   { bitsize_int (bits); }
>> +                                   { bitsize_int (lane * bits); })))
>>        (with
>>         {
>>           if (!single_arg)
>> @@ -13022,7 +13044,7 @@ and,
>>           (bit_insert { op0; } { ins; }
>>            { bitsize_int (at * vector_element_bits (type)); })
>>           (if (changed)
>> -          (vec_perm { op0; } { op1; } { op2; }))))))))))))
>> +          (vec_perm { op0; } { op1; } { op2; })))))))))))))
>>
>>  /* VEC_PERM_EXPR (v, v, mask) -> v where v contains same element.  */
>>
>> --
>> 2.56.0
>>

Reply via email to