-
Notifications
You must be signed in to change notification settings - Fork 13.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LLVM poisons partially undef constant, leading to infinite loops. #21996
Comments
One workaround would be to replace |
I haven't fully analyzed this, but that changing the memcpy size helps is coincidental. That just breaks a memcpy optimization that is required for the problem to show up, because the memcpy sizes now differ. AFAICT for now, this is some problem with aliasing. |
So looking through the relevant changes in LLVM, I noticed that the docs for See http://llvm.org/docs/LangRef.html#noalias Testing a patch now. |
FWIW, removing |
Nice find! |
On return values `noalias` has a stricter meaning than on arguments. It means that the function is malloc-like. To quote the LLVM docs: Furthermore, the semantics of the noalias attribute on return values are stronger than the semantics of the attribute when used on function arguments. On function return values, the noalias attribute indicates that the function acts like a system memory allocation function, returning a pointer to allocated storage disjoint from the storage for any other object accessible to the caller. We use it for all kinds of functions, which is wrong, so let's stop doing that. Fixes rust-lang#21996
@eddyb Fun fact, our suspicion that our usage of lifetime intrinsics was at fault for a bunch of failures might have been totally off. Different usage of lifetimes might just have killed different memcpy optimizations, hiding the real culprit lol I still need to fix them to allow for better optimization though :-/ |
So here's the minimal LLVM IR I have so far: target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"
%struct.S = type { i64, i64 }
@take.s = internal constant %struct.S { i64 1, i64 0 }
define internal void @swap(%struct.S* noalias %x, %struct.S* noalias %y) {
%tmp = alloca %struct.S
%1 = bitcast %struct.S* %tmp to i8*
%2 = bitcast %struct.S* %x to i8*
%3 = bitcast %struct.S* %y to i8*
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* %2, i64 16, i32 8, i1 false)
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %2, i8* %3, i64 16, i32 8, i1 false)
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %3, i8* %1, i64 16, i32 8, i1 false)
ret void
}
; Function Attrs: nounwind
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i32, i1) #0
define internal void @replace(%struct.S* noalias sret %agg.result, %struct.S* noalias %x, %struct.S* noalias %y) {
call void @swap(%struct.S* %x, %struct.S* %y)
%1 = bitcast %struct.S* %agg.result to i8*
%2 = bitcast %struct.S* %y to i8*
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* %2, i64 16, i32 8, i1 false)
ret void
}
define internal void @take(%struct.S* noalias sret %agg.result, %struct.S* noalias %x) {
%arg = alloca %struct.S
%1 = bitcast %struct.S* %arg to i8*
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* bitcast (%struct.S* @take.s to i8*), i64 16, i32 8, i1 false)
call void @replace(%struct.S* sret %agg.result, %struct.S* %x, %struct.S* %arg)
ret void
}
define void @take2(%struct.S* noalias sret %agg.result, %struct.S* noalias %x) {
call void @take(%struct.S* sret %agg.result, %struct.S* %x)
ret void
}
attributes #0 = { nounwind } Removing the |
Pretty sure this is a bug in the memcpyopt pass that doesn't update the scoped alias data. |
This happens only after the recent LLVM upgrade. The culprit seems to be half of
NO_FOO
:Changing the
memcpy
call to copy only 8 bytes instead of 16 (to not touch theundef
portion) removes the infinite loop.cc @dotdash @Aatch
The text was updated successfully, but these errors were encountered: