[polly] r297473 - [Simplify] Add -polly-simplify pass.

Michael Kruse via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 10 08:05:24 PST 2017


Author: meinersbur
Date: Fri Mar 10 10:05:24 2017
New Revision: 297473

URL: http://llvm.org/viewvc/llvm-project?rev=297473&view=rev
Log:
[Simplify] Add -polly-simplify pass.

This new pass removes unnecessary accesses and writes. It currently
supports 2 simplifications, but more are planned.

It removes write accesses that write a loaded value back to the location
it was loaded from. It is a typical artifact from DeLICM. Removing it
will get rid of bogus dependencies later in dependency analysis.

It also removes statements without side-effects. ScopInfo already
removes these, but the removal of unnecessary writes can result in
more side-effect free statements.

Differential Revision: https://reviews.llvm.org/D30820

Added:
    polly/trunk/include/polly/Simplify.h
    polly/trunk/lib/Transform/Simplify.cpp
    polly/trunk/test/Simplify/
    polly/trunk/test/Simplify/pass_existence.ll
    polly/trunk/test/Simplify/redundant.ll
    polly/trunk/test/Simplify/redundant_differentindex.ll
    polly/trunk/test/Simplify/redundant_storebetween.ll
Modified:
    polly/trunk/include/polly/LinkAllPasses.h
    polly/trunk/include/polly/ScopInfo.h
    polly/trunk/lib/Analysis/ScopInfo.cpp
    polly/trunk/lib/CMakeLists.txt
    polly/trunk/lib/CodeGen/BlockGenerators.cpp
    polly/trunk/lib/Support/RegisterPasses.cpp

Modified: polly/trunk/include/polly/LinkAllPasses.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/LinkAllPasses.h?rev=297473&r1=297472&r2=297473&view=diff
==============================================================================
--- polly/trunk/include/polly/LinkAllPasses.h (original)
+++ polly/trunk/include/polly/LinkAllPasses.h Fri Mar 10 10:05:24 2017
@@ -16,6 +16,7 @@
 #define POLLY_LINKALLPASSES_H
 
 #include "polly/Config/config.h"
+#include "polly/Simplify.h"
 #include "polly/Support/DumpModulePass.h"
 #include "llvm/ADT/StringRef.h"
 #include <cstdlib>
@@ -87,6 +88,7 @@ struct PollyForcePassLinking {
     polly::createFlattenSchedulePass();
     polly::createDeLICMPass();
     polly::createDumpModulePass("", true);
+    polly::createSimplifyPass();
   }
 } PollyForcePassLinking; // Force link by creating a global definition.
 } // namespace

Modified: polly/trunk/include/polly/ScopInfo.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/ScopInfo.h?rev=297473&r1=297472&r2=297473&view=diff
==============================================================================
--- polly/trunk/include/polly/ScopInfo.h (original)
+++ polly/trunk/include/polly/ScopInfo.h Fri Mar 10 10:05:24 2017
@@ -1381,6 +1381,11 @@ public:
   /// be eliminated too.
   void removeMemoryAccess(MemoryAccess *MA);
 
+  /// Remove @p MA from this statement.
+  ///
+  /// In contrast to removeMemoryAccess(), no other access will be eliminated.
+  void removeSingleMemoryAccess(MemoryAccess *MA);
+
   typedef MemoryAccessVec::iterator iterator;
   typedef MemoryAccessVec::const_iterator const_iterator;
 

Added: polly/trunk/include/polly/Simplify.h
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/include/polly/Simplify.h?rev=297473&view=auto
==============================================================================
--- polly/trunk/include/polly/Simplify.h (added)
+++ polly/trunk/include/polly/Simplify.h Fri Mar 10 10:05:24 2017
@@ -0,0 +1,30 @@
+//===------ Simplify.h ------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Simplify a SCoP by removing unnecessary statements and accesses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef POLLY_TRANSFORM_SIMPLIFY_H
+#define POLLY_TRANSFORM_SIMPLIFY_H
+
+namespace llvm {
+class PassRegistry;
+class Pass;
+} // namespace llvm
+
+namespace polly {
+llvm::Pass *createSimplifyPass();
+} // namespace polly
+
+namespace llvm {
+void initializeSimplifyPass(llvm::PassRegistry &);
+} // namespace llvm
+
+#endif /* POLLY_TRANSFORM_SIMPLIFY_H */

