[llvm] r245195 - Fix PR24469 resulting from r245025 and re-enable dead store elimination across basicblocks.
KARTHIK VENKATESH BHAT via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 17 04:02:28 PDT 2015
Hi Nakamura,
Thanks for the link. I'm a bit new to this can you please let me know if my understanding of nondeterministic behavior is correct here.
So build seems to be successful. The warning in stage1_build_clang seems to be from other files. So I assume we are talking about "compare_23" in the link?
From what I could understand we are building llvm with clang and comparing the .o files generated and checking if there is a difference with and without the current change list. Is my understanding correct?
If that is true the current patch can remove few dead stores if any and create difference in .o files generated.
Please if you could guide me if my understanding is correct I can investigate more to see if there is actually a problem.
Thanks and Regards
Karthik Bhat
------- Original Message -------
Sender : NAKAMURA Takumi<geek4civic at gmail.com>
Date : Aug 17, 2015 18:53 (GMT+09:00)
Title : Re: [llvm] r245195 - Fix PR24469 resulting from r245025 and re-enable dead store elimination across basicblocks.
Seems it has nondeterministic behavior. See;
http://bb.pgr.jp/builders/clang-3stage-i686-linux/builds/2960
2015-08-17 14:51 GMT+09:00 Karthik Bhat via llvm-commits
:
> Author: karthik
> Date: Mon Aug 17 00:51:39 2015
> New Revision: 245195
>
> URL: http://llvm.org/viewvc/llvm-project?rev=245195&view=rev
> Log:
> Fix PR24469 resulting from r245025 and re-enable dead store elimination across basicblocks.
> PR24469 resulted because DeleteDeadInstruction in handleNonLocalStoreDeletion was
> deleting the next basic block iterator. Fixed the same by resetting the basic block iterator
> post call to DeleteDeadInstruction.
>
>
> 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=245195&r1=245194&r2=245195&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/Scalar/DeadStoreElimination.cpp (original)
> +++ llvm/trunk/lib/Transforms/Scalar/DeadStoreElimination.cpp Mon Aug 17 00:51:39 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, 16> Candidates;
> + SetVector DeadStores;
> + SmallVector, 32>
> + BackEdges;
> + DenseSet> 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 getStores(BasicBlock *BB) {
> + SmallVector VecStores;
> + for (auto &BI : *BB) {
> + if (StoreInst *SI = dyn_cast(&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 VecStores = getStores(&I);
> + Candidates[DFSIn] = VecStores;
> + }
> + }
>
> bool runOnFunction(Function &F) override {
> if (skipOptnoneFunction(F))
> @@ -64,7 +97,21 @@ namespace {
> MD = &getAnalysis();
> DT = &getAnalysis().getDomTree();
> TLI = &getAnalysis().getTLI();
> -
> + PDT = &getAnalysis();
> + if (PDT->getRootNode()) {
> + int Count = PDT->getRootNode()->getDFSNumOut();
> + SmallVector 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,24 @@ namespace {
> void RemoveAccessedObjects(const MemoryLocation &LoadedLoc,
> SmallSetVector &DeadStackObjects,
> const DataLayout &DL);
> -
> + void handleNonLocalStoreDeletion(StoreInst *SI, BasicBlock::iterator &BBI,
> + BasicBlock &CurBlock);
> + bool isSafeCandidateForDeletion(BasicBlock *SrcBlock, BasicBlock *SinkBlock,
> + StoreInst *SI);
> + void DeleteDeadInstruction(Instruction *I, MemoryDependenceAnalysis &MD,
> + const TargetLibraryInfo &TLI,
> + SmallSetVector *ValueSet = nullptr);
> void getAnalysisUsage(AnalysisUsage &AU) const override {
> AU.setPreservesCFG();
> AU.addRequired();
> AU.addRequired();
> AU.addRequired();
> + AU.addRequired();
> AU.addRequired();
> AU.addPreserved();
> AU.addPreserved();
> AU.addPreserved();
> + AU.addPreserved();
> }
> };
> }
> @@ -102,6 +157,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 +167,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 *ValueSet = nullptr) {
> - SmallVector 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(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 +539,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(Inst))
> + handleNonLocalStoreDeletion(SI, BBI, BB);
> + continue;
> + }
>
> // Figure out what location is being stored to.
> MemoryLocation Loc = getLocForWrite(Inst, *AA);
> @@ -704,6 +721,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 *ValueSet) {
> + SmallVector 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(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(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 +992,122 @@ 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 WorkList;
> + SmallPtrSet 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(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(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::iterator &BBI,
> + BasicBlock &CurBlock) {
> + 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;
> + // DeleteDeadInstruction can delete the current instruction in loop
> + // cases, reset BBI.
> + BBI = SI;
> + if (BBI != CurBlock.begin())
> + --BBI;
> + }
> + }
> + }
> +}
>
> 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=245195&view=auto
> ==============================================================================
> --- llvm/trunk/test/Transforms/DeadStoreElimination/cross_block_dse.ll (added)
> +++ llvm/trunk/test/Transforms/DeadStoreElimination/cross_block_dse.ll Mon Aug 17 00:51:39 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 x = common global i32 0
> + at y = common global i32 0
> + at a = external global i32
> + at b = external global i32
> +
> +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
> +
> +; :4
> + store i32 5, i32* @x
> + br label %5
> +
> +; :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
> +
> +; :4
> + store i32 5, i32* @x
> + br label %7
> +
> +; :5
> + %6 = load i32, i32* @x
> + store i32 %6, i32* @y
> + br label %7
> +
> +; :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
> +
> +; :4 ; preds = %0
> + %5 = load i32, i32* @x
> + store i32 %5, i32* @y
> + br label %6
> +
> +; :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
> +
> +
> +
> +; Check we safely delete store i32 %g.02, i32* @b below.(PR24469)
> +define void @test_04() {
> +entry:
> + br i1 false, label %for.body, label %for.end.9
> +
> +for.cond.1.loopexit: ; preds = %for.body
> + store i32 0, i32* @b
> + %0 = load i32, i32* @a
> + br i1 false, label %for.body, label %for.end.9
> +
> +for.body: ; preds = %for.cond.1.loopexit, %entry
> + %g.02 = phi i32 [ undef, %entry ], [ %0, %for.cond.1.loopexit ]
> + store i32 %g.02, i32* @b
> + br label %for.cond.1.loopexit
> +
> +for.end.9: ; preds = %for.cond.1.loopexit, %entry
> + ret void
> +}
> +
> +; CHECK-LABEL: @test_04(
> +; CHECK-NOT: store i32 %g.02, i32* @b
> +; CHECK-NOT: %g.02 = phi i32 [ undef, %entry ], [ %0, %for.cond.1.loopexit ]
> +; CHECK-NOT: %0 = load i32, i32* @a
>
> 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=245195&view=auto
> ==============================================================================
> --- llvm/trunk/test/Transforms/DeadStoreElimination/cross_block_dse_loop.ll (added)
> +++ llvm/trunk/test/Transforms/DeadStoreElimination/cross_block_dse_loop.ll Mon Aug 17 00:51:39 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> +; 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
> +
> +; :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
> +
> +; :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
> +
> +; :14 ; preds = %7
> + %15 = load i32, i32* %i
> + %16 = add nsw i32 %15, 1
> + store i32 %16, i32* %i
> + br label %3
> +
> +; :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> +; 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
> +
> +; :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
> +
> +; :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
> +
> +; :12 ; preds = %7
> + %13 = load i32, i32* %i
> + %14 = add nsw i32 %13, 1
> + store i32 %14, i32* %i
> + br label %3
> +
> +; :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
More information about the llvm-commits
mailing list