This isn't safe to do.
Link: https://github.com/llvm/llvm-project/issues/53562
Fixes: https://github.com/llvm/llvm-project/issues/61023
Differential D144927
[GVNHoist] don't hoist callbr users into the callbr's block nickdesaulniers on Feb 27 2023, 3:27 PM. Authored by
Details This isn't safe to do. Link: https://github.com/llvm/llvm-project/issues/53562
Diff Detail
Unit Tests Event Timeline
Comment Actions I've verified that this fixes the problem I saw ( https://github.com/llvm/llvm-project/issues/61023 ). Comment Actions
Comment Actions If you're going to enable hoisting past a callbr, please add a testcase to ensure we don't hoist a load past a callbr which modifies the memory in question. Comment Actions Will do. Curiously, GVNHoist::safeToHoistLdSt returns false even for cases of loads not modified by callbr, so HoistGVN doesn't optimize those cases. FWICT, the call to GVNHoist::firstInBB is checking the callbr against itself. It looks like MemorySSA is perhaps claiming that for this input: @x = global i32 0 @y = global i32 0 define i32 @foo4(i1 %z) { entry: callbr void asm "", "=*m,!i"(ptr elementtype(i32) @x) to label %a [label %b] a: ; preds = %entry %0 = load i32, ptr @y, align 4 ret i32 %0 b: ; preds = %entry %1 = load i32, ptr @y, align 4 ret i32 %1 } that callbr is a "defining access" for the access of @y (IIUC)? That seems incorrect...but I'm unfamiliar with MemorySSA. Comment Actions Ok, a quick read of https://llvm.org/docs/MemorySSA.html and running opt -S -passes=gvn-hoist,'print<memoryssa>' llvm/test/Transforms/GVNHoist/hoist-call.ll -disable-output gives: MemorySSA for function: foo4 define i32 @foo4(i1 %z) { entry: ; 1 = MemoryDef(liveOnEntry) callbr void asm "", "=*m,!i"(ptr elementtype(i32) @x) to label %a [label %b] a: ; preds = %entry ; MemoryUse(1) %0 = load i32, ptr @y, align 4 ret i32 %0 b: ; preds = %entry ; MemoryUse(1) %1 = load i32, ptr @y, align 4 ret i32 %1 } Shouldn't callbr have it's own dedicated MemoryDef that's distinct from liveOnEntry? Comment Actions Hmm..maybe not? We don't for vanilla inline asm (non-asm-goto) that modifies memory: https://godbolt.org/z/4144Wd7e1. Shouldn't inline asm qualify as a MemoryAccess when "m" constraints are used?
Comment Actions MemorySSA is a very conservative wrapper on top of alias analysis. for any global, it is unlikely to be precise.
Comment Actions
Comment Actions
Comment Actions Huh, the Windows buildbot seems to be complaining about this: https://lab.llvm.org/buildbot/#/builders/127/builds/45021/steps/7/logs/stdio Not sure what's going wrong though... |
I guess CallBrInst is the only terminator that may define values today, but who knows about the future. So it would be nice generalize this somehow, i.e. not explicitly checking if the Terminator is a CallBrInst but rather checking if the terminator is a def.
Maybe we could just skip the IsCallBrTerminated check?