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.