[PATCH 5/6] arm: Fix DWARF register span for Q8-Q15 register variables [PR91381]

Dominic P <[email protected]> Sun, 2 Aug 2026 11:56:07 +0100
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
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)

	PR debug/91381

gcc/ChangeLog:

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

gcc/testsuite/ChangeLog:

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

Signed-off-by: Dominic P <[email protected]>
---
 gcc/config/arm/arm.cc                  |  7 ++++++-
 gcc/testsuite/gcc.target/arm/pr91381.c | 26 ++++++++++++++++++++++++++
 2 files changed, 32 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 62534baca..71932ee4a 100644
--- a/gcc/config/arm/arm.cc
+++ b/gcc/config/arm/arm.cc
@@ -30120,9 +30120,14 @@ arm_dwarf_register_span (rtx rtl)
     }
   else
     {
+      /* D16-D31 (the high VFP registers) have no single-precision aliases,
+	 so GCC still models each of them as two consecutive 32-bit hard
+	 registers.  Consecutive DImode (D) registers are therefore spaced
+	 two GCC register numbers apart; stepping by one would describe the
+	 same D register twice (PR debug/91381).  */
       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 000000000..fe45e54b9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/pr91381.c
@@ -0,0 +1,26 @@
+/* PR debug/91381: a 128-bit NEON Q register variable bound to Q8 or above
+   (D16-D31, which have no single-precision aliases) must describe its two
+   constituent D registers with distinct DWARF register numbers.  Before the
+   fix the DWARF location repeated the low D register twice, e.g. for Q8:
+   DW_OP_regx 272; DW_OP_piece 8; DW_OP_regx 272; DW_OP_piece 8.  */
+
+/* { 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