https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128515
Bug ID: 128515
Summary: [14/15/16/17 Regression] wrong code at -O2:
subtract-with-borrow on a 33-bit unsigned type becomes
.USUBC and is not reduced to 33 bits since r14-3541
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: wrong-code
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: jeffchen006 at gmail dot com
Target Milestone: ---
Target: x86_64-pc-linux-gnu
Test 1 (bit-fields):
int printf(const char *, ...);
struct S { unsigned long long a : 33, b : 33; };
struct S x = { 0, 0 }, y = { 1, 0 };
int main(void)
{
__typeof(x.a + 0) r0 = x.a - y.a;
__typeof(x.a + 0) c = r0 > x.a;
__typeof(x.a + 0) r1 = x.b - y.b - c;
printf("%llx %llx\n", (unsigned long long)r0, (unsigned long long)r1);
return 0;
}
Test 2 (_BitInt):
int printf(const char *, ...);
typedef unsigned _BitInt(33) T;
T a0 = 0, a1 = 0, b0 = 1, b1 = 0;
int main(void)
{
T r0 = a0 - b0;
T c = r0 > a0;
T r1 = a1 - b1 - c;
printf("%llx %llx\n", (unsigned long long)r0, (unsigned long long)r1);
return 0;
}
$ gcc -O0 t.c && ./a.out
1ffffffff 1ffffffff
$ gcc -O2 t.c && ./a.out
ffffffffffffffff ffffffffffffffff
Both tests give this output.
Expected 1ffffffff: 0 - 1 in a 33-bit unsigned type is 0x1ffffffff.
Cause: widening_mul makes .USUBC from the subtract-with-borrow chain.
match_uaddc_usubc (tree-ssa-math-opts.cc) does not check that the type has the
precision of its mode. The DImode usubc5 pattern is used, and the result is
never reduced to 33 bits. Add-with-carry (.UADDC) has the same problem.
Since GCC 14: test 1 is correct on 13.4 and wrong on 14.3, 15.2, 16.2 and
trunk. First bad commit: r14-3541-ga7aec76a74d (improved uaddc/usubc pattern
matching, PR111209).
UBSan and ASan are clean at -O0.
gcc version 17.0.0 20261029 (experimental), r17-5747-g85867b0c935,
x86_64-pc-linux-gnu