https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128025

            Bug ID: 128025
           Summary: [DebugInfo] multiple_reg_loc_descriptor emits invalid
                    register pieces with -m32
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: debug
          Assignee: unassigned at gcc dot gnu.org
          Reporter: wujielun402 at gmail dot com
  Target Milestone: ---

With -m32 -m128bit-long-double, GCC describes a long double local using
three 5-byte DW_OP_piece operations, each attached to a 32-bit
general-purpose register. Each register can supply only 4 bytes.

Here -m32 selects 32-bit x86 code. The -m128bit-long-double option gives
long double a 16-byte storage size, including padding, and the emitted
type has DW_AT_byte_size 16. The floating-point format remains 80-bit
x87 extended precision; eax, edx, and ecx remain 32-bit registers.

Reproducer source (repro.c):

        static volatile long double sink;

        __attribute__ ((noinline, noclone)) long double
        keep_extended_in_gprs (long double input)
        {
          long double value = input + 1.0L;
          __asm__ volatile ("nop" : "+r" (value) : : "memory");
          sink = value;
          return value;
        }

Compile to an object:

        gcc -m32 -m128bit-long-double -O2 -g -gdwarf-5 -c repro.c -o repro.o

Compiler Explorer example:

https://godbolt.org/z/74n4joaxh

The "+r" asm constraint exercises the path that holds value in several
general-purpose registers. In the corresponding location-list range,
GCC emits:

        DW_OP_reg0 (eax); DW_OP_piece 5
        DW_OP_reg2 (edx); DW_OP_piece 5
        DW_OP_reg1 (ecx); DW_OP_piece 5

DWARF 5 section 2.6.1.2 defines the DW_OP_piece operand as the byte size
of the object piece described by the preceding location. For example,
DW_OP_reg0 (eax); DW_OP_piece 5 requests 5 bytes from eax. This asks a
32-bit register to supply 40 bits, so the register location cannot
provide the described piece. The same problem affects edx and ecx.

The producer is the contiguous-register path in multiple_reg_loc_descriptor
in gcc/dwarf2out.cc. It divides the XFmode storage size by REG_NREGS using
size /= nregs. Here that calculation is 16 / 3, which truncates to 5, so
all three registers receive DW_OP_piece 5. The resulting pieces also
total only 15 bytes.

The piece sizes should follow the actual register layout and fit within
the referenced registers, with unavailable padding accounted for
separately. Dividing the padded storage size equally among the registers
does not produce a valid location description in this case.

Reply via email to