On 2026-09-07 18:53, Torbjorn SVENSSON wrote:
Hi,

Looks like this commit caused regression for arm-none-eabi:

Testing arm/vfp-shift-a2t2.c
doing compile
Executing on host: /build/r17-3926-g93ac5163b5d02c/bin/arm-none-eabi-gcc  
/build/gcc_src/gcc/testsuite/gcc.target/arm/vfp-shift-a2t2.c  
-march=armv7ve+simd -mtune=cortex-a7 -mfloat-abi=hard -mfpu=auto   
-fdiagnostics-plain-output  -save-temps -ffat-lto-objects -fno-ident -S     -o 
vfp-shift-a2t2.s    (timeout = 800)
spawn -ignore SIGHUP /build/r17-3926-g93ac5163b5d02c/bin/arm-none-eabi-gcc 
/build/gcc_src/gcc/testsuite/gcc.target/arm/vfp-shift-a2t2.c 
-march=armv7ve+simd -mtune=cortex-a7 -mfloat-abi=hard -mfpu=auto 
-fdiagnostics-plain-output -save-temps -ffat-lto-objects -fno-ident -S -o 
vfp-shift-a2t2.s
pid is 89545 -89545
pid is -1
output is  status 0
PASS: gcc.target/arm/vfp-shift-a2t2.c (test for excess errors)
FAIL: gcc.target/arm/vfp-shift-a2t2.c scan-assembler vshll.u16[ \t]+[qQ][0-9]+, 
[dD][0-9]+, #[0-9]+!?([ \t]+@[a-zA-Z0-9 ]+)?\n
FAIL: gcc.target/arm/vfp-shift-a2t2.c scan-assembler vshll.u32[ \t]+[qQ][0-9]+, 
[dD][0-9]+, #[0-9]+!?([ \t]+@[a-zA-Z0-9 ]+)?\n
FAIL: gcc.target/arm/vfp-shift-a2t2.c scan-assembler vshll.u8[ \t]+[qQ][0-9]+, 
[dD][0-9]+, #[0-9]+!?([ \t]+@[a-zA-Z0-9 ]+)?\n

I see the same issue for Cortex-M, but then it also switches target to 
armv7ve+simd.

Am I missing something here?

Ah! Just found out that you fixed this while my bisect was running.
Sorry for the noise!

Kind regards,
Torbjörn


Kind regards,
Torbjörn

On 2026-09-04 16:34, Richard Earnshaw wrote:
From: Dominic P <[email protected]>

I noticed another issue with the code you were updating.  It was probably
benign in that the assembler accepted the GCC output; but it wasn't
strictly correct.  I've fixed that and pushed the following:

--

The NEON widening-shift-left-long intrinsics (vshll_n_s8/s16/s32 and
vshll_n_u8/u16/u32) accept a shift amount in the range [0, element_size].
The bounds check in neon_vshll<sup>_n<mode> already permits a shift of
zero (its stale comment said "0 < imm" while the code implements
"0 <= imm"), but it then emitted a literal "vshll.<sz> qD, dN, #0".

The VSHLL encoding cannot represent a shift of zero -- valid immediates
are 1..element_size -- so the assembler rejected the output with
"Error: immediate value out of range".

The ACLE semantics of a widening shift-left by zero are exactly those of
a widening move, so divert the imm == 0 case to VMOVL, which is the
correct and encodable instruction.  This turns previously-broken valid
ACLE code into working code (better QoI than rejecting it).  Nonzero
shifts, including a shift by the element size, are unchanged.

A related issue exists when the shift size is equal to the element size.
For these cases the mnemonic should use a signless form (i8, i16, i32).

Assisted-by: Claude Opus 5 (Anthropic)

    PR target/111609

gcc/ChangeLog:

    * config/arm/neon.md (neon_vshll<sup>_n<mode>): Emit vmovl for a
    shift of zero.  Use signless form when the shift amount == element
    size.

gcc/testsuite/ChangeLog:

    * gcc.target/arm/pr111609.c: New test.

Signed-off-by: Dominic P <[email protected]>
Co-authored-by: Richard Earnshaw <[email protected]>
---
  gcc/config/arm/neon.md                  | 12 ++++++---
  gcc/testsuite/gcc.target/arm/pr111609.c | 33 +++++++++++++++++++++++++
  2 files changed, 42 insertions(+), 3 deletions(-)
  create mode 100644 gcc/testsuite/gcc.target/arm/pr111609.c

diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md
index bb1fc4818e1..3c908db4538 100644
--- a/gcc/config/arm/neon.md
+++ b/gcc/config/arm/neon.md
@@ -4710,9 +4710,15 @@ (define_insn "neon_vshll<sup>_n<mode>"
                VSHLL_N))]
    "TARGET_NEON"
  {
-  /* The boundaries are: 0 < imm <= size.  */
-  arm_const_bounds (operands[2], 0, neon_element_bits (<MODE>mode) + 1);
-  return "vshll.<sup>%#<V_sz_elem>\t%q0, %P1, %2";
+  /* The boundaries are: 0 <= imm <= size, but the upper and lower
+     bounds need specific handling.  */
+  HOST_WIDE_INT elt_size = neon_element_bits (<MODE>mode);
+  arm_const_bounds (operands[2], 0, elt_size + 1);
+  if (INTVAL (operands[2]) == 0)
+    return "vmovl.<sup><V_sz_elem>\t%q0, %P1";
+  else if (INTVAL (operands[2]) == elt_size)
+    return "vshll.i<V_sz_elem>\t%q0, %P1, %2";
+  return "vshll.<sup><V_sz_elem>\t%q0, %P1, %2";
  }
    [(set_attr "type" "neon_shift_imm_long")]
  )
diff --git a/gcc/testsuite/gcc.target/arm/pr111609.c 
b/gcc/testsuite/gcc.target/arm/pr111609.c
new file mode 100644
index 00000000000..1b060624f28
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr111609.c
@@ -0,0 +1,33 @@
+/* PR target/111609 : a widening shift-left by zero must not emit an
+   unencodable "vshll #0"; it is a plain widening move (vmovl).  */
+/* { dg-do assemble } */
+/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-options "-O2 --save-temps" } */
+/* { dg-add-options arm_neon } */
+
+#include <arm_neon.h>
+
+int16x8_t  f_s8  (int8x8_t a)   { return vshll_n_s8  (a, 0); }
+/* { dg-final { scan-assembler-times {vmovl\.s8\t} 1 } } */
+int32x4_t  f_s16 (int16x4_t a)  { return vshll_n_s16 (a, 0); }
+/* { dg-final { scan-assembler-times {vmovl\.s16\t} 1 } } */
+int64x2_t  f_s32 (int32x2_t a)  { return vshll_n_s32 (a, 0); }
+/* { dg-final { scan-assembler-times {vmovl\.s32\t} 1 } } */
+uint16x8_t f_u8  (uint8x8_t a)  { return vshll_n_u8  (a, 0); }
+/* { dg-final { scan-assembler-times {vmovl\.u8\t} 1 } } */
+uint32x4_t f_u16 (uint16x4_t a) { return vshll_n_u16 (a, 0); }
+/* { dg-final { scan-assembler-times {vmovl\.u16\t} 1 } } */
+uint64x2_t f_u32 (uint32x2_t a) { return vshll_n_u32 (a, 0); }
+/* { dg-final { scan-assembler-times {vmovl\.u32\t} 1 } } */
+
+int16x8_t  g_s8  (int8x8_t a)   { return vshll_n_s8  (a, 1); }
+/* { dg-final { scan-assembler-times {vshll\.s8\tq[0-9]+, d[0-9]+, #1} 1 } } */
+
+int16x8_t  h_s8  (int8x8_t a)    { return vshll_n_s8  (a, 8); }
+/* { dg-final { scan-assembler-times {vshll\.i8\tq[0-9]+, d[0-9]+, #8} 1 } } */
+uint32x4_t  h_u16  (uint16x4_t a) { return vshll_n_u16  (a, 16); }
+/* { dg-final { scan-assembler-times {vshll\.i16\tq[0-9]+, d[0-9]+, #16} 1 } } 
*/
+int64x2_t  h_s32  (int32x2_t a)  { return vshll_n_s32  (a, 32); }
+/* { dg-final { scan-assembler-times {vshll\.i32\tq[0-9]+, d[0-9]+, #32} 1 } } 
*/
+
+/* { dg-final { scan-assembler-not {vshll\.[su][0-9]+\t[^\n]*#0\n} } } */


Reply via email to