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