Modified: polly/trunk/lib/Analysis/ScopInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Analysis/ScopInfo.cpp?rev=297473&r1=297472&r2=297473&view=diff
==============================================================================
--- polly/trunk/lib/Analysis/ScopInfo.cpp (original)
+++ polly/trunk/lib/Analysis/ScopInfo.cpp Fri Mar 10 10:05:24 2017
@@ -1819,6 +1819,19 @@ void ScopStmt::removeMemoryAccess(Memory
   InstructionToAccess.erase(MA->getAccessInstruction());
 }
 
+void ScopStmt::removeSingleMemoryAccess(MemoryAccess *MA) {
+  auto MAIt = std::find(MemAccs.begin(), MemAccs.end(), MA);
+  assert(MAIt != MemAccs.end());
+  MemAccs.erase(MAIt);
+
+  auto It = InstructionToAccess.find(MA->getAccessInstruction());
+  if (It != InstructionToAccess.end()) {
+    It->second.remove(MA);
+    if (It->second.empty())
+      InstructionToAccess.erase(MA->getAccessInstruction());
+  }
+}
+
 //===----------------------------------------------------------------------===//
 /// Scop class implement
 

Modified: polly/trunk/lib/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/CMakeLists.txt?rev=297473&r1=297472&r2=297473&view=diff
==============================================================================
--- polly/trunk/lib/CMakeLists.txt (original)
+++ polly/trunk/lib/CMakeLists.txt Fri Mar 10 10:05:24 2017
@@ -60,6 +60,7 @@ add_polly_library(Polly
   Transform/FlattenSchedule.cpp
   Transform/FlattenAlgo.cpp
   Transform/DeLICM.cpp
+  Transform/Simplify.cpp
   ${POLLY_HEADER_FILES}
   )
 

Modified: polly/trunk/lib/CodeGen/BlockGenerators.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/CodeGen/BlockGenerators.cpp?rev=297473&r1=297472&r2=297473&view=diff
==============================================================================
--- polly/trunk/lib/CodeGen/BlockGenerators.cpp (original)
+++ polly/trunk/lib/CodeGen/BlockGenerators.cpp Fri Mar 10 10:05:24 2017
@@ -281,6 +281,10 @@ void BlockGenerator::copyInstruction(Sco
   }
 
   if (auto *Store = dyn_cast<StoreInst>(Inst)) {
+    // Identified as redundant by -polly-simplify.
+    if (!Stmt.getArrayAccessOrNULLFor(Store))
+      return;
+
     generateArrayStore(Stmt, Store, BBMap, LTS, NewAccesses);
     return;
   }
@@ -1006,6 +1010,10 @@ void VectorBlockGenerator::copyInstructi
 
   if (hasVectorOperands(Inst, VectorMap)) {
     if (auto *Store = dyn_cast<StoreInst>(Inst)) {
+      // Identified as redundant by -polly-simplify.
+      if (!Stmt.getArrayAccessOrNULLFor(Store))
+        return;
+
       copyStore(Stmt, Store, VectorMap, ScalarMaps, NewAccesses);
       return;
     }

Modified: polly/trunk/lib/Support/RegisterPasses.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Support/RegisterPasses.cpp?rev=297473&r1=297472&r2=297473&view=diff
==============================================================================
--- polly/trunk/lib/Support/RegisterPasses.cpp (original)
+++ polly/trunk/lib/Support/RegisterPasses.cpp Fri Mar 10 10:05:24 2017
@@ -31,6 +31,7 @@
 #include "polly/PolyhedralInfo.h"
 #include "polly/ScopDetection.h"
 #include "polly/ScopInfo.h"
+#include "polly/Simplify.h"
 #include "polly/Support/DumpModulePass.h"
 #include "llvm/Analysis/CFGPrinter.h"
 #include "llvm/IR/LegacyPassManager.h"
@@ -188,6 +189,11 @@ static cl::opt<bool>
                  cl::desc("Eliminate scalar loop carried dependences"),
                  cl::Hidden, cl::init(false), cl::cat(PollyCategory));
 
+static cl::opt<bool>
+    EnableSimplify("polly-enable-simplify",
+                   cl::desc("Simplify SCoP after optimizations"),
+                   cl::init(false), cl::cat(PollyCategory));
+
 namespace polly {
 void initializePollyPasses(PassRegistry &Registry) {
   initializeCodeGenerationPass(Registry);
@@ -211,6 +217,7 @@ void initializePollyPasses(PassRegistry
   initializeCodegenCleanupPass(Registry);
   initializeFlattenSchedulePass(Registry);
   initializeDeLICMPass(Registry);
+  initializeSimplifyPass(Registry);
   initializeDumpModulePass(Registry);
 }
 
@@ -266,6 +273,8 @@ void registerPollyPasses(llvm::legacy::P
 
   if (EnableDeLICM)
     PM.add(polly::createDeLICMPass());
+  if (EnableSimplify)
+    PM.add(polly::createSimplifyPass());
 
   if (ImportJScop)
     PM.add(polly::createJSONImporterPass());

Added: polly/trunk/lib/Transform/Simplify.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Transform/Simplify.cpp?rev=297473&view=auto
==============================================================================
--- polly/trunk/lib/Transform/Simplify.cpp (added)
+++ polly/trunk/lib/Transform/Simplify.cpp Fri Mar 10 10:05:24 2017
@@ -0,0 +1,285 @@
+//===------ Simplify.cpp ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Simplify a SCoP by removing unnecessary statements and accesses.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/Simplify.h"
+#include "polly/ScopInfo.h"
+#include "polly/ScopPass.h"
+#include "polly/Support/GICHelper.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/Support/Debug.h"
+#define DEBUG_TYPE "polly-simplify"
+
+using namespace llvm;
+using namespace polly;
+
+namespace {
+
+STATISTIC(ScopsProcessed, "Number of SCoPs processed");
+STATISTIC(ScopsModified, "Number of SCoPs simplified");
+
+STATISTIC(PairUnequalAccRels, "Number of Load-Store pairs NOT removed because "
+                              "of different access relations");
+STATISTIC(InBetweenStore, "Number of Load-Store pairs NOT removed because "
+                          "there is another store between them");
+STATISTIC(TotalRedundantWritesRemoved,
+          "Number of writes of same value removed in any SCoP");
+STATISTIC(TotalStmtsRemoved, "Number of statements removed in any SCoP");
+
+class Simplify : public ScopPass {
+private:
+  /// The last/current SCoP that is/has been processed.
+  Scop *S;
+
+  /// Number of redundant writes removed from this SCoP.
+  int RedundantWritesRemoved = 0;
+
+  /// Number of unnecessary statements removed from the SCoP.
+  int StmtsRemoved = 0;
+
+  /// Return whether at least one simplification has been applied.
+  bool isModified() const {
+    return RedundantWritesRemoved > 0 || StmtsRemoved > 0;
+  }
+
+  MemoryAccess *getReadAccessForValue(ScopStmt *Stmt, llvm::Value *Val) {
+    if (!isa<Instruction>(Val))
+      return nullptr;
+
+    for (auto *MA : *Stmt) {
+      if (!MA->isRead())
+        continue;
+      if (MA->getAccessValue() != Val)
+        continue;
+
+      return MA;
+    }
+
+    return nullptr;
+  }
+
+  /// Return a write access that occurs between @p From and @p To.
+  ///
+  /// In region statements the order is ignored because we cannot predict it.
+  ///
+  /// @param Stmt    Statement of both writes.
+  /// @param From    Start looking after this access.
+  /// @param To      Stop looking at this access, with the access itself.
+  /// @param Targets Look for an access that may wrote to one of these elements.
+  ///
+  /// @return A write access between @p From and @p To that writes to at least
+  ///         one element in @p Targets.
+  MemoryAccess *hasWriteBetween(ScopStmt *Stmt, MemoryAccess *From,
+                                MemoryAccess *To, isl::map Targets) {
+    auto TargetsSpace = give(isl_map_get_space(Targets.keep()));
+
+    bool Started = Stmt->isRegionStmt();
+    for (auto *Acc : *Stmt) {
+      if (Acc->isLatestScalarKind())
+        continue;
+
+      if (Stmt->isBlockStmt() && From == Acc) {
+        assert(!Started);
+        Started = true;
+        continue;
+      }
+      if (Stmt->isBlockStmt() && To == Acc) {
+        assert(Started);
+        return nullptr;
+      }
+      if (!Started)
+        continue;
+
+      if (!Acc->isWrite())
+        continue;
+
+      auto AccRel = give(Acc->getAccessRelation());
+      auto AccRelSpace = give(isl_map_get_space(AccRel.keep()));
+
+      // Spaces being different means that they access different arrays.
+      if (isl_space_has_equal_tuples(TargetsSpace.keep(), AccRelSpace.keep()) ==
+          isl_bool_false)
+        continue;
+
+      AccRel = give(isl_map_intersect_domain(AccRel.take(),
+                                             Acc->getStatement()->getDomain()));
+      AccRel = give(isl_map_intersect_params(AccRel.take(), S->getContext()));
+      auto CommonElt = give(isl_map_intersect(Targets.copy(), AccRel.copy()));
+      if (isl_map_is_empty(CommonElt.keep()) != isl_bool_true)
+        return Acc;
+    }
+    assert(Stmt->isRegionStmt() &&
+           "To must be encountered in block statements");
+    return nullptr;
+  }
+
+  /// Remove writes that just write the same value already stored in the
+  /// element.
+  void removeRedundantWrites() {
+    // Delay actual removal to not invalidate iterators.
+    SmallVector<MemoryAccess *, 8> StoresToRemove;
+
+    for (auto &Stmt : *S) {
+      for (auto *WA : Stmt) {
+        if (!WA->isMustWrite())
+          continue;
+        if (!WA->isLatestArrayKind())
+          continue;
+        if (!isa<StoreInst>(WA->getAccessInstruction()))
+          continue;
+
+        auto ReadingValue = WA->getAccessValue();
+        if (!ReadingValue)
+          continue;
+
+        auto RA = getReadAccessForValue(&Stmt, ReadingValue);
+        if (!RA)
+          continue;
+        if (!RA->isLatestArrayKind())
+          continue;
+
+        auto WARel = give(WA->getLatestAccessRelation());
+        WARel = give(isl_map_intersect_domain(WARel.take(),
+                                              WA->getStatement()->getDomain()));
+        WARel = give(isl_map_intersect_params(WARel.take(), S->getContext()));
+        auto RARel = give(RA->getLatestAccessRelation());
+        RARel = give(isl_map_intersect_domain(RARel.take(),
+                                              RA->getStatement()->getDomain()));
+        RARel = give(isl_map_intersect_params(RARel.take(), S->getContext()));
+
+        if (isl_map_is_equal(RARel.keep(), WARel.keep()) != isl_bool_true) {
+          PairUnequalAccRels++;
+          DEBUG(dbgs() << "Not cleaning up " << WA
+                       << " because of unequal access relations:\n");
+          DEBUG(dbgs() << "      RA: " << RARel << "\n");
+          DEBUG(dbgs() << "      WA: " << WARel << "\n");
+          continue;
+        }
+
+        if (auto *Conflicting = hasWriteBetween(&Stmt, RA, WA, WARel)) {
+          InBetweenStore++;
+          DEBUG(dbgs() << "Not cleaning up " << WA
+                       << " because there is another store to the same element "
+                          "between\n");
+          DEBUG(Conflicting->print(dbgs()));
+          continue;
+        }
+
+        StoresToRemove.push_back(WA);
+      }
+    }
+
+    for (auto *WA : StoresToRemove) {
+      auto Stmt = WA->getStatement();
+      auto AccRel = give(WA->getAccessRelation());
+      auto AccVal = WA->getAccessValue();
+
+      DEBUG(dbgs() << "Cleanup of " << WA << ":\n");
+      DEBUG(dbgs() << "      Scalar: " << *AccVal << "\n");
+      DEBUG(dbgs() << "      AccRel: " << AccRel << "\n");
+
+      Stmt->removeSingleMemoryAccess(WA);
+
+      RedundantWritesRemoved++;
+      TotalRedundantWritesRemoved++;
+    }
+  }
+
+  /// Remove statements without side effects.
+  void removeUnnecessayStmts() {
+    auto NumStmtsBefore = S->getSize();
+    S->simplifySCoP(true);
+    assert(NumStmtsBefore >= S->getSize());
+    StmtsRemoved = NumStmtsBefore - S->getSize();
+    DEBUG(dbgs() << "Removed " << StmtsRemoved << " (of " << NumStmtsBefore
+                 << ") statements\n");
+    TotalStmtsRemoved += StmtsRemoved;
+  }
+
+  /// Print simplification statistics to @p OS.
+  void printStatistics(llvm::raw_ostream &OS, int Indent = 0) const {
+    OS.indent(Indent) << "Statistics {\n";
+    OS.indent(Indent + 4) << "Redundant writes removed: "
+                          << RedundantWritesRemoved << "\n";
+    OS.indent(Indent + 4) << "Stmts removed: " << StmtsRemoved << "\n";
+    OS.indent(Indent) << "}\n";
+  }
+
+  /// Print the current state of all MemoryAccesses to @p OS.
+  void printAccesses(llvm::raw_ostream &OS, int Indent = 0) const {
+    OS.indent(Indent) << "After accesses {\n";
+    for (auto &Stmt : *S) {
+      OS.indent(Indent + 4) << Stmt.getBaseName() << "\n";
+      for (auto *MA : Stmt)
+        MA->print(OS);
+    }
+    OS.indent(Indent) << "}\n";
+  }
+
+public:
+  static char ID;
+  explicit Simplify() : ScopPass(ID) {}
+
+  virtual void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.addRequiredTransitive<ScopInfoRegionPass>();
+    AU.setPreservesAll();
+  }
+
+  virtual bool runOnScop(Scop &S) override {
+    // Reset statistics of last processed SCoP.
+    releaseMemory();
+
+    // Prepare processing of this SCoP.
+    this->S = &S;
+    ScopsProcessed++;
+
+    DEBUG(dbgs() << "Removing redundant writes...\n");
+    removeRedundantWrites();
+
+    DEBUG(dbgs() << "Removing statements without side effects...\n");
+    removeUnnecessayStmts();
+
+    if (isModified())
+      ScopsModified++;
+    DEBUG(dbgs() << "\nFinal Scop:\n");
+    DEBUG(S.print(dbgs()));
+
+    return false;
+  }
+
+  virtual void printScop(raw_ostream &OS, Scop &S) const override {
+    assert(&S == this->S &&
+           "Can only print analysis for the last processed SCoP");
+    printStatistics(OS);
+
+    if (!isModified()) {
+      OS << "SCoP could not be simplified\n";
+      return;
+    }
+    printAccesses(OS);
+  }
+
+  virtual void releaseMemory() override {
+    S = nullptr;
+    StmtsRemoved = 0;
+  }
+};
+
+char Simplify::ID;
+} // anonymous namespace
+
+Pass *polly::createSimplifyPass() { return new Simplify(); }
+
+INITIALIZE_PASS_BEGIN(Simplify, "polly-simplify", "Polly - Simplify", false,
+                      false)
+INITIALIZE_PASS_END(Simplify, "polly-simplify", "Polly - Simplify", false,
+                    false)

Added: polly/trunk/test/Simplify/pass_existence.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/Simplify/pass_existence.ll?rev=297473&view=auto
==============================================================================
--- polly/trunk/test/Simplify/pass_existence.ll (added)
+++ polly/trunk/test/Simplify/pass_existence.ll Fri Mar 10 10:05:24 2017
@@ -0,0 +1,33 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck %s
+;
+; Simple test for the existence of the Simplify pass.
+;
+; for (int j = 0; j < n; j += 1)
+;   A[0] = 0.0;
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      store double 0.0, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: SCoP could not be simplified

Added: polly/trunk/test/Simplify/redundant.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/Simplify/redundant.ll?rev=297473&view=auto
==============================================================================
--- polly/trunk/test/Simplify/redundant.ll (added)
+++ polly/trunk/test/Simplify/redundant.ll Fri Mar 10 10:05:24 2017
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+;
+; Remove redundant store (a store that writes the same value already
+; at the destination)
+;
+; for (int j = 0; j < n; j += 1)
+;   A[0] = A[0];
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %val = load double, double* %A
+      store double %val, double* %A
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: Statistics {
+; CHECK:     Redundant writes removed: 1
+; CHECK:     Stmts removed: 1
+; CHECK: }
+
+; CHECK:      After accesses {
+; CHECK-NEXT: }

Added: polly/trunk/test/Simplify/redundant_differentindex.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/Simplify/redundant_differentindex.ll?rev=297473&view=auto
==============================================================================
--- polly/trunk/test/Simplify/redundant_differentindex.ll (added)
+++ polly/trunk/test/Simplify/redundant_differentindex.ll Fri Mar 10 10:05:24 2017
@@ -0,0 +1,40 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+; RUN: opt %loadPolly -polly-simplify -disable-output -stats < %s 2>&1 | FileCheck %s --check-prefix=STATS -match-full-lines
+; REQUIRES: asserts
+;
+; A store that has a different index than the load it is storing is
+; not redundant.
+;
+; for (int j = 0; j < n; j += 1)
+;   A[0] = A[0];
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %val = load double, double* %A
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      store double %val, double* %A_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: SCoP could not be simplified
+
+; STATS: 1 polly-simplify   - Number of Load-Store pairs NOT removed because of different access relations

Added: polly/trunk/test/Simplify/redundant_storebetween.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/Simplify/redundant_storebetween.ll?rev=297473&view=auto
==============================================================================
--- polly/trunk/test/Simplify/redundant_storebetween.ll (added)
+++ polly/trunk/test/Simplify/redundant_storebetween.ll Fri Mar 10 10:05:24 2017
@@ -0,0 +1,41 @@
+; RUN: opt %loadPolly -polly-simplify -analyze < %s | FileCheck %s -match-full-lines
+; RUN: opt %loadPolly -polly-simplify -disable-output -stats < %s 2>&1 | FileCheck %s --check-prefix=STATS -match-full-lines
+; REQUIRES: asserts
+;
+; Don't remove store where there is another store to the same target
+; in-between them.
+;
+; for (int j = 0; j < n; j += 1)
+;   A[0] = A[0];
+;
+define void @func(i32 %n, double* noalias nonnull %A) {
+entry:
+  br label %for
+
+for:
+  %j = phi i32 [0, %entry], [%j.inc, %inc]
+  %j.cmp = icmp slt i32 %j, %n
+  br i1 %j.cmp, label %body, label %exit
+
+    body:
+      %A_idx = getelementptr inbounds double, double* %A, i32 %j
+      %val = load double, double* %A_idx
+      store double 0.0, double* %A
+      store double %val, double* %A_idx
+      br label %inc
+
+inc:
+  %j.inc = add nuw nsw i32 %j, 1
+  br label %for
+
+exit:
+  br label %return
+
+return:
+  ret void
+}
+
+
+; CHECK: SCoP could not be simplified
+
+; STATS: 1 polly-simplify   - Number of Load-Store pairs NOT removed because there is another store between them




More information about the llvm-commits mailing list