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

            Bug ID: 128392
           Summary: [DebugInfo] x86_64: negative shift in DWARF location
                    for signed _BitInt remainders
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: debug
          Assignee: unassigned at gcc dot gnu.org
          Reporter: MrEven132 at outlook dot com
  Target Milestone: ---

With GCC 17.0.0 20261003 (experimental) and GDB 17.2 on x86_64 GNU/Linux, GDB
prints 0 instead of -1 for signed _BitInt(7) and _BitInt(8) remainders at -O2.
The same variables and breakpoints give the correct value at -O0. Evaluating
the optimized remainder also produces "warning: left shift count is negative".

Test case 1 (_BitInt(7), case.c):

    volatile int sink_bitint;

    __attribute__((noinline))
    int
    test_bitint_signed (_BitInt(7) a, _BitInt(7) b)
    {
      _BitInt(7) quotient = a / b;
      _BitInt(7) remainder = a % b;
      sink_bitint += a + b;
      return quotient + remainder;
    }

    __attribute__((noinline))
    int
    test_bitint_unsigned (unsigned _BitInt(9) a, unsigned _BitInt(9) b)
    {
      unsigned _BitInt(9) remainder = a % b;
      sink_bitint += a + b;
      return remainder;
    }

    int
    main (void)
    {
      return test_bitint_signed (-55, 3)
        + test_bitint_unsigned (400, 9);
    }

Test case 2 (_BitInt(8), case.c):

    volatile int sink_bitint_width;

    __attribute__((noinline))
    int
    test_bitint8 (_BitInt(8) a, _BitInt(8) b)
    {
      _BitInt(8) quotient = a / b;
      _BitInt(8) remainder = a % b;
      sink_bitint_width += a + b;
      return quotient + remainder;
    }

    __attribute__((noinline))
    int
    test_bitint9 (_BitInt(9) a, _BitInt(9) b)
    {
      _BitInt(9) quotient = a / b;
      _BitInt(9) remainder = a % b;
      sink_bitint_width += a + b;
      return quotient + remainder;
    }

    __attribute__((noinline))
    int
    test_bitint16 (_BitInt(16) a, _BitInt(16) b)
    {
      _BitInt(16) quotient = a / b;
      _BitInt(16) remainder = a % b;
      sink_bitint_width += a + b;
      return quotient + remainder;
    }

    int
    main (void)
    {
      return test_bitint8 (-55, 3)
        + test_bitint9 (-251, 7)
        + test_bitint16 (-30001, 7);
    }

Build each test case separately on x86_64:

    gcc -O0 -g case.c -o case-O0
    gcc -O2 -g case.c -o case-O2

In a fresh GDB session for each executable, break at case.c:9 (the sink update
in test_bitint_signed or test_bitint8), run, and print quotient and remainder:

    break case.c:9
    run
    print quotient
    print remainder

Both calls have a = -55 and b = 3. The results are:

                            Expected   GDB -O0   GDB -O2
    _BitInt(7) quotient          -18       -18       -18
    _BitInt(7) remainder          -1        -1         0
    _BitInt(8) quotient          -18       -18       -18
    _BitInt(8) remainder          -1        -1         0

GDB emits "warning: left shift count is negative" when printing remainder in
both -O2 executables.

The active DW_AT_location list entries for remainder at these optimized
breakpoints are:

    _BitInt(7), test_bitint_signed, breakpoint PC 0x401153:
    [0x401153, 0x401169): DW_OP_breg0 (rax): 0; DW_OP_const1s: -8; DW_OP_shl;
DW_OP_lit1; DW_OP_shl; DW_OP_lit1; DW_OP_shra; DW_OP_stack_value

    _BitInt(8), test_bitint8, breakpoint PC 0x401159:
    [0x401159, 0x40116a): DW_OP_breg0 (rax): 0; DW_OP_const1s: -8; DW_OP_shl;
DW_OP_stack_value

For example, at the _BitInt(8) breakpoint, RAX is 0xffffffee. The preceding
instruction is a byte division, idiv %sil, so AL contains the quotient -18 and
AH contains 0xff, representing the correct remainder -1. GDB nevertheless
prints remainder = 0.

The generated expressions use a negative left-shift count when extracting the
remainder from the high byte of AX. This appears to be incorrect debug-info
lowering of the byte extraction; the machine remainder is correct.

Reply via email to