forked from OSchip/llvm-project
[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:
parent
377d70cdea
commit
28a91473e3
|
@ -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)
|
||||
|
|
|
@ -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}
|
Loading…
Reference in New Issue