[PATCH] D37460: [GVN] Prevent LoadPRE from hoisting through guards
Max Kazantsev via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 11 00:12:29 PDT 2017
mkazantsev added inline comments.
================
Comment at: lib/Transforms/Scalar/GVN.cpp:2042
+ auto *II = dyn_cast<IntrinsicInst>(&I);
+ return II && II->getIntrinsicID() == Intrinsic::experimental_guard;
+ };
----------------
dberlin wrote:
> efriedma wrote:
> > Why does this specifically apply to guards, as opposed to anything where isGuaranteedToTransferExecutionToSuccessor() is false?
> Yeah, it looks like GVN presumes that if it's a straight line non-infinite loop, they have the same "guaranteed to execute" properties.
>
> As you correctly point out, since LLVM has implicit control flow, this is not always true.
> I suspect GVN's PRE is quite broken here in that respect in theory.
>
> However, most of the effect of isGuaranteed is on memory instructions, and those almost certainly get corrected by memdep (IE it ends up respecting the same things that isGuaranteed* is respecting).
> Going through the rest:
>
> ```
> if (const auto *CRI = dyn_cast<CleanupReturnInst>(I))
> return !CRI->unwindsToCaller();
> if (const auto *CatchSwitch = dyn_cast<CatchSwitchInst>(I))
> return !CatchSwitch->unwindsToCaller();
> if (isa<ResumeInst>(I))
> return false;
> if (isa<ReturnInst>(I))
> return false;
> if (isa<UnreachableInst>(I))
> return false;
>
> ```
> None of these will have successors, so there shouldn't be a predecessor we hit to check anyway.
> You can hoist above them, just not sink below them.
>
> So those should be fine.
>
> The callsite checking, except for throwing, is probably also handled by memdep's insertion of memory dependencies.
>
> So I suspect you may be able to rig up a testcase where memdep and isGuaranteed* end up disagreeing in a way that causes this to break. But i also suspect it's hard.
>
> Thoughts?
>
>
Hi Eli,
I tried to use use `isGuaranteedToTransferExecutionToSuccessor`, and it works for my example, but another tests starts failing. The test is `test7` from `Transforms/GVN/PRE/volatile.ll` which is:
; Does cross block PRE work with volatiles?
define i32 @test7(i1 %c, i32* noalias nocapture %p, i32* noalias nocapture %q) {
; CHECK-LABEL: test7
; CHECK-LABEL: entry.header_crit_edge:
; CHECK: %y.pre = load i32, i32* %p
; CHECK-LABEL: skip:
; CHECK: %y1 = load i32, i32* %p
; CHECK-LABEL: header:
; CHECK: %y = phi i32
; CHECK-NEXT: %x = load volatile i32, i32* %q
; CHECK-NEXT: %add = sub i32 %y, %x
entry:
br i1 %c, label %header, label %skip
skip:
%y1 = load i32, i32* %p
call void @use(i32 %y1)
br label %header
header:
%x = load volatile i32, i32* %q
%y = load i32, i32* %p
%add = sub i32 %y, %x
%cnd = icmp eq i32 %add, 0
br i1 %cnd, label %exit, label %header
exit:
ret i32 %add
}
It now fails because this function returns false for olatile loads and stores because `they are allowed to trap`. This logic was added in patch https://reviews.llvm.org/D21167 and Sanjoy's comment about why we do that remained unanswered. I don't clearly understand why you've added that, could you please clarify why it was done and is it OK if this test now fails?
Thanks,
Max
https://reviews.llvm.org/D37460
More information about the llvm-commits
mailing list