1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-26 12:43:36 +01:00

Revert "[LoopDeletion] Break backedge if we can prove that the loop is exited on 1st iteration"

This reverts commit 2531fd70d19aa5d61feb533bbdeee7717a4129eb due to
performance regression on the PPC buildbot.
This commit is contained in:
Matt Morehouse 2021-05-25 13:58:13 -07:00
parent 77c89471fd
commit 86272fe99b
4 changed files with 43 additions and 205 deletions

View File

@ -17,7 +17,6 @@
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h" #include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/GlobalsModRef.h"
#include "llvm/Analysis/LoopIterator.h"
#include "llvm/Analysis/LoopPass.h" #include "llvm/Analysis/LoopPass.h"
#include "llvm/Analysis/MemorySSA.h" #include "llvm/Analysis/MemorySSA.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h"
@ -136,155 +135,6 @@ static bool isLoopNeverExecuted(Loop *L) {
return true; return true;
} }
static const SCEV *
getSCEVOnFirstIteration(Value *V, Loop *L, ScalarEvolution &SE,
DenseMap<Value *, const SCEV *> &FirstIterSCEV) {
// Fist, check in cache.
auto Existing = FirstIterSCEV.find(V);
if (Existing != FirstIterSCEV.end())
return Existing->second;
const SCEV *S = nullptr;
// TODO: Once ScalarEvolution supports getValueOnNthIteration for anything
// else but AddRecs, it's a good use case for it. So far, just consider some
// simple cases, like arithmetic operations.
Value *LHS, *RHS;
using namespace PatternMatch;
if (match(V, m_Add(m_Value(LHS), m_Value(RHS)))) {
const SCEV *LHSS = getSCEVOnFirstIteration(LHS, L, SE, FirstIterSCEV);
const SCEV *RHSS = getSCEVOnFirstIteration(RHS, L, SE, FirstIterSCEV);
S = SE.getAddExpr(LHSS, RHSS);
} else if (match(V, m_Sub(m_Value(LHS), m_Value(RHS)))) {
const SCEV *LHSS = getSCEVOnFirstIteration(LHS, L, SE, FirstIterSCEV);
const SCEV *RHSS = getSCEVOnFirstIteration(RHS, L, SE, FirstIterSCEV);
S = SE.getMinusSCEV(LHSS, RHSS);
} else if (match(V, m_Mul(m_Value(LHS), m_Value(RHS)))) {
const SCEV *LHSS = getSCEVOnFirstIteration(LHS, L, SE, FirstIterSCEV);
const SCEV *RHSS = getSCEVOnFirstIteration(RHS, L, SE, FirstIterSCEV);
S = SE.getMulExpr(LHSS, RHSS);
} else
S = SE.getSCEV(V);
assert(S && "Case not handled?");
FirstIterSCEV[V] = S;
return S;
}
// Try to prove that one of conditions that dominates the latch must exit on 1st
// iteration.
static bool canProveExitOnFirstIteration(Loop *L, DominatorTree &DT,
ScalarEvolution &SE, LoopInfo &LI) {
BasicBlock *Latch = L->getLoopLatch();
if (!Latch)
return false;
LoopBlocksRPO RPOT(L);
RPOT.perform(&LI);
BasicBlock *Header = L->getHeader();
// Blocks that are reachable on the 1st iteration.
SmallPtrSet<BasicBlock *, 4> LiveBlocks;
// Edges that are reachable on the 1st iteration.
DenseSet<BasicBlockEdge> LiveEdges;
LiveBlocks.insert(L->getHeader());
auto MarkLiveEdge = [&](BasicBlock *From, BasicBlock *To) {
assert(LiveBlocks.count(From) && "Must be live!");
LiveBlocks.insert(To);
LiveEdges.insert({ From, To });
};
auto MarkAllSuccessorsLive = [&](BasicBlock *BB) {
for (auto *Succ : successors(BB))
MarkLiveEdge(BB, Succ);
};
// Check if there is only one predecessor on 1st iteration. Note that because
// we iterate in RPOT, we have already visited all its (non-latch)
// predecessors.
auto GetSolePredecessorOnFirstIteration = [&](BasicBlock * BB)->BasicBlock * {
if (BB == Header)
return L->getLoopPredecessor();
BasicBlock *OnlyPred = nullptr;
for (auto *Pred : predecessors(BB))
if (OnlyPred != Pred && LiveEdges.count({ Pred, BB })) {
// 2 live preds.
if (OnlyPred)
return nullptr;
OnlyPred = Pred;
}
assert(OnlyPred && "No live predecessors?");
return OnlyPred;
};
DenseMap<Value *, const SCEV *> FirstIterSCEV;
// Use the following algorithm to prove we never take the latch on the 1st
// iteration:
// 1. Traverse in topological order, so that whenever we visit a block, all
// its predecessors are already visited.
// 2. If we can prove that the block may have only 1 predecessor on the 1st
// iteration, map all its phis onto input from this predecessor.
// 3a. If we can prove which successor of out block is taken on the 1st
// iteration, mark this successor live.
// 3b. If we cannot prove it, conservatively assume that all successors are
// live.
for (auto *BB : RPOT) {
// This block is not reachable on the 1st iterations.
if (!LiveBlocks.count(BB))
continue;
// Skip inner loops.
if (LI.getLoopFor(BB) != L) {
MarkAllSuccessorsLive(BB);
continue;
}
// If this block has only one live pred, map its phis onto their SCEVs.
if (auto *OnlyPred = GetSolePredecessorOnFirstIteration(BB))
for (auto &PN : BB->phis()) {
if (!SE.isSCEVable(PN.getType()))
continue;
auto *Incoming = PN.getIncomingValueForBlock(OnlyPred);
if (DT.dominates(Incoming, BB->getTerminator())) {
const SCEV *IncSCEV =
getSCEVOnFirstIteration(Incoming, L, SE, FirstIterSCEV);
FirstIterSCEV[&PN] = IncSCEV;
}
}
using namespace PatternMatch;
ICmpInst::Predicate Pred;
Value *LHS, *RHS;
const BasicBlock *IfTrue, *IfFalse;
// TODO: Handle switches.
if (!match(BB->getTerminator(),
m_Br(m_ICmp(Pred, m_Value(LHS), m_Value(RHS)),
m_BasicBlock(IfTrue), m_BasicBlock(IfFalse)))) {
MarkAllSuccessorsLive(BB);
continue;
}
if (!SE.isSCEVable(LHS->getType())) {
MarkAllSuccessorsLive(BB);
continue;
}
// Can we prove constant true or false for this condition?
const SCEV *LHSS = getSCEVOnFirstIteration(LHS, L, SE, FirstIterSCEV);
const SCEV *RHSS = getSCEVOnFirstIteration(RHS, L, SE, FirstIterSCEV);
if (SE.isKnownPredicateAt(Pred, LHSS, RHSS, BB->getTerminator()))
MarkLiveEdge(BB, BB->getTerminator()->getSuccessor(0));
else if (SE.isKnownPredicateAt(ICmpInst::getInversePredicate(Pred), LHSS,
RHSS, BB->getTerminator()))
MarkLiveEdge(BB, BB->getTerminator()->getSuccessor(1));
else
MarkAllSuccessorsLive(BB);
}
// We can break the latch if it wasn't live.
return !LiveEdges.count({ Latch, Header });
}
/// If we can prove the backedge is untaken, remove it. This destroys the /// If we can prove the backedge is untaken, remove it. This destroys the
/// loop, but leaves the (now trivially loop invariant) control flow and /// loop, but leaves the (now trivially loop invariant) control flow and
/// side effects (if any) in place. /// side effects (if any) in place.
@ -298,7 +148,7 @@ breakBackedgeIfNotTaken(Loop *L, DominatorTree &DT, ScalarEvolution &SE,
return LoopDeletionResult::Unmodified; return LoopDeletionResult::Unmodified;
auto *BTC = SE.getBackedgeTakenCount(L); auto *BTC = SE.getBackedgeTakenCount(L);
if (!BTC->isZero() && !canProveExitOnFirstIteration(L, DT, SE, LI)) if (!BTC->isZero())
return LoopDeletionResult::Unmodified; return LoopDeletionResult::Unmodified;
breakLoopBackedge(L, DT, SE, LI, MSSA); breakLoopBackedge(L, DT, SE, LI, MSSA);

View File

@ -7,6 +7,7 @@
; and therefore prove that %sum.next = %sum + %sub = %sum + %limit - %sum = %limit, ; and therefore prove that %sum.next = %sum + %sub = %sum + %limit - %sum = %limit,
; and predicate is false. ; and predicate is false.
; TODO: We can break the backedge here.
define i32 @test_ne(i32 %limit) { define i32 @test_ne(i32 %limit) {
; CHECK-LABEL: @test_ne( ; CHECK-LABEL: @test_ne(
; CHECK-NEXT: entry: ; CHECK-NEXT: entry:
@ -15,19 +16,17 @@ define i32 @test_ne(i32 %limit) {
; CHECK: loop.preheader: ; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop: ; CHECK: loop:
; CHECK-NEXT: [[SUM:%.*]] = phi i32 [ 0, [[LOOP_PREHEADER]] ] ; CHECK-NEXT: [[SUM:%.*]] = phi i32 [ [[SUM_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[LIMIT]], [[SUM]] ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[LIMIT]], [[SUM]]
; CHECK-NEXT: [[IS_POSITIVE:%.*]] = icmp sgt i32 [[SUB]], 0 ; CHECK-NEXT: [[IS_POSITIVE:%.*]] = icmp sgt i32 [[SUB]], 0
; CHECK-NEXT: br i1 [[IS_POSITIVE]], label [[BACKEDGE:%.*]], label [[IF_FALSE:%.*]] ; CHECK-NEXT: br i1 [[IS_POSITIVE]], label [[BACKEDGE]], label [[IF_FALSE:%.*]]
; CHECK: if.false: ; CHECK: if.false:
; CHECK-NEXT: br label [[BACKEDGE]] ; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: backedge: ; CHECK: backedge:
; CHECK-NEXT: [[MERGE_PHI:%.*]] = phi i32 [ 0, [[IF_FALSE]] ], [ [[SUB]], [[LOOP]] ] ; CHECK-NEXT: [[MERGE_PHI:%.*]] = phi i32 [ 0, [[IF_FALSE]] ], [ [[SUB]], [[LOOP]] ]
; CHECK-NEXT: [[SUM_NEXT:%.*]] = add i32 [[SUM]], [[MERGE_PHI]] ; CHECK-NEXT: [[SUM_NEXT]] = add i32 [[SUM]], [[MERGE_PHI]]
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ne i32 [[SUM_NEXT]], [[LIMIT]] ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ne i32 [[SUM_NEXT]], [[LIMIT]]
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[BACKEDGE_LOOP_CRIT_EDGE:%.*]], label [[DONE:%.*]] ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[DONE:%.*]]
; CHECK: backedge.loop_crit_edge:
; CHECK-NEXT: unreachable
; CHECK: done: ; CHECK: done:
; CHECK-NEXT: [[SUM_NEXT_LCSSA:%.*]] = phi i32 [ [[SUM_NEXT]], [[BACKEDGE]] ] ; CHECK-NEXT: [[SUM_NEXT_LCSSA:%.*]] = phi i32 [ [[SUM_NEXT]], [[BACKEDGE]] ]
; CHECK-NEXT: ret i32 [[SUM_NEXT_LCSSA]] ; CHECK-NEXT: ret i32 [[SUM_NEXT_LCSSA]]
@ -61,6 +60,7 @@ failure:
unreachable unreachable
} }
; TODO: We can break the backedge here.
define i32 @test_slt(i32 %limit) { define i32 @test_slt(i32 %limit) {
; CHECK-LABEL: @test_slt( ; CHECK-LABEL: @test_slt(
; CHECK-NEXT: entry: ; CHECK-NEXT: entry:
@ -69,19 +69,17 @@ define i32 @test_slt(i32 %limit) {
; CHECK: loop.preheader: ; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop: ; CHECK: loop:
; CHECK-NEXT: [[SUM:%.*]] = phi i32 [ 0, [[LOOP_PREHEADER]] ] ; CHECK-NEXT: [[SUM:%.*]] = phi i32 [ [[SUM_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[LIMIT]], [[SUM]] ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[LIMIT]], [[SUM]]
; CHECK-NEXT: [[IS_POSITIVE:%.*]] = icmp sgt i32 [[SUB]], 0 ; CHECK-NEXT: [[IS_POSITIVE:%.*]] = icmp sgt i32 [[SUB]], 0
; CHECK-NEXT: br i1 [[IS_POSITIVE]], label [[BACKEDGE:%.*]], label [[IF_FALSE:%.*]] ; CHECK-NEXT: br i1 [[IS_POSITIVE]], label [[BACKEDGE]], label [[IF_FALSE:%.*]]
; CHECK: if.false: ; CHECK: if.false:
; CHECK-NEXT: br label [[BACKEDGE]] ; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: backedge: ; CHECK: backedge:
; CHECK-NEXT: [[MERGE_PHI:%.*]] = phi i32 [ 0, [[IF_FALSE]] ], [ [[SUB]], [[LOOP]] ] ; CHECK-NEXT: [[MERGE_PHI:%.*]] = phi i32 [ 0, [[IF_FALSE]] ], [ [[SUB]], [[LOOP]] ]
; CHECK-NEXT: [[SUM_NEXT:%.*]] = add i32 [[SUM]], [[MERGE_PHI]] ; CHECK-NEXT: [[SUM_NEXT]] = add i32 [[SUM]], [[MERGE_PHI]]
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[SUM_NEXT]], [[LIMIT]] ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp slt i32 [[SUM_NEXT]], [[LIMIT]]
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[BACKEDGE_LOOP_CRIT_EDGE:%.*]], label [[DONE:%.*]] ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[DONE:%.*]]
; CHECK: backedge.loop_crit_edge:
; CHECK-NEXT: unreachable
; CHECK: done: ; CHECK: done:
; CHECK-NEXT: [[SUM_NEXT_LCSSA:%.*]] = phi i32 [ [[SUM_NEXT]], [[BACKEDGE]] ] ; CHECK-NEXT: [[SUM_NEXT_LCSSA:%.*]] = phi i32 [ [[SUM_NEXT]], [[BACKEDGE]] ]
; CHECK-NEXT: ret i32 [[SUM_NEXT_LCSSA]] ; CHECK-NEXT: ret i32 [[SUM_NEXT_LCSSA]]
@ -115,6 +113,7 @@ failure:
unreachable unreachable
} }
; TODO: We can break the backedge here.
define i32 @test_ult(i32 %limit) { define i32 @test_ult(i32 %limit) {
; CHECK-LABEL: @test_ult( ; CHECK-LABEL: @test_ult(
; CHECK-NEXT: entry: ; CHECK-NEXT: entry:
@ -123,19 +122,17 @@ define i32 @test_ult(i32 %limit) {
; CHECK: loop.preheader: ; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop: ; CHECK: loop:
; CHECK-NEXT: [[SUM:%.*]] = phi i32 [ 0, [[LOOP_PREHEADER]] ] ; CHECK-NEXT: [[SUM:%.*]] = phi i32 [ [[SUM_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[LIMIT]], [[SUM]] ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[LIMIT]], [[SUM]]
; CHECK-NEXT: [[IS_POSITIVE:%.*]] = icmp sgt i32 [[SUB]], 0 ; CHECK-NEXT: [[IS_POSITIVE:%.*]] = icmp sgt i32 [[SUB]], 0
; CHECK-NEXT: br i1 [[IS_POSITIVE]], label [[BACKEDGE:%.*]], label [[IF_FALSE:%.*]] ; CHECK-NEXT: br i1 [[IS_POSITIVE]], label [[BACKEDGE]], label [[IF_FALSE:%.*]]
; CHECK: if.false: ; CHECK: if.false:
; CHECK-NEXT: br label [[BACKEDGE]] ; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: backedge: ; CHECK: backedge:
; CHECK-NEXT: [[MERGE_PHI:%.*]] = phi i32 [ 0, [[IF_FALSE]] ], [ [[SUB]], [[LOOP]] ] ; CHECK-NEXT: [[MERGE_PHI:%.*]] = phi i32 [ 0, [[IF_FALSE]] ], [ [[SUB]], [[LOOP]] ]
; CHECK-NEXT: [[SUM_NEXT:%.*]] = add i32 [[SUM]], [[MERGE_PHI]] ; CHECK-NEXT: [[SUM_NEXT]] = add i32 [[SUM]], [[MERGE_PHI]]
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[SUM_NEXT]], [[LIMIT]] ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ult i32 [[SUM_NEXT]], [[LIMIT]]
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[BACKEDGE_LOOP_CRIT_EDGE:%.*]], label [[DONE:%.*]] ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[DONE:%.*]]
; CHECK: backedge.loop_crit_edge:
; CHECK-NEXT: unreachable
; CHECK: done: ; CHECK: done:
; CHECK-NEXT: [[SUM_NEXT_LCSSA:%.*]] = phi i32 [ [[SUM_NEXT]], [[BACKEDGE]] ] ; CHECK-NEXT: [[SUM_NEXT_LCSSA:%.*]] = phi i32 [ [[SUM_NEXT]], [[BACKEDGE]] ]
; CHECK-NEXT: ret i32 [[SUM_NEXT_LCSSA]] ; CHECK-NEXT: ret i32 [[SUM_NEXT_LCSSA]]
@ -169,6 +166,7 @@ failure:
unreachable unreachable
} }
; TODO: We can break the backedge here.
define i32 @test_sgt(i32 %limit) { define i32 @test_sgt(i32 %limit) {
; CHECK-LABEL: @test_sgt( ; CHECK-LABEL: @test_sgt(
; CHECK-NEXT: entry: ; CHECK-NEXT: entry:
@ -177,19 +175,17 @@ define i32 @test_sgt(i32 %limit) {
; CHECK: loop.preheader: ; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop: ; CHECK: loop:
; CHECK-NEXT: [[SUM:%.*]] = phi i32 [ 0, [[LOOP_PREHEADER]] ] ; CHECK-NEXT: [[SUM:%.*]] = phi i32 [ [[SUM_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[LIMIT]], [[SUM]] ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[LIMIT]], [[SUM]]
; CHECK-NEXT: [[IS_POSITIVE:%.*]] = icmp sgt i32 [[SUB]], 0 ; CHECK-NEXT: [[IS_POSITIVE:%.*]] = icmp sgt i32 [[SUB]], 0
; CHECK-NEXT: br i1 [[IS_POSITIVE]], label [[BACKEDGE:%.*]], label [[IF_FALSE:%.*]] ; CHECK-NEXT: br i1 [[IS_POSITIVE]], label [[BACKEDGE]], label [[IF_FALSE:%.*]]
; CHECK: if.false: ; CHECK: if.false:
; CHECK-NEXT: br label [[BACKEDGE]] ; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: backedge: ; CHECK: backedge:
; CHECK-NEXT: [[MERGE_PHI:%.*]] = phi i32 [ 0, [[IF_FALSE]] ], [ [[SUB]], [[LOOP]] ] ; CHECK-NEXT: [[MERGE_PHI:%.*]] = phi i32 [ 0, [[IF_FALSE]] ], [ [[SUB]], [[LOOP]] ]
; CHECK-NEXT: [[SUM_NEXT:%.*]] = add i32 [[SUM]], [[MERGE_PHI]] ; CHECK-NEXT: [[SUM_NEXT]] = add i32 [[SUM]], [[MERGE_PHI]]
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp sgt i32 [[SUM_NEXT]], [[LIMIT]] ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp sgt i32 [[SUM_NEXT]], [[LIMIT]]
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[BACKEDGE_LOOP_CRIT_EDGE:%.*]], label [[DONE:%.*]] ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[DONE:%.*]]
; CHECK: backedge.loop_crit_edge:
; CHECK-NEXT: unreachable
; CHECK: done: ; CHECK: done:
; CHECK-NEXT: [[SUM_NEXT_LCSSA:%.*]] = phi i32 [ [[SUM_NEXT]], [[BACKEDGE]] ] ; CHECK-NEXT: [[SUM_NEXT_LCSSA:%.*]] = phi i32 [ [[SUM_NEXT]], [[BACKEDGE]] ]
; CHECK-NEXT: ret i32 [[SUM_NEXT_LCSSA]] ; CHECK-NEXT: ret i32 [[SUM_NEXT_LCSSA]]
@ -223,6 +219,7 @@ failure:
unreachable unreachable
} }
; TODO: We can break the backedge here.
define i32 @test_ugt(i32 %limit) { define i32 @test_ugt(i32 %limit) {
; CHECK-LABEL: @test_ugt( ; CHECK-LABEL: @test_ugt(
; CHECK-NEXT: entry: ; CHECK-NEXT: entry:
@ -231,19 +228,17 @@ define i32 @test_ugt(i32 %limit) {
; CHECK: loop.preheader: ; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop: ; CHECK: loop:
; CHECK-NEXT: [[SUM:%.*]] = phi i32 [ 0, [[LOOP_PREHEADER]] ] ; CHECK-NEXT: [[SUM:%.*]] = phi i32 [ [[SUM_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[LIMIT]], [[SUM]] ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[LIMIT]], [[SUM]]
; CHECK-NEXT: [[IS_POSITIVE:%.*]] = icmp sgt i32 [[SUB]], 0 ; CHECK-NEXT: [[IS_POSITIVE:%.*]] = icmp sgt i32 [[SUB]], 0
; CHECK-NEXT: br i1 [[IS_POSITIVE]], label [[BACKEDGE:%.*]], label [[IF_FALSE:%.*]] ; CHECK-NEXT: br i1 [[IS_POSITIVE]], label [[BACKEDGE]], label [[IF_FALSE:%.*]]
; CHECK: if.false: ; CHECK: if.false:
; CHECK-NEXT: br label [[BACKEDGE]] ; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: backedge: ; CHECK: backedge:
; CHECK-NEXT: [[MERGE_PHI:%.*]] = phi i32 [ 0, [[IF_FALSE]] ], [ [[SUB]], [[LOOP]] ] ; CHECK-NEXT: [[MERGE_PHI:%.*]] = phi i32 [ 0, [[IF_FALSE]] ], [ [[SUB]], [[LOOP]] ]
; CHECK-NEXT: [[SUM_NEXT:%.*]] = add i32 [[SUM]], [[MERGE_PHI]] ; CHECK-NEXT: [[SUM_NEXT]] = add i32 [[SUM]], [[MERGE_PHI]]
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ugt i32 [[SUM_NEXT]], [[LIMIT]] ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ugt i32 [[SUM_NEXT]], [[LIMIT]]
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[BACKEDGE_LOOP_CRIT_EDGE:%.*]], label [[DONE:%.*]] ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[DONE:%.*]]
; CHECK: backedge.loop_crit_edge:
; CHECK-NEXT: unreachable
; CHECK: done: ; CHECK: done:
; CHECK-NEXT: [[SUM_NEXT_LCSSA:%.*]] = phi i32 [ [[SUM_NEXT]], [[BACKEDGE]] ] ; CHECK-NEXT: [[SUM_NEXT_LCSSA:%.*]] = phi i32 [ [[SUM_NEXT]], [[BACKEDGE]] ]
; CHECK-NEXT: ret i32 [[SUM_NEXT_LCSSA]] ; CHECK-NEXT: ret i32 [[SUM_NEXT_LCSSA]]
@ -277,6 +272,7 @@ failure:
unreachable unreachable
} }
; TODO: We can break the backedge here.
define i32 @test_multiple_pred(i32 %limit) { define i32 @test_multiple_pred(i32 %limit) {
; CHECK-LABEL: @test_multiple_pred( ; CHECK-LABEL: @test_multiple_pred(
; CHECK-NEXT: entry: ; CHECK-NEXT: entry:
@ -285,24 +281,22 @@ define i32 @test_multiple_pred(i32 %limit) {
; CHECK: loop.preheader: ; CHECK: loop.preheader:
; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop: ; CHECK: loop:
; CHECK-NEXT: [[SUM:%.*]] = phi i32 [ 0, [[LOOP_PREHEADER]] ] ; CHECK-NEXT: [[SUM:%.*]] = phi i32 [ [[SUM_NEXT:%.*]], [[BACKEDGE:%.*]] ], [ 0, [[LOOP_PREHEADER]] ]
; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[LIMIT]], [[SUM]] ; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[LIMIT]], [[SUM]]
; CHECK-NEXT: [[IS_POSITIVE:%.*]] = icmp sgt i32 [[SUB]], 0 ; CHECK-NEXT: [[IS_POSITIVE:%.*]] = icmp sgt i32 [[SUB]], 0
; CHECK-NEXT: br i1 [[IS_POSITIVE]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] ; CHECK-NEXT: br i1 [[IS_POSITIVE]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
; CHECK: if.true: ; CHECK: if.true:
; CHECK-NEXT: switch i32 [[LIMIT]], label [[FAILURE_LOOPEXIT:%.*]] [ ; CHECK-NEXT: switch i32 [[LIMIT]], label [[FAILURE_LOOPEXIT:%.*]] [
; CHECK-NEXT: i32 100, label [[BACKEDGE:%.*]] ; CHECK-NEXT: i32 100, label [[BACKEDGE]]
; CHECK-NEXT: i32 200, label [[BACKEDGE]] ; CHECK-NEXT: i32 200, label [[BACKEDGE]]
; CHECK-NEXT: ] ; CHECK-NEXT: ]
; CHECK: if.false: ; CHECK: if.false:
; CHECK-NEXT: br label [[BACKEDGE]] ; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: backedge: ; CHECK: backedge:
; CHECK-NEXT: [[MERGE_PHI:%.*]] = phi i32 [ 0, [[IF_FALSE]] ], [ [[SUB]], [[IF_TRUE]] ], [ [[SUB]], [[IF_TRUE]] ] ; CHECK-NEXT: [[MERGE_PHI:%.*]] = phi i32 [ 0, [[IF_FALSE]] ], [ [[SUB]], [[IF_TRUE]] ], [ [[SUB]], [[IF_TRUE]] ]
; CHECK-NEXT: [[SUM_NEXT:%.*]] = add i32 [[SUM]], [[MERGE_PHI]] ; CHECK-NEXT: [[SUM_NEXT]] = add i32 [[SUM]], [[MERGE_PHI]]
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ne i32 [[SUM_NEXT]], [[LIMIT]] ; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ne i32 [[SUM_NEXT]], [[LIMIT]]
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[BACKEDGE_LOOP_CRIT_EDGE:%.*]], label [[DONE:%.*]] ; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[DONE:%.*]]
; CHECK: backedge.loop_crit_edge:
; CHECK-NEXT: unreachable
; CHECK: done: ; CHECK: done:
; CHECK-NEXT: [[SUM_NEXT_LCSSA:%.*]] = phi i32 [ [[SUM_NEXT]], [[BACKEDGE]] ] ; CHECK-NEXT: [[SUM_NEXT_LCSSA:%.*]] = phi i32 [ [[SUM_NEXT]], [[BACKEDGE]] ]
; CHECK-NEXT: ret i32 [[SUM_NEXT_LCSSA]] ; CHECK-NEXT: ret i32 [[SUM_NEXT_LCSSA]]

View File

@ -50,7 +50,7 @@ define void @test2_sideeffect_in_outer(i64 %N, i64 %M, %pair_t* %ptr) willreturn
; CHECK-NEXT: entry: ; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[OUTER_HEADER:%.*]] ; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
; CHECK: outer.header: ; CHECK: outer.header:
; CHECK-NEXT: [[OUTER_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ] ; CHECK-NEXT: [[OUTER_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[OUTER_IV_NEXT:%.*]], [[OUTER_LATCH:%.*]] ]
; CHECK-NEXT: br label [[INNER:%.*]] ; CHECK-NEXT: br label [[INNER:%.*]]
; CHECK: inner: ; CHECK: inner:
; CHECK-NEXT: [[INNER_IV:%.*]] = phi i64 [ 0, [[OUTER_HEADER]] ], [ [[INNER_IV_NEXT:%.*]], [[INNER]] ] ; CHECK-NEXT: [[INNER_IV:%.*]] = phi i64 [ 0, [[OUTER_HEADER]] ], [ [[INNER_IV_NEXT:%.*]], [[INNER]] ]
@ -60,15 +60,13 @@ define void @test2_sideeffect_in_outer(i64 %N, i64 %M, %pair_t* %ptr) willreturn
; CHECK-NEXT: [[V_1:%.*]] = extractvalue [[PAIR_T]] [[P]], 1 ; CHECK-NEXT: [[V_1:%.*]] = extractvalue [[PAIR_T]] [[P]], 1
; CHECK-NEXT: [[INNER_EC:%.*]] = icmp ult i64 [[V_0]], [[V_1]] ; CHECK-NEXT: [[INNER_EC:%.*]] = icmp ult i64 [[V_0]], [[V_1]]
; CHECK-NEXT: [[INNER_IV_NEXT]] = add i64 [[INNER_IV]], 1 ; CHECK-NEXT: [[INNER_IV_NEXT]] = add i64 [[INNER_IV]], 1
; CHECK-NEXT: br i1 [[INNER_EC]], label [[OUTER_LATCH:%.*]], label [[INNER]] ; CHECK-NEXT: br i1 [[INNER_EC]], label [[OUTER_LATCH]], label [[INNER]]
; CHECK: outer.latch: ; CHECK: outer.latch:
; CHECK-NEXT: [[LCSSA:%.*]] = phi i64 [ [[V_1]], [[INNER]] ] ; CHECK-NEXT: [[LCSSA:%.*]] = phi i64 [ [[V_1]], [[INNER]] ]
; CHECK-NEXT: [[OUTER_EC:%.*]] = icmp ult i64 [[OUTER_IV]], [[LCSSA]] ; CHECK-NEXT: [[OUTER_EC:%.*]] = icmp ult i64 [[OUTER_IV]], [[LCSSA]]
; CHECK-NEXT: [[OUTER_IV_NEXT:%.*]] = add i64 [[OUTER_IV]], 1 ; CHECK-NEXT: [[OUTER_IV_NEXT]] = add i64 [[OUTER_IV]], 1
; CHECK-NEXT: call void @sideeffect() ; CHECK-NEXT: call void @sideeffect()
; CHECK-NEXT: br i1 [[OUTER_EC]], label [[EXIT:%.*]], label [[OUTER_LATCH_OUTER_HEADER_CRIT_EDGE:%.*]] ; CHECK-NEXT: br i1 [[OUTER_EC]], label [[EXIT:%.*]], label [[OUTER_HEADER]]
; CHECK: outer.latch.outer.header_crit_edge:
; CHECK-NEXT: unreachable
; CHECK: exit: ; CHECK: exit:
; CHECK-NEXT: ret void ; CHECK-NEXT: ret void
; ;
@ -107,7 +105,7 @@ define void @test3_sideeffect_in_inner(i64 %N, i64 %M, %pair_t* %ptr) willreturn
; CHECK-NEXT: entry: ; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[OUTER_HEADER:%.*]] ; CHECK-NEXT: br label [[OUTER_HEADER:%.*]]
; CHECK: outer.header: ; CHECK: outer.header:
; CHECK-NEXT: [[OUTER_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ] ; CHECK-NEXT: [[OUTER_IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[OUTER_IV_NEXT:%.*]], [[OUTER_LATCH:%.*]] ]
; CHECK-NEXT: br label [[INNER:%.*]] ; CHECK-NEXT: br label [[INNER:%.*]]
; CHECK: inner: ; CHECK: inner:
; CHECK-NEXT: [[INNER_IV:%.*]] = phi i64 [ 0, [[OUTER_HEADER]] ], [ [[INNER_IV_NEXT:%.*]], [[INNER]] ] ; CHECK-NEXT: [[INNER_IV:%.*]] = phi i64 [ 0, [[OUTER_HEADER]] ], [ [[INNER_IV_NEXT:%.*]], [[INNER]] ]
@ -118,14 +116,12 @@ define void @test3_sideeffect_in_inner(i64 %N, i64 %M, %pair_t* %ptr) willreturn
; CHECK-NEXT: [[INNER_EC:%.*]] = icmp ult i64 [[V_0]], [[V_1]] ; CHECK-NEXT: [[INNER_EC:%.*]] = icmp ult i64 [[V_0]], [[V_1]]
; CHECK-NEXT: [[INNER_IV_NEXT]] = add i64 [[INNER_IV]], 1 ; CHECK-NEXT: [[INNER_IV_NEXT]] = add i64 [[INNER_IV]], 1
; CHECK-NEXT: call void @sideeffect() ; CHECK-NEXT: call void @sideeffect()
; CHECK-NEXT: br i1 [[INNER_EC]], label [[OUTER_LATCH:%.*]], label [[INNER]] ; CHECK-NEXT: br i1 [[INNER_EC]], label [[OUTER_LATCH]], label [[INNER]]
; CHECK: outer.latch: ; CHECK: outer.latch:
; CHECK-NEXT: [[LCSSA:%.*]] = phi i64 [ [[V_1]], [[INNER]] ] ; CHECK-NEXT: [[LCSSA:%.*]] = phi i64 [ [[V_1]], [[INNER]] ]
; CHECK-NEXT: [[OUTER_EC:%.*]] = icmp ult i64 [[OUTER_IV]], [[LCSSA]] ; CHECK-NEXT: [[OUTER_EC:%.*]] = icmp ult i64 [[OUTER_IV]], [[LCSSA]]
; CHECK-NEXT: [[OUTER_IV_NEXT:%.*]] = add i64 [[OUTER_IV]], 1 ; CHECK-NEXT: [[OUTER_IV_NEXT]] = add i64 [[OUTER_IV]], 1
; CHECK-NEXT: br i1 [[OUTER_EC]], label [[EXIT:%.*]], label [[OUTER_LATCH_OUTER_HEADER_CRIT_EDGE:%.*]] ; CHECK-NEXT: br i1 [[OUTER_EC]], label [[EXIT:%.*]], label [[OUTER_HEADER]]
; CHECK: outer.latch.outer.header_crit_edge:
; CHECK-NEXT: unreachable
; CHECK: exit: ; CHECK: exit:
; CHECK-NEXT: ret void ; CHECK-NEXT: ret void
; ;

View File

@ -161,16 +161,14 @@ define void @test_multi_exit3(i1 %cond1) {
; CHECK-NEXT: entry: ; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop: ; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ] ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_INC:%.*]], [[LATCH:%.*]] ]
; CHECK-NEXT: store i32 0, i32* @G, align 4 ; CHECK-NEXT: store i32 0, i32* @G, align 4
; CHECK-NEXT: br i1 [[COND1:%.*]], label [[LATCH:%.*]], label [[EXIT:%.*]] ; CHECK-NEXT: br i1 [[COND1:%.*]], label [[LATCH]], label [[EXIT:%.*]]
; CHECK: latch: ; CHECK: latch:
; CHECK-NEXT: store i32 1, i32* @G, align 4 ; CHECK-NEXT: store i32 1, i32* @G, align 4
; CHECK-NEXT: [[IV_INC:%.*]] = add i32 [[IV]], 1 ; CHECK-NEXT: [[IV_INC]] = add i32 [[IV]], 1
; CHECK-NEXT: [[BE_TAKEN:%.*]] = icmp ne i32 [[IV_INC]], 1 ; CHECK-NEXT: [[BE_TAKEN:%.*]] = icmp ne i32 [[IV_INC]], 1
; CHECK-NEXT: br i1 [[BE_TAKEN]], label [[LATCH_LOOP_CRIT_EDGE:%.*]], label [[EXIT]] ; CHECK-NEXT: br i1 [[BE_TAKEN]], label [[LOOP]], label [[EXIT]]
; CHECK: latch.loop_crit_edge:
; CHECK-NEXT: unreachable
; CHECK: exit: ; CHECK: exit:
; CHECK-NEXT: ret void ; CHECK-NEXT: ret void
; ;