-
Notifications
You must be signed in to change notification settings - Fork 14.7k
Description
Bugzilla Link | 52570 |
Version | trunk |
OS | Linux |
CC | @dwblaikie,@DougGregor,@randomnetcat,@JohelEGP,@momchil-velikov,@zygoloid |
Extended Description
extern int x[1], y;
int f(int *p, int *q) {
*q = y;
if (p == (x + 1)) {
*p = 2;
return y;
}
return 0;
}
LLVM trunk currently outputs the following code with -O3 -mtune=znver3 (without it it outputs correct code but I'm pretty sure it still makes the same wrong assumption about the value of p
):
f:
mov eax, dword ptr [rip + y]
mov dword ptr [rsi], eax
xor eax, eax
cmp rdi, offset x+4
je .LBB0_1
ret
.LBB0_1:
mov eax, dword ptr [rip + y]
mov dword ptr [rip + x+4], 2
ret
Which is incorrect because p
could point to y
, for example if f
was called as such:
int whatever;
f(&y, &whatever);
and y
could happen to be located in memory right after x
.
Also, although the comparison's result is unspecified, this still means only two results are possible according to the standard:
- if
p == (x + 1)
results infalse
, then the result off
is 0 - if
p == (x + 1)
results intrue
, then the result off
is 2 since we do*p = 2
andp
points toy
LLVM's optimization makes it so the result can also be the previous value of y
, which could be something else than 0 or 2.
It seems that LLVM assumes that because p == (x + 1)
it can replace all occurences of p
with x + 1
without any regard to provenance, and doing that change manually would indeed mean the return y;
could be optimized to use the previous store (and the store to x + 1
would be UB, too...), but this isn't the case here: p
could simultaneously validly point to y
and be equal to x + 1
.
Godbolt link: https://godbolt.org/z/v73ME48qd