A 128-bit NEON Q register variable bound to Q8 or above (using the high
VFP registers D16-D31) was given an incorrect DWARF location: the two
DW_OP_regx operands both named the low D register, e.g. for Q8

  DW_OP_regx 272; DW_OP_piece 8; DW_OP_regx 272; DW_OP_piece 8

instead of naming D16 (272) and D17 (273).

D16-D31 have no single-precision aliases, so GCC still models each of
them as two consecutive 32-bit hard registers.  arm_dwarf_register_span
built the DImode (D register) pieces stepping the hard register number
by one, which selected the same D register twice: arm_debugger_regno
maps hard register N to 256 + (N - FIRST_VFP_REGNUM) / 2, so an odd
offset rounds down to the previous D register.  Step by two so each
piece names a distinct D register.

Assisted-by: Claude Opus 5 (Anthropic)

gcc/ChangeLog:

        PR target/91381
        * config/arm/arm.cc (arm_dwarf_register_span): Step the DImode
        pieces for D16-D31 by two hard register numbers.

gcc/testsuite/ChangeLog:

        PR target/91381
        * gcc.target/arm/pr91381.c: New test.

Signed-off-by: Dominic P <[email protected]>
---
Changes in v2:

 - drop the five-line comment v1 added to arm_dwarf_register_span; it repeats
   the commit message, and you asked for exactly that when you pushed 2/6 of
   this series.
 - cut the test's header comment to one sentence.
 - ChangeLog: PR target/91381, in the per-file blocks as in 1/6 and 4/6 --
   the bug was re-componented from debug to target on 4 Sep.

The one code line is unchanged.  Still reproduces on trunk 2cb78d1a0e5: for a
uint32x4_t bound to q8, -g -O0 -mfpu=neon -mfloat-abi=softfp -march=armv7-a
emits .uleb128 0x110 twice and 0x111 never; with the patch, each once.

Retested on arm-none-eabi against a pristine build of that commit, arm.exp
mve.exp simd.exp on the default board and on an arm-linux-gnueabihf-like board
(-mthumb -mfloat-abi=hard -mtune=cortex-a9 -march=armv7-a -mfpu=neon-fp-armv8):
no test changes status on either, and pr91381.c is the only addition.

OK for trunk?

 gcc/config/arm/arm.cc                  |  2 +-
 gcc/testsuite/gcc.target/arm/pr91381.c | 23 +++++++++++++++++++++++
 2 files changed, 24 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.target/arm/pr91381.c

diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc
index 33b64995442..cb2141186ea 100644
--- a/gcc/config/arm/arm.cc
+++ b/gcc/config/arm/arm.cc
@@ -30121,7 +30121,7 @@ arm_dwarf_register_span (rtx rtl)
     {
       nregs = GET_MODE_SIZE (mode) / 8;
       for (i = 0; i < nregs; i++)
-       parts[i] = gen_rtx_REG (DImode, regno + i);
+       parts[i] = gen_rtx_REG (DImode, regno + i * 2);
     }
 
   return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nregs , parts));
diff --git a/gcc/testsuite/gcc.target/arm/pr91381.c 
b/gcc/testsuite/gcc.target/arm/pr91381.c
new file mode 100644
index 00000000000..2c6b76aac4b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr91381.c
@@ -0,0 +1,23 @@
+/* PR target/91381: a Q8-Q15 register variable must name two distinct D
+   registers.  */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-options "-g -dA -O0" } */
+/* { dg-add-options arm_neon } */
+
+#include <arm_neon.h>
+
+int
+foo (void)
+{
+  register uint32x4_t q8v asm ("q8") = vdupq_n_u32 (0);
+  __asm__ __volatile__ ("" : : "w" (q8v));
+  return 0;
+}
+
+/* Q8 == D16:D17, whose DWARF register numbers are 272 (0x110) and 273 (0x111).
+   The low D register (0x110) must be described once and the high D register
+   (0x111) once; the buggy output emitted 0x110 twice and never 0x111.  */
+/* { dg-final { scan-assembler-times "uleb128 0x110\[^0-9a-f\]" 1 } } */
+/* { dg-final { scan-assembler-times "uleb128 0x111\[^0-9a-f\]" 1 } } */
-- 
2.55.0

Reply via email to