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

Reply via email to