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