[llvm] r245025 - Add support for cross block dse.
NAKAMURA Takumi via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 14 09:39:32 PDT 2015
Seems nondeteministic behavior. Investigating.
See, http://bb.pgr.jp/builders/clang-3stage-i686-linux/builds/2935
On Fri, Aug 14, 2015 at 1:18 PM Karthik Bhat via llvm-commits <
llvm-commits at lists.llvm.org> wrote:
> Author: karthik
> Date: Thu Aug 13 23:17:23 2015
> New Revision: 245025
>
> URL: http://llvm.org/viewvc/llvm-project?rev=245025&view=rev
> Log:
> Add support for cross block dse.
> This patch enables dead stroe elimination across basicblocks.
>
> Example:
> define void @test_02(i32 %N) {
> %1 = alloca i32
> store i32 %N, i32* %1
> store i32 10, i32* @x
> %2 = load i32, i32* %1
> %3 = icmp ne i32 %2, 0
> br i1 %3, label %4, label %5
>
> ; <label>:4
> store i32 5, i32* @x
> br label %7
>
> ; <label>:5
> %6 = load i32, i32* @x
> store i32 %6, i32* @y
> br label %7
>
> ; <label>:7
> store i32 15, i32* @x
> ret void
> }
> In the above example dead store "store i32 5, i32* @x" is now eliminated.
>
> Differential Revision: http://reviews.llvm.org/D11143
>
>
> Added:
> llvm/trunk/test/Transforms/DeadStoreElimination/cross_block_dse.ll
> llvm/trunk/test/Transforms/DeadStoreElimination/cross_block_dse_loop.ll
> Modified:
> llvm/trunk/lib/Transforms/Scalar/DeadStoreElimination.cpp
>
> Modified: llvm/trunk/lib/Transforms/Scalar/DeadStoreElimination.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/DeadStoreElimination.cpp?rev=245025&r1=245024&r2=245025&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Transforms/Scalar/DeadStoreElimination.cpp (original)
> +++ llvm/trunk/lib/Transforms/Scalar/DeadStoreElimination.cpp Thu Aug 13
> 23:17:23 2015
> @@ -16,13 +16,16 @@
>
> //===----------------------------------------------------------------------===//
>
> #include "llvm/Transforms/Scalar.h"
> +#include "llvm/ADT/DenseSet.h"
> #include "llvm/ADT/STLExtras.h"
> #include "llvm/ADT/SetVector.h"
> #include "llvm/ADT/Statistic.h"
> #include "llvm/Analysis/AliasAnalysis.h"
> #include "llvm/Analysis/CaptureTracking.h"
> +#include "llvm/Analysis/CFG.h"
> #include "llvm/Analysis/MemoryBuiltins.h"
> #include "llvm/Analysis/MemoryDependenceAnalysis.h"
> +#include "llvm/Analysis/PostDominators.h"
> #include "llvm/Analysis/TargetLibraryInfo.h"
> #include "llvm/Analysis/ValueTracking.h"
> #include "llvm/IR/Constants.h"
> @@ -42,6 +45,7 @@ using namespace llvm;
>
> STATISTIC(NumRedundantStores, "Number of redundant stores deleted");
> STATISTIC(NumFastStores, "Number of stores deleted");
> +STATISTIC(NumCrossBlockStores, "Number of cross block stores deleted");
> STATISTIC(NumFastOther , "Number of other instrs removed");
>
> namespace {
> @@ -49,12 +53,41 @@ namespace {
> AliasAnalysis *AA;
> MemoryDependenceAnalysis *MD;
> DominatorTree *DT;
> + PostDominatorTree *PDT;
> const TargetLibraryInfo *TLI;
> -
> + SmallVector<SmallVector<StoreInst *, 8>, 16> Candidates;
> + SetVector<StoreInst *> DeadStores;
> + SmallVector<std::pair<const BasicBlock *, const BasicBlock *>, 32>
> + BackEdges;
> + DenseSet<std::pair<const BasicBlock *, const BasicBlock *>>
> BackEdgesMap;
> static char ID; // Pass identification, replacement for typeid
> - DSE() : FunctionPass(ID), AA(nullptr), MD(nullptr), DT(nullptr) {
> + DSE()
> + : FunctionPass(ID), AA(nullptr), MD(nullptr), DT(nullptr),
> + PDT(nullptr) {
> initializeDSEPass(*PassRegistry::getPassRegistry());
> }
> + // Return all stores in a given BasicBlock.
> + SmallVector<StoreInst *, 8> getStores(BasicBlock *BB) {
> + SmallVector<StoreInst *, 8> VecStores;
> + for (auto &BI : *BB) {
> + if (StoreInst *SI = dyn_cast<StoreInst>(&BI))
> + VecStores.push_back(SI);
> + }
> + return VecStores;
> + }
> +
> + // Get dfs in/out on the PDT and populate Candidates store list which
> + // is used to find potential dead stores for a given block
> + void populateCandidateStores(Function &F) {
> + for (auto &I : F) {
> + DomTreeNode *DTNode = PDT->getNode(&I);
> + if (!DTNode)
> + continue;
> + int DFSIn = DTNode->getDFSNumIn();
> + SmallVector<StoreInst *, 8> VecStores = getStores(&I);
> + Candidates[DFSIn] = VecStores;
> + }
> + }
>
> bool runOnFunction(Function &F) override {
> if (skipOptnoneFunction(F))
> @@ -64,7 +97,21 @@ namespace {
> MD = &getAnalysis<MemoryDependenceAnalysis>();
> DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
> TLI = &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
> -
> + PDT = &getAnalysis<PostDominatorTree>();
> + if (PDT->getRootNode()) {
> + int Count = PDT->getRootNode()->getDFSNumOut();
> + SmallVector<StoreInst *, 8> VecStores;
> + Candidates.resize(Count + 1);
> + Candidates.assign(Count + 1, VecStores);
> +
> + // If we have more than 1 block try to populate candidate store.
> + if (Count > 1) {
> + populateCandidateStores(F);
> + FindFunctionBackedges(F, BackEdges);
> + for (auto I : BackEdges)
> + BackEdgesMap.insert(I);
> + }
> + }
> bool Changed = false;
> for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I)
> // Only check non-dead blocks. Dead blocks may have strange
> pointer
> @@ -83,16 +130,23 @@ namespace {
> void RemoveAccessedObjects(const MemoryLocation &LoadedLoc,
> SmallSetVector<Value *, 16>
> &DeadStackObjects,
> const DataLayout &DL);
> -
> + void handleNonLocalStoreDeletion(StoreInst *SI);
> + bool isSafeCandidateForDeletion(BasicBlock *SrcBlock, BasicBlock
> *SinkBlock,
> + StoreInst *SI);
> + void DeleteDeadInstruction(Instruction *I, MemoryDependenceAnalysis
> &MD,
> + const TargetLibraryInfo &TLI,
> + SmallSetVector<Value *, 16> *ValueSet =
> nullptr);
> void getAnalysisUsage(AnalysisUsage &AU) const override {
> AU.setPreservesCFG();
> AU.addRequired<DominatorTreeWrapperPass>();
> AU.addRequired<AliasAnalysis>();
> AU.addRequired<MemoryDependenceAnalysis>();
> + AU.addRequired<PostDominatorTree>();
> AU.addRequired<TargetLibraryInfoWrapperPass>();
> AU.addPreserved<AliasAnalysis>();
> AU.addPreserved<DominatorTreeWrapperPass>();
> AU.addPreserved<MemoryDependenceAnalysis>();
> + AU.addPreserved<PostDominatorTree>();
> }
> };
> }
> @@ -102,6 +156,7 @@ INITIALIZE_PASS_BEGIN(DSE, "dse", "Dead
> INITIALIZE_AG_DEPENDENCY(AliasAnalysis)
> INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
> INITIALIZE_PASS_DEPENDENCY(MemoryDependenceAnalysis)
> +INITIALIZE_PASS_DEPENDENCY(PostDominatorTree)
> INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
> INITIALIZE_PASS_END(DSE, "dse", "Dead Store Elimination", false, false)
>
> @@ -111,50 +166,6 @@ FunctionPass *llvm::createDeadStoreElimi
> // Helper functions
>
> //===----------------------------------------------------------------------===//
>
> -/// DeleteDeadInstruction - Delete this instruction. Before we do, go
> through
> -/// and zero out all the operands of this instruction. If any of them
> become
> -/// dead, delete them and the computation tree that feeds them.
> -///
> -/// If ValueSet is non-null, remove any deleted instructions from it as
> well.
> -///
> -static void DeleteDeadInstruction(Instruction *I,
> - MemoryDependenceAnalysis &MD,
> - const TargetLibraryInfo &TLI,
> - SmallSetVector<Value*, 16> *ValueSet =
> nullptr) {
> - SmallVector<Instruction*, 32> NowDeadInsts;
> -
> - NowDeadInsts.push_back(I);
> - --NumFastOther;
> -
> - // Before we touch this instruction, remove it from memdep!
> - do {
> - Instruction *DeadInst = NowDeadInsts.pop_back_val();
> - ++NumFastOther;
> -
> - // This instruction is dead, zap it, in stages. Start by removing it
> from
> - // MemDep, which needs to know the operands and needs it to be in the
> - // function.
> - MD.removeInstruction(DeadInst);
> -
> - for (unsigned op = 0, e = DeadInst->getNumOperands(); op != e; ++op) {
> - Value *Op = DeadInst->getOperand(op);
> - DeadInst->setOperand(op, nullptr);
> -
> - // If this operand just became dead, add it to the NowDeadInsts
> list.
> - if (!Op->use_empty()) continue;
> -
> - if (Instruction *OpI = dyn_cast<Instruction>(Op))
> - if (isInstructionTriviallyDead(OpI, &TLI))
> - NowDeadInsts.push_back(OpI);
> - }
> -
> - DeadInst->eraseFromParent();
> -
> - if (ValueSet) ValueSet->remove(DeadInst);
> - } while (!NowDeadInsts.empty());
> -}
> -
> -
> /// hasMemoryWrite - Does this instruction write some memory? This only
> returns
> /// true for things that we can analyze with other helpers below.
> static bool hasMemoryWrite(Instruction *I, const TargetLibraryInfo &TLI) {
> @@ -527,10 +538,15 @@ bool DSE::runOnBasicBlock(BasicBlock &BB
>
> MemDepResult InstDep = MD->getDependency(Inst);
>
> - // Ignore any store where we can't find a local dependence.
> - // FIXME: cross-block DSE would be fun. :)
> - if (!InstDep.isDef() && !InstDep.isClobber())
> + if (!InstDep.isDef() && !InstDep.isClobber() && !InstDep.isNonLocal())
> continue;
> + if (InstDep.isNonLocal()) {
> + if (!PDT->getRootNode())
> + continue;
> + if (StoreInst *SI = dyn_cast<StoreInst>(Inst))
> + handleNonLocalStoreDeletion(SI);
> + continue;
> + }
>
> // Figure out what location is being stored to.
> MemoryLocation Loc = getLocForWrite(Inst, *AA);
> @@ -704,6 +720,50 @@ static void FindUnconditionalPreds(Small
> }
> }
>
> +/// DeleteDeadInstruction - Delete this instruction. Before we do, go
> through
> +/// and zero out all the operands of this instruction. If any of them
> become
> +/// dead, delete them and the computation tree that feeds them.
> +/// If ValueSet is non-null, remove any deleted instructions from it as
> well.
> +void DSE::DeleteDeadInstruction(Instruction *I, MemoryDependenceAnalysis
> &MD,
> + const TargetLibraryInfo &TLI,
> + SmallSetVector<Value *, 16> *ValueSet) {
> + SmallVector<Instruction *, 32> NowDeadInsts;
> +
> + NowDeadInsts.push_back(I);
> + --NumFastOther;
> +
> + // Before we touch this instruction, remove it from memdep!
> + do {
> + Instruction *DeadInst = NowDeadInsts.pop_back_val();
> + ++NumFastOther;
> + if (StoreInst *SI = dyn_cast<StoreInst>(DeadInst))
> + DeadStores.insert(SI);
> +
> + // This instruction is dead, zap it, in stages. Start by removing it
> from
> + // MemDep, which needs to know the operands and needs it to be in the
> + // function.
> + MD.removeInstruction(DeadInst);
> +
> + for (unsigned op = 0, e = DeadInst->getNumOperands(); op != e; ++op) {
> + Value *Op = DeadInst->getOperand(op);
> + DeadInst->setOperand(op, nullptr);
> +
> + // If this operand just became dead, add it to the NowDeadInsts
> list.
> + if (!Op->use_empty())
> + continue;
> +
> + if (Instruction *OpI = dyn_cast<Instruction>(Op))
> + if (isInstructionTriviallyDead(OpI, &TLI))
> + NowDeadInsts.push_back(OpI);
> + }
> +
> + DeadInst->eraseFromParent();
> +
> + if (ValueSet)
> + ValueSet->remove(DeadInst);
> + } while (!NowDeadInsts.empty());
> +}
> +
> /// HandleFree - Handle frees of entire structures whose dependency is a
> store
> /// to a field of that structure.
> bool DSE::HandleFree(CallInst *F) {
> @@ -931,3 +991,116 @@ void DSE::RemoveAccessedObjects(const Me
> return !AA->isNoAlias(StackLoc, LoadedLoc);
> });
> }
> +
> +/// isSafeCandidateForDeletion- Check all paths from the SrcBlock till
> +/// SinkBlock to see if Store 'SI' is safe to be remove.
> +/// Returns true if the candidate store SI is safe to delete
> +/// else returns false.
> +bool DSE::isSafeCandidateForDeletion(BasicBlock *SrcBlock,
> + BasicBlock *SinkBlock, StoreInst
> *SI) {
> + SmallVector<BasicBlock *, 16> WorkList;
> + SmallPtrSet<BasicBlock *, 8> Visited;
> + BasicBlock::iterator BBI(SI);
> +
> + // Check from the store till end of block and make sure we have no
> references
> + // to memory stored by this Store Instruction.
> + for (auto BI = ++BBI, BE = SrcBlock->end(); BI != BE; ++BI) {
> + Instruction *I = BI;
> + StoreInst *CSI = dyn_cast<StoreInst>(I);
> + if (CSI) {
> + AliasResult R =
> + AA->alias(MemoryLocation::get(SI), MemoryLocation::get(CSI));
> + if (R == MustAlias)
> + return true;
> + } else {
> + ModRefInfo Res = AA->getModRefInfo(I, MemoryLocation::get(SI));
> + if (Res != MRI_NoModRef)
> + return false;
> + }
> + }
> +
> + // Add successors of the block to stack and start DFS.
> + for (succ_iterator I = succ_begin(SrcBlock), E = succ_end(SrcBlock); I
> != E;
> + ++I) {
> + if (!Visited.insert(*I).second)
> + continue;
> + // A path with backedge may not be safe. Conservatively mark
> + // this store unsafe.
> + if (BackEdgesMap.count(std::make_pair(SrcBlock, *I)))
> + return false;
> + WorkList.push_back(*I);
> + }
> +
> + while (!WorkList.empty()) {
> + BasicBlock *B = WorkList.pop_back_val();
> + auto BI = B->begin();
> + auto BE = B->end();
> + for (; BI != BE; ++BI) {
> + Instruction *I = BI;
> + StoreInst *CSI = dyn_cast<StoreInst>(I);
> + if (CSI) {
> + AliasResult R =
> + AA->alias(MemoryLocation::get(SI), MemoryLocation::get(CSI));
> + if (R == MustAlias)
> + break;
> + } else {
> + ModRefInfo Res = AA->getModRefInfo(I, MemoryLocation::get(SI));
> + if (Res != MRI_NoModRef)
> + return false;
> + }
> + }
> +
> + // If we reached the sink node or we found a block which has a stores
> that
> + // overwrites the candidate block we need not look at their
> successors.
> + if (B == SinkBlock || BI != BE)
> + continue;
> +
> + for (succ_iterator I = succ_begin(B), E = succ_end(B); I != E; ++I) {
> + if (!Visited.insert(*I).second)
> + continue;
> + // A path with backedge may not be safe.Conservatively mark
> + // this store unsafe.
> + if (BackEdgesMap.count(std::make_pair(B, *I)))
> + return false;
> + WorkList.push_back(*I);
> + }
> + }
> +
> + return true;
> +}
> +
> +/// handleNonLocalStoreDeletion - Handle non local dead store elimination.
> +/// This works by finding candidate stores using PDT and then running DFS
> +/// from candidate store block checking all paths to make sure the store
> is
> +/// safe to delete.
> +void DSE::handleNonLocalStoreDeletion(StoreInst *SI) {
> + BasicBlock *BB = SI->getParent();
> + Value *Pointer = SI->getPointerOperand();
> + DomTreeNode *DTNode = PDT->getNode(BB);
> + if (!DTNode)
> + return;
> +
> + int DFSNumIn = DTNode->getDFSNumIn();
> + int DFSNumOut = DTNode->getDFSNumOut();
> + for (int i = DFSNumIn + 1; i < DFSNumOut; ++i) {
> + for (auto &I : Candidates[i]) {
> + StoreInst *CandidateSI = I;
> + if (DeadStores.count(CandidateSI))
> + continue;
> + Value *MemPtr = CandidateSI->getPointerOperand();
> + if (!MemPtr)
> + continue;
> + if (Pointer->getType() != MemPtr->getType())
> + continue;
> + AliasResult R =
> + AA->alias(MemoryLocation::get(SI),
> MemoryLocation::get(CandidateSI));
> + if (R != MustAlias)
> + continue;
> + if (isSafeCandidateForDeletion(CandidateSI->getParent(), BB,
> + CandidateSI)) {
> + DeleteDeadInstruction(CandidateSI, *MD, *TLI);
> + ++NumCrossBlockStores;
> + }
> + }
> + }
> +}
>
> Added: llvm/trunk/test/Transforms/DeadStoreElimination/cross_block_dse.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/DeadStoreElimination/cross_block_dse.ll?rev=245025&view=auto
>
> ==============================================================================
> --- llvm/trunk/test/Transforms/DeadStoreElimination/cross_block_dse.ll
> (added)
> +++ llvm/trunk/test/Transforms/DeadStoreElimination/cross_block_dse.ll Thu
> Aug 13 23:17:23 2015
> @@ -0,0 +1,76 @@
> +; RUN: opt < %s -basicaa -dse -S | FileCheck %s
> +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
> +
> + at x = common global i32 0
> + at y = common global i32 0
> +
> +define void @test_01(i32 %N) {
> + %1 = alloca i32
> + store i32 %N, i32* %1
> + store i32 10, i32* @x
> + %2 = load i32, i32* %1
> + %3 = icmp ne i32 %2, 0
> + br i1 %3, label %4, label %5
> +
> +; <label>:4
> + store i32 5, i32* @x
> + br label %5
> +
> +; <label>:5
> + store i32 15, i32* @x
> + ret void
> +}
> +; CHECK-LABEL: @test_01(
> +; CHECK-NOT: store i32 10, i32* @x
> +; CHECK-NOT: store i32 5, i32* @x
> +; CHECK: store i32 15, i32* @x
> +
> +
> +define void @test_02(i32 %N) {
> + %1 = alloca i32
> + store i32 %N, i32* %1
> + store i32 10, i32* @x
> + %2 = load i32, i32* %1
> + %3 = icmp ne i32 %2, 0
> + br i1 %3, label %4, label %5
> +
> +; <label>:4
> + store i32 5, i32* @x
> + br label %7
> +
> +; <label>:5
> + %6 = load i32, i32* @x
> + store i32 %6, i32* @y
> + br label %7
> +
> +; <label>:7
> + store i32 15, i32* @x
> + ret void
> +}
> +; CHECK-LABEL: @test_02(
> +; CHECK: store i32 10, i32* @x
> +; CHECK-NOT: store i32 5, i32* @x
> +; CHECK: store i32 %6, i32* @y
> +
> +
> +define void @test_03(i32 %N) #0 {
> + %1 = alloca i32
> + store i32 %N, i32* %1
> + store i32 10, i32* @x
> + %2 = load i32, i32* %1
> + %3 = icmp ne i32 %2, 0
> + br i1 %3, label %4, label %6
> +
> +; <label>:4 ; preds = %0
> + %5 = load i32, i32* @x
> + store i32 %5, i32* @y
> + br label %6
> +
> +; <label>:6 ; preds = %4, %0
> + store i32 15, i32* @x
> + ret void
> +}
> +; CHECK-LABEL: @test_03(
> +; CHECK: store i32 10, i32* @x
> +; CHECK: store i32 %5, i32* @y
> +; CHECK: store i32 15, i32* @x
>
> Added:
> llvm/trunk/test/Transforms/DeadStoreElimination/cross_block_dse_loop.ll
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/DeadStoreElimination/cross_block_dse_loop.ll?rev=245025&view=auto
>
> ==============================================================================
> ---
> llvm/trunk/test/Transforms/DeadStoreElimination/cross_block_dse_loop.ll
> (added)
> +++
> llvm/trunk/test/Transforms/DeadStoreElimination/cross_block_dse_loop.ll Thu
> Aug 13 23:17:23 2015
> @@ -0,0 +1,104 @@
> +; RUN: opt < %s -basicaa -dse -S | FileCheck %s
> +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
> +
> + at A = common global [100 x i32] zeroinitializer, align 16
> + at x = common global i32 0
> +
> +; Negative Test case-
> +;void foo(int N) {
> +; A[0] = N;
> +; for(int i=0;i<N;++i)
> +; A[i]+=i;
> +; A[0] = 10;
> +;}
> +;; Stores should not be optimized away.
> +
> +define void @test_01(i32 %N) #0 {
> + %1 = alloca i32
> + %i = alloca i32
> + store i32 %N, i32* %1
> + %2 = load i32, i32* %1
> + store i32 %2, i32* getelementptr inbounds ([100 x i32], [100 x i32]*
> @A, i32 0, i64 0)
> + store i32 0, i32* %i
> + br label %3
> +
> +; <label>:3 ; preds = %14, %0
> + %4 = load i32, i32* %i
> + %5 = load i32, i32* %1
> + %6 = icmp slt i32 %4, %5
> + br i1 %6, label %7, label %17
> +
> +; <label>:7 ; preds = %3
> + %8 = load i32, i32* %i
> + %9 = load i32, i32* %i
> + %10 = sext i32 %9 to i64
> + %11 = getelementptr inbounds [100 x i32], [100 x i32]* @A, i32 0, i64
> %10
> + %12 = load i32, i32* %11
> + %13 = add nsw i32 %12, %8
> + store i32 %13, i32* %11
> + br label %14
> +
> +; <label>:14 ; preds = %7
> + %15 = load i32, i32* %i
> + %16 = add nsw i32 %15, 1
> + store i32 %16, i32* %i
> + br label %3
> +
> +; <label>:17 ; preds = %3
> + store i32 10, i32* getelementptr inbounds ([100 x i32], [100 x i32]*
> @A, i32 0, i64 0)
> + ret void
> +}
> +; CHECK-LABEL: @test_01(
> +; CHECK: store i32 %2, i32* getelementptr inbounds ([100 x i32], [100 x
> i32]* @A, i32 0, i64 0)
> +; CHECK: store i32 %13, i32* %11
> +; CHECK: store i32 10, i32* getelementptr inbounds ([100 x i32], [100 x
> i32]* @A, i32 0, i64 0)
> +
> +
> +; Postive Test case-
> +;void foo(int N) {
> +; A[0] = N;
> +; for(int i=0;i<N;++i)
> +; A[i]=i;
> +; A[0] = 10;
> +;}
> +;; Stores should not be optimized away.
> +define void @test_02(i32 %N) #0 {
> + %1 = alloca i32
> + %i = alloca i32
> + store i32 %N, i32* %1
> + %2 = load i32, i32* %1
> + store i32 %2, i32* getelementptr inbounds ([100 x i32], [100 x i32]*
> @A, i32 0, i64 0)
> + store i32 0, i32* %i
> + br label %3
> +
> +; <label>:3 ; preds = %12, %0
> + %4 = load i32, i32* %i
> + %5 = load i32, i32* %1
> + %6 = icmp slt i32 %4, %5
> + br i1 %6, label %7, label %15
> +
> +; <label>:7 ; preds = %3
> + %8 = load i32, i32* %i
> + %9 = load i32, i32* %i
> + %10 = sext i32 %9 to i64
> + %11 = getelementptr inbounds [100 x i32], [100 x i32]* @A, i32 0, i64
> %10
> + store i32 %8, i32* %11
> + br label %12
> +
> +; <label>:12 ; preds = %7
> + %13 = load i32, i32* %i
> + %14 = add nsw i32 %13, 1
> + store i32 %14, i32* %i
> + br label %3
> +
> +; <label>:15 ; preds = %3
> + store i32 10, i32* getelementptr inbounds ([100 x i32], [100 x i32]*
> @A, i32 0, i64 0)
> + ret void
> +}
> +
> +; CHECK-LABEL: @test_02(
> +; CHECK-NOT: store i32 %2, i32* getelementptr inbounds ([100 x i32], [100
> x i32]* @A, i32 0, i64 0)
> +; CHECK: store i32 %7, i32* %10
> +; CHECK: store i32 10, i32* getelementptr inbounds ([100 x i32], [100 x
> i32]* @A, i32 0, i64 0)
> +
> +
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20150814/5194fdbe/attachment.html>
More information about the llvm-commits
mailing list