From af322dba458887a0c17e3f5418c948fa6d7c1472 Mon Sep 17 00:00:00 2001 From: Ettore Tiotto Date: Fri, 11 Oct 2019 13:06:51 -0400 Subject: [PATCH 01/10] Add the ability to split a loop --- .../llvm/Transforms/Scalar/LoopOptTutorial.h | 21 +++++++ .../lib/Transforms/Scalar/LoopOptTutorial.cpp | 57 ++++++++++++++++++- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/llvm/include/llvm/Transforms/Scalar/LoopOptTutorial.h b/llvm/include/llvm/Transforms/Scalar/LoopOptTutorial.h index f82d2b370567c..95d48f4522f5f 100644 --- a/llvm/include/llvm/Transforms/Scalar/LoopOptTutorial.h +++ b/llvm/include/llvm/Transforms/Scalar/LoopOptTutorial.h @@ -18,12 +18,33 @@ #include "llvm/Analysis/LoopAnalysisManager.h" #include "llvm/IR/PassManager.h" +#include "llvm/Transforms/Utils/ValueMapper.h" +#include "llvm/Analysis/LoopInfo.h" namespace llvm { class Loop; class LPMUpdater; +/// This class splits the innermost loop in a loop nest in the middle. +class LoopSplit { +public: + LoopSplit(LoopInfo &LI) : LI(LI) {} + + bool run(Loop &L) const; + +private: + /// + bool splitLoop(Loop &L) const; + + /// Clone the loop rooted by \p L. + Loop *cloneLoop(Loop &L, BasicBlock &Preheader, BasicBlock &Pred, + ValueToValueMapTy &VMap) const; + + private: + LoopInfo &LI; +}; + class LoopOptTutorialPass : public PassInfoMixin { public: PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM, diff --git a/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp b/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp index a44c0f6b97194..650d70de67f1b 100644 --- a/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp +++ b/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp @@ -18,15 +18,70 @@ #include "llvm/IR/Function.h" #include "llvm/Pass.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Transforms/Utils/ValueMapper.h" using namespace llvm; #define DEBUG_TYPE "loop-opt-tutorial" +//===----------------------------------------------------------------------===// +// LoopSplit implementation +// + +bool LoopSplit::run(Loop &L) const { + return splitLoop(L); +} + +bool LoopSplit::splitLoop(Loop &L) const { + assert(L.isLoopSimplifyForm() && "Expecting a loop in simplify form"); + assert(L.isSafeToClone() && "Loop is not safe to be cloned"); + + // Clone the original loop. + + BasicBlock *Preheader = L.getLoopPreheader(); + BasicBlock *Pred = Preheader; + //Preheader = SplitBlock(Preheader, Preheader->getTerminator(), &DT); + + ValueToValueMapTy VMap; + LLVM_DEBUG(dbgs() << "InsertPoint: " << Preheader->getName() << "\n"); + Loop *ClonedLoop = cloneLoop(L, *Preheader, *Pred, VMap); + LLVM_DEBUG(dbgs() << "Created " << ClonedLoop << ":" << *ClonedLoop << "\n"); + + Preheader = ClonedLoop->getLoopPreheader(); + + return true; +} + +Loop *LoopSplit::cloneLoop(Loop &L, BasicBlock &Preheader, BasicBlock &Pred, + ValueToValueMapTy &VMap) const { + assert(L.getSubLoops().empty() && "Expecting a innermost loop"); + + BasicBlock *ExitBlock = L.getExitBlock(); + assert(ExitBlock && "Expecting outermost loop to have a valid exit block"); + + // Clone the original loop and remap instructions in the cloned loop. + SmallVector ClonedLoopBlocks; + DominatorTree *DT = nullptr; + Loop *NewLoop = cloneLoopWithPreheader(&Preheader, &Pred, &L, + VMap, "", &LI, DT, ClonedLoopBlocks); + VMap[ExitBlock] = &Preheader; + remapInstructionsInBlocks(ClonedLoopBlocks, VMap); + Pred.getTerminator()->replaceUsesOfWith(&Preheader, + NewLoop->getLoopPreheader()); + + // Update the immediate dominator for the origianl loop with the exiting block + // of the new loop created. Dominance within the loop is updated in + // cloneLoopWithPreheader. + //DT.changeImmediateDominator(&Preheader, NewLoop->getExitingBlock()); + + return NewLoop; +} + PreservedAnalyses LoopOptTutorialPass::run(Loop &L, LoopAnalysisManager &LAM, LoopStandardAnalysisResults &AR, LPMUpdater &U) { - bool Changed = false; + bool Changed = LoopSplit(AR.LI).run(L); LLVM_DEBUG(dbgs() << "Entering LoopOptTutorialPass::run\n"); LLVM_DEBUG(dbgs() << "Loop: "; L.dump(); dbgs() << "\n"); From a524f9d296d5d6cb9713b32241f83513c3bb91da Mon Sep 17 00:00:00 2001 From: Ettore Tiotto Date: Tue, 15 Oct 2019 11:27:30 -0400 Subject: [PATCH 02/10] [SplitLoop]: add code to split the cloned loop and the original loop in half. --- .../lib/Transforms/Scalar/LoopOptTutorial.cpp | 58 +++++++++++++++++-- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp b/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp index 9e948366e87d3..f1b3f5606eab4 100644 --- a/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp +++ b/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp @@ -14,13 +14,14 @@ //===----------------------------------------------------------------------=== #include "llvm/Transforms/Scalar/LoopOptTutorial.h" +#include "llvm/Analysis/IVDescriptors.h" #include "llvm/Analysis/LoopPass.h" #include "llvm/IR/Function.h" #include "llvm/Pass.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/ValueMapper.h" -#include "llvm/Transforms/Utils/BasicBlockUtils.h" using namespace llvm; @@ -56,11 +57,11 @@ bool LoopSplit::run(Loop &L) const { } bool LoopSplit::isCandidate(const Loop &L) const { - // Require loops with preheaders and dedicated exits + // Require loops with preheaders and dedicated exits. if (!L.isLoopSimplifyForm()) return false; - // Since we use cloning to split the loop, it has to be safe to clone + // Since we use cloning to split the loop, it has to be safe to clone. if (!L.isSafeToClone()) return false; @@ -90,7 +91,7 @@ bool LoopSplit::splitLoopInHalf(Loop &L) const { BasicBlock *Pred = Preheader; DEBUG_WITH_TYPE(VerboseDebug, dumpLoopFunction("Before splitting preheader:\n", L);); - BasicBlock *InsertBefore = SplitBlock(Preheader, Preheader->getTerminator(), DT); + BasicBlock *InsertBefore = SplitBlock(Preheader, Preheader->getTerminator(), &DT); DEBUG_WITH_TYPE(VerboseDebug, dumpLoopFunction("After splitting preheader:\n", L);); @@ -99,6 +100,18 @@ bool LoopSplit::splitLoopInHalf(Loop &L) const { DEBUG_WITH_TYPE(VerboseDebug, dumpLoopFunction("After cloning the loop:\n", L);); + // Modify the upper bound of the cloned loop. + Instruction *Split = + computeSplitPoint(L, ClonedLoop->getLoopPreheader()->getTerminator()); + ICmpInst *LatchCmpInst = getLatchCmpInst(*ClonedLoop); + assert(LatchCmpInst && "Unable to find the latch comparison instruction"); + LatchCmpInst->setOperand(1, Split); + + // Modify the lower bound of the original loop. + PHINode *IndVar = L.getInductionVariable(SE); + assert(IndVar && "Unable to find the induction variable PHI node"); + IndVar->setIncomingValueForBlock(L.getLoopPreheader(), Split); + return true; } @@ -107,8 +120,17 @@ Loop *LoopSplit::cloneLoop(Loop &L, BasicBlock &InsertBefore, // Clone the original loop, insert the clone before the "InsertBefore" BB. SmallVector ClonedLoopBlocks; ValueToValueMapTy VMap; + +#ifdef BUG + // Same as cloneLoopWithPreheader but does not update the dominator tree. + // Consequently code that requires scalar evolution computation will fail. Loop *NewLoop = myCloneLoopWithPreheader(&InsertBefore, &Pred, &L, VMap, - "ClonedLoop", &LI, ClonedLoopBlocks); + "", &LI, ClonedLoopBlocks); +#else + Loop *NewLoop = cloneLoopWithPreheader(&InsertBefore, &Pred, &L, VMap, + "", &LI, &DT, ClonedLoopBlocks); +#endif + assert(NewLoop && "Run ot of memory"); DEBUG_WITH_TYPE(VerboseDebug, dbgs() << "Create new loop: " << NewLoop->getName() << "\n"; @@ -133,6 +155,30 @@ Loop *LoopSplit::cloneLoop(Loop &L, BasicBlock &InsertBefore, return NewLoop; } +Instruction *LoopSplit::computeSplitPoint(const Loop &L, + Instruction *InsertBefore) const { + Optional Bounds = L.getBounds(SE); + assert(Bounds.hasValue() && "Unable to retrieve the loop bounds"); + + Value &IVInitialVal = Bounds->getInitialIVValue(); + Value &IVFinalVal = Bounds->getFinalIVValue(); + auto *Sub = + BinaryOperator::Create(Instruction::Sub, &IVFinalVal, &IVInitialVal, "", InsertBefore); + + return BinaryOperator::Create(Instruction::UDiv, Sub, + ConstantInt::get(IVFinalVal.getType(), 2), + "", InsertBefore); +} + +ICmpInst *LoopSplit::getLatchCmpInst(const Loop &L) const { + if (BasicBlock *Latch = L.getLoopLatch()) + if (BranchInst *BI = dyn_cast_or_null(Latch->getTerminator())) + if (BI->isConditional()) + return dyn_cast(BI->getCondition()); + + return nullptr; +} + void LoopSplit::dumpLoopFunction(const StringRef Msg, const Loop &L) const { const Function &F = *L.getHeader()->getParent(); dbgs() << Msg; @@ -219,7 +265,7 @@ PreservedAnalyses LoopOptTutorialPass::run(Loop &L, LoopAnalysisManager &LAM, LLVM_DEBUG(dbgs() << "Entering LoopOptTutorialPass::run\n"); LLVM_DEBUG(dbgs() << "Loop: "; L.dump(); dbgs() << "\n"); - bool Changed = LoopSplit(AR.LI, AR.SE).run(L); + bool Changed = LoopSplit(AR.LI, AR.SE, AR.DT).run(L); if (!Changed) return PreservedAnalyses::all(); From d3c959a699dc7fb68518dea24e903232d89d0730 Mon Sep 17 00:00:00 2001 From: Ettore Tiotto Date: Tue, 15 Oct 2019 14:54:12 -0400 Subject: [PATCH 03/10] [SplitLoop]: add support for splitting the inner loop in a loop nest. --- .../llvm/Transforms/Scalar/LoopOptTutorial.h | 18 ++- .../lib/Transforms/Scalar/LoopOptTutorial.cpp | 45 ++++-- .../Transforms/LoopOptTutorial/loop_nest.ll | 132 ++++++++++-------- .../test/Transforms/LoopOptTutorial/simple.ll | 76 ++++++---- 4 files changed, 171 insertions(+), 100 deletions(-) diff --git a/llvm/include/llvm/Transforms/Scalar/LoopOptTutorial.h b/llvm/include/llvm/Transforms/Scalar/LoopOptTutorial.h index 66f3116216969..969da9512c9f5 100644 --- a/llvm/include/llvm/Transforms/Scalar/LoopOptTutorial.h +++ b/llvm/include/llvm/Transforms/Scalar/LoopOptTutorial.h @@ -29,7 +29,8 @@ class LPMUpdater; /// This class splits the innermost loop in a loop nest in the middle. class LoopSplit { public: - LoopSplit(LoopInfo &LI, ScalarEvolution &SE) : LI(LI), SE(SE) {} + LoopSplit(LoopInfo &LI, ScalarEvolution &SE, DominatorTree &DT) + : LI(LI), SE(SE), DT(DT) {} // Execute the transformation on the loop nest rooted by \p L. bool run(Loop &L) const; @@ -51,13 +52,22 @@ class LoopSplit { /// level loop. Loop *cloneLoop(Loop &L, BasicBlock &InsertBefore, BasicBlock &Pred) const; - // Dump the LLVM IR for function containing the given loop \p L. - void dumpLoopFunction(const StringRef Msg, const Loop &L) const; + /// Compute the point where to split the loop \p L. Return the instruction + /// calculating the split point. + Instruction *computeSplitPoint(const Loop &L, + Instruction *InsertBefore) const; + + + /// Get the latch comparison instruction of loop \p L. + ICmpInst *getLatchCmpInst(const Loop &L) const; + + // Dump the LLVM IR for function \p F. + void dumpFunction(const StringRef Msg, const Function &F) const; private: LoopInfo &LI; ScalarEvolution &SE; - DominatorTree *DT = nullptr; + DominatorTree &DT; }; class LoopOptTutorialPass : public PassInfoMixin { diff --git a/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp b/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp index f1b3f5606eab4..0d1d4537d8cb0 100644 --- a/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp +++ b/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp @@ -28,6 +28,11 @@ using namespace llvm; #define DEBUG_TYPE "loop-opt-tutorial" static const char *VerboseDebug = DEBUG_TYPE "-verbose"; +static cl::opt + Verify(DEBUG_TYPE "-verify", cl::Hidden, + cl::desc("Turn on DominatorTree and LoopInfo verification"), + cl::init(false)); + /// Clones a loop \p OrigLoop. Returns the loop and the blocks in \p /// Blocks. /// Updates LoopInfo assuming the loop is dominated by block \p LoopDomBB. @@ -86,19 +91,19 @@ bool LoopSplit::splitLoopInHalf(Loop &L) const { assert(L.isSafeToClone() && "Loop is not safe to be cloned"); assert(L.getSubLoops().empty() && "Expecting a innermost loop"); + LLVM_DEBUG(dbgs() << "Splitting loop " << L.getName() << "\n"); + const Function &F = *L.getHeader()->getParent(); + // Split the loop preheader to create an insertion point for the cloned loop. BasicBlock *Preheader = L.getLoopPreheader(); BasicBlock *Pred = Preheader; + BasicBlock *InsertBefore = + SplitBlock(Preheader, Preheader->getTerminator(), &DT, &LI); DEBUG_WITH_TYPE(VerboseDebug, - dumpLoopFunction("Before splitting preheader:\n", L);); - BasicBlock *InsertBefore = SplitBlock(Preheader, Preheader->getTerminator(), &DT); - DEBUG_WITH_TYPE(VerboseDebug, - dumpLoopFunction("After splitting preheader:\n", L);); + dumpFunction("After splitting preheader:\n", F);); // Clone the original loop. Loop *ClonedLoop = cloneLoop(L, *InsertBefore, *Pred); - DEBUG_WITH_TYPE(VerboseDebug, - dumpLoopFunction("After cloning the loop:\n", L);); // Modify the upper bound of the cloned loop. Instruction *Split = @@ -112,12 +117,16 @@ bool LoopSplit::splitLoopInHalf(Loop &L) const { assert(IndVar && "Unable to find the induction variable PHI node"); IndVar->setIncomingValueForBlock(L.getLoopPreheader(), Split); + DEBUG_WITH_TYPE(VerboseDebug, + dumpFunction("After splitting the loop:\n", F);); + return true; } Loop *LoopSplit::cloneLoop(Loop &L, BasicBlock &InsertBefore, BasicBlock &Pred) const { // Clone the original loop, insert the clone before the "InsertBefore" BB. + const Function &F = *L.getHeader()->getParent(); SmallVector ClonedLoopBlocks; ValueToValueMapTy VMap; @@ -134,23 +143,34 @@ Loop *LoopSplit::cloneLoop(Loop &L, BasicBlock &InsertBefore, assert(NewLoop && "Run ot of memory"); DEBUG_WITH_TYPE(VerboseDebug, dbgs() << "Create new loop: " << NewLoop->getName() << "\n"; - dumpLoopFunction("After cloning loop:\n", L);); + dumpFunction("After cloning loop:\n", F);); // Update instructions referencing the original loop basic blocks to // reference the corresponding block in the cloned loop. VMap[L.getExitBlock()] = &InsertBefore; remapInstructionsInBlocks(ClonedLoopBlocks, VMap); - DEBUG_WITH_TYPE( - VerboseDebug, dumpLoopFunction("After instruction remapping:\n", L);); + DEBUG_WITH_TYPE(VerboseDebug, + dumpFunction("After instruction remapping:\n", F);); // Make the predecessor of original loop jump to the cloned loop. Pred.getTerminator()->replaceUsesOfWith(&InsertBefore, NewLoop->getLoopPreheader()); - // Update the immediate dominator for the origianl loop with the exiting block + // Update the immediate dominator for the original loop with the exiting block // of the new loop created. Dominance within the loop is updated in // cloneLoopWithPreheader. - //DT.changeImmediateDominator(&Preheader, NewLoop->getExitingBlock()); + DT.changeImmediateDominator(&InsertBefore, NewLoop->getExitingBlock()); + assert(DT.verify(DominatorTree::VerificationLevel::Fast) && + "Dominator tree is invalid"); + + if (Verify) { + L.verifyLoop(); + NewLoop->verifyLoop(); + if (L.getParentLoop()) + L.getParentLoop()->verifyLoop(); + + LI.verify(DT); + } return NewLoop; } @@ -179,8 +199,7 @@ ICmpInst *LoopSplit::getLatchCmpInst(const Loop &L) const { return nullptr; } -void LoopSplit::dumpLoopFunction(const StringRef Msg, const Loop &L) const { - const Function &F = *L.getHeader()->getParent(); +void LoopSplit::dumpFunction(const StringRef Msg, const Function &F) const { dbgs() << Msg; F.dump(); } diff --git a/llvm/test/Transforms/LoopOptTutorial/loop_nest.ll b/llvm/test/Transforms/LoopOptTutorial/loop_nest.ll index d42ead57741dc..37c172fdbd24b 100644 --- a/llvm/test/Transforms/LoopOptTutorial/loop_nest.ll +++ b/llvm/test/Transforms/LoopOptTutorial/loop_nest.ll @@ -1,4 +1,4 @@ -; RUN: opt -S -passes=loop-opt-tutorial -debug-only=loop-opt-tutorial < %s 2>&1 | FileCheck %s +; RUN: opt -S -passes='loop(rotate,loop-opt-tutorial)' -debug-only=loop-opt-tutorial < %s 2>&1 | FileCheck %s ; REQUIRES: asserts ; ; Opts: -correlated-propagation -mem2reg -instcombine -loop-simplify -indvars -instnamer @@ -18,67 +18,83 @@ @A = common dso_local global [1024 x [1024 x i32]] zeroinitializer, align 4 @B = common dso_local global [1024 x [1024 x i32]] zeroinitializer, align 4 -; CHECK: Entering LoopOptTutorialPass::run -; CHECK: Loop at depth 2 -; CHECK: Entering LoopOptTutorialPass::run -; CHECK: Loop at depth 1 -; CHECK: Loop at depth 2 -define dso_local void @dep_free() { +; CHECK-LABEL: dep_free +; CHECK-LABEL: entry: +; CHECK-NEXT: br label %[[I_HEADER:.*]] +; CHECK: [[I_HEADER:.*]]: +; CHECK-NEXT: [[I:%i[0-9]*]] = phi i64 [ 0, %entry ], [ [[INCI:%inci[0-9]*]], %[[I_LATCH:.*]] ] +; CHECK-NEXT: br label %[[L1_PREHEADER:.*]] +; First loop: +; for (long j = 0; j < 100/2; ++j) +; ... +; CHECK: [[L1_PREHEADER]]: +; CHECK-NEXT: [[SUB:%[0-9]*]] = sub i64 100, 0 +; CHECK-NEXT: [[SPLIT:%[0-9]*]] = udiv i64 [[SUB]], 2 +; CHECK-NEXT: br label %[[L1_HEADER:.*]] +; CHECK: [[L1_HEADER]]: +; CHECK-NEXT: [[L1_J:%j[0-9]*]] = phi i64 [ 0, %[[L1_PREHEADER]] ], [ [[L1_INCJ:%incj[0-9]*]], %[[L1_LATCH:.*]] ] +; CHECK: br label %[[L1_LATCH]] +; CHECK: [[L1_LATCH]]: +; CHECK-NEXT: [[L1_INCJ]] = add nuw nsw i64 [[L1_J]], 1 +; CHECK-NEXT: [[L1_CMP:%exitcond[0-9]*]] = icmp ne i64 [[L1_INCJ]], [[SPLIT]] +; CHECK-NEXT: br i1 [[L1_CMP]], label %[[L1_HEADER]], label %[[L2_PREHEADER:.*]] + +; Second loop: +; for (long j = 100/2; j < 100; ++j) +; ... +; CHECK: [[L2_PREHEADER]]: +; CHECK-NEXT: br label %[[L2_HEADER:.*]] +; CHECK: [[L2_HEADER]]: +; CHECK-NEXT: [[L2_J:%j[0-9]*]] = phi i64 [ [[SPLIT]], %[[L2_PREHEADER]] ], [ [[L2_INCJ:%incj[0-9]*]], %[[L2_LATCH:.*]] ] +; CHECK: br label %[[L2_LATCH]] +; CHECK: [[L2_LATCH]]: +; CHECK-NEXT: [[L2_INCJ]] = add nuw nsw i64 [[L2_J]], 1 +; CHECK-NEXT: [[L2_CMP:%exitcond[0-9]*]] = icmp ne i64 [[L2_INCJ]], 100 +; CHECK-NEXT: br i1 [[L2_CMP]], label %[[L2_HEADER]], label %[[I_LATCH:.*]] + +; CHECK: [[I_LATCH]]: +; CHECK-NEXT: [[INCI]] = add nuw nsw i64 [[I]], 1 +; CHECK-NEXT: [[I_CMP:%exitcond[0-9]*]] = icmp ne i64 [[INCI]], 100 +; CHECK-NEXT: br i1 [[I_CMP]], label %[[I_HEADER]], label %[[EXIT:.*]] + +; CHECK: [[EXIT]]: + +define void @dep_free() { entry: - br label %for.cond - -for.cond: ; preds = %for.inc7, %entry - %indvars.iv1 = phi i64 [ %indvars.iv.next2, %for.inc7 ], [ 0, %entry ] - %i.0 = phi i32 [ 0, %entry ], [ %inc8, %for.inc7 ] - %exitcond5 = icmp ne i64 %indvars.iv1, 100 - br i1 %exitcond5, label %for.body, label %for.cond.cleanup - -for.cond.cleanup: ; preds = %for.cond - br label %for.end9 - -for.body: ; preds = %for.cond - br label %for.cond1 - -for.cond1: ; preds = %for.inc, %for.body - %indvars.iv = phi i64 [ %indvars.iv.next, %for.inc ], [ 0, %for.body ] - %exitcond = icmp ne i64 %indvars.iv, 100 - br i1 %exitcond, label %for.body4, label %for.cond.cleanup3 - -for.cond.cleanup3: ; preds = %for.cond1 - br label %for.end - -for.body4: ; preds = %for.cond1 - %sub = add nsw i32 %i.0, -3 - %tmp = add nuw nsw i64 %indvars.iv1, 3 - %tmp6 = trunc i64 %tmp to i32 - %mul = mul nsw i32 %sub, %tmp6 - %tmp7 = trunc i64 %indvars.iv1 to i32 - %rem = srem i32 %mul, %tmp7 - %arrayidx6 = getelementptr inbounds [1024 x [1024 x i32]], [1024 x [1024 x i32]]* @A, i64 0, i64 %indvars.iv1, i64 %indvars.iv - store i32 %rem, i32* %arrayidx6, align 4, !tbaa !2 - br label %for.inc - -for.inc: ; preds = %for.body4 - %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 - br label %for.cond1 - -for.end: ; preds = %for.cond.cleanup3 - br label %for.inc7 - -for.inc7: ; preds = %for.end - %indvars.iv.next2 = add nuw nsw i64 %indvars.iv1, 1 - %inc8 = add nuw nsw i32 %i.0, 1 - br label %for.cond - -for.end9: ; preds = %for.cond.cleanup + br label %i_header + +i_header: + %i = phi i64 [ %inci, %i_latch ], [ 0, %entry ] + %exitcond5 = icmp ne i64 %i, 100 + br i1 %exitcond5, label %j_header, label %exit + +j_header: + %j = phi i64 [ %incj, %j_latch ], [ 0, %i_header ] + %exitcond = icmp ne i64 %j, 100 + br i1 %exitcond, label %j_body, label %i_latch + +j_body: + %sub = add nsw i64 %i, -3 + %tmp = add nuw nsw i64 %i, 3 + %mul = mul nsw i64 %sub, %tmp + %rem = srem i64 %mul, %i + %arrayidx6 = getelementptr inbounds [1024 x [1024 x i32]], [1024 x [1024 x i32]]* @A, i64 0, i64 %i, i64 %j + %tmp7 = trunc i64 %sub to i32 + store i32 %tmp7, i32* %arrayidx6, align 4, !tbaa !2 + br label %j_latch + +j_latch: + %incj = add nuw nsw i64 %j, 1 + br label %j_header + +i_latch: + %inci = add nuw nsw i64 %i, 1 + br label %i_header + +exit: ret void } -declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) - -declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) - - !llvm.module.flags = !{!0} !llvm.ident = !{!1} diff --git a/llvm/test/Transforms/LoopOptTutorial/simple.ll b/llvm/test/Transforms/LoopOptTutorial/simple.ll index b24f200a194df..64d8d7592812c 100644 --- a/llvm/test/Transforms/LoopOptTutorial/simple.ll +++ b/llvm/test/Transforms/LoopOptTutorial/simple.ll @@ -1,35 +1,61 @@ -; RUN: opt -S -passes=loop-opt-tutorial -debug-only=loop-opt-tutorial < %s 2>&1 | FileCheck %s +; RUN: opt -S -passes='loop(rotate,loop-opt-tutorial)' < %s 2>&1 | FileCheck %s ; REQUIRES: asserts -@B = common global [1024 x i32] zeroinitializer, align 16 +; CHECK-LABEL: dep_free +; CHECK-LABEL: entry: +; First loop: +; for (long i = 0; i < 100/2; ++i) +; ... +; CHECK-NEXT: br label %[[L1_PREHEADER:.*]] +; CHECK: [[L1_PREHEADER]]: +; CHECK-NEXT: [[SUB:%[0-9]*]] = sub i64 100, 0 +; CHECK-NEXT: [[SPLIT:%[0-9]*]] = udiv i64 [[SUB]], 2 +; CHECK-NEXT: br label %[[L1_HEADER:.*]] +; CHECK: [[L1_HEADER]]: +; CHECK-NEXT: [[L1_I:%i[0-9]*]] = phi i64 [ 0, %[[L1_PREHEADER]] ], [ [[L1_INCI:%inci[0-9]*]], %[[L1_LATCH:.*]] ] +; CHECK: br label %[[L1_LATCH]] +; CHECK: [[L1_LATCH]]: +; CHECK-NEXT: [[L1_INCI]] = add nuw nsw i64 [[L1_I]], 1 +; CHECK-NEXT: [[L1_CMP:%exitcond[0-9]*]] = icmp ne i64 [[L1_INCI]], [[SPLIT]] +; CHECK-NEXT: br i1 [[L1_CMP]], label %[[L1_HEADER]], label %[[L2_PREHEADER:.*]] + +; Second loop: +; for (long i = 100/2; i < 100; ++i) +; ... +; CHECK: [[L2_PREHEADER]]: +; CHECK-NEXT: br label %[[L2_HEADER:.*]] +; CHECK: [[L2_HEADER]]: +; CHECK-NEXT: [[L2_I:%i[0-9]*]] = phi i64 [ [[SPLIT]], %[[L2_PREHEADER]] ], [ [[L2_INCI:%inci[0-9]*]], %[[L2_LATCH:.*]] ] +; CHECK: br label %[[L2_LATCH]] +; CHECK: [[L2_LATCH]]: +; CHECK-NEXT: [[L2_INCI]] = add nuw nsw i64 [[L2_I]], 1 +; CHECK-NEXT: [[L2_CMP:%exitcond[0-9]*]] = icmp ne i64 [[L2_INCI]], 100 +; CHECK-NEXT: br i1 [[L2_CMP]], label %[[L2_HEADER]], label %[[EXIT:.*]] +; CHECK: [[EXIT]]: -; CHECK: Entering LoopOptTutorialPass::run define void @dep_free(i32* noalias %arg) { -bb: - br label %bb5 +entry: + br label %header -bb5: ; preds = %bb14, %bb - %indvars.iv2 = phi i64 [ %indvars.iv.next3, %bb14 ], [ 0, %bb ] - %.01 = phi i32 [ 0, %bb ], [ %tmp15, %bb14 ] - %exitcond4 = icmp ne i64 %indvars.iv2, 100 - br i1 %exitcond4, label %bb7, label %bb17 +header: + %i = phi i64 [ %inci, %latch ], [ 0, %entry ] + %exitcond4 = icmp ne i64 %i, 100 + br i1 %exitcond4, label %body, label %exit -bb7: ; preds = %bb5 - %tmp = add nsw i32 %.01, -3 - %tmp8 = add nuw nsw i64 %indvars.iv2, 3 - %tmp9 = trunc i64 %tmp8 to i32 - %tmp10 = mul nsw i32 %tmp, %tmp9 - %tmp11 = trunc i64 %indvars.iv2 to i32 - %tmp12 = srem i32 %tmp10, %tmp11 - %tmp13 = getelementptr inbounds i32, i32* %arg, i64 %indvars.iv2 - store i32 %tmp12, i32* %tmp13, align 4 - br label %bb14 +body: + %tmp = add nsw i64 %i, -3 + %tmp8 = add nuw nsw i64 %i, 3 + %tmp10 = mul nsw i64 %tmp, %tmp8 + %tmp12 = srem i64 %tmp10, %i + %tmp13 = getelementptr inbounds i32, i32* %arg, i64 %i + %tmp14 = trunc i64 %tmp12 to i32 + store i32 %tmp14, i32* %tmp13, align 4 + br label %latch -bb14: ; preds = %bb7 - %indvars.iv.next3 = add nuw nsw i64 %indvars.iv2, 1 - %tmp15 = add nuw nsw i32 %.01, 1 - br label %bb5 +latch: + %inci = add nuw nsw i64 %i, 1 + br label %header -bb17: ; preds = %bb5 +exit: ret void } From 73498b7f813dbb36a51979d5c6d63d854e84df51 Mon Sep 17 00:00:00 2001 From: Ettore Tiotto Date: Wed, 16 Oct 2019 15:04:27 -0400 Subject: [PATCH 04/10] [SplitLoop]: compute the split point before cloning the loop. Factor out code to update dominator tree in a member function. --- .../llvm/Transforms/Scalar/LoopOptTutorial.h | 6 ++ .../lib/Transforms/Scalar/LoopOptTutorial.cpp | 56 +++++++++++++------ 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/llvm/include/llvm/Transforms/Scalar/LoopOptTutorial.h b/llvm/include/llvm/Transforms/Scalar/LoopOptTutorial.h index 969da9512c9f5..3d3c9ce4d722f 100644 --- a/llvm/include/llvm/Transforms/Scalar/LoopOptTutorial.h +++ b/llvm/include/llvm/Transforms/Scalar/LoopOptTutorial.h @@ -61,6 +61,12 @@ class LoopSplit { /// Get the latch comparison instruction of loop \p L. ICmpInst *getLatchCmpInst(const Loop &L) const; + /// Update the dominator tree after cloning the loop. + void updateDominatorTree(const Loop &OrigLoop, const Loop &ClonedLoop, + BasicBlock &InsertBefore, + BasicBlock &Pred, + ValueToValueMapTy &VMap) const; + // Dump the LLVM IR for function \p F. void dumpFunction(const StringRef Msg, const Function &F) const; diff --git a/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp b/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp index 0d1d4537d8cb0..fc6c7b648ca9f 100644 --- a/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp +++ b/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp @@ -91,8 +91,12 @@ bool LoopSplit::splitLoopInHalf(Loop &L) const { assert(L.isSafeToClone() && "Loop is not safe to be cloned"); assert(L.getSubLoops().empty() && "Expecting a innermost loop"); - LLVM_DEBUG(dbgs() << "Splitting loop " << L.getName() << "\n"); const Function &F = *L.getHeader()->getParent(); + LLVM_DEBUG(dbgs() << "Splitting loop " << L.getName() << "\n"); + + // Generate the code that computes the split point. + Instruction *Split = + computeSplitPoint(L, L.getLoopPreheader()->getTerminator()); // Split the loop preheader to create an insertion point for the cloned loop. BasicBlock *Preheader = L.getLoopPreheader(); @@ -102,12 +106,10 @@ bool LoopSplit::splitLoopInHalf(Loop &L) const { DEBUG_WITH_TYPE(VerboseDebug, dumpFunction("After splitting preheader:\n", F);); - // Clone the original loop. + // Clone the original loop, and insert the clone before the original loop. Loop *ClonedLoop = cloneLoop(L, *InsertBefore, *Pred); // Modify the upper bound of the cloned loop. - Instruction *Split = - computeSplitPoint(L, ClonedLoop->getLoopPreheader()->getTerminator()); ICmpInst *LatchCmpInst = getLatchCmpInst(*ClonedLoop); assert(LatchCmpInst && "Unable to find the latch comparison instruction"); LatchCmpInst->setOperand(1, Split); @@ -130,15 +132,11 @@ Loop *LoopSplit::cloneLoop(Loop &L, BasicBlock &InsertBefore, SmallVector ClonedLoopBlocks; ValueToValueMapTy VMap; -#ifdef BUG // Same as cloneLoopWithPreheader but does not update the dominator tree. - // Consequently code that requires scalar evolution computation will fail. + // Use for education purposes only, use cloneLoopWithPreheader in production + // code. Loop *NewLoop = myCloneLoopWithPreheader(&InsertBefore, &Pred, &L, VMap, "", &LI, ClonedLoopBlocks); -#else - Loop *NewLoop = cloneLoopWithPreheader(&InsertBefore, &Pred, &L, VMap, - "", &LI, &DT, ClonedLoopBlocks); -#endif assert(NewLoop && "Run ot of memory"); DEBUG_WITH_TYPE(VerboseDebug, @@ -156,14 +154,15 @@ Loop *LoopSplit::cloneLoop(Loop &L, BasicBlock &InsertBefore, Pred.getTerminator()->replaceUsesOfWith(&InsertBefore, NewLoop->getLoopPreheader()); - // Update the immediate dominator for the original loop with the exiting block - // of the new loop created. Dominance within the loop is updated in - // cloneLoopWithPreheader. - DT.changeImmediateDominator(&InsertBefore, NewLoop->getExitingBlock()); - assert(DT.verify(DominatorTree::VerificationLevel::Fast) && - "Dominator tree is invalid"); + // Now that we have cloned the loop we need to update the dominator tree. + updateDominatorTree(L, *NewLoop, InsertBefore, Pred, VMap); + + // Verify that the dominator tree and the loops are correct. if (Verify) { + assert(DT.verify(DominatorTree::VerificationLevel::Fast) && + "Dominator tree is invalid"); + L.verifyLoop(); NewLoop->verifyLoop(); if (L.getParentLoop()) @@ -199,6 +198,31 @@ ICmpInst *LoopSplit::getLatchCmpInst(const Loop &L) const { return nullptr; } +void LoopSplit::updateDominatorTree(const Loop &OrigLoop, + const Loop &ClonedLoop, + BasicBlock &InsertBefore, + BasicBlock &Pred, + ValueToValueMapTy &VMap) const { + // Add the basic block that belongs to the cloned loop we have created to the + // dominator tree. + BasicBlock *NewPH = ClonedLoop.getLoopPreheader(); + assert(NewPH && "Expecting a valid preheader"); + + DT.addNewBlock(NewPH, &Pred); + for (BasicBlock *BB : ClonedLoop.getBlocks()) + DT.addNewBlock(BB, NewPH); + + // Now update the immediate dominator of the cloned loop blocks. + for (BasicBlock *BB : OrigLoop.getBlocks()) { + BasicBlock *IDomBB = DT.getNode(BB)->getIDom()->getBlock(); + DT.changeImmediateDominator(cast(VMap[BB]), + cast(VMap[IDomBB])); + } + + // The cloned loop exiting block now dominates the original loop. + DT.changeImmediateDominator(&InsertBefore, ClonedLoop.getExitingBlock()); +} + void LoopSplit::dumpFunction(const StringRef Msg, const Function &F) const { dbgs() << Msg; F.dump(); From 67a5fb6ff4779c6a0fca0f482c50980877c5ba50 Mon Sep 17 00:00:00 2001 From: Ettore Tiotto Date: Wed, 16 Oct 2019 15:09:24 -0400 Subject: [PATCH 05/10] [SplitLoop]: adjust test cases to expect the computation of the split point in the predecessor of the cloned loop. --- llvm/test/Transforms/LoopOptTutorial/loop_nest.ll | 4 ++-- llvm/test/Transforms/LoopOptTutorial/simple.ll | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/llvm/test/Transforms/LoopOptTutorial/loop_nest.ll b/llvm/test/Transforms/LoopOptTutorial/loop_nest.ll index 37c172fdbd24b..66c35321e6fd9 100644 --- a/llvm/test/Transforms/LoopOptTutorial/loop_nest.ll +++ b/llvm/test/Transforms/LoopOptTutorial/loop_nest.ll @@ -23,13 +23,13 @@ ; CHECK-NEXT: br label %[[I_HEADER:.*]] ; CHECK: [[I_HEADER:.*]]: ; CHECK-NEXT: [[I:%i[0-9]*]] = phi i64 [ 0, %entry ], [ [[INCI:%inci[0-9]*]], %[[I_LATCH:.*]] ] +; CHECK-NEXT: [[SUB:%[0-9]*]] = sub i64 100, 0 +; CHECK-NEXT: [[SPLIT:%[0-9]*]] = udiv i64 [[SUB]], 2 ; CHECK-NEXT: br label %[[L1_PREHEADER:.*]] ; First loop: ; for (long j = 0; j < 100/2; ++j) ; ... ; CHECK: [[L1_PREHEADER]]: -; CHECK-NEXT: [[SUB:%[0-9]*]] = sub i64 100, 0 -; CHECK-NEXT: [[SPLIT:%[0-9]*]] = udiv i64 [[SUB]], 2 ; CHECK-NEXT: br label %[[L1_HEADER:.*]] ; CHECK: [[L1_HEADER]]: ; CHECK-NEXT: [[L1_J:%j[0-9]*]] = phi i64 [ 0, %[[L1_PREHEADER]] ], [ [[L1_INCJ:%incj[0-9]*]], %[[L1_LATCH:.*]] ] diff --git a/llvm/test/Transforms/LoopOptTutorial/simple.ll b/llvm/test/Transforms/LoopOptTutorial/simple.ll index 64d8d7592812c..3ef1826c4c352 100644 --- a/llvm/test/Transforms/LoopOptTutorial/simple.ll +++ b/llvm/test/Transforms/LoopOptTutorial/simple.ll @@ -3,13 +3,13 @@ ; CHECK-LABEL: dep_free ; CHECK-LABEL: entry: +; CHECK-NEXT: [[SUB:%[0-9]*]] = sub i64 100, 0 +; CHECK-NEXT: [[SPLIT:%[0-9]*]] = udiv i64 [[SUB]], 2 +; CHECK-NEXT: br label %[[L1_PREHEADER:.*]] ; First loop: ; for (long i = 0; i < 100/2; ++i) ; ... -; CHECK-NEXT: br label %[[L1_PREHEADER:.*]] ; CHECK: [[L1_PREHEADER]]: -; CHECK-NEXT: [[SUB:%[0-9]*]] = sub i64 100, 0 -; CHECK-NEXT: [[SPLIT:%[0-9]*]] = udiv i64 [[SUB]], 2 ; CHECK-NEXT: br label %[[L1_HEADER:.*]] ; CHECK: [[L1_HEADER]]: ; CHECK-NEXT: [[L1_I:%i[0-9]*]] = phi i64 [ 0, %[[L1_PREHEADER]] ], [ [[L1_INCI:%inci[0-9]*]], %[[L1_LATCH:.*]] ] From 171d34218050b2fa2245b160fcf6b6b96f440b18 Mon Sep 17 00:00:00 2001 From: Kit Barton Date: Fri, 18 Oct 2019 15:33:23 -0500 Subject: [PATCH 06/10] Back port changes from Tutorial_step4_dtu into this branch to make diffs as small as possible. --- .../llvm/Transforms/Scalar/LoopOptTutorial.h | 8 +-- .../lib/Transforms/Scalar/LoopOptTutorial.cpp | 57 +++++-------------- 2 files changed, 16 insertions(+), 49 deletions(-) diff --git a/llvm/include/llvm/Transforms/Scalar/LoopOptTutorial.h b/llvm/include/llvm/Transforms/Scalar/LoopOptTutorial.h index 3d3c9ce4d722f..7480b17c625fc 100644 --- a/llvm/include/llvm/Transforms/Scalar/LoopOptTutorial.h +++ b/llvm/include/llvm/Transforms/Scalar/LoopOptTutorial.h @@ -17,9 +17,9 @@ #define LLVM_TRANSFORMS_SCALAR_LOOPOPTTUTORIAL_H #include "llvm/Analysis/LoopAnalysisManager.h" +#include "llvm/Analysis/LoopInfo.h" #include "llvm/IR/PassManager.h" #include "llvm/Transforms/Utils/ValueMapper.h" -#include "llvm/Analysis/LoopInfo.h" namespace llvm { @@ -57,20 +57,18 @@ class LoopSplit { Instruction *computeSplitPoint(const Loop &L, Instruction *InsertBefore) const; - /// Get the latch comparison instruction of loop \p L. ICmpInst *getLatchCmpInst(const Loop &L) const; /// Update the dominator tree after cloning the loop. void updateDominatorTree(const Loop &OrigLoop, const Loop &ClonedLoop, - BasicBlock &InsertBefore, - BasicBlock &Pred, + BasicBlock &InsertBefore, BasicBlock &Pred, ValueToValueMapTy &VMap) const; // Dump the LLVM IR for function \p F. void dumpFunction(const StringRef Msg, const Function &F) const; - private: +private: LoopInfo &LI; ScalarEvolution &SE; DominatorTree &DT; diff --git a/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp b/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp index fc6c7b648ca9f..767b09940da8f 100644 --- a/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp +++ b/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp @@ -28,11 +28,6 @@ using namespace llvm; #define DEBUG_TYPE "loop-opt-tutorial" static const char *VerboseDebug = DEBUG_TYPE "-verbose"; -static cl::opt - Verify(DEBUG_TYPE "-verify", cl::Hidden, - cl::desc("Turn on DominatorTree and LoopInfo verification"), - cl::init(false)); - /// Clones a loop \p OrigLoop. Returns the loop and the blocks in \p /// Blocks. /// Updates LoopInfo assuming the loop is dominated by block \p LoopDomBB. @@ -96,7 +91,7 @@ bool LoopSplit::splitLoopInHalf(Loop &L) const { // Generate the code that computes the split point. Instruction *Split = - computeSplitPoint(L, L.getLoopPreheader()->getTerminator()); + computeSplitPoint(L, L.getLoopPreheader()->getTerminator()); // Split the loop preheader to create an insertion point for the cloned loop. BasicBlock *Preheader = L.getLoopPreheader(); @@ -128,15 +123,15 @@ bool LoopSplit::splitLoopInHalf(Loop &L) const { Loop *LoopSplit::cloneLoop(Loop &L, BasicBlock &InsertBefore, BasicBlock &Pred) const { // Clone the original loop, insert the clone before the "InsertBefore" BB. - const Function &F = *L.getHeader()->getParent(); + Function &F = *L.getHeader()->getParent(); SmallVector ClonedLoopBlocks; ValueToValueMapTy VMap; // Same as cloneLoopWithPreheader but does not update the dominator tree. // Use for education purposes only, use cloneLoopWithPreheader in production // code. - Loop *NewLoop = myCloneLoopWithPreheader(&InsertBefore, &Pred, &L, VMap, - "", &LI, ClonedLoopBlocks); + Loop *NewLoop = myCloneLoopWithPreheader(&InsertBefore, &Pred, &L, VMap, "", + &LI, ClonedLoopBlocks); assert(NewLoop && "Run ot of memory"); DEBUG_WITH_TYPE(VerboseDebug, @@ -154,13 +149,12 @@ Loop *LoopSplit::cloneLoop(Loop &L, BasicBlock &InsertBefore, Pred.getTerminator()->replaceUsesOfWith(&InsertBefore, NewLoop->getLoopPreheader()); - - // Now that we have cloned the loop we need to update the dominator tree. - updateDominatorTree(L, *NewLoop, InsertBefore, Pred, VMap); + // Recompute the dominator tree + DT.recalculate(F); // Verify that the dominator tree and the loops are correct. - if (Verify) { - assert(DT.verify(DominatorTree::VerificationLevel::Fast) && +#ifndef NDEBUG + assert(DT.verify(DominatorTree::VerificationLevel::Fast) && "Dominator tree is invalid"); L.verifyLoop(); @@ -169,7 +163,7 @@ Loop *LoopSplit::cloneLoop(Loop &L, BasicBlock &InsertBefore, L.getParentLoop()->verifyLoop(); LI.verify(DT); - } +#endif return NewLoop; } @@ -181,12 +175,12 @@ Instruction *LoopSplit::computeSplitPoint(const Loop &L, Value &IVInitialVal = Bounds->getInitialIVValue(); Value &IVFinalVal = Bounds->getFinalIVValue(); - auto *Sub = - BinaryOperator::Create(Instruction::Sub, &IVFinalVal, &IVInitialVal, "", InsertBefore); + auto *Sub = BinaryOperator::Create(Instruction::Sub, &IVFinalVal, + &IVInitialVal, "", InsertBefore); return BinaryOperator::Create(Instruction::UDiv, Sub, - ConstantInt::get(IVFinalVal.getType(), 2), - "", InsertBefore); + ConstantInt::get(IVFinalVal.getType(), 2), "", + InsertBefore); } ICmpInst *LoopSplit::getLatchCmpInst(const Loop &L) const { @@ -198,31 +192,6 @@ ICmpInst *LoopSplit::getLatchCmpInst(const Loop &L) const { return nullptr; } -void LoopSplit::updateDominatorTree(const Loop &OrigLoop, - const Loop &ClonedLoop, - BasicBlock &InsertBefore, - BasicBlock &Pred, - ValueToValueMapTy &VMap) const { - // Add the basic block that belongs to the cloned loop we have created to the - // dominator tree. - BasicBlock *NewPH = ClonedLoop.getLoopPreheader(); - assert(NewPH && "Expecting a valid preheader"); - - DT.addNewBlock(NewPH, &Pred); - for (BasicBlock *BB : ClonedLoop.getBlocks()) - DT.addNewBlock(BB, NewPH); - - // Now update the immediate dominator of the cloned loop blocks. - for (BasicBlock *BB : OrigLoop.getBlocks()) { - BasicBlock *IDomBB = DT.getNode(BB)->getIDom()->getBlock(); - DT.changeImmediateDominator(cast(VMap[BB]), - cast(VMap[IDomBB])); - } - - // The cloned loop exiting block now dominates the original loop. - DT.changeImmediateDominator(&InsertBefore, ClonedLoop.getExitingBlock()); -} - void LoopSplit::dumpFunction(const StringRef Msg, const Function &F) const { dbgs() << Msg; F.dump(); From 0bad4aa1e493c1edc49416730c6682d530b1a4d3 Mon Sep 17 00:00:00 2001 From: Kit Barton Date: Fri, 18 Oct 2019 15:36:30 -0500 Subject: [PATCH 07/10] Remove recalculating the dom tree. This should be the code we want to apply for step3. --- llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp b/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp index 767b09940da8f..dc6ada20786ca 100644 --- a/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp +++ b/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp @@ -149,22 +149,6 @@ Loop *LoopSplit::cloneLoop(Loop &L, BasicBlock &InsertBefore, Pred.getTerminator()->replaceUsesOfWith(&InsertBefore, NewLoop->getLoopPreheader()); - // Recompute the dominator tree - DT.recalculate(F); - - // Verify that the dominator tree and the loops are correct. -#ifndef NDEBUG - assert(DT.verify(DominatorTree::VerificationLevel::Fast) && - "Dominator tree is invalid"); - - L.verifyLoop(); - NewLoop->verifyLoop(); - if (L.getParentLoop()) - L.getParentLoop()->verifyLoop(); - - LI.verify(DT); -#endif - return NewLoop; } From 04b9931138b665ae227fa3be60051fe028e4714c Mon Sep 17 00:00:00 2001 From: etiotto <56368199+etiotto@users.noreply.github.com> Date: Wed, 23 Oct 2019 14:42:43 -0700 Subject: [PATCH 08/10] Update LoopOptTutorial.cpp --- llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp b/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp index dc6ada20786ca..d280f219654fb 100644 --- a/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp +++ b/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp @@ -44,24 +44,20 @@ static Loop *myCloneLoopWithPreheader(BasicBlock *Before, BasicBlock *LoopDomBB, bool LoopSplit::run(Loop &L) const { LLVM_DEBUG(dbgs() << "Entering " << __func__ << "\n"); - if (!isCandidate(L)) { + if (isCandidate(L)) LLVM_DEBUG(dbgs() << "Loop " << L.getName() - << " is not a candidate for splitting.\n"); - return false; - } - - LLVM_DEBUG(dbgs() << "Loop " << L.getName() - << " is a candidate for splitting!\n"); + << " is a candidate for splitting!\n"); + else return splitLoopInHalf(L); } bool LoopSplit::isCandidate(const Loop &L) const { - // Require loops with preheaders and dedicated exits. + // Require loops with preheaders and dedicated exits if (!L.isLoopSimplifyForm()) return false; - // Since we use cloning to split the loop, it has to be safe to clone. + // Since we use cloning to split the loop, it has to be safe to clone if (!L.isSafeToClone()) return false; @@ -75,6 +71,7 @@ bool LoopSplit::isCandidate(const Loop &L) const { // Only split innermost loops. Thus, if the loop has any children, it cannot // be split. + //auto Children = L.getSubLoops(); if (!L.getSubLoops().empty()) return false; From 356bc0205bf031384cf13cf4244154644fb1a611 Mon Sep 17 00:00:00 2001 From: etiotto <56368199+etiotto@users.noreply.github.com> Date: Wed, 23 Oct 2019 14:43:36 -0700 Subject: [PATCH 09/10] Update LoopOptTutorial.cpp --- llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp b/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp index d280f219654fb..18d0b28b54e42 100644 --- a/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp +++ b/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp @@ -48,7 +48,9 @@ bool LoopSplit::run(Loop &L) const { LLVM_DEBUG(dbgs() << "Loop " << L.getName() << " is a candidate for splitting!\n"); else - + LLVM_DEBUG(dbgs() << "Loop " << L.getName() + << " is not a candidate for splitting.\n"); + return splitLoopInHalf(L); } From 38baa31aa8f2f31704ae4e34608ee7d49a312d75 Mon Sep 17 00:00:00 2001 From: etiotto <56368199+etiotto@users.noreply.github.com> Date: Wed, 23 Oct 2019 14:44:35 -0700 Subject: [PATCH 10/10] Update LoopOptTutorial.cpp --- llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp b/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp index 18d0b28b54e42..472285f46568a 100644 --- a/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp +++ b/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp @@ -50,7 +50,6 @@ bool LoopSplit::run(Loop &L) const { else LLVM_DEBUG(dbgs() << "Loop " << L.getName() << " is not a candidate for splitting.\n"); - return splitLoopInHalf(L); }