diff --git a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp index 7b42559ddebe..a44e798f121b 100644 --- a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp +++ b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp @@ -16,7 +16,7 @@ // TODO List: // // Future loop memory idioms to recognize: -// memcmp, strlen, etc. +// memcmp, memmove, strlen, etc. // Future floating point idioms to recognize in -ffast-math mode: // fpowi // Future integer operation idioms to recognize: @@ -48,7 +48,6 @@ #include "llvm/Module.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/AliasAnalysis.h" -#include "llvm/Analysis/DependenceAnalysis.h" #include "llvm/Analysis/LoopPass.h" #include "llvm/Analysis/ScalarEvolutionExpander.h" #include "llvm/Analysis/ScalarEvolutionExpressions.h" @@ -60,9 +59,8 @@ #include "llvm/Transforms/Utils/Local.h" using namespace llvm; -STATISTIC(NumMemSet, "Number of memsets formed from loop stores"); -STATISTIC(NumMemCpy, "Number of memcpys formed from loop load+stores"); -STATISTIC(NumMemMove, "Number of memmoves formed from loop load+stores"); +STATISTIC(NumMemSet, "Number of memset's formed from loop stores"); +STATISTIC(NumMemCpy, "Number of memcpy's formed from loop load+stores"); namespace { class LoopIdiomRecognize : public LoopPass { @@ -108,8 +106,6 @@ namespace { AU.addPreserved(); AU.addRequired(); AU.addPreserved(); - AU.addRequired(); - AU.addPreserved(); AU.addPreserved(); AU.addRequired(); AU.addRequired(); @@ -126,7 +122,6 @@ INITIALIZE_PASS_DEPENDENCY(LoopSimplify) INITIALIZE_PASS_DEPENDENCY(LCSSA) INITIALIZE_PASS_DEPENDENCY(ScalarEvolution) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfo) -INITIALIZE_PASS_DEPENDENCY(DependenceAnalysis) INITIALIZE_AG_DEPENDENCY(AliasAnalysis) INITIALIZE_PASS_END(LoopIdiomRecognize, "loop-idiom", "Recognize loop idioms", false, false) @@ -168,6 +163,15 @@ static void deleteDeadInstruction(Instruction *I, ScalarEvolution &SE, } while (!NowDeadInsts.empty()); } +/// deleteIfDeadInstruction - If the specified value is a dead instruction, +/// delete it and any recursively used instructions. +static void deleteIfDeadInstruction(Value *V, ScalarEvolution &SE, + const TargetLibraryInfo *TLI) { + if (Instruction *I = dyn_cast(V)) + if (isInstructionTriviallyDead(I, TLI)) + deleteDeadInstruction(I, SE, TLI); +} + bool LoopIdiomRecognize::runOnLoop(Loop *L, LPPassManager &LPM) { CurLoop = L; @@ -178,7 +182,7 @@ bool LoopIdiomRecognize::runOnLoop(Loop *L, LPPassManager &LPM) { // Disable loop idiom recognition if the function's name is a common idiom. StringRef Name = L->getHeader()->getParent()->getName(); - if (Name == "memset" || Name == "memcpy" || Name == "memmove") + if (Name == "memset" || Name == "memcpy") return false; // The trip count of the loop must be analyzable. @@ -364,6 +368,40 @@ processLoopMemSet(MemSetInst *MSI, const SCEV *BECount) { MSI, Ev, BECount); } + +/// mayLoopAccessLocation - Return true if the specified loop might access the +/// specified pointer location, which is a loop-strided access. The 'Access' +/// argument specifies what the verboten forms of access are (read or write). +static bool mayLoopAccessLocation(Value *Ptr,AliasAnalysis::ModRefResult Access, + Loop *L, const SCEV *BECount, + unsigned StoreSize, AliasAnalysis &AA, + Instruction *IgnoredStore) { + // Get the location that may be stored across the loop. Since the access is + // strided positively through memory, we say that the modified location starts + // at the pointer and has infinite size. + uint64_t AccessSize = AliasAnalysis::UnknownSize; + + // If the loop iterates a fixed number of times, we can refine the access size + // to be exactly the size of the memset, which is (BECount+1)*StoreSize + if (const SCEVConstant *BECst = dyn_cast(BECount)) + AccessSize = (BECst->getValue()->getZExtValue()+1)*StoreSize; + + // TODO: For this to be really effective, we have to dive into the pointer + // operand in the store. Store to &A[i] of 100 will always return may alias + // with store of &A[100], we need to StoreLoc to be "A" with size of 100, + // which will then no-alias a store to &A[100]. + AliasAnalysis::Location StoreLoc(Ptr, AccessSize); + + for (Loop::block_iterator BI = L->block_begin(), E = L->block_end(); BI != E; + ++BI) + for (BasicBlock::iterator I = (*BI)->begin(), E = (*BI)->end(); I != E; ++I) + if (&*I != IgnoredStore && + (AA.getModRefInfo(I, StoreLoc) & Access)) + return true; + + return false; +} + /// getMemSetPatternValue - If a strided store of the specified value is safe to /// turn into a memset_pattern16, return a ConstantArray of 16 bytes that should /// be passed in. Otherwise, return null. @@ -436,18 +474,6 @@ processLoopStridedStore(Value *DestPtr, unsigned StoreSize, return false; } - // Make sure the store has no dependencies (i.e. other loads and stores) in - // the loop. - DependenceAnalysis &DA = getAnalysis(); - for (Loop::block_iterator BI = CurLoop->block_begin(), - BE = CurLoop->block_end(); BI != BE; ++BI) - for (BasicBlock::iterator I = (*BI)->begin(), E = (*BI)->end(); I != E; ++I) - if (&*I != TheStore && I->mayReadOrWriteMemory()) { - OwningPtr D(DA.depends(TheStore, I, true)); - if (D) - return false; - } - // The trip count of the loop and the base pointer of the addrec SCEV is // guaranteed to be loop invariant, which means that it should dominate the // header. This allows us to insert code for it in the preheader. @@ -466,6 +492,15 @@ processLoopStridedStore(Value *DestPtr, unsigned StoreSize, Preheader->getTerminator()); + if (mayLoopAccessLocation(BasePtr, AliasAnalysis::ModRef, + CurLoop, BECount, + StoreSize, getAnalysis(), TheStore)){ + Expander.clear(); + // If we generated new code for the base pointer, clean up. + deleteIfDeadInstruction(BasePtr, *SE, TLI); + return false; + } + // Okay, everything looks good, insert the memset. // The # stored bytes is (BECount+1)*Size. Expand the trip count out to @@ -523,46 +558,11 @@ processLoopStoreOfLoopLoad(StoreInst *SI, unsigned StoreSize, const SCEVAddRecExpr *LoadEv, const SCEV *BECount) { // If we're not allowed to form memcpy, we fail. - if (!TLI->has(LibFunc::memcpy) || !TLI->has(LibFunc::memmove)) + if (!TLI->has(LibFunc::memcpy)) return false; LoadInst *LI = cast(SI->getValueOperand()); - // Make sure the load and the store have no dependencies (i.e. other loads and - // stores) in the loop. We ignore the direct dependency between SI and LI here - // and check it later. - DependenceAnalysis &DA = getAnalysis(); - bool isMemcpySafe = true; - for (Loop::block_iterator BI = CurLoop->block_begin(), - BE = CurLoop->block_end(); BI != BE; ++BI) - for (BasicBlock::iterator I = (*BI)->begin(), E = (*BI)->end(); I != E; ++I) - if (&*I != SI && &*I != LI && I->mayReadOrWriteMemory()) { - // First, check if there is a dependence of the store. - OwningPtr DS(DA.depends(SI, I, true)); - if (DS) - return false; - // If the scanned instructon may modify memory then we also have to - // check for dependencys on the load. - if (I->mayWriteToMemory()) { - OwningPtr DL(DA.depends(I, LI, true)); - if (DL) - return false; - } - } - - // Now check the dependency between SI and LI. If there is no dependency we - // can safely emit a memcpy. - OwningPtr Dep(DA.depends(SI, LI, true)); - if (Dep) { - // If there is a dependence but the direction is positive (or none) we can - // still safely turn this into memmove. - unsigned Direction = Dep->getDirection(Dep->getLevels()); - if (Direction != Dependence::DVEntry::NONE && - Direction != Dependence::DVEntry::GT) - return false; - isMemcpySafe = false; - } - // The trip count of the loop and the base pointer of the addrec SCEV is // guaranteed to be loop invariant, which means that it should dominate the // header. This allows us to insert code for it in the preheader. @@ -571,16 +571,41 @@ processLoopStoreOfLoopLoad(StoreInst *SI, unsigned StoreSize, SCEVExpander Expander(*SE, "loop-idiom"); // Okay, we have a strided store "p[i]" of a loaded value. We can turn - // this into a memcpy in the loop preheader now if we want. + // this into a memcpy in the loop preheader now if we want. However, this + // would be unsafe to do if there is anything else in the loop that may read + // or write the memory region we're storing to. This includes the load that + // feeds the stores. Check for an alias by generating the base address and + // checking everything. Value *StoreBasePtr = Expander.expandCodeFor(StoreEv->getStart(), Builder.getInt8PtrTy(SI->getPointerAddressSpace()), Preheader->getTerminator()); + + if (mayLoopAccessLocation(StoreBasePtr, AliasAnalysis::ModRef, + CurLoop, BECount, StoreSize, + getAnalysis(), SI)) { + Expander.clear(); + // If we generated new code for the base pointer, clean up. + deleteIfDeadInstruction(StoreBasePtr, *SE, TLI); + return false; + } + + // For a memcpy, we have to make sure that the input array is not being + // mutated by the loop. Value *LoadBasePtr = Expander.expandCodeFor(LoadEv->getStart(), Builder.getInt8PtrTy(LI->getPointerAddressSpace()), Preheader->getTerminator()); + if (mayLoopAccessLocation(LoadBasePtr, AliasAnalysis::Mod, CurLoop, BECount, + StoreSize, getAnalysis(), SI)) { + Expander.clear(); + // If we generated new code for the base pointer, clean up. + deleteIfDeadInstruction(LoadBasePtr, *SE, TLI); + deleteIfDeadInstruction(StoreBasePtr, *SE, TLI); + return false; + } + // Okay, everything is safe, we can transform this! @@ -598,19 +623,12 @@ processLoopStoreOfLoopLoad(StoreInst *SI, unsigned StoreSize, Value *NumBytes = Expander.expandCodeFor(NumBytesS, IntPtr, Preheader->getTerminator()); - CallInst *NewCall; - unsigned Align = std::min(SI->getAlignment(), LI->getAlignment()); - if (isMemcpySafe) { - NewCall = Builder.CreateMemCpy(StoreBasePtr, LoadBasePtr, NumBytes, Align); - ++NumMemCpy; - } else { - NewCall = Builder.CreateMemMove(StoreBasePtr, LoadBasePtr, NumBytes, Align); - ++NumMemMove; - } + CallInst *NewCall = + Builder.CreateMemCpy(StoreBasePtr, LoadBasePtr, NumBytes, + std::min(SI->getAlignment(), LI->getAlignment())); NewCall->setDebugLoc(SI->getDebugLoc()); - DEBUG(dbgs() << " Formed " << (isMemcpySafe ? "memcpy: " : "memmove: ") - << *NewCall << "\n" + DEBUG(dbgs() << " Formed memcpy: " << *NewCall << "\n" << " from load ptr=" << *LoadEv << " at: " << *LI << "\n" << " from store ptr=" << *StoreEv << " at: " << *SI << "\n"); @@ -618,5 +636,6 @@ processLoopStoreOfLoopLoad(StoreInst *SI, unsigned StoreSize, // Okay, the memset has been formed. Zap the original store and anything that // feeds into it. deleteDeadInstruction(SI, *SE, TLI); + ++NumMemCpy; return true; } diff --git a/llvm/test/Transforms/LoopIdiom/basic.ll b/llvm/test/Transforms/LoopIdiom/basic.ll index 5afc405fa6be..46ab7e5542b6 100644 --- a/llvm/test/Transforms/LoopIdiom/basic.ll +++ b/llvm/test/Transforms/LoopIdiom/basic.ll @@ -383,26 +383,4 @@ for.end: ; preds = %for.inc } -@p = common global [1024 x i8] zeroinitializer, align 16 -define void @test15(i32 %n) nounwind { -entry: - %cmp6 = icmp eq i32 %n, 0 - br i1 %cmp6, label %for.end, label %for.body - -for.body: ; preds = %entry, %for.body - %indvars.iv = phi i64 [ %indvars.iv.next, %for.body ], [ 0, %entry ] - %indvars.iv.next = add i64 %indvars.iv, 1 - %arrayidx = getelementptr inbounds [1024 x i8]* @p, i64 0, i64 %indvars.iv.next - %0 = load i8* %arrayidx, align 1 - %arrayidx2 = getelementptr inbounds [1024 x i8]* @p, i64 0, i64 %indvars.iv - store i8 %0, i8* %arrayidx2, align 1 - %lftr.wideiv = trunc i64 %indvars.iv.next to i32 - %exitcond = icmp eq i32 %lftr.wideiv, %n - br i1 %exitcond, label %for.end, label %for.body - -for.end: ; preds = %for.body, %entry - ret void -; CHECK: @test15 -; CHECK: call void @llvm.memmove.p0i8.p0i8.i64(i8* getelementptr inbounds ([1024 x i8]* @p, i32 0, i32 0), i8* getelementptr inbounds ([1024 x i8]* @p, i64 0, i64 1), -} diff --git a/llvm/test/Transforms/LoopIdiom/memmove.ll b/llvm/test/Transforms/LoopIdiom/memmove.ll deleted file mode 100644 index bfa0902a0d2b..000000000000 --- a/llvm/test/Transforms/LoopIdiom/memmove.ll +++ /dev/null @@ -1,42 +0,0 @@ -; RUN: opt -S -basicaa -loop-idiom < %s | FileCheck %s -target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" -target triple = "x86_64-apple-macosx10.8.0" - -declare i64 @foo() nounwind - -; Nested loops -define void @test1(i8* nocapture %A, i64 %n) nounwind { -entry: - %call8 = tail call i64 @foo() nounwind - %tobool9 = icmp eq i64 %call8, 0 - br i1 %tobool9, label %while.end, label %for.cond.preheader.lr.ph - -for.cond.preheader.lr.ph: ; preds = %entry - %cmp6 = icmp eq i64 %n, 0 - br label %for.cond.preheader - -while.cond.loopexit: ; preds = %for.body, %for.cond.preheader - %call = tail call i64 @foo() nounwind - %tobool = icmp eq i64 %call, 0 - br i1 %tobool, label %while.end, label %for.cond.preheader - -for.cond.preheader: ; preds = %for.cond.preheader.lr.ph, %while.cond.loopexit - br i1 %cmp6, label %while.cond.loopexit, label %for.body - -for.body: ; preds = %for.cond.preheader, %for.body - %i.07 = phi i64 [ %inc, %for.body ], [ 0, %for.cond.preheader ] - %add = add i64 %i.07, 10 - %arrayidx = getelementptr inbounds i8* %A, i64 %add - %0 = load i8* %arrayidx, align 1 - %arrayidx1 = getelementptr inbounds i8* %A, i64 %i.07 - store i8 %0, i8* %arrayidx1, align 1 - %inc = add i64 %i.07, 1 - %exitcond = icmp eq i64 %inc, %n - br i1 %exitcond, label %while.cond.loopexit, label %for.body - -while.end: ; preds = %while.cond.loopexit, %entry - ret void - -; CHECK: @test1 -; CHECK: call void @llvm.memmove.p0i8.p0i8.i64( -} diff --git a/llvm/test/Transforms/LoopIdiom/memset_noidiom.ll b/llvm/test/Transforms/LoopIdiom/memset_noidiom.ll index 27ef4f639c7b..168eb95357c4 100644 --- a/llvm/test/Transforms/LoopIdiom/memset_noidiom.ll +++ b/llvm/test/Transforms/LoopIdiom/memset_noidiom.ll @@ -1,4 +1,4 @@ -; RUN: opt -basicaa -loop-idiom < %s -S | FileCheck %s +; RUN: opt -loop-idiom < %s -S | FileCheck %s target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" target triple = "x86_64-apple-darwin10.0.0" @@ -28,54 +28,3 @@ for.end: ; preds = %for.cond.for.end_cr ret i8* %b } -; CHECK: @memcpy -; CHECK-NOT: llvm.memcpy -define i8* @memcpy(i8* noalias %dst, i8* noalias %src, i64 %n) nounwind { -entry: - %tobool3 = icmp eq i64 %n, 0 - br i1 %tobool3, label %while.end, label %while.body - -while.body: ; preds = %entry, %while.body - %c2.06 = phi i8* [ %incdec.ptr, %while.body ], [ %src, %entry ] - %c1.05 = phi i8* [ %incdec.ptr1, %while.body ], [ %dst, %entry ] - %n.addr.04 = phi i64 [ %dec, %while.body ], [ %n, %entry ] - %dec = add i64 %n.addr.04, -1 - %incdec.ptr = getelementptr inbounds i8* %c2.06, i64 1 - %0 = load i8* %c2.06, align 1 - %incdec.ptr1 = getelementptr inbounds i8* %c1.05, i64 1 - store i8 %0, i8* %c1.05, align 1 - %tobool = icmp eq i64 %dec, 0 - br i1 %tobool, label %while.end, label %while.body - -while.end: ; preds = %while.body, %entry - ret i8* %dst -} - -; CHECK: @memmove -; CHECK-NOT: llvm.memmove -define i8* @memmove(i8* %dst, i8* nocapture %src, i64 %count) nounwind { -entry: - %sub = add i64 %count, -1 - %tobool9 = icmp eq i64 %count, 0 - br i1 %tobool9, label %while.end, label %while.body.lr.ph - -while.body.lr.ph: ; preds = %entry - %add.ptr2 = getelementptr inbounds i8* %src, i64 %sub - %add.ptr = getelementptr inbounds i8* %dst, i64 %sub - br label %while.body - -while.body: ; preds = %while.body.lr.ph, %while.body - %b.012 = phi i8* [ %add.ptr2, %while.body.lr.ph ], [ %incdec.ptr, %while.body ] - %a.011 = phi i8* [ %add.ptr, %while.body.lr.ph ], [ %incdec.ptr3, %while.body ] - %count.addr.010 = phi i64 [ %count, %while.body.lr.ph ], [ %dec, %while.body ] - %dec = add i64 %count.addr.010, -1 - %incdec.ptr = getelementptr inbounds i8* %b.012, i64 -1 - %0 = load i8* %b.012, align 1 - %incdec.ptr3 = getelementptr inbounds i8* %a.011, i64 -1 - store i8 %0, i8* %a.011, align 1 - %tobool = icmp eq i64 %dec, 0 - br i1 %tobool, label %while.end, label %while.body - -while.end: ; preds = %while.body, %entry - ret i8* %dst -} diff --git a/llvm/test/Transforms/LoopIdiom/multi-dimensional.ll b/llvm/test/Transforms/LoopIdiom/multi-dimensional.ll deleted file mode 100644 index 991f2688d765..000000000000 --- a/llvm/test/Transforms/LoopIdiom/multi-dimensional.ll +++ /dev/null @@ -1,49 +0,0 @@ -; RUN: opt -basicaa -loop-idiom < %s -S | FileCheck %s -target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" -target triple = "x86_64-apple-darwin10.0.0" - -%struct.ham = type { [2 x [2 x [2 x [16 x [8 x i32]]]]], i32, %struct.zot } -%struct.zot = type { i32, i16, i16, [2 x [1152 x i32]] } - -define void @test1(%struct.ham* nocapture %arg) nounwind { -bb: - br label %bb1 - -bb1: ; preds = %bb11, %bb - %tmp = phi i64 [ 0, %bb ], [ %tmp12, %bb11 ] - br label %bb2 - -bb2: ; preds = %bb2, %bb1 - %tmp3 = phi i64 [ 0, %bb1 ], [ %tmp8, %bb2 ] - %tmp4 = getelementptr inbounds %struct.ham* %arg, i64 0, i32 0, i64 0, i64 1, i64 1, i64 %tmp, i64 %tmp3 - store i32 0, i32* %tmp4, align 4 - %tmp5 = getelementptr inbounds %struct.ham* %arg, i64 0, i32 0, i64 0, i64 1, i64 0, i64 %tmp, i64 %tmp3 - store i32 0, i32* %tmp5, align 4 - %tmp6 = getelementptr inbounds %struct.ham* %arg, i64 0, i32 0, i64 0, i64 0, i64 1, i64 %tmp, i64 %tmp3 - store i32 0, i32* %tmp6, align 4 - %tmp7 = getelementptr inbounds %struct.ham* %arg, i64 0, i32 0, i64 0, i64 0, i64 0, i64 %tmp, i64 %tmp3 - store i32 0, i32* %tmp7, align 4 - %tmp8 = add i64 %tmp3, 1 - %tmp9 = trunc i64 %tmp8 to i32 - %tmp10 = icmp eq i32 %tmp9, 8 - br i1 %tmp10, label %bb11, label %bb2 - -bb11: ; preds = %bb2 - %tmp12 = add i64 %tmp, 1 - %tmp13 = trunc i64 %tmp12 to i32 - %tmp14 = icmp eq i32 %tmp13, 16 - br i1 %tmp14, label %bb15, label %bb1 - -bb15: ; preds = %bb11 - ret void - -; CHECK: @test1 -; CHECK: bb1: -; CHECK-NOT: store -; CHECK: call void @llvm.memset.p0i8.i64 -; CHECK-NEXT: call void @llvm.memset.p0i8.i64 -; CHECK-NEXT: call void @llvm.memset.p0i8.i64 -; CHECK-NEXT: call void @llvm.memset.p0i8.i64 -; CHECK-NOT: store -; CHECK: br -} diff --git a/llvm/test/Transforms/LoopIdiom/sideeffect.ll b/llvm/test/Transforms/LoopIdiom/sideeffect.ll deleted file mode 100644 index 460e5233f958..000000000000 --- a/llvm/test/Transforms/LoopIdiom/sideeffect.ll +++ /dev/null @@ -1,53 +0,0 @@ -; RUN: opt -basicaa -loop-idiom < %s -S | FileCheck %s -target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" -target triple = "x86_64-apple-darwin10.0.0" - -; PR9481 -define i32 @test1() nounwind uwtable ssp { -entry: - %a = alloca [10 x i8], align 1 - br label %for.body - -for.cond1.preheader: ; preds = %for.body - %arrayidx5.phi.trans.insert = getelementptr inbounds [10 x i8]* %a, i64 0, i64 0 - %.pre = load i8* %arrayidx5.phi.trans.insert, align 1 - br label %for.body3 - -for.body: ; preds = %for.body, %entry - %indvars.iv29 = phi i64 [ 0, %entry ], [ %indvars.iv.next30, %for.body ] - call void (...)* @bar() nounwind - %arrayidx = getelementptr inbounds [10 x i8]* %a, i64 0, i64 %indvars.iv29 - store i8 23, i8* %arrayidx, align 1 - %indvars.iv.next30 = add i64 %indvars.iv29, 1 - %lftr.wideiv31 = trunc i64 %indvars.iv.next30 to i32 - %exitcond32 = icmp eq i32 %lftr.wideiv31, 1000000 - br i1 %exitcond32, label %for.cond1.preheader, label %for.body - -for.body3: ; preds = %for.body3, %for.cond1.preheader - %0 = phi i8 [ %.pre, %for.cond1.preheader ], [ %add, %for.body3 ] - %indvars.iv = phi i64 [ 1, %for.cond1.preheader ], [ %indvars.iv.next, %for.body3 ] - call void (...)* @bar() nounwind - %arrayidx7 = getelementptr inbounds [10 x i8]* %a, i64 0, i64 %indvars.iv - %1 = load i8* %arrayidx7, align 1 - %add = add i8 %1, %0 - store i8 %add, i8* %arrayidx7, align 1 - %indvars.iv.next = add i64 %indvars.iv, 1 - %lftr.wideiv = trunc i64 %indvars.iv.next to i32 - %exitcond = icmp eq i32 %lftr.wideiv, 1000000 - br i1 %exitcond, label %for.end12, label %for.body3 - -for.end12: ; preds = %for.body3 - %arrayidx13 = getelementptr inbounds [10 x i8]* %a, i64 0, i64 2 - %2 = load i8* %arrayidx13, align 1 - %conv14 = sext i8 %2 to i32 - %arrayidx15 = getelementptr inbounds [10 x i8]* %a, i64 0, i64 6 - %3 = load i8* %arrayidx15, align 1 - %conv16 = sext i8 %3 to i32 - %add17 = add nsw i32 %conv16, %conv14 - ret i32 %add17 - -; CHECK: @test1 -; CHECK-NOT: @llvm.memset -} - -declare void @bar(...)