[GuardWidening] Remove WidenFrequentBranches transform

This code has never been enabled.  While it is tested, it's complicating some refactoring.  If we decide to re-implement this, doing it in SimplifyCFG would probably make more sense anyways.
This commit is contained in:
Philip Reames 2019-11-19 15:14:41 -08:00
parent 377d70cdea
commit 28a91473e3
2 changed files with 6 additions and 888 deletions

View File

@ -69,22 +69,6 @@ using namespace llvm;
STATISTIC(GuardsEliminated, "Number of eliminated guards");
STATISTIC(CondBranchEliminated, "Number of eliminated conditional branches");
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));
static cl::opt<bool>
WidenBranchGuards("guard-widening-widen-branch-guards", cl::Hidden,
cl::desc("Whether or not we should widen guards "
@ -129,7 +113,6 @@ 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.
@ -287,10 +270,9 @@ class GuardWideningImpl {
public:
explicit GuardWideningImpl(DominatorTree &DT, PostDominatorTree *PDT,
LoopInfo &LI, BranchProbabilityInfo *BPI,
DomTreeNode *Root,
LoopInfo &LI, DomTreeNode *Root,
std::function<bool(BasicBlock*)> BlockFilter)
: DT(DT), PDT(PDT), LI(LI), BPI(BPI), Root(Root), BlockFilter(BlockFilter)
: DT(DT), PDT(PDT), LI(LI), Root(Root), BlockFilter(BlockFilter)
{}
/// The entry point for this pass.
@ -309,13 +291,6 @@ static bool isSupportedGuardInstruction(const Instruction *Insn) {
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 = BranchProbability(Threshold - 1, Threshold);
}
for (auto DFI = df_begin(Root), DFE = df_end(Root);
DFI != DFE; ++DFI) {
auto *BB = (*DFI)->getBlock();
@ -330,17 +305,6 @@ bool GuardWideningImpl::run() {
for (auto *II : CurrentList)
Changed |= eliminateInstrViaWidening(II, DFI, GuardsInBlock);
if (WidenFrequentBranches && BPI)
if (auto *BI = dyn_cast<BranchInst>(BB->getTerminator()))
if (BI->isConditional()) {
// If one of branches of a conditional is likely taken, try to
// eliminate it.
if (BPI->getEdgeProbability(BB, 0U) >= *LikelyTaken)
Changed |= eliminateInstrViaWidening(BI, DFI, GuardsInBlock);
else if (BPI->getEdgeProbability(BB, 1U) >= *LikelyTaken)
Changed |= eliminateInstrViaWidening(BI, DFI, GuardsInBlock,
/*InvertCondition*/true);
}
}
assert(EliminatedGuardsAndBranches.empty() || Changed);
@ -805,10 +769,7 @@ PreservedAnalyses GuardWideningPass::run(Function &F,
auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
auto &LI = AM.getResult<LoopAnalysis>(F);
auto &PDT = AM.getResult<PostDominatorTreeAnalysis>(F);
BranchProbabilityInfo *BPI = nullptr;
if (WidenFrequentBranches)
BPI = AM.getCachedResult<BranchProbabilityAnalysis>(F);
if (!GuardWideningImpl(DT, &PDT, LI, BPI, DT.getRootNode(),
if (!GuardWideningImpl(DT, &PDT, LI, DT.getRootNode(),
[](BasicBlock*) { return true; } ).run())
return PreservedAnalyses::all();
@ -820,22 +781,13 @@ PreservedAnalyses GuardWideningPass::run(Function &F,
PreservedAnalyses GuardWideningPass::run(Loop &L, LoopAnalysisManager &AM,
LoopStandardAnalysisResults &AR,
LPMUpdater &U) {
const auto &FAM =
AM.getResult<FunctionAnalysisManagerLoopProxy>(L, AR).getManager();
Function &F = *L.getHeader()->getParent();
BranchProbabilityInfo *BPI = nullptr;
if (WidenFrequentBranches)
BPI = FAM.getCachedResult<BranchProbabilityAnalysis>(F);
BasicBlock *RootBB = L.getLoopPredecessor();
if (!RootBB)
RootBB = L.getHeader();
auto BlockFilter = [&](BasicBlock *BB) {
return BB == RootBB || L.contains(BB);
};
if (!GuardWideningImpl(AR.DT, nullptr, AR.LI, BPI,
AR.DT.getNode(RootBB),
if (!GuardWideningImpl(AR.DT, nullptr, AR.LI, AR.DT.getNode(RootBB),
BlockFilter).run())
return PreservedAnalyses::all();
@ -856,10 +808,7 @@ struct GuardWideningLegacyPass : public FunctionPass {
auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
auto &PDT = getAnalysis<PostDominatorTreeWrapperPass>().getPostDomTree();
BranchProbabilityInfo *BPI = nullptr;
if (WidenFrequentBranches)
BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
return GuardWideningImpl(DT, &PDT, LI, BPI, DT.getRootNode(),
return GuardWideningImpl(DT, &PDT, LI, DT.getRootNode(),
[](BasicBlock*) { return true; } ).run();
}
@ -868,8 +817,6 @@ struct GuardWideningLegacyPass : public FunctionPass {
AU.addRequired<DominatorTreeWrapperPass>();
AU.addRequired<PostDominatorTreeWrapperPass>();
AU.addRequired<LoopInfoWrapperPass>();
if (WidenFrequentBranches)
AU.addRequired<BranchProbabilityInfoWrapperPass>();
}
};
@ -895,16 +842,11 @@ struct LoopGuardWideningLegacyPass : public LoopPass {
auto BlockFilter = [&](BasicBlock *BB) {
return BB == RootBB || L->contains(BB);
};
BranchProbabilityInfo *BPI = nullptr;
if (WidenFrequentBranches)
BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
return GuardWideningImpl(DT, PDT, LI, BPI,
return GuardWideningImpl(DT, PDT, LI,
DT.getNode(RootBB), BlockFilter).run();
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
if (WidenFrequentBranches)
AU.addRequired<BranchProbabilityInfoWrapperPass>();
AU.setPreservesCFG();
getLoopAnalysisUsage(AU);
AU.addPreserved<PostDominatorTreeWrapperPass>();
@ -920,8 +862,6 @@ INITIALIZE_PASS_BEGIN(GuardWideningLegacyPass, "guard-widening", "Widen guards",
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)
@ -931,8 +871,6 @@ INITIALIZE_PASS_BEGIN(LoopGuardWideningLegacyPass, "loop-guard-widening",
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)

View File

@ -1,820 +0,0 @@
; 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
}
; Similar to test_03, but the likely taken branch is the false branch.
define void @test_03_not_taken(i1 %cond_0, i1 %cond_1) {
; CHECK-LABEL: @test_03_not_taken(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[INVERTED:%.*]] = xor i1 [[COND_1:%.*]], true
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[INVERTED]]
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
; CHECK-NEXT: br i1 false, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !2
; 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 !3
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
}
; Similar to test_04, but the likely taken branch is the false branch.
define void @test_04_not_taken(i1 %cond_0, i1 %cond_1, i32 %n) {
; CHECK-LABEL: @test_04_not_taken(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[INVERTED:%.*]] = xor i1 [[COND_1:%.*]], true
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[INVERTED]]
; 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 false, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !2
; 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 !3
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
}
; Similar to test_05, but the likely taken branch is the false branch.
define void @test_05_not_taken(i1 %cond_0, i1 %cond_1, i32 %n) {
; CHECK-LABEL: @test_05_not_taken(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[MERGE:%.*]] ]
; CHECK-NEXT: [[INVERTED:%.*]] = xor i1 [[COND_1:%.*]], true
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[INVERTED]]
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
; CHECK-NEXT: br i1 false, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !2
; 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 !3
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 !3
; 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 !3
; 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
}
; Similar to test_06, but the likely taken branch is the false branch.
define void @test_06_not_taken(i1 %cond_0, i1 %cond_1, i1 %cond_2, i1 %cond_3, i1 %cond_4, i32 %n) {
; CHECK-LABEL: @test_06_not_taken(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[INVERTED:%.*]] = xor i1 [[COND_2:%.*]], true
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[INVERTED]]
; CHECK-NEXT: [[INVERTED1:%.*]] = xor i1 [[COND_4:%.*]], true
; CHECK-NEXT: [[WIDE_CHK2:%.*]] = and i1 [[WIDE_CHK]], [[INVERTED1]]
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "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 !3
; 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 false, label [[IF_TRUE_2:%.*]], label [[IF_FALSE_2:%.*]], !prof !2
; 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 !3
; 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 false, label [[IF_TRUE_4:%.*]], label [[IF_FALSE_4:%.*]], !prof !2
; 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 !3
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 !3
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
}
; Similar to test_07, but the likely taken branch is the false branch.
define void @test_07_not_taken(i1 %cond_0, i1 %cond_1) {
; CHECK-LABEL: @test_07_not_taken(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[INVERTED:%.*]] = xor i1 [[COND_1:%.*]], true
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[INVERTED]]
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
; CHECK-NEXT: br i1 false, label [[IF_TRUE:%.*]], label [[MERGE:%.*]], !prof !2
; 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 !3
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
}
define void @test_08_not_taken(i1 %cond_0, i1 %cond_1) {
; CHECK-LABEL: @test_08_not_taken(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[INVERTED:%.*]] = xor i1 [[COND_1:%.*]], true
; CHECK-NEXT: [[WIDE_CHK:%.*]] = and i1 [[COND_0:%.*]], [[INVERTED]]
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
; CHECK-NEXT: br i1 false, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !2
; 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 !3
if.true:
call void @foo()
br label %merge
if.false:
ret void
merge:
ret void
}
; Check that L >u C0 && L >u C1 -> L >u max(C0, C1).
define void @test_09(i32 %L) {
; CHECK-LABEL: @test_09(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND_0:%.*]] = icmp ugt i32 [[L:%.*]], 123
; CHECK-NEXT: [[COND_1:%.*]] = icmp ugt i32 [[L]], 456
; CHECK-NEXT: [[WIDE_CHK:%.*]] = icmp uge i32 [[L]], 457
; 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:
%cond_0 = icmp ugt i32 %L, 123
%cond_1 = icmp ugt i32 %L, 456
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
}
; Check that L >u C0 && !(L <=u C1) -> L >u max(C0, C1).
define void @test_09_not_taken(i32 %L) {
; CHECK-LABEL: @test_09_not_taken(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND_0:%.*]] = icmp ugt i32 [[L:%.*]], 123
; CHECK-NEXT: [[COND_1:%.*]] = icmp ule i32 [[L]], 456
; CHECK-NEXT: [[WIDE_CHK:%.*]] = icmp uge i32 [[L]], 457
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
; CHECK-NEXT: br i1 false, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !2
; 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:
%cond_0 = icmp ugt i32 %L, 123
%cond_1 = icmp ule i32 %L, 456
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
br i1 %cond_1, label %if.true, label %if.false, !prof !3
if.true:
call void @foo()
br label %merge
if.false:
ret void
merge:
ret void
}
; Check that a profitable transform is preferred over non-profitable.
define void @test_10(i32 %L, i1 %irrelevant_cond, i1 %infinite_loop_cond) {
; CHECK-LABEL: @test_10(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND_0:%.*]] = icmp ugt i32 [[L:%.*]], 123
; CHECK-NEXT: [[COND_1:%.*]] = icmp ugt i32 [[L]], 456
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[IRRELEVANT_COND:%.*]]) [ "deopt"() ]
; CHECK-NEXT: br i1 [[INFINITE_LOOP_COND:%.*]], label [[LOOP]], label [[AFTER_LOOP:%.*]]
; CHECK: after_loop:
; CHECK-NEXT: [[WIDE_CHK:%.*]] = icmp uge i32 [[L]], 457
; 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: br label [[MERGE]]
; CHECK: merge:
; CHECK-NEXT: ret void
;
entry:
%cond_0 = icmp ugt i32 %L, 123
%cond_1 = icmp ugt i32 %L, 456
br label %loop
loop:
call void(i1, ...) @llvm.experimental.guard(i1 %irrelevant_cond) [ "deopt"() ]
br i1 %infinite_loop_cond, label %loop, label %after_loop
after_loop:
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:
br label %merge
merge:
ret void
}
; Check that a profitable transform is preferred over non-profitable.
define void @test_10_not_taken(i32 %L, i1 %irrelevant_cond, i1 %infinite_loop_cond) {
; CHECK-LABEL: @test_10_not_taken(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND_0:%.*]] = icmp ugt i32 [[L:%.*]], 123
; CHECK-NEXT: [[COND_1:%.*]] = icmp ule i32 [[L]], 456
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[IRRELEVANT_COND:%.*]]) [ "deopt"() ]
; CHECK-NEXT: br i1 [[INFINITE_LOOP_COND:%.*]], label [[LOOP]], label [[AFTER_LOOP:%.*]]
; CHECK: after_loop:
; CHECK-NEXT: [[WIDE_CHK:%.*]] = icmp uge i32 [[L]], 457
; CHECK-NEXT: call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
; CHECK-NEXT: br i1 false, label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]], !prof !2
; CHECK: if.true:
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: br label [[MERGE:%.*]]
; CHECK: if.false:
; CHECK-NEXT: br label [[MERGE]]
; CHECK: merge:
; CHECK-NEXT: ret void
;
entry:
%cond_0 = icmp ugt i32 %L, 123
%cond_1 = icmp ule i32 %L, 456
br label %loop
loop:
call void(i1, ...) @llvm.experimental.guard(i1 %irrelevant_cond) [ "deopt"() ]
br i1 %infinite_loop_cond, label %loop, label %after_loop
after_loop:
call void(i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
br i1 %cond_1, label %if.true, label %if.false, !prof !3
if.true:
call void @foo()
br label %merge
if.false:
br label %merge
merge:
ret void
}
!0 = !{!"branch_weights", i32 998, i32 1}
!1 = !{!"branch_weights", i32 999, i32 1}
!2 = !{!"branch_weights", i32 500, i32 500}
!3 = !{!"branch_weights", i32 1, i32 999}