dw_sra_loc_expr uses a field's memory size for DW_OP_piece. For an x87
long double field, this emits a 12- or 16-byte piece for a register that
holds only 10 bytes, producing an invalid DWARF location.
Limit the register piece to its value bits and use the existing padding
handling to mark the remaining 2 or 6 bytes as unavailable. This
preserves the offsets of subsequent fields.
gcc/ChangeLog:
PR debug/128031
* dwarf2out.cc: Include regs.h.
(dw_sra_loc_expr): Separate trailing floating-point padding from
single-register pieces.
gcc/testsuite/ChangeLog:
PR debug/128031
* gcc.dg/debug/dwarf2/pr128031.c: New test.
Signed-off-by: Jielun Wu <[email protected]>
---
Bootstrapped and regression tested on x86_64-pc-linux-gnu with no new
regressions. Existing baseline failures are unchanged. Also tested
the DWARF testsuite with -m32.
gcc/dwarf2out.cc | 19 +++++-
gcc/testsuite/gcc.dg/debug/dwarf2/pr128031.c | 64 ++++++++++++++++++++
2 files changed, 82 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/pr128031.c
diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
index
ca21fe6f1000034802a5ef71dfb50dda9f351be6..d806d904f342543916af46b741abf651e933c54f
100644
--- a/gcc/dwarf2out.cc
+++ b/gcc/dwarf2out.cc
@@ -66,6 +66,7 @@ along with GCC; see the file COPYING3. If not see
#include "tm_p.h"
#include "stringpool.h"
#include "insn-config.h"
+#include "regs.h"
#include "ira.h"
#include "cgraph.h"
#include "diagnostic.h"
@@ -17991,7 +17992,6 @@ dw_sra_loc_expr (tree decl, rtx loc)
descr_tail = tail;
if (bitsize > decl_size)
goto discard_descr;
- decl_size -= bitsize;
if (last == NULL)
{
HOST_WIDE_INT offset = 0;
@@ -18002,6 +18002,22 @@ dw_sra_loc_expr (tree decl, rtx loc)
if (GET_CODE (varloc) == EXPR_LIST)
varloc = XEXP (varloc, 0);
}
+ /* A floating-point register need not supply the mode's trailing
+ padding. Require a mode that can save the register, and only
+ split layouts with trailing padding in little-endian memory. */
+ scalar_float_mode mode;
+ if (REG_P (varloc)
+ && is_a <scalar_float_mode> (GET_MODE (varloc), &mode)
+ && mode == HARD_REGNO_CALLER_SAVE_MODE (REGNO (varloc), 1, mode)
+ && GET_MODE_PRECISION (mode) < bitsize
+ && !BYTES_BIG_ENDIAN
+ && !FLOAT_WORDS_BIG_ENDIAN
+ && REAL_MODE_FORMAT (mode)->signbit_ro
+ == GET_MODE_PRECISION (mode) - 1)
+ {
+ padsize = bitsize - GET_MODE_PRECISION (mode);
+ bitsize -= padsize;
+ }
do
{
if (GET_CODE (varloc) == CONST
@@ -18041,6 +18057,7 @@ dw_sra_loc_expr (tree decl, rtx loc)
goto discard_descr;
descr_tail = &(*descr_tail)->dw_loc_next;
}
+ decl_size -= bitsize;
}
/* If there were any non-empty expressions, add padding till the end of
diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/pr128031.c
b/gcc/testsuite/gcc.dg/debug/dwarf2/pr128031.c
new file mode 100644
index
0000000000000000000000000000000000000000..aaed057bd296f78725b765c9341da362ab1bf4e7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/dwarf2/pr128031.c
@@ -0,0 +1,64 @@
+/* PR debug/128031 */
+/* { dg-do compile { target { i?86-*-* x86_64-*-* } } } */
+/* { dg-options "-O2 -g -gdwarf-5 -dA" } */
+/* { dg-additional-options "-m96bit-long-double" { target ia32 } } */
+/* { dg-additional-options "-m128bit-long-double" { target { ! ia32 } } } */
+
+struct record
+{
+ long double value;
+ unsigned int tag;
+};
+
+__attribute__ ((noinline, noclone)) long double
+sra_x87_piece_live (long double input, unsigned int tag)
+{
+ struct record value;
+ value.value = input * 3.0L;
+ value.tag = tag;
+ return value.value + (long double) value.tag;
+}
+
+struct final_record
+{
+ unsigned int tag;
+ long double value;
+};
+
+__attribute__ ((noinline, noclone)) long double
+sra_x87_final_piece (long double input, unsigned int tag)
+{
+ struct final_record value;
+ value.tag = tag;
+ value.value = input * 3.0L;
+ return value.value + (long double) value.tag;
+}
+
+struct missing_record
+{
+ long double value;
+ unsigned int unused;
+ unsigned int tag;
+};
+
+__attribute__ ((noinline, noclone)) long double
+sra_x87_missing_piece (long double input, unsigned int tag)
+{
+ struct missing_record value;
+ value.value = input * 3.0L;
+ value.tag = tag;
+ return value.value + (long double) value.tag;
+}
+
+/* The register supplies 10 bytes, followed by 2 or 6 unavailable padding
+ bytes and the 4-byte tag. */
+/* { dg-final { scan-assembler
{DW_OP_reg[0-9]+\n[^\n]*DW_OP_piece\n[^\n]*0xa\n[^\n]*DW_OP_piece\n[^\n]*0x2\n[^\n]*DW_OP_fbreg\n[^\n]*\n[^\n]*DW_OP_piece\n[^\n]*0x4}
{ target ia32 } } } */
+/* { dg-final { scan-assembler
{DW_OP_regx\n[^\n]*\n[^\n]*DW_OP_piece\n[^\n]*0xa\n[^\n]*DW_OP_piece\n[^\n]*0x6\n[^\n]*DW_OP_reg[0-9]+\n[^\n]*DW_OP_piece\n[^\n]*0x4}
{ target { ! ia32 } } } } */
+
+/* Ordinary and final fields have the same padding. */
+/* { dg-final { scan-assembler-times
{DW_OP_reg[0-9x]+(\n[^\n]*)?\n[^\n]*DW_OP_piece\n[^\n]*0xa\n[^\n]*DW_OP_piece\n[^\n]*0x2}
2 { target ia32 } } } */
+/* { dg-final { scan-assembler-times
{DW_OP_reg[0-9x]+(\n[^\n]*)?\n[^\n]*DW_OP_piece\n[^\n]*0xa\n[^\n]*DW_OP_piece\n[^\n]*0x6}
2 { target { ! ia32 } } } } */
+
+/* Padding coalesces with the following unavailable field. */
+/* { dg-final { scan-assembler-times
{DW_OP_reg[0-9x]+(\n[^\n]*)?\n[^\n]*DW_OP_piece\n[^\n]*0xa\n[^\n]*DW_OP_piece\n[^\n]*0x6}
1 { target ia32 } } } */
+/* { dg-final { scan-assembler-times
{DW_OP_reg[0-9x]+(\n[^\n]*)?\n[^\n]*DW_OP_piece\n[^\n]*0xa\n[^\n]*DW_OP_piece\n[^\n]*0xa}
1 { target { ! ia32 } } } } */
base-commit: 56ea963549ef4eeba0d6d3fe01ef5ad9a62e334e