llvm-project icon indicating copy to clipboard operation
llvm-project copied to clipboard

Instcombine miscompile removing memcpy from constant memory to alloca

Open aeubanks opened this issue 1 year ago • 3 comments

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

aeubanks avatar Jun 27 '23 21:06 aeubanks

(also this optimization seems like it should be in memcpyopt, not instcombine)

aeubanks avatar Jun 27 '23 21:06 aeubanks

FWIW, Alive2 isn't great with alloca pointers passed as argument to other functions. The implementation is not finished yet, sorry.

nunoplopes avatar Jun 27 '23 22:06 nunoplopes

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.

efriedma-quic avatar Jun 27 '23 22:06 efriedma-quic