forked from OSchip/llvm-project
Revert "[LoopNest] Allow empty basic blocks without loops"
This reverts commit 9a17bff4f7
.
This commit is contained in:
parent
191552344b
commit
de6d43f16c
|
@ -128,12 +128,6 @@ public:
|
||||||
[](const Loop *L) { return L->isLoopSimplifyForm(); });
|
[](const Loop *L) { return L->isLoopSimplifyForm(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return true if all loops in the loop nest are in rotated form.
|
|
||||||
bool areAllLoopsRotatedForm() const {
|
|
||||||
return std::all_of(Loops.begin(), Loops.end(),
|
|
||||||
[](const Loop *L) { return L->isRotatedForm(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
StringRef getName() const { return Loops.front()->getName(); }
|
StringRef getName() const { return Loops.front()->getName(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -244,12 +244,6 @@ unsigned SplitAllCriticalEdges(Function &F,
|
||||||
const CriticalEdgeSplittingOptions &Options =
|
const CriticalEdgeSplittingOptions &Options =
|
||||||
CriticalEdgeSplittingOptions());
|
CriticalEdgeSplittingOptions());
|
||||||
|
|
||||||
/// Recursivelly traverse all empty 'single successor' basic blocks of \p From
|
|
||||||
/// (if there are any). Return the last basic block found or \p End if it was
|
|
||||||
/// reached during the search.
|
|
||||||
const BasicBlock &skipEmptyBlockUntil(const BasicBlock *From,
|
|
||||||
const BasicBlock *End);
|
|
||||||
|
|
||||||
/// Split the edge connecting the specified blocks, and return the newly created
|
/// Split the edge connecting the specified blocks, and return the newly created
|
||||||
/// basic block between \p From and \p To.
|
/// basic block between \p From and \p To.
|
||||||
BasicBlock *SplitEdge(BasicBlock *From, BasicBlock *To,
|
BasicBlock *SplitEdge(BasicBlock *From, BasicBlock *To,
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#include "llvm/ADT/Statistic.h"
|
#include "llvm/ADT/Statistic.h"
|
||||||
#include "llvm/Analysis/PostDominators.h"
|
#include "llvm/Analysis/PostDominators.h"
|
||||||
#include "llvm/Analysis/ValueTracking.h"
|
#include "llvm/Analysis/ValueTracking.h"
|
||||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
|
@ -254,66 +253,49 @@ static bool checkLoopsStructure(const Loop &OuterLoop, const Loop &InnerLoop,
|
||||||
// Ensure the only branch that may exist between the loops is the inner loop
|
// Ensure the only branch that may exist between the loops is the inner loop
|
||||||
// guard.
|
// guard.
|
||||||
if (OuterLoopHeader != InnerLoopPreHeader) {
|
if (OuterLoopHeader != InnerLoopPreHeader) {
|
||||||
const BasicBlock &SingleSucc =
|
const BranchInst *BI =
|
||||||
skipEmptyBlockUntil(OuterLoopHeader, InnerLoopPreHeader);
|
dyn_cast<BranchInst>(OuterLoopHeader->getTerminator());
|
||||||
|
|
||||||
// no conditional branch present
|
if (!BI || BI != InnerLoop.getLoopGuardBranch())
|
||||||
if (&SingleSucc != InnerLoopPreHeader) {
|
return false;
|
||||||
const BranchInst *BI = dyn_cast<BranchInst>(SingleSucc.getTerminator());
|
|
||||||
|
|
||||||
if (!BI || BI != InnerLoop.getLoopGuardBranch())
|
bool InnerLoopExitContainsLCSSA = ContainsLCSSAPhi(*InnerLoopExit);
|
||||||
return false;
|
|
||||||
|
|
||||||
bool InnerLoopExitContainsLCSSA = ContainsLCSSAPhi(*InnerLoopExit);
|
// The successors of the inner loop guard should be the inner loop
|
||||||
|
// preheader and the outer loop latch.
|
||||||
|
for (const BasicBlock *Succ : BI->successors()) {
|
||||||
|
if (Succ == InnerLoopPreHeader)
|
||||||
|
continue;
|
||||||
|
if (Succ == OuterLoopLatch)
|
||||||
|
continue;
|
||||||
|
|
||||||
// The successors of the inner loop guard should be the inner loop
|
// If `InnerLoopExit` contains LCSSA Phi instructions, additional block
|
||||||
// preheader or the outer loop latch possibly through empty blocks.
|
// may be inserted before the `OuterLoopLatch` to which `BI` jumps. The
|
||||||
for (const BasicBlock *Succ : BI->successors()) {
|
// loops are still considered perfectly nested if the extra block only
|
||||||
const BasicBlock *PotentialInnerPreHeader = Succ;
|
// contains Phi instructions from InnerLoopExit and OuterLoopHeader.
|
||||||
const BasicBlock *PotentialOuterLatch = Succ;
|
if (InnerLoopExitContainsLCSSA && IsExtraPhiBlock(*Succ) &&
|
||||||
|
Succ->getSingleSuccessor() == OuterLoopLatch) {
|
||||||
// Ensure the inner loop guard successor is empty before skipping
|
// Points to the extra block so that we can reference it later in the
|
||||||
// blocks.
|
// final check. We can also conclude that the inner loop is
|
||||||
if (Succ->getInstList().size() == 1) {
|
// guarded and there exists LCSSA Phi node in the exit block later if we
|
||||||
PotentialInnerPreHeader =
|
// see a non-null `ExtraPhiBlock`.
|
||||||
&skipEmptyBlockUntil(Succ, InnerLoopPreHeader);
|
ExtraPhiBlock = Succ;
|
||||||
PotentialOuterLatch = &skipEmptyBlockUntil(Succ, OuterLoopLatch);
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
if (PotentialInnerPreHeader == InnerLoopPreHeader)
|
|
||||||
continue;
|
|
||||||
if (PotentialOuterLatch == OuterLoopLatch)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// If `InnerLoopExit` contains LCSSA Phi instructions, additional block
|
|
||||||
// may be inserted before the `OuterLoopLatch` to which `BI` jumps. The
|
|
||||||
// loops are still considered perfectly nested if the extra block only
|
|
||||||
// contains Phi instructions from InnerLoopExit and OuterLoopHeader.
|
|
||||||
if (InnerLoopExitContainsLCSSA && IsExtraPhiBlock(*Succ) &&
|
|
||||||
Succ->getSingleSuccessor() == OuterLoopLatch) {
|
|
||||||
// Points to the extra block so that we can reference it later in the
|
|
||||||
// final check. We can also conclude that the inner loop is
|
|
||||||
// guarded and there exists LCSSA Phi node in the exit block later if
|
|
||||||
// we see a non-null `ExtraPhiBlock`.
|
|
||||||
ExtraPhiBlock = Succ;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_WITH_TYPE(VerboseDebug, {
|
|
||||||
dbgs() << "Inner loop guard successor " << Succ->getName()
|
|
||||||
<< " doesn't lead to inner loop preheader or "
|
|
||||||
"outer loop latch.\n";
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEBUG_WITH_TYPE(VerboseDebug, {
|
||||||
|
dbgs() << "Inner loop guard successor " << Succ->getName()
|
||||||
|
<< " doesn't lead to inner loop preheader or "
|
||||||
|
"outer loop latch.\n";
|
||||||
|
});
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the inner loop exit block lead to the outer loop latch possibly
|
// Ensure the inner loop exit block leads to the outer loop latch.
|
||||||
// through empty blocks.
|
const BasicBlock *SuccInner = InnerLoopExit->getSingleSuccessor();
|
||||||
const BasicBlock &SuccInner =
|
if (!SuccInner ||
|
||||||
skipEmptyBlockUntil(InnerLoop.getExitBlock(), OuterLoopLatch);
|
(SuccInner != OuterLoopLatch && SuccInner != ExtraPhiBlock)) {
|
||||||
if (&SuccInner != OuterLoopLatch && &SuccInner != ExtraPhiBlock) {
|
|
||||||
DEBUG_WITH_TYPE(
|
DEBUG_WITH_TYPE(
|
||||||
VerboseDebug,
|
VerboseDebug,
|
||||||
dbgs() << "Inner loop exit block " << *InnerLoopExit
|
dbgs() << "Inner loop exit block " << *InnerLoopExit
|
||||||
|
|
|
@ -494,31 +494,6 @@ void llvm::ReplaceInstWithInst(Instruction *From, Instruction *To) {
|
||||||
ReplaceInstWithInst(From->getParent()->getInstList(), BI, To);
|
ReplaceInstWithInst(From->getParent()->getInstList(), BI, To);
|
||||||
}
|
}
|
||||||
|
|
||||||
const BasicBlock &llvm::skipEmptyBlockUntil(const BasicBlock *From,
|
|
||||||
const BasicBlock *End) {
|
|
||||||
assert(From && "Expecting valid From");
|
|
||||||
assert(End && "Expecting valid End");
|
|
||||||
|
|
||||||
if (From == End || !From->getSingleSuccessor())
|
|
||||||
return *From;
|
|
||||||
|
|
||||||
auto IsEmpty = [](const BasicBlock *BB) {
|
|
||||||
return (BB->getInstList().size() == 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Visited is used to avoid running into an infinite loop.
|
|
||||||
SmallPtrSet<const BasicBlock *, 4> Visited;
|
|
||||||
const BasicBlock *BB = From->getSingleSuccessor();
|
|
||||||
const BasicBlock *PredBB = BB;
|
|
||||||
while (BB && BB != End && IsEmpty(BB) && !Visited.count(BB)) {
|
|
||||||
Visited.insert(BB);
|
|
||||||
PredBB = BB;
|
|
||||||
BB = BB->getSingleSuccessor();
|
|
||||||
}
|
|
||||||
|
|
||||||
return (BB == End) ? *End : *PredBB;
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicBlock *llvm::SplitEdge(BasicBlock *BB, BasicBlock *Succ, DominatorTree *DT,
|
BasicBlock *llvm::SplitEdge(BasicBlock *BB, BasicBlock *Succ, DominatorTree *DT,
|
||||||
LoopInfo *LI, MemorySSAUpdater *MSSAU) {
|
LoopInfo *LI, MemorySSAUpdater *MSSAU) {
|
||||||
unsigned SuccNum = GetSuccessorNumber(BB, Succ);
|
unsigned SuccNum = GetSuccessorNumber(BB, Succ);
|
||||||
|
|
|
@ -85,55 +85,6 @@ perf_nest_2D_2_loop_i_end:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
define void @perf_nest_2D_3(i32** %y, i32** %x, i64 signext %nx, i64 signext %ny) {
|
|
||||||
; CHECK-LABEL: IsPerfect=true, Depth=1, OutermostLoop: perf_nest_2D_3_loop_j, Loops: ( perf_nest_2D_3_loop_j )
|
|
||||||
; CHECK-LABEL: IsPerfect=true, Depth=2, OutermostLoop: perf_nest_2D_3_loop_i, Loops: ( perf_nest_2D_3_loop_i perf_nest_2D_3_loop_j )
|
|
||||||
entry:
|
|
||||||
br label %perf_nest_2D_3_loop_i
|
|
||||||
|
|
||||||
perf_nest_2D_3_loop_i:
|
|
||||||
%i = phi i64 [ 0, %entry ], [ %inc13, %inc_i ]
|
|
||||||
%cmp21 = icmp slt i64 0, %ny
|
|
||||||
br label %singleSucc
|
|
||||||
|
|
||||||
singleSucc:
|
|
||||||
br i1 %cmp21, label %preheader.j, label %for.end
|
|
||||||
|
|
||||||
preheader.j:
|
|
||||||
br label %perf_nest_2D_3_loop_j
|
|
||||||
|
|
||||||
perf_nest_2D_3_loop_j:
|
|
||||||
%j = phi i64 [ 0, %preheader.j ], [ %inc, %inc_j ]
|
|
||||||
%arrayidx = getelementptr inbounds i32*, i32** %x, i64 %j
|
|
||||||
%0 = load i32*, i32** %arrayidx, align 8
|
|
||||||
%arrayidx6 = getelementptr inbounds i32, i32* %0, i64 %j
|
|
||||||
%1 = load i32, i32* %arrayidx6, align 4
|
|
||||||
%arrayidx8 = getelementptr inbounds i32*, i32** %y, i64 %j
|
|
||||||
%2 = load i32*, i32** %arrayidx8, align 8
|
|
||||||
%arrayidx11 = getelementptr inbounds i32, i32* %2, i64 %i
|
|
||||||
store i32 %1, i32* %arrayidx11, align 4
|
|
||||||
br label %inc_j
|
|
||||||
|
|
||||||
inc_j:
|
|
||||||
%inc = add nsw i64 %j, 1
|
|
||||||
%cmp2 = icmp slt i64 %inc, %ny
|
|
||||||
br i1 %cmp2, label %perf_nest_2D_3_loop_j, label %for.exit
|
|
||||||
|
|
||||||
for.exit:
|
|
||||||
br label %for.end
|
|
||||||
|
|
||||||
for.end:
|
|
||||||
br label %inc_i
|
|
||||||
|
|
||||||
inc_i:
|
|
||||||
%inc13 = add nsw i64 %i, 1
|
|
||||||
%cmp = icmp slt i64 %inc13, %nx
|
|
||||||
br i1 %cmp, label %perf_nest_2D_3_loop_i, label %perf_nest_2D_3_loop_i_end
|
|
||||||
|
|
||||||
perf_nest_2D_3_loop_i_end:
|
|
||||||
ret void
|
|
||||||
}
|
|
||||||
|
|
||||||
; Test a perfect 3-dim loop nest of the form:
|
; Test a perfect 3-dim loop nest of the form:
|
||||||
; for (i=0; i<nx; ++i)
|
; for (i=0; i<nx; ++i)
|
||||||
; for (j=0; j<ny; ++j)
|
; for (j=0; j<ny; ++j)
|
||||||
|
|
Loading…
Reference in New Issue