From 1cdbb3b74eaae1135080e9fee7d9d39309b52de6 Mon Sep 17 00:00:00 2001 From: Philip Reames Date: Tue, 19 Nov 2019 15:14:41 -0800 Subject: [PATCH] [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. --- lib/Transforms/Scalar/GuardWidening.cpp | 74 +- .../GuardWidening/widen-frequent-branches.ll | 820 ------------------ 2 files changed, 6 insertions(+), 888 deletions(-) delete mode 100644 test/Transforms/GuardWidening/widen-frequent-branches.ll diff --git a/lib/Transforms/Scalar/GuardWidening.cpp b/lib/Transforms/Scalar/GuardWidening.cpp index 943cc9ac593..69d9507b356 100644 --- a/lib/Transforms/Scalar/GuardWidening.cpp +++ b/lib/Transforms/Scalar/GuardWidening.cpp @@ -69,22 +69,6 @@ using namespace llvm; STATISTIC(GuardsEliminated, "Number of eliminated guards"); STATISTIC(CondBranchEliminated, "Number of eliminated conditional branches"); -static cl::opt 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 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 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 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> GuardsInBlock; bool Changed = false; - Optional 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(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(F); auto &LI = AM.getResult(F); auto &PDT = AM.getResult(F); - BranchProbabilityInfo *BPI = nullptr; - if (WidenFrequentBranches) - BPI = AM.getCachedResult(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(L, AR).getManager(); - Function &F = *L.getHeader()->getParent(); - BranchProbabilityInfo *BPI = nullptr; - if (WidenFrequentBranches) - BPI = FAM.getCachedResult(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().getDomTree(); auto &LI = getAnalysis().getLoopInfo(); auto &PDT = getAnalysis().getPostDomTree(); - BranchProbabilityInfo *BPI = nullptr; - if (WidenFrequentBranches) - BPI = &getAnalysis().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(); AU.addRequired(); AU.addRequired(); - if (WidenFrequentBranches) - AU.addRequired(); } }; @@ -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().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(); AU.setPreservesCFG(); getLoopAnalysisUsage(AU); AU.addPreserved(); @@ -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) diff --git a/test/Transforms/GuardWidening/widen-frequent-branches.ll b/test/Transforms/GuardWidening/widen-frequent-branches.ll deleted file mode 100644 index 2f6dceadf49..00000000000 --- a/test/Transforms/GuardWidening/widen-frequent-branches.ll +++ /dev/null @@ -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,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}