llvm-project
llvm-project copied to clipboard
Instcombine miscompile removing memcpy from constant memory to alloca
https://alive2.llvm.org/ce/z/4Qv6c5
$ cat /tmp/a.ll
@g = external constant [128 x i8]
define void @f() {
%a = alloca [128 x i8]
call void @bar(ptr %a) readonly
call void @llvm.memcpy.p0.p0.i64(ptr %a, ptr @g, i64 128, i1 false)
ret void
}
declare void @llvm.memcpy.p0.p0.i64(ptr nocapture, ptr nocapture, i64, i1)
declare void @bar(ptr)
$ opt -p instcombine -S /tmp/a.ll
@g = external constant [128 x i8]
define void @f() {
call void @bar(ptr nonnull @g) #1
ret void
}
; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #0
declare void @bar(ptr)
attributes #0 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
attributes #1 = { memory(read) }
I don't understand what UB alive2 claims the optimized function is triggering. But separately this does seem wrong in the context of poison vs undef. Previously we'd hand bar
an alloca containing undef, but now we pass bar
g
which may contain poison.
https://github.com/llvm/llvm-project/blob/3a4e9f7ae50980ce8f103cbe86d24c574c8c6cac/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp#L525 is where this happens.
@nunoplopes
(also this optimization seems like it should be in memcpyopt, not instcombine)
FWIW, Alive2 isn't great with alloca pointers passed as argument to other functions. The implementation is not finished yet, sorry.
Even ignoring the poison vs undef thing, the transform isn't legal: the function @bar
could check if it's passed a pointer to @g
.