From: Max Kazantsev Date: Fri, 28 Apr 2017 06:25:39 +0000 (+0000) Subject: [EarlyCSE] Mark the condition of assume intrinsic as true X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6faf1a3c280834a0eab92a59ebe94da4fd8e4d81;p=llvm [EarlyCSE] Mark the condition of assume intrinsic as true EarlyCSE should not just ignore assumes. It should use the fact that its condition is true for all dominated instructions. Reviewers: sanjoy, reames, apilipenko, anna, skatkov Reviewed By: reames, sanjoy Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D32482 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@301625 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Transforms/Scalar/EarlyCSE.cpp b/lib/Transforms/Scalar/EarlyCSE.cpp index da33c7aa836..def10f1d41b 100644 --- a/lib/Transforms/Scalar/EarlyCSE.cpp +++ b/lib/Transforms/Scalar/EarlyCSE.cpp @@ -635,10 +635,16 @@ bool EarlyCSE::processNode(DomTreeNode *Node) { // Skip assume intrinsics, they don't really have side effects (although // they're marked as such to ensure preservation of control dependencies), - // and this pass will not disturb any of the assumption's control - // dependencies. + // and this pass will not bother with its removal. However, we should mark + // its condition as true for all dominated blocks. if (match(Inst, m_Intrinsic())) { - DEBUG(dbgs() << "EarlyCSE skipping assumption: " << *Inst << '\n'); + auto *CondI = + dyn_cast(cast(Inst)->getArgOperand(0)); + if (CondI && SimpleValue::canHandle(CondI)) { + DEBUG(dbgs() << "EarlyCSE considering assumption: " << *Inst << '\n'); + AvailableValues.insert(CondI, ConstantInt::getTrue(BB->getContext())); + } else + DEBUG(dbgs() << "EarlyCSE skipping assumption: " << *Inst << '\n'); continue; } diff --git a/test/Transforms/EarlyCSE/guards.ll b/test/Transforms/EarlyCSE/guards.ll index 5d1e3835c9a..de43264db6f 100644 --- a/test/Transforms/EarlyCSE/guards.ll +++ b/test/Transforms/EarlyCSE/guards.ll @@ -3,6 +3,8 @@ declare void @llvm.experimental.guard(i1,...) +declare void @llvm.assume(i1) + define i32 @test0(i32* %ptr, i1 %cond) { ; We can do store to load forwarding over a guard, since it does not ; clobber memory @@ -336,3 +338,191 @@ if.false: merge: ret void } + +define void @test12(i32 %a, i32 %b) { +; Check that the assume marks its condition as being true (and thus allows to +; eliminate the dominated guards). + +; CHECK-LABEL: @test12( +; CHECK-NEXT: %cmp = icmp eq i32 %a, %b +; CHECK-NEXT: call void @llvm.assume(i1 %cmp) +; CHECK-NEXT: ret void + + %cmp = icmp eq i32 %a, %b + call void @llvm.assume(i1 %cmp) + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + ret void +} + +define void @test13(i32 %a, i32 %b, i32* %ptr) { +; Check that we deal correctly with stores when removing guards due to assume. + +; CHECK-LABEL: @test13( +; CHECK-NEXT: %cmp = icmp eq i32 %a, %b +; CHECK-NEXT: call void @llvm.assume(i1 %cmp) +; CHECK-NEXT: store i32 400, i32* %ptr +; CHECK-NEXT: ret void + + %cmp = icmp eq i32 %a, %b + call void @llvm.assume(i1 %cmp) + store i32 100, i32* %ptr + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + store i32 200, i32* %ptr + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + store i32 300, i32* %ptr + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + store i32 400, i32* %ptr + ret void +} + +define void @test14(i32 %a, i32 %b, i1 %c, i32* %ptr) { +; Similar to test13, but with more control flow. +; TODO: Can we get rid of the store in the end of entry given that it is +; post-dominated by other stores? + +; CHECK-LABEL: @test14( +; CHECK: entry: +; CHECK-NEXT: %cmp = icmp eq i32 %a, %b +; CHECK-NEXT: call void @llvm.assume(i1 %cmp) +; CHECK-NEXT: store i32 400, i32* %ptr +; CHECK-NEXT: br i1 %c, label %if.true, label %if.false +; CHECK: if.true: +; CHECK-NEXT: store i32 500, i32* %ptr +; CHECK-NEXT: br label %merge +; CHECK: if.false: +; CHECK-NEXT: store i32 600, i32* %ptr +; CHECK-NEXT: br label %merge +; CHECK: merge: +; CHECK-NEXT: ret void + +entry: + %cmp = icmp eq i32 %a, %b + call void @llvm.assume(i1 %cmp) + store i32 100, i32* %ptr + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + store i32 200, i32* %ptr + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + store i32 300, i32* %ptr + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + store i32 400, i32* %ptr + br i1 %c, label %if.true, label %if.false + +if.true: + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + store i32 500, i32* %ptr + br label %merge + +if.false: + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + store i32 600, i32* %ptr + br label %merge + +merge: + ret void +} + +define void @test15(i32 %a, i32 %b, i1 %c, i32* %ptr) { +; Make sure that non-dominating assumes do not cause guards removal. + +; CHECK-LABEL: @test15( +; CHECK: entry: +; CHECK-NEXT: %cmp = icmp eq i32 %a, %b +; CHECK-NEXT: br i1 %c, label %if.true, label %if.false +; CHECK: if.true: +; CHECK-NEXT: call void @llvm.assume(i1 %cmp) +; CHECK-NEXT: store i32 100, i32* %ptr +; CHECK-NEXT: br label %merge +; CHECK: if.false: +; CHECK-NEXT: store i32 200, i32* %ptr +; CHECK-NEXT: br label %merge +; CHECK: merge: +; CHECK-NEXT: store i32 300, i32* %ptr +; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] +; CHECK-NEXT: store i32 400, i32* %ptr +; CHECK-NEXT: ret void + +entry: + %cmp = icmp eq i32 %a, %b + br i1 %c, label %if.true, label %if.false + +if.true: + call void @llvm.assume(i1 %cmp) + store i32 100, i32* %ptr + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + br label %merge + +if.false: + store i32 200, i32* %ptr + br label %merge + +merge: + store i32 300, i32* %ptr + call void (i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ] + store i32 400, i32* %ptr + ret void +} + +define void @test16(i32 %a, i32 %b) { +; Check that we don't bother to do anything with assumes even if we know the +; condition being true. + +; CHECK-LABEL: @test16( +; CHECK-NEXT: %cmp = icmp eq i32 %a, %b +; CHECK-NEXT: call void @llvm.assume(i1 %cmp) +; CHECK-NEXT: call void @llvm.assume(i1 %cmp) +; CHECK-NEXT: ret void + + %cmp = icmp eq i32 %a, %b + call void @llvm.assume(i1 %cmp) + call void @llvm.assume(i1 %cmp) + ret void +} + +define void @test17(i32 %a, i32 %b, i1 %c, i32* %ptr) { +; Check that we don't bother to do anything with assumes even if we know the +; condition being true or false (includes come control flow). + +; CHECK-LABEL: @test17( +; CHECK: entry: +; CHECK-NEXT: %cmp = icmp eq i32 %a, %b +; CHECK-NEXT: br i1 %c, label %if.true, label %if.false +; CHECK: if.true: +; CHECK-NEXT: call void @llvm.assume(i1 %cmp) +; CHECK-NEXT: br label %merge +; CHECK: if.false: +; CHECK-NEXT: call void @llvm.assume(i1 %cmp) +; CHECK-NEXT: br label %merge +; CHECK: merge: +; CHECK-NEXT: ret void + +entry: + %cmp = icmp eq i32 %a, %b + br i1 %c, label %if.true, label %if.false + +if.true: + call void @llvm.assume(i1 %cmp) + br label %merge + +if.false: + call void @llvm.assume(i1 %cmp) + br label %merge + +merge: + ret void +} + +define void @test18(i1 %c) { +; Check that we don't bother to do anything with assumes even if we know the +; condition being true and not being an instruction. + +; CHECK-LABEL: @test18( +; CHECK-NEXT: call void @llvm.assume(i1 %c) +; CHECK-NEXT: call void @llvm.assume(i1 %c) +; CHECK-NEXT: ret void + + call void @llvm.assume(i1 %c) + call void @llvm.assume(i1 %c) + ret void +}