[llvm] r338988 - [GuardWidening] Widen guards with conditions of frequently taken dominated branches
Max Kazantsev via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 5 22:49:20 PDT 2018
Author: mkazantsev
Date: Sun Aug 5 22:49:19 2018
New Revision: 338988
URL: http://llvm.org/viewvc/llvm-project?rev=338988&view=rev
Log:
[GuardWidening] Widen guards with conditions of frequently taken dominated branches
If there is a frequently taken branch dominated by a guard, and its condition is available
at the point of the guard, we can widen guard with condition of this branch and convert
the branch into unconditional:
guard(cond1)
if (cond2) {
// taken in 99.9% cases
// do something
} else {
// do something else
}
Converts to
guard(cond1 && cond2)
// do something
Differential Revision: https://reviews.llvm.org/D49974
Reviewed By: reames
Added:
llvm/trunk/test/Transforms/GuardWidening/widen-frequent-branches.ll
Modified:
llvm/trunk/lib/Transforms/Scalar/GuardWidening.cpp
Modified: llvm/trunk/lib/Transforms/Scalar/GuardWidening.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/GuardWidening.cpp?rev=338988&r1=338987&r2=338988&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/GuardWidening.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/GuardWidening.cpp Sun Aug 5 22:49:19 2018
@@ -44,6 +44,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/Statistic.h"
+#include "llvm/Analysis/BranchProbabilityInfo.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/LoopPass.h"
#include "llvm/Analysis/PostDominators.h"
@@ -63,23 +64,47 @@ using namespace llvm;
#define DEBUG_TYPE "guard-widening"
STATISTIC(GuardsEliminated, "Number of eliminated guards");
+STATISTIC(CondBranchEliminated, "Number of eliminated conditional branches");
-namespace {
+static cl::opt<bool> WidenFrequentBranches(
+ "guard-widening-widen-frequent-branches", cl::Hidden,
+ cl::desc("Widen conditions of explicit branches into dominating guards in "
+ "case if their taken frequency exceeds threshold set by "
+ "guard-widening-frequent-branch-threshold option"),
+ cl::init(false));
+
+static cl::opt<unsigned> FrequentBranchThreshold(
+ "guard-widening-frequent-branch-threshold", cl::Hidden,
+ cl::desc("When WidenFrequentBranches is set to true, this option is used "
+ "to determine which branches are frequently taken. The criteria "
+ "that a branch is taken more often than "
+ "((FrequentBranchThreshold - 1) / FrequentBranchThreshold), then "
+ "it is considered frequently taken"),
+ cl::init(1000));
-// Get the condition of \p GuardInst.
-static Value *getGuardCondition(Instruction *GuardInst) {
- IntrinsicInst *GI = cast<IntrinsicInst>(GuardInst);
- assert(GI->getIntrinsicID() == Intrinsic::experimental_guard &&
- "Bad guard intrinsic?");
- return GI->getArgOperand(0);
-}
-// Set the condition for \p GuardInst to \p NewCond.
-static void setGuardCondition(Instruction *GuardInst, Value *NewCond) {
- IntrinsicInst *GI = cast<IntrinsicInst>(GuardInst);
- assert(GI->getIntrinsicID() == Intrinsic::experimental_guard &&
- "Bad guard intrinsic?");
- GI->setArgOperand(0, NewCond);
+namespace {
+
+// Get the condition of \p I. It can either be a guard or a conditional branch.
+static Value *getCondition(Instruction *I) {
+ if (IntrinsicInst *GI = dyn_cast<IntrinsicInst>(I)) {
+ assert(GI->getIntrinsicID() == Intrinsic::experimental_guard &&
+ "Bad guard intrinsic?");
+ return GI->getArgOperand(0);
+ }
+ return cast<BranchInst>(I)->getCondition();
+}
+
+// Set the condition for \p I to \p NewCond. \p I can either be a guard or a
+// conditional branch.
+static void setCondition(Instruction *I, Value *NewCond) {
+ if (IntrinsicInst *GI = dyn_cast<IntrinsicInst>(I)) {
+ assert(GI->getIntrinsicID() == Intrinsic::experimental_guard &&
+ "Bad guard intrinsic?");
+ GI->setArgOperand(0, NewCond);
+ return;
+ }
+ cast<BranchInst>(I)->setCondition(NewCond);
}
// Whether or not the particular instruction \p I is a guard.
@@ -98,15 +123,16 @@ class GuardWideningImpl {
DominatorTree &DT;
PostDominatorTree *PDT;
LoopInfo &LI;
+ BranchProbabilityInfo *BPI;
/// Together, these describe the region of interest. This might be all of
/// the blocks within a function, or only a given loop's blocks and preheader.
DomTreeNode *Root;
std::function<bool(BasicBlock*)> BlockFilter;
- /// The set of guards whose conditions have been widened into dominating
- /// guards.
- SmallVector<Instruction *, 16> EliminatedGuards;
+ /// The set of guards and conditional branches whose conditions have been
+ /// widened into dominating guards.
+ SmallVector<Instruction *, 16> EliminatedGuardsAndBranches;
/// The set of guards which have been widened to include conditions to other
/// guards.
@@ -240,15 +266,17 @@ class GuardWideningImpl {
void widenGuard(Instruction *ToWiden, Value *NewCondition) {
Value *Result;
widenCondCommon(ToWiden->getOperand(0), NewCondition, ToWiden, Result);
- setGuardCondition(ToWiden, Result);
+ setCondition(ToWiden, Result);
}
public:
explicit GuardWideningImpl(DominatorTree &DT, PostDominatorTree *PDT,
- LoopInfo &LI, DomTreeNode *Root,
+ LoopInfo &LI, BranchProbabilityInfo *BPI,
+ DomTreeNode *Root,
std::function<bool(BasicBlock*)> BlockFilter)
- : DT(DT), PDT(PDT), LI(LI), Root(Root), BlockFilter(BlockFilter) {}
+ : DT(DT), PDT(PDT), LI(LI), BPI(BPI), Root(Root), BlockFilter(BlockFilter)
+ {}
/// The entry point for this pass.
bool run();
@@ -258,6 +286,12 @@ public:
bool GuardWideningImpl::run() {
DenseMap<BasicBlock *, SmallVector<Instruction *, 8>> GuardsInBlock;
bool Changed = false;
+ Optional<BranchProbability> LikelyTaken = None;
+ if (WidenFrequentBranches && BPI) {
+ unsigned Threshold = FrequentBranchThreshold;
+ assert(Threshold > 0 && "Zero threshold makes no sense!");
+ LikelyTaken = std::move(BranchProbability(Threshold - 1, Threshold));
+ }
for (auto DFI = df_begin(Root), DFE = df_end(Root);
DFI != DFE; ++DFI) {
@@ -273,12 +307,25 @@ bool GuardWideningImpl::run() {
for (auto *II : CurrentList)
Changed |= eliminateGuardViaWidening(II, DFI, GuardsInBlock);
- }
-
- assert(EliminatedGuards.empty() || Changed);
- for (auto *II : EliminatedGuards)
- if (!WidenedGuards.count(II))
- eliminateGuard(II);
+ if (WidenFrequentBranches && BPI)
+ if (auto *BI = dyn_cast<BranchInst>(BB->getTerminator()))
+ if (BI->isConditional() &&
+ BPI->getEdgeProbability(BB, 0U) >= *LikelyTaken)
+ Changed |= eliminateGuardViaWidening(BI, DFI, GuardsInBlock);
+ }
+
+ assert(EliminatedGuardsAndBranches.empty() || Changed);
+ for (auto *I : EliminatedGuardsAndBranches)
+ if (!WidenedGuards.count(I)) {
+ assert(isa<ConstantInt>(getCondition(I)) && "Should be!");
+ if (isGuard(I))
+ eliminateGuard(I);
+ else {
+ assert(isa<BranchInst>(I) &&
+ "Eliminated something other than guard or branch?");
+ ++CondBranchEliminated;
+ }
+ }
return Changed;
}
@@ -320,7 +367,7 @@ bool GuardWideningImpl::eliminateGuardVi
assert((i == (e - 1)) == (GuardInst->getParent() == CurBB) && "Bad DFS?");
- if (i == (e - 1)) {
+ if (i == (e - 1) && CurBB->getTerminator() != GuardInst) {
// Corner case: make sure we're only looking at guards strictly dominating
// GuardInst when visiting GuardInst->getParent().
auto NewEnd = std::find(I, E, GuardInst);
@@ -331,8 +378,8 @@ bool GuardWideningImpl::eliminateGuardVi
for (auto *Candidate : make_range(I, E)) {
auto Score =
computeWideningScore(GuardInst, GuardInstLoop, Candidate, CurLoop);
- LLVM_DEBUG(dbgs() << "Score between " << *getGuardCondition(GuardInst)
- << " and " << *getGuardCondition(Candidate) << " is "
+ LLVM_DEBUG(dbgs() << "Score between " << *getCondition(GuardInst)
+ << " and " << *getCondition(Candidate) << " is "
<< scoreTypeToString(Score) << "\n");
if (Score > BestScoreSoFar) {
BestScoreSoFar = Score;
@@ -352,9 +399,9 @@ bool GuardWideningImpl::eliminateGuardVi
LLVM_DEBUG(dbgs() << "Widening " << *GuardInst << " into " << *BestSoFar
<< " with score " << scoreTypeToString(BestScoreSoFar)
<< "\n");
- widenGuard(BestSoFar, getGuardCondition(GuardInst));
- setGuardCondition(GuardInst, ConstantInt::getTrue(GuardInst->getContext()));
- EliminatedGuards.push_back(GuardInst);
+ widenGuard(BestSoFar, getCondition(GuardInst));
+ setCondition(GuardInst, ConstantInt::getTrue(GuardInst->getContext()));
+ EliminatedGuardsAndBranches.push_back(GuardInst);
WidenedGuards.insert(BestSoFar);
return true;
}
@@ -374,7 +421,7 @@ GuardWideningImpl::WideningScore GuardWi
HoistingOutOfLoop = true;
}
- if (!isAvailableAt(getGuardCondition(DominatedGuard), DominatingGuard))
+ if (!isAvailableAt(getCondition(DominatedGuard), DominatingGuard))
return WS_IllegalOrNegative;
// If the guard was conditional executed, it may never be reached
@@ -385,8 +432,8 @@ GuardWideningImpl::WideningScore GuardWi
// here. TODO: evaluate cost model for spurious deopt
// NOTE: As written, this also lets us hoist right over another guard which
// is essentially just another spelling for control flow.
- if (isWideningCondProfitable(getGuardCondition(DominatedGuard),
- getGuardCondition(DominatingGuard)))
+ if (isWideningCondProfitable(getCondition(DominatedGuard),
+ getCondition(DominatingGuard)))
return HoistingOutOfLoop ? WS_VeryPositive : WS_Positive;
if (HoistingOutOfLoop)
@@ -719,7 +766,10 @@ PreservedAnalyses GuardWideningPass::run
auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
auto &LI = AM.getResult<LoopAnalysis>(F);
auto &PDT = AM.getResult<PostDominatorTreeAnalysis>(F);
- if (!GuardWideningImpl(DT, &PDT, LI, DT.getRootNode(),
+ BranchProbabilityInfo *BPI = nullptr;
+ if (WidenFrequentBranches)
+ BPI = AM.getCachedResult<BranchProbabilityAnalysis>(F);
+ if (!GuardWideningImpl(DT, &PDT, LI, BPI, DT.getRootNode(),
[](BasicBlock*) { return true; } ).run())
return PreservedAnalyses::all();
@@ -742,7 +792,10 @@ struct GuardWideningLegacyPass : public
auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
auto &PDT = getAnalysis<PostDominatorTreeWrapperPass>().getPostDomTree();
- return GuardWideningImpl(DT, &PDT, LI, DT.getRootNode(),
+ BranchProbabilityInfo *BPI = nullptr;
+ if (WidenFrequentBranches)
+ BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
+ return GuardWideningImpl(DT, &PDT, LI, BPI, DT.getRootNode(),
[](BasicBlock*) { return true; } ).run();
}
@@ -751,6 +804,8 @@ struct GuardWideningLegacyPass : public
AU.addRequired<DominatorTreeWrapperPass>();
AU.addRequired<PostDominatorTreeWrapperPass>();
AU.addRequired<LoopInfoWrapperPass>();
+ if (WidenFrequentBranches)
+ AU.addRequired<BranchProbabilityInfoWrapperPass>();
}
};
@@ -776,11 +831,16 @@ struct LoopGuardWideningLegacyPass : pub
auto BlockFilter = [&](BasicBlock *BB) {
return BB == RootBB || L->contains(BB);
};
- return GuardWideningImpl(DT, PDT, LI,
+ BranchProbabilityInfo *BPI = nullptr;
+ if (WidenFrequentBranches)
+ BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
+ return GuardWideningImpl(DT, PDT, LI, BPI,
DT.getNode(RootBB), BlockFilter).run();
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
+ if (WidenFrequentBranches)
+ AU.addRequired<BranchProbabilityInfoWrapperPass>();
AU.setPreservesCFG();
getLoopAnalysisUsage(AU);
AU.addPreserved<PostDominatorTreeWrapperPass>();
@@ -796,6 +856,8 @@ INITIALIZE_PASS_BEGIN(GuardWideningLegac
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
+if (WidenFrequentBranches)
+ INITIALIZE_PASS_DEPENDENCY(BranchProbabilityInfoWrapperPass)
INITIALIZE_PASS_END(GuardWideningLegacyPass, "guard-widening", "Widen guards",
false, false)
@@ -805,6 +867,8 @@ INITIALIZE_PASS_BEGIN(LoopGuardWideningL
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
+if (WidenFrequentBranches)
+ INITIALIZE_PASS_DEPENDENCY(BranchProbabilityInfoWrapperPass)
INITIALIZE_PASS_END(LoopGuardWideningLegacyPass, "loop-guard-widening",
"Widen guards (within a single loop, as a loop pass)",
false, false)
Added: llvm/trunk/test/Transforms/GuardWidening/widen-frequent-branches.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/GuardWidening/widen-frequent-branches.ll?rev=338988&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/GuardWidening/widen-frequent-branches.ll (added)
+++ llvm/trunk/test/Transforms/GuardWidening/widen-frequent-branches.ll Sun Aug 5 22:49:19 2018
@@ -0,0 +1,363 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -guard-widening-widen-frequent-branches=true -guard-widening-frequent-branch-threshold=1000 -S -guard-widening < %s | FileCheck %s
+; RUN: opt -guard-widening-widen-frequent-branches=true -guard-widening-frequent-branch-threshold=1000 -S -passes='require<branch-prob>,guard-widening' < %s | FileCheck %s
+
+declare void @llvm.experimental.guard(i1,...)
+declare void @foo()
+declare void @bar()
+
+; Check that we don't widen without branch probability.
+define void @test_01(i1 %cond_0, i1 %cond_1) {
+; CHECK-LABEL: @test_01(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"() ]
+; CHECK-NEXT: br i1 [[COND_1:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
+; CHECK: if.true:
+; CHECK-NEXT: call void @foo()
+; CHECK-NEXT: br label [[MERGE:%.*]]
+; CHECK: if.false:
+; CHECK-NEXT: call void @bar()
+; CHECK-NEXT: br label [[MERGE]]
+; CHECK: merge:
+; CHECK-NEXT: ret void
+;
+entry:
+ call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
+ br i1 %cond_1, label %if.true, label %if.false
+
+if.true:
+ call void @foo()
+ br label %merge
+
+if.false:
+ call void @bar()
+ br label %merge
+
+merge:
+ ret void
+}
+
+; Check that we don't widen with branch probability below threshold.
+define void @test_02(i1 %cond_0, i1 %cond_1) {
+; CHECK-LABEL: @test_02(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[COND_0:%.*]]) [ "deopt"() ]
+; CHECK-NEXT: br i1 [[COND_1:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !0
+; CHECK: if.true:
+; CHECK-NEXT: call void @foo()
+; CHECK-NEXT: br label [[MERGE:%.*]]
+; CHECK: if.false:
+; CHECK-NEXT: call void @bar()
+; CHECK-NEXT: br label [[MERGE]]
+; CHECK: merge:
+; CHECK-NEXT: ret void
+;
+entry:
+ call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
+ br i1 %cond_1, label %if.true, label %if.false, !prof !0
+
+if.true:
+ call void @foo()
+ br label %merge
+
+if.false:
+ call void @bar()
+ br label %merge
+
+merge:
+ ret void
+}
+
+; Check that we widen conditions of explicit branches into dominating guards
+; when the probability is high enough.
+define void @test_03(i1 %cond_0, i1 %cond_1) {
+; CHECK-LABEL: @test_03(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
+; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
+; CHECK-NEXT: br i1 true, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !1
+; CHECK: if.true:
+; CHECK-NEXT: call void @foo()
+; CHECK-NEXT: br label [[MERGE:%.*]]
+; CHECK: if.false:
+; CHECK-NEXT: call void @bar()
+; CHECK-NEXT: br label [[MERGE]]
+; CHECK: merge:
+; CHECK-NEXT: ret void
+;
+entry:
+ call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
+ br i1 %cond_1, label %if.true, label %if.false, !prof !1
+
+if.true:
+ call void @foo()
+ br label %merge
+
+if.false:
+ call void @bar()
+ br label %merge
+
+merge:
+ ret void
+}
+
+; Widen loop-invariant condition into the guard in preheader.
+define void @test_04(i1 %cond_0, i1 %cond_1, i32 %n) {
+; CHECK-LABEL: @test_04(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
+; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
+; CHECK-NEXT: br label [[LOOP:%.*]]
+; CHECK: loop:
+; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[MERGE:%.*]] ]
+; CHECK-NEXT: br i1 true, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !1
+; CHECK: if.true:
+; CHECK-NEXT: call void @foo()
+; CHECK-NEXT: br label [[MERGE]]
+; CHECK: if.false:
+; CHECK-NEXT: call void @bar()
+; CHECK-NEXT: br label [[MERGE]]
+; CHECK: merge:
+; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
+; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[N:%.*]]
+; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
+; CHECK: exit:
+; CHECK-NEXT: ret void
+;
+entry:
+ call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
+ br label %loop
+
+loop:
+ %iv = phi i32 [ 0, %entry ], [ %iv.next, %merge ]
+ br i1 %cond_1, label %if.true, label %if.false, !prof !1
+
+if.true:
+ call void @foo()
+ br label %merge
+
+if.false:
+ call void @bar()
+ br label %merge
+
+merge:
+ %iv.next = add i32 %iv, 1
+ %cond = icmp slt i32 %iv.next, %n
+ br i1 %cond, label %loop, label %exit
+
+exit:
+ ret void
+}
+
+; Widen loop-invariant condition into the guard in the same loop.
+define void @test_05(i1 %cond_0, i1 %cond_1, i32 %n) {
+; CHECK-LABEL: @test_05(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br label [[LOOP:%.*]]
+; CHECK: loop:
+; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[MERGE:%.*]] ]
+; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
+; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
+; CHECK-NEXT: br i1 true, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !1
+; CHECK: if.true:
+; CHECK-NEXT: call void @foo()
+; CHECK-NEXT: br label [[MERGE]]
+; CHECK: if.false:
+; CHECK-NEXT: call void @bar()
+; CHECK-NEXT: br label [[MERGE]]
+; CHECK: merge:
+; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
+; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[N:%.*]]
+; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
+; CHECK: exit:
+; CHECK-NEXT: ret void
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i32 [ 0, %entry ], [ %iv.next, %merge ]
+ call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
+ br i1 %cond_1, label %if.true, label %if.false, !prof !1
+
+if.true:
+ call void @foo()
+ br label %merge
+
+if.false:
+ call void @bar()
+ br label %merge
+
+merge:
+ %iv.next = add i32 %iv, 1
+ %cond = icmp slt i32 %iv.next, %n
+ br i1 %cond, label %loop, label %exit
+
+exit:
+ ret void
+}
+
+; Some of checks are frequently taken and some are not, make sure that we only
+; widen frequent ones.
+define void @test_06(i1 %cond_0, i1 %cond_1, i1 %cond_2, i1 %cond_3, i1 %cond_4, i32 %n) {
+; CHECK-LABEL: @test_06(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_2:%.*]]
+; CHECK-NEXT: [[WIDE_CHK1:%.*]] = and i1 [[WIDE_CHK]], [[COND_4:%.*]]
+; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK1]]) [ "deopt"() ]
+; CHECK-NEXT: br label [[LOOP:%.*]]
+; CHECK: loop:
+; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE:%.*]] ]
+; CHECK-NEXT: br i1 [[COND_1:%.*]], label [[IF_TRUE_1:%.*]], label [[IF_FALSE_1:%.*]], !prof !2
+; CHECK: if.true_1:
+; CHECK-NEXT: call void @foo()
+; CHECK-NEXT: br label [[MERGE_1:%.*]]
+; CHECK: if.false_1:
+; CHECK-NEXT: call void @bar()
+; CHECK-NEXT: br label [[MERGE_1]]
+; CHECK: merge_1:
+; CHECK-NEXT: br i1 true, label [[IF_TRUE_2:%.*]], label [[IF_FALSE_2:%.*]], !prof !1
+; CHECK: if.true_2:
+; CHECK-NEXT: call void @foo()
+; CHECK-NEXT: br label [[MERGE_2:%.*]]
+; CHECK: if.false_2:
+; CHECK-NEXT: call void @bar()
+; CHECK-NEXT: br label [[MERGE_2]]
+; CHECK: merge_2:
+; CHECK-NEXT: br i1 [[COND_3:%.*]], label [[IF_TRUE_3:%.*]], label [[IF_FALSE_3:%.*]], !prof !2
+; CHECK: if.true_3:
+; CHECK-NEXT: call void @foo()
+; CHECK-NEXT: br label [[MERGE_3:%.*]]
+; CHECK: if.false_3:
+; CHECK-NEXT: call void @bar()
+; CHECK-NEXT: br label [[MERGE_3]]
+; CHECK: merge_3:
+; CHECK-NEXT: br i1 true, label [[IF_TRUE_4:%.*]], label [[IF_FALSE_4:%.*]], !prof !1
+; CHECK: if.true_4:
+; CHECK-NEXT: call void @foo()
+; CHECK-NEXT: br label [[BACKEDGE]]
+; CHECK: if.false_4:
+; CHECK-NEXT: call void @bar()
+; CHECK-NEXT: br label [[BACKEDGE]]
+; CHECK: backedge:
+; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
+; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[IV_NEXT]], [[N:%.*]]
+; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
+; CHECK: exit:
+; CHECK-NEXT: ret void
+;
+entry:
+ call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
+ br label %loop
+
+loop:
+ %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]
+ br i1 %cond_1, label %if.true_1, label %if.false_1, !prof !2
+
+if.true_1:
+ call void @foo()
+ br label %merge_1
+
+if.false_1:
+ call void @bar()
+ br label %merge_1
+
+merge_1:
+ br i1 %cond_2, label %if.true_2, label %if.false_2, !prof !1
+
+if.true_2:
+ call void @foo()
+ br label %merge_2
+
+if.false_2:
+ call void @bar()
+ br label %merge_2
+
+merge_2:
+ br i1 %cond_3, label %if.true_3, label %if.false_3, !prof !2
+
+if.true_3:
+ call void @foo()
+ br label %merge_3
+
+if.false_3:
+ call void @bar()
+ br label %merge_3
+
+merge_3:
+ br i1 %cond_4, label %if.true_4, label %if.false_4, !prof !1
+
+if.true_4:
+ call void @foo()
+ br label %backedge
+
+if.false_4:
+ call void @bar()
+ br label %backedge
+
+backedge:
+ %iv.next = add i32 %iv, 1
+ %cond = icmp slt i32 %iv.next, %n
+ br i1 %cond, label %loop, label %exit
+
+exit:
+ ret void
+}
+
+; Check triangle CFG pattern.
+define void @test_07(i1 %cond_0, i1 %cond_1) {
+; CHECK-LABEL: @test_07(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
+; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
+; CHECK-NEXT: br i1 true, label [[IF_TRUE:%.*]], label [[MERGE:%.*]], !prof !1
+; CHECK: if.true:
+; CHECK-NEXT: call void @foo()
+; CHECK-NEXT: br label [[MERGE]]
+; CHECK: merge:
+; CHECK-NEXT: ret void
+;
+entry:
+ call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
+ br i1 %cond_1, label %if.true, label %merge, !prof !1
+
+if.true:
+ call void @foo()
+ br label %merge
+
+merge:
+ ret void
+}
+
+define void @test_08(i1 %cond_0, i1 %cond_1) {
+; CHECK-LABEL: @test_08(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[COND_1:%.*]]
+; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
+; CHECK-NEXT: br i1 true, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !1
+; CHECK: if.true:
+; CHECK-NEXT: call void @foo()
+; CHECK-NEXT: br label [[MERGE:%.*]]
+; CHECK: if.false:
+; CHECK-NEXT: ret void
+; CHECK: merge:
+; CHECK-NEXT: ret void
+;
+entry:
+ call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
+ br i1 %cond_1, label %if.true, label %if.false, !prof !1
+
+if.true:
+ call void @foo()
+ br label %merge
+
+if.false:
+ ret void
+
+merge:
+ ret void
+}
+
+!0 = !{!"branch_weights", i32 998, i32 1}
+!1 = !{!"branch_weights", i32 999, i32 1}
+!2 = !{!"branch_weights", i32 500, i32 500}
More information about the llvm-commits
mailing list