Commit fb9c9eb
authored
[X86][GISel] Fix carry-in for selectUAddSub. (llvm#199261)
When G_UADDE/G_USUBE was chained off a previous G_UADDE/G_UADDO/
G_USUBE/G_USUBO, selectUAddSub re-materialized EFLAGS.CF from the
previous SETB byte using CMP r, 1. That computes (r - 1) and sets
CF iff r < 1 unsigned, i.e. CF = (r == 0) -- the inverse of the
desired carry. The following ADC/SBB then consumed the wrong CF and
produced an off-by-one upper word; e.g. `add i128 0xFF..FF, 1` under
-global-isel returned hi=0 lo=0 instead of hi=1 lo=0.
Emit NEG r instead: NEG sets CF iff its operand is non-zero, matching
the SETB byte. NEG is a two-address (tied) instruction, so emit it
into a fresh virtual register rather than redefining the carry-in
vreg.
C reproducer (compile on x86_64-linux-gnu and run):
```
// clang -O2 -fglobal-isel repro.c -o repro && ./repro
#include <stdio.h>
__attribute__((noinline))
__int128 add128(__int128 a, __int128 b) { return a + b; }
int main(void) {
__int128 a = (__int128)0xFFFFFFFFFFFFFFFFULL;
__int128 r = add128(a, 1);
unsigned long long lo = r, hi = r >> 64;
printf("hi=0x%llx lo=0x%llx\n", hi, lo);
return (hi == 1 && lo == 0) ? 0 : 1;
}
```
Without -fglobal-isel: prints "hi=0x1 lo=0x0", exits 0.
With -fglobal-isel: prints "hi=0x0 lo=0x0", exits 1.
The buggy code-gen emits the inverted-carry sequence (clang trunk,
pre-fix):
```
add128:
movq %rdx, %rax
addq %rdi, %rax
setb %dl
cmpb $1, %dl # CF = (dl == 0), inverse of intended
adcq %rsi, %rcx
movq %rcx, %rdx
retq
```
This bug was found by a large run of Opus 4.7 looking for bugs in
LLVM.1 parent c0c56f4 commit fb9c9eb
4 files changed
Lines changed: 18 additions & 17 deletions
File tree
- llvm
- lib/Target/X86/GISel
- test/CodeGen/X86/GlobalISel
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1272 | 1272 | | |
1273 | 1273 | | |
1274 | 1274 | | |
1275 | | - | |
1276 | | - | |
1277 | | - | |
1278 | | - | |
1279 | | - | |
1280 | | - | |
| 1275 | + | |
| 1276 | + | |
| 1277 | + | |
1281 | 1278 | | |
1282 | 1279 | | |
1283 | 1280 | | |
| 1281 | + | |
| 1282 | + | |
| 1283 | + | |
| 1284 | + | |
1284 | 1285 | | |
1285 | 1286 | | |
1286 | 1287 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | | - | |
| 11 | + | |
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
28 | | - | |
| 28 | + | |
29 | 29 | | |
30 | 30 | | |
31 | | - | |
| 31 | + | |
32 | 32 | | |
33 | 33 | | |
34 | | - | |
| 34 | + | |
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
| |||
57 | 57 | | |
58 | 58 | | |
59 | 59 | | |
60 | | - | |
| 60 | + | |
61 | 61 | | |
62 | 62 | | |
63 | 63 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
32 | 32 | | |
33 | 33 | | |
34 | 34 | | |
35 | | - | |
| 35 | + | |
36 | 36 | | |
37 | 37 | | |
38 | 38 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
11 | | - | |
| 11 | + | |
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
28 | | - | |
| 28 | + | |
29 | 29 | | |
30 | 30 | | |
31 | | - | |
| 31 | + | |
32 | 32 | | |
33 | 33 | | |
34 | | - | |
| 34 | + | |
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
| |||
58 | 58 | | |
59 | 59 | | |
60 | 60 | | |
61 | | - | |
| 61 | + | |
62 | 62 | | |
63 | 63 | | |
64 | 64 | | |
| |||
0 commit comments