diff --git a/llvm/include/llvm/Transforms/Scalar/LoopOptTutorial.h b/llvm/include/llvm/Transforms/Scalar/LoopOptTutorial.h index 4ed633dd336ec..7480b17c625fc 100644 --- a/llvm/include/llvm/Transforms/Scalar/LoopOptTutorial.h +++ b/llvm/include/llvm/Transforms/Scalar/LoopOptTutorial.h @@ -17,6 +17,7 @@ #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" @@ -25,18 +26,52 @@ 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) {} + 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; private: - LoopInfo &LI; - /// Determines if \p L is a candidate for splitting bool isCandidate(const Loop &L) const; + /// Split the given loop in the middle by creating a new loop that traverse + /// the first half of the original iteration space and adjusting the loop + /// bounds of \p L to traverse the remaining half. + /// Note: \p L is expected to be the innermost loop in a loop nest or a top + /// level loop. + bool splitLoopInHalf(Loop &L) const; + + /// Clone loop \p L and insert the cloned loop before the basic block \p + /// InsertBefore, \p Pred is the predecessor of \p L. + /// Note: \p L is expected to be the innermost loop in a loop nest or a top + /// level loop. + Loop *cloneLoop(Loop &L, BasicBlock &InsertBefore, BasicBlock &Pred) 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; + + /// 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; + +private: + LoopInfo &LI; + ScalarEvolution &SE; + DominatorTree &DT; }; class LoopOptTutorialPass : public PassInfoMixin { diff --git a/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp b/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp index c8cf0a2c19093..472285f46568a 100644 --- a/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp +++ b/llvm/lib/Transforms/Scalar/LoopOptTutorial.cpp @@ -14,17 +14,34 @@ //===----------------------------------------------------------------------=== #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" using namespace llvm; #define DEBUG_TYPE "loop-opt-tutorial" +static const char *VerboseDebug = DEBUG_TYPE "-verbose"; -bool LoopSplit::run(Loop &L) const { +/// 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. +/// Insert the new blocks before block specified in \p Before. +static Loop *myCloneLoopWithPreheader(BasicBlock *Before, BasicBlock *LoopDomBB, + Loop *OrigLoop, ValueToValueMapTy &VMap, + const Twine &NameSuffix, LoopInfo *LI, + SmallVectorImpl &Blocks); + +//===----------------------------------------------------------------------===// +// LoopSplit implementation +// +bool LoopSplit::run(Loop &L) const { LLVM_DEBUG(dbgs() << "Entering " << __func__ << "\n"); if (isCandidate(L)) @@ -33,8 +50,7 @@ bool LoopSplit::run(Loop &L) const { else LLVM_DEBUG(dbgs() << "Loop " << L.getName() << " is not a candidate for splitting.\n"); - - return false; + return splitLoopInHalf(L); } bool LoopSplit::isCandidate(const Loop &L) const { @@ -63,17 +79,187 @@ bool LoopSplit::isCandidate(const Loop &L) const { return true; } +bool LoopSplit::splitLoopInHalf(Loop &L) const { + assert(L.isLoopSimplifyForm() && "Expecting a loop in simplify form"); + assert(L.isSafeToClone() && "Loop is not safe to be cloned"); + assert(L.getSubLoops().empty() && "Expecting a innermost loop"); + + 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(); + BasicBlock *Pred = Preheader; + BasicBlock *InsertBefore = + SplitBlock(Preheader, Preheader->getTerminator(), &DT, &LI); + DEBUG_WITH_TYPE(VerboseDebug, + dumpFunction("After splitting preheader:\n", F);); + + // 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. + 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); + + 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. + 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); + + assert(NewLoop && "Run ot of memory"); + DEBUG_WITH_TYPE(VerboseDebug, + dbgs() << "Create new loop: " << NewLoop->getName() << "\n"; + 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, + dumpFunction("After instruction remapping:\n", F);); + + // Make the predecessor of original loop jump to the cloned loop. + Pred.getTerminator()->replaceUsesOfWith(&InsertBefore, + NewLoop->getLoopPreheader()); + + 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::dumpFunction(const StringRef Msg, const Function &F) const { + dbgs() << Msg; + F.dump(); +} + +/// 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. +/// Insert the new blocks before block specified in \p Before. +static Loop *myCloneLoopWithPreheader(BasicBlock *Before, BasicBlock *LoopDomBB, + Loop *OrigLoop, ValueToValueMapTy &VMap, + const Twine &NameSuffix, LoopInfo *LI, + SmallVectorImpl &Blocks) { + Function *F = OrigLoop->getHeader()->getParent(); + Loop *ParentLoop = OrigLoop->getParentLoop(); + DenseMap LMap; + + Loop *NewLoop = LI->AllocateLoop(); + LMap[OrigLoop] = NewLoop; + if (ParentLoop) + ParentLoop->addChildLoop(NewLoop); + else + LI->addTopLevelLoop(NewLoop); + + BasicBlock *OrigPH = OrigLoop->getLoopPreheader(); + assert(OrigPH && "No preheader"); + BasicBlock *NewPH = CloneBasicBlock(OrigPH, VMap, NameSuffix, F); + // To rename the loop PHIs. + VMap[OrigPH] = NewPH; + Blocks.push_back(NewPH); + + // Update LoopInfo. + if (ParentLoop) + ParentLoop->addBasicBlockToLoop(NewPH, *LI); + + for (Loop *CurLoop : OrigLoop->getLoopsInPreorder()) { + Loop *&NewLoop = LMap[CurLoop]; + if (!NewLoop) { + NewLoop = LI->AllocateLoop(); + + // Establish the parent/child relationship. + Loop *OrigParent = CurLoop->getParentLoop(); + assert(OrigParent && "Could not find the original parent loop"); + Loop *NewParentLoop = LMap[OrigParent]; + assert(NewParentLoop && "Could not find the new parent loop"); + + NewParentLoop->addChildLoop(NewLoop); + } + } + + for (BasicBlock *BB : OrigLoop->getBlocks()) { + Loop *CurLoop = LI->getLoopFor(BB); + Loop *&NewLoop = LMap[CurLoop]; + assert(NewLoop && "Expecting new loop to be allocated"); + + BasicBlock *NewBB = CloneBasicBlock(BB, VMap, NameSuffix, F); + VMap[BB] = NewBB; + + // Update LoopInfo. + NewLoop->addBasicBlockToLoop(NewBB, *LI); + if (BB == CurLoop->getHeader()) + NewLoop->moveToHeader(NewBB); + + Blocks.push_back(NewBB); + } + + // Move them physically from the end of the block list. + F->getBasicBlockList().splice(Before->getIterator(), F->getBasicBlockList(), + NewPH); + F->getBasicBlockList().splice(Before->getIterator(), F->getBasicBlockList(), + NewLoop->getHeader()->getIterator(), F->end()); + + return NewLoop; +} + +//===----------------------------------------------------------------------===// +// LoopOptTutorialPass implementation +// + PreservedAnalyses LoopOptTutorialPass::run(Loop &L, LoopAnalysisManager &LAM, LoopStandardAnalysisResults &AR, LPMUpdater &U) { - bool Changed = false; - LLVM_DEBUG(dbgs() << "Entering LoopOptTutorialPass::run\n"); LLVM_DEBUG(dbgs() << "Loop: "; L.dump(); dbgs() << "\n"); - LoopSplit LS(AR.LI); - - Changed = LS.run(L); + bool Changed = LoopSplit(AR.LI, AR.SE, AR.DT).run(L); if (!Changed) return PreservedAnalyses::all(); diff --git a/llvm/test/Transforms/LoopOptTutorial/loop_nest.ll b/llvm/test/Transforms/LoopOptTutorial/loop_nest.ll index d42ead57741dc..66c35321e6fd9 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: [[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: 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 8e4165c46f206..3ef1826c4c352 100644 --- a/llvm/test/Transforms/LoopOptTutorial/simple.ll +++ b/llvm/test/Transforms/LoopOptTutorial/simple.ll @@ -1,61 +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: +; 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: [[L1_PREHEADER]]: +; 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 -; CHECK: Entering LoopOptTutorialPass::run define void @dep_free(i32* noalias %arg) { -bb: - br label %bb5 - -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 - -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 - -bb14: ; preds = %bb7 - %indvars.iv.next3 = add nuw nsw i64 %indvars.iv2, 1 - %tmp15 = add nuw nsw i32 %.01, 1 - br label %bb5 - -bb17: ; preds = %bb27, %bb5 - %indvars.iv = phi i64 [ %indvars.iv.next, %bb27 ], [ 0, %bb5 ] - %.0 = phi i32 [ 0, %bb5 ], [ %tmp28, %bb27 ] - %exitcond = icmp ne i64 %indvars.iv, 100 - br i1 %exitcond, label %bb19, label %bb18 - -bb18: ; preds = %bb17 - br label %bb29 - -bb19: ; preds = %bb17 - %tmp20 = add nsw i32 %.0, -3 - %tmp21 = add nuw nsw i64 %indvars.iv, 3 - %tmp22 = trunc i64 %tmp21 to i32 - %tmp23 = mul nsw i32 %tmp20, %tmp22 - %tmp24 = trunc i64 %indvars.iv to i32 - %tmp25 = srem i32 %tmp23, %tmp24 - %tmp26 = getelementptr inbounds [1024 x i32], [1024 x i32]* @B, i64 0, i64 %indvars.iv - store i32 %tmp25, i32* %tmp26, align 4 - br label %bb27 - -bb27: ; preds = %bb19 - %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 - %tmp28 = add nuw nsw i32 %.0, 1 - br label %bb17 - -bb29: ; preds = %bb18 +entry: + br label %header + +header: + %i = phi i64 [ %inci, %latch ], [ 0, %entry ] + %exitcond4 = icmp ne i64 %i, 100 + br i1 %exitcond4, label %body, label %exit + +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 + +latch: + %inci = add nuw nsw i64 %i, 1 + br label %header + +exit: ret void }