[polly] r310304 - [Polly] Fully-Indexed static expansion

Andreas Simbuerger via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 7 13:54:20 PDT 2017


Author: simbuerg
Date: Mon Aug  7 13:54:20 2017
New Revision: 310304

URL: http://llvm.org/viewvc/llvm-project?rev=310304&view=rev
Log:
[Polly] Fully-Indexed static expansion

This commit implements the initial version of fully-indexed static
expansion.

```
 for(int i = 0; i<Ni; i++)
   for(int j = 0; j<Ni; j++)
S:     B[j] = j;
T: A[i] = B[i]
```

After the pass, we want this :
```
 for(int i = 0; i<Ni; i++)
   for(int j = 0; j<Ni; j++)
S:     B[i][j] = j;
T: A[i] = B[i][i]
```

For now we bail (fail) in the following cases:
  - Scalar access
  - Multiple writes per SAI
  - MayWrite Access
  - Expansion that leads to an access to the original array

Furthermore: We still miss checks for escaping references to the array
base pointers. A future commit will add the missing escape-checks to
stay correct in those cases. The expansion is still locked behind a
CLI-Option and should not yet be used.

Patch contributed by: Nicholas Bonfante <bonfante.nicolas at gmail.com>

Reviewers: simbuerg, Meinersbur, bollu

Reviewed By: Meinersbur

Subscribers: mgorny, llvm-commits, pollydev

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

Added:
    polly/trunk/lib/Transform/MaximalStaticExpansion.cpp
    polly/trunk/test/MaximalStaticExpansion/
    polly/trunk/test/MaximalStaticExpansion/read_from_original.ll
    polly/trunk/test/MaximalStaticExpansion/too_many_writes.ll
    polly/trunk/test/MaximalStaticExpansion/working_expansion.ll
Modified:
    polly/trunk/include/polly/LinkAllPasses.h
    polly/trunk/lib/CMakeLists.txt
    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=310304&r1=310303&r2=310304&view=diff
==============================================================================
--- polly/trunk/include/polly/LinkAllPasses.h (original)
+++ polly/trunk/include/polly/LinkAllPasses.h Mon Aug  7 13:54:20 2017
@@ -55,6 +55,7 @@ llvm::Pass *createPPCGCodeGenerationPass
 llvm::Pass *createIslScheduleOptimizerPass();
 llvm::Pass *createFlattenSchedulePass();
 llvm::Pass *createDeLICMPass();
+llvm::Pass *createMaximalStaticExpansionPass();
 
 extern char &CodePreparationID;
 } // namespace polly
@@ -88,6 +89,7 @@ struct PollyForcePassLinking {
     polly::createPPCGCodeGenerationPass();
 #endif
     polly::createIslScheduleOptimizerPass();
+    polly::createMaximalStaticExpansionPass();
     polly::createFlattenSchedulePass();
     polly::createDeLICMPass();
     polly::createDumpModulePass("", true);
@@ -109,6 +111,7 @@ void initializeCodeGenerationPass(llvm::
 void initializePPCGCodeGenerationPass(llvm::PassRegistry &);
 #endif
 void initializeIslScheduleOptimizerPass(llvm::PassRegistry &);
+void initializeMaximalStaticExpanderPass(llvm::PassRegistry &);
 void initializePollyCanonicalizePass(llvm::PassRegistry &);
 void initializeFlattenSchedulePass(llvm::PassRegistry &);
 void initializeDeLICMPass(llvm::PassRegistry &);

Modified: polly/trunk/lib/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/CMakeLists.txt?rev=310304&r1=310303&r2=310304&view=diff
==============================================================================
--- polly/trunk/lib/CMakeLists.txt (original)
+++ polly/trunk/lib/CMakeLists.txt Mon Aug  7 13:54:20 2017
@@ -62,6 +62,7 @@ add_library(PollyCore OBJECT
   Transform/DeLICM.cpp
   Transform/ZoneAlgo.cpp
   Transform/Simplify.cpp
+  Transform/MaximalStaticExpansion.cpp
   ${POLLY_HEADER_FILES}
   )
 set_target_properties(PollyCore PROPERTIES FOLDER "Polly")

Modified: polly/trunk/lib/Support/RegisterPasses.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Support/RegisterPasses.cpp?rev=310304&r1=310303&r2=310304&view=diff
==============================================================================
--- polly/trunk/lib/Support/RegisterPasses.cpp (original)
+++ polly/trunk/lib/Support/RegisterPasses.cpp Mon Aug  7 13:54:20 2017
@@ -149,6 +149,11 @@ static cl::opt<bool> ImportJScop(
     cl::desc("Import the polyhedral description of the detected Scops"),
     cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
 
+static cl::opt<bool> FullyIndexedStaticExpansion(
+    "polly-enable-mse",
+    cl::desc("Fully expand the memory accesses of the detected Scops"),
+    cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory));
+
 static cl::opt<bool> ExportJScop(
     "polly-export",
     cl::desc("Export the polyhedral description of the detected Scops"),
@@ -251,6 +256,7 @@ void initializePollyPasses(PassRegistry
   initializeDependenceInfoWrapperPassPass(Registry);
   initializeJSONExporterPass(Registry);
   initializeJSONImporterPass(Registry);
+  initializeMaximalStaticExpanderPass(Registry);
   initializeIslAstInfoWrapperPassPass(Registry);
   initializeIslScheduleOptimizerPass(Registry);
   initializePollyCanonicalizePass(Registry);
@@ -330,6 +336,9 @@ void registerPollyPasses(llvm::legacy::P
   if (DeadCodeElim)
     PM.add(polly::createDeadCodeElimPass());
 
+  if (FullyIndexedStaticExpansion)
+    PM.add(polly::createMaximalStaticExpansionPass());
+
   if (EnablePruneUnprofitable)
     PM.add(polly::createPruneUnprofitablePass());
 

Added: polly/trunk/lib/Transform/MaximalStaticExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/lib/Transform/MaximalStaticExpansion.cpp?rev=310304&view=auto
==============================================================================
--- polly/trunk/lib/Transform/MaximalStaticExpansion.cpp (added)
+++ polly/trunk/lib/Transform/MaximalStaticExpansion.cpp Mon Aug  7 13:54:20 2017
@@ -0,0 +1,394 @@
+//===----------------  MaximalStaticExpansion.cpp -------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass fully expand the memory accesses of a Scop to get rid of
+// dependencies.
+//
+//===----------------------------------------------------------------------===//
+
+#include "polly/DependenceInfo.h"
+#include "polly/FlattenAlgo.h"
+#include "polly/LinkAllPasses.h"
+#include "polly/Options.h"
+#include "polly/ScopInfo.h"
+#include "polly/Support/GICHelper.h"
+#include "polly/Support/ISLOStream.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
+#include "llvm/Support/Debug.h"
+
+using namespace llvm;
+using namespace polly;
+
+#define DEBUG_TYPE "polly-mse"
+
+namespace {
+class MaximalStaticExpander : public ScopPass {
+public:
+  static char ID;
+  explicit MaximalStaticExpander() : ScopPass(ID) {}
+
+  ~MaximalStaticExpander() {}
+
+  /// Expand the accesses of the SCoP.
+  ///
+  /// @param S The SCoP that must be expanded.
+  bool runOnScop(Scop &S) override;
+
+  /// Print the SCoP.
+  ///
+  /// @param OS The stream where to print.
+  /// @param S The SCop that must be printed.
+  void printScop(raw_ostream &OS, Scop &S) const override;
+
+  /// Register all analyses and transformations required.
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+
+private:
+  /// OptimizationRemarkEmitter object for displaying diagnostic remarks
+  OptimizationRemarkEmitter *ORE;
+
+  /// Emit remark
+  void emitRemark(StringRef Msg, Instruction *Inst);
+
+  /// Return true if the SAI in parameter is expandable.
+  ///
+  /// @param SAI the SAI that need to be checked.
+  /// @param Writes A set that will contains all the write accesses.
+  /// @param Reads A set that will contains all the read accesses.
+  /// @param S The SCop in which the SAI is in.
+  /// @param Dependences The RAW dependences of the SCop.
+  bool isExpandable(const ScopArrayInfo *SAI,
+                    SmallPtrSetImpl<MemoryAccess *> &Writes,
+                    SmallPtrSetImpl<MemoryAccess *> &Reads, Scop &S,
+                    isl::union_map &Dependences);
+
+  /// Expand a write memory access.
+  ///
+  /// @param S The SCop in which the memory access appears in.
+  /// @param MA The memory access that need to be expanded.
+  ScopArrayInfo *expandWrite(Scop &S, MemoryAccess *MA);
+
+  /// Expand the read memory access.
+  ///
+  /// @param The SCop in which the memory access appears in.
+  /// @param The memory access that need to be expanded.
+  /// @param Dependences The RAW dependences of the SCop.
+  /// @param ExpandedSAI The expanded SAI created during write expansion.
+  void expandRead(Scop &S, MemoryAccess *MA, isl::union_map &Dependences,
+                  ScopArrayInfo *ExpandedSAI);
+};
+} // namespace
+
+namespace {
+
+/// Whether a dimension of a set is bounded (lower and upper) by a constant,
+/// i.e. there are two constants Min and Max, such that every value x of the
+/// chosen dimensions is Min <= x <= Max.
+bool isDimBoundedByConstant(isl::set Set, unsigned dim) {
+  auto ParamDims = Set.dim(isl::dim::param);
+  Set = Set.project_out(isl::dim::param, 0, ParamDims);
+  Set = Set.project_out(isl::dim::set, 0, dim);
+  auto SetDims = Set.dim(isl::dim::set);
+  Set = Set.project_out(isl::dim::set, 1, SetDims - 1);
+  return bool(Set.is_bounded());
+}
+
+/// If @p PwAff maps to a constant, return said constant. If @p Max/@p Min, it
+/// can also be a piecewise constant and it would return the minimum/maximum
+/// value. Otherwise, return NaN.
+isl::val getConstant(isl::pw_aff PwAff, bool Max, bool Min) {
+  assert(!Max || !Min);
+  isl::val Result;
+  PwAff.foreach_piece([=, &Result](isl::set Set, isl::aff Aff) -> isl::stat {
+    if (Result && Result.is_nan())
+      return isl::stat::ok;
+
+    // TODO: If Min/Max, we can also determine a minimum/maximum value if
+    // Set is constant-bounded.
+    if (!Aff.is_cst()) {
+      Result = isl::val::nan(Aff.get_ctx());
+      return isl::stat::error;
+    }
+
+    auto ThisVal = Aff.get_constant_val();
+    if (!Result) {
+      Result = ThisVal;
+      return isl::stat::ok;
+    }
+
+    if (Result.eq(ThisVal))
+      return isl::stat::ok;
+
+    if (Max && ThisVal.gt(Result)) {
+      Result = ThisVal;
+      return isl::stat::ok;
+    }
+
+    if (Min && ThisVal.lt(Result)) {
+      Result = ThisVal;
+      return isl::stat::ok;
+    }
+
+    // Not compatible
+    Result = isl::val::nan(Aff.get_ctx());
+    return isl::stat::error;
+  });
+  return Result;
+}
+
+} // namespace
+
+char MaximalStaticExpander::ID = 0;
+
+bool MaximalStaticExpander::isExpandable(
+    const ScopArrayInfo *SAI, SmallPtrSetImpl<MemoryAccess *> &Writes,
+    SmallPtrSetImpl<MemoryAccess *> &Reads, Scop &S,
+    isl::union_map &Dependences) {
+
+  int NumberWrites = 0;
+  for (ScopStmt &Stmt : S) {
+    for (MemoryAccess *MA : Stmt) {
+
+      // Check if the current MemoryAccess involved the current SAI.
+      if (SAI != MA->getLatestScopArrayInfo())
+        continue;
+
+      // For now, we are not able to expand Scalar.
+      if (MA->isLatestScalarKind()) {
+        emitRemark(SAI->getName() + " is a Scalar access.",
+                   MA->getAccessInstruction());
+        return false;
+      }
+
+      // For now, we are not able to expand MayWrite.
+      if (MA->isMayWrite()) {
+        emitRemark(SAI->getName() + " has a maywrite access.",
+                   MA->getAccessInstruction());
+        return false;
+      }
+
+      // For now, we are not able to expand SAI with more than one write.
+      if (MA->isMustWrite()) {
+        Writes.insert(MA);
+        NumberWrites++;
+        if (NumberWrites > 1) {
+          emitRemark(SAI->getName() + " has more than 1 write access.",
+                     MA->getAccessInstruction());
+          return false;
+        }
+      }
+
+      // Check if it is possible to expand this read.
+      if (MA->isRead()) {
+
+        // Get the domain of the current ScopStmt.
+        auto StmtDomain = Stmt.getDomain();
+
+        // Get the domain of the future Read access.
+
+        auto ReadDomainSet = MA->getAccessRelation().domain();
+        auto ReadDomain = isl::union_set(ReadDomainSet);
+        auto CurrentReadWriteDependences =
+            Dependences.reverse().intersect_domain(ReadDomain);
+        auto DepsDomain = CurrentReadWriteDependences.domain();
+
+        unsigned NumberElementMap =
+            isl_union_map_n_map(CurrentReadWriteDependences.get());
+
+        // If there are multiple maps in the Deps, we cannot handle this case
+        // for now.
+        if (NumberElementMap != 1) {
+          emitRemark(SAI->getName() +
+                         " has too many dependences to be handle for now.",
+                     MA->getAccessInstruction());
+          return false;
+        }
+
+        auto DepsDomainSet = isl::set(DepsDomain);
+
+        // For now, read from the original array is not possible.
+        if (!StmtDomain.is_subset(DepsDomainSet)) {
+          emitRemark("The expansion of " + SAI->getName() +
+                         " would lead to a read from the original array.",
+                     MA->getAccessInstruction());
+          return false;
+        }
+
+        Reads.insert(MA);
+      }
+    }
+  }
+
+  // No need to expand SAI with no write.
+  if (NumberWrites == 0) {
+    emitRemark(SAI->getName() + " has 0 write access.",
+               S.getEnteringBlock()->getFirstNonPHI());
+    return false;
+  }
+
+  return true;
+}
+
+void MaximalStaticExpander::expandRead(Scop &S, MemoryAccess *MA,
+                                       isl::union_map &Dependences,
+                                       ScopArrayInfo *ExpandedSAI) {
+
+  // Get the current AM.
+  auto CurrentAccessMap = MA->getAccessRelation();
+
+  // Get RAW dependences for the current WA.
+  auto WriteDomainSet = MA->getAccessRelation().domain();
+  auto WriteDomain = isl::union_set(WriteDomainSet);
+
+  auto CurrentReadWriteDependences =
+      Dependences.reverse().intersect_domain(WriteDomain);
+
+  // If no dependences, no need to modify anything.
+  if (CurrentReadWriteDependences.is_empty()) {
+    return;
+  }
+
+  assert(isl_union_map_n_map(CurrentReadWriteDependences.get()) == 1 &&
+         "There are more than one RAW dependencies in the union map.");
+  auto NewAccessMap = isl::map::from_union_map(CurrentReadWriteDependences);
+
+  auto Id = ExpandedSAI->getBasePtrId();
+
+  // Replace the out tuple id with the one of the access array.
+  NewAccessMap = NewAccessMap.set_tuple_id(isl::dim::out, Id);
+
+  // Set the new access relation.
+  MA->setNewAccessRelation(NewAccessMap);
+}
+
+ScopArrayInfo *MaximalStaticExpander::expandWrite(Scop &S, MemoryAccess *MA) {
+
+  // Get the current AM.
+  auto CurrentAccessMap = MA->getAccessRelation();
+
+  unsigned in_dimensions = CurrentAccessMap.dim(isl::dim::in);
+
+  // Get domain from the current AM.
+  auto Domain = CurrentAccessMap.domain();
+
+  // Create a new AM from the domain.
+  auto NewAccessMap = isl::map::from_domain(Domain);
+
+  // Add dimensions to the new AM according to the current in_dim.
+  NewAccessMap = NewAccessMap.add_dims(isl::dim::out, in_dimensions);
+
+  // Create the string representing the name of the new SAI.
+  // One new SAI for each statement so that each write go to a different memory
+  // cell.
+  auto CurrentStmtDomain = MA->getStatement()->getDomain();
+  auto CurrentStmtName = CurrentStmtDomain.get_tuple_name();
+  auto CurrentOutId = CurrentAccessMap.get_tuple_id(isl::dim::out);
+  std::string CurrentOutIdString =
+      MA->getScopArrayInfo()->getName() + "_" + CurrentStmtName + "_expanded";
+
+  // Set the tuple id for the out dimension.
+  NewAccessMap = NewAccessMap.set_tuple_id(isl::dim::out, CurrentOutId);
+
+  // Create the size vector.
+  std::vector<unsigned> Sizes;
+  for (unsigned i = 0; i < in_dimensions; i++) {
+    assert(isDimBoundedByConstant(CurrentStmtDomain, i) &&
+           "Domain boundary are not constant.");
+    auto UpperBound = getConstant(CurrentStmtDomain.dim_max(i), true, false);
+    assert(!UpperBound.is_null() && UpperBound.is_pos() &&
+           !UpperBound.is_nan() &&
+           "The upper bound is not a positive integer.");
+    assert(UpperBound.le(isl::val(CurrentAccessMap.get_ctx(),
+                                  std::numeric_limits<int>::max() - 1)) &&
+           "The upper bound overflow a int.");
+    Sizes.push_back(UpperBound.get_num_si() + 1);
+  }
+
+  // Get the ElementType of the current SAI.
+  auto ElementType = MA->getLatestScopArrayInfo()->getElementType();
+
+  // Create (or get if already existing) the new expanded SAI.
+  auto ExpandedSAI =
+      S.createScopArrayInfo(ElementType, CurrentOutIdString, Sizes);
+  ExpandedSAI->setIsOnHeap(true);
+
+  // Get the out Id of the expanded Array.
+  auto NewOutId = ExpandedSAI->getBasePtrId();
+
+  // Set the out id of the new AM to the new SAI id.
+  NewAccessMap = NewAccessMap.set_tuple_id(isl::dim::out, NewOutId);
+
+  // Add constraints to linked output with input id.
+  auto SpaceMap = NewAccessMap.get_space();
+  auto ConstraintBasicMap =
+      isl::basic_map::equal(SpaceMap, SpaceMap.dim(isl::dim::in));
+  NewAccessMap = isl::map(ConstraintBasicMap);
+
+  // Set the new access relation map.
+  MA->setNewAccessRelation(NewAccessMap);
+
+  return ExpandedSAI;
+}
+
+void MaximalStaticExpander::emitRemark(StringRef Msg, Instruction *Inst) {
+  ORE->emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "ExpansionRejection", Inst)
+            << Msg);
+}
+
+bool MaximalStaticExpander::runOnScop(Scop &S) {
+
+  // Get the ORE from OptimizationRemarkEmitterWrapperPass.
+  ORE = &(getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE());
+
+  // Get the RAW Dependences.
+  auto &DI = getAnalysis<DependenceInfo>();
+  auto &D = DI.getDependences(Dependences::AL_Statement);
+  auto Dependences = isl::give(D.getDependences(Dependences::TYPE_RAW));
+
+  SmallPtrSet<ScopArrayInfo *, 4> CurrentSAI(S.arrays().begin(),
+                                             S.arrays().end());
+
+  for (auto SAI : CurrentSAI) {
+    SmallPtrSet<MemoryAccess *, 4> AllWrites;
+    SmallPtrSet<MemoryAccess *, 4> AllReads;
+    if (!isExpandable(SAI, AllWrites, AllReads, S, Dependences))
+      continue;
+
+    assert(AllWrites.size() == 1);
+
+    auto TheWrite = *(AllWrites.begin());
+    ScopArrayInfo *ExpandedArray = expandWrite(S, TheWrite);
+
+    for (MemoryAccess *MA : AllReads)
+      expandRead(S, MA, Dependences, ExpandedArray);
+  }
+
+  return false;
+}
+
+void MaximalStaticExpander::printScop(raw_ostream &OS, Scop &S) const {
+  S.print(OS, false);
+}
+
+void MaximalStaticExpander::getAnalysisUsage(AnalysisUsage &AU) const {
+  ScopPass::getAnalysisUsage(AU);
+  AU.addRequired<DependenceInfo>();
+  AU.addRequired<OptimizationRemarkEmitterWrapperPass>();
+}
+
+Pass *polly::createMaximalStaticExpansionPass() {
+  return new MaximalStaticExpander();
+}
+
+INITIALIZE_PASS_BEGIN(MaximalStaticExpander, "polly-mse",
+                      "Polly - Maximal static expansion of SCoP", false, false);
+INITIALIZE_PASS_DEPENDENCY(DependenceInfo);
+INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass);
+INITIALIZE_PASS_END(MaximalStaticExpander, "polly-mse",
+                    "Polly - Maximal static expansion of SCoP", false, false)

Added: polly/trunk/test/MaximalStaticExpansion/read_from_original.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/MaximalStaticExpansion/read_from_original.ll?rev=310304&view=auto
==============================================================================
--- polly/trunk/test/MaximalStaticExpansion/read_from_original.ll (added)
+++ polly/trunk/test/MaximalStaticExpansion/read_from_original.ll Mon Aug  7 13:54:20 2017
@@ -0,0 +1,105 @@
+; RUN: opt -polly-canonicalize %loadPolly -polly-mse -analyze < %s | FileCheck %s
+; RUN: opt -polly-canonicalize %loadPolly -polly-mse -pass-remarks-analysis="polly-mse" -analyze < %s 2>&1| FileCheck %s --check-prefix=MSE
+;
+; Verify that Polly detects problems and does not expand the array
+;
+; Original source code :
+;
+; #define Ni 2000
+; #define Nj 3000
+; 
+; double mse(double A[Ni], double B[Nj]) {
+;   int i;
+;   double tmp = 6;
+;   for (i = 0; i < Ni; i++) {
+;     for (int j = 2; j<Nj; j++) {
+;       B[j-1] = j;
+;     }
+;     A[i] = B[i]; 
+;   }
+;   return tmp;
+; }
+;
+; Check that the pass detects the problem of read from original array after expansion.
+;
+; MSE: The expansion of MemRef_B would lead to a read from the original array.
+;
+; CHECK-NOT: double MemRef_B2_expanded[2000][3000]; // Element size 8
+;
+; Check that the  memory accesses are not modified
+;
+; CHECK-NOT: new: { Stmt_for_body3[i0, i1] -> MemRef_B_Stmt_for_body3_expanded[i0, i1] };
+; CHECK-NOT: new: { Stmt_for_end[i0] -> MemRef_B_Stmt_for_body3_expanded
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: noinline nounwind uwtable
+define double @mse(double* %A, double* %B) {
+entry:
+  %A.addr = alloca double*, align 8
+  %B.addr = alloca double*, align 8
+  %i = alloca i32, align 4
+  %tmp = alloca double, align 8
+  %j = alloca i32, align 4
+  store double* %A, double** %A.addr, align 8
+  store double* %B, double** %B.addr, align 8
+  store double 6.000000e+00, double* %tmp, align 8
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc8, %entry
+  %0 = load i32, i32* %i, align 4
+  %cmp = icmp slt i32 %0, 2000
+  br i1 %cmp, label %for.body, label %for.end10
+
+for.body:                                         ; preds = %for.cond
+  store i32 2, i32* %j, align 4
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %1 = load i32, i32* %j, align 4
+  %cmp2 = icmp slt i32 %1, 3000
+  br i1 %cmp2, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %2 = load i32, i32* %j, align 4
+  %conv = sitofp i32 %2 to double
+  %3 = load double*, double** %B.addr, align 8
+  %4 = load i32, i32* %j, align 4
+  %sub = sub nsw i32 %4, 1
+  %idxprom = sext i32 %sub to i64
+  %arrayidx = getelementptr inbounds double, double* %3, i64 %idxprom
+  store double %conv, double* %arrayidx, align 8
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %5 = load i32, i32* %j, align 4
+  %inc = add nsw i32 %5, 1
+  store i32 %inc, i32* %j, align 4
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  %6 = load double*, double** %B.addr, align 8
+  %7 = load i32, i32* %i, align 4
+  %idxprom4 = sext i32 %7 to i64
+  %arrayidx5 = getelementptr inbounds double, double* %6, i64 %idxprom4
+  %8 = load double, double* %arrayidx5, align 8
+  %9 = load double*, double** %A.addr, align 8
+  %10 = load i32, i32* %i, align 4
+  %idxprom6 = sext i32 %10 to i64
+  %arrayidx7 = getelementptr inbounds double, double* %9, i64 %idxprom6
+  store double %8, double* %arrayidx7, align 8
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %for.end
+  %11 = load i32, i32* %i, align 4
+  %inc9 = add nsw i32 %11, 1
+  store i32 %inc9, i32* %i, align 4
+  br label %for.cond
+
+for.end10:                                        ; preds = %for.cond
+  %12 = load double, double* %tmp, align 8
+  ret double %12
+}
+

Added: polly/trunk/test/MaximalStaticExpansion/too_many_writes.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/MaximalStaticExpansion/too_many_writes.ll?rev=310304&view=auto
==============================================================================
--- polly/trunk/test/MaximalStaticExpansion/too_many_writes.ll (added)
+++ polly/trunk/test/MaximalStaticExpansion/too_many_writes.ll Mon Aug  7 13:54:20 2017
@@ -0,0 +1,111 @@
+; RUN: opt -polly-canonicalize %loadPolly -polly-mse -analyze < %s | FileCheck %s
+; RUN: opt -polly-canonicalize %loadPolly -polly-mse -pass-remarks-analysis="polly-mse" -analyze < %s 2>&1 | FileCheck %s --check-prefix=MSE
+;
+; Verify that Polly detects problems and does not expand the array
+;
+; Original source code :
+;
+; #define Ni 2000
+; #define Nj 2000
+; 
+; double mse(double A[Ni], double B[Nj]) {
+;   int i;
+;   double tmp = 6;
+;   for (i = 0; i < Ni; i++) {
+;     B[i] = 2; 
+;     for (int j = 0; j<Nj; j++) {
+;       B[j] = j;
+;     }
+;     A[i] = B[i]; 
+;   }
+;   return tmp;
+; }
+;
+; Check that the pass detects that there are more than 1 write access per array.
+;
+; MSE: MemRef_B has more than 1 write access.
+;
+; Check that the SAI is not expanded
+;
+; CHECK-NOT: double MemRef_B2_expanded[2000][3000]; // Element size 8
+;
+; Check that the  memory accesses are not modified
+;
+; CHECK-NOT: new: { Stmt_for_body3[i0, i1] -> MemRef_B_Stmt_for_body3_expanded[i0, i1] };
+; CHECK-NOT: new: { Stmt_for_end[i0] -> MemRef_B_Stmt_for_body3_expanded
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: noinline nounwind uwtable
+define double @mse(double* %A, double* %B) {
+entry:
+  %A.addr = alloca double*, align 8
+  %B.addr = alloca double*, align 8
+  %i = alloca i32, align 4
+  %tmp = alloca double, align 8
+  %j = alloca i32, align 4
+  store double* %A, double** %A.addr, align 8
+  store double* %B, double** %B.addr, align 8
+  store double 6.000000e+00, double* %tmp, align 8
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc10, %entry
+  %0 = load i32, i32* %i, align 4
+  %cmp = icmp slt i32 %0, 2000
+  br i1 %cmp, label %for.body, label %for.end12
+
+for.body:                                         ; preds = %for.cond
+  %1 = load double*, double** %B.addr, align 8
+  %2 = load i32, i32* %i, align 4
+  %idxprom = sext i32 %2 to i64
+  %arrayidx = getelementptr inbounds double, double* %1, i64 %idxprom
+  store double 2.000000e+00, double* %arrayidx, align 8
+  store i32 0, i32* %j, align 4
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %3 = load i32, i32* %j, align 4
+  %cmp2 = icmp slt i32 %3, 2000
+  br i1 %cmp2, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %4 = load i32, i32* %j, align 4
+  %conv = sitofp i32 %4 to double
+  %5 = load double*, double** %B.addr, align 8
+  %6 = load i32, i32* %j, align 4
+  %idxprom4 = sext i32 %6 to i64
+  %arrayidx5 = getelementptr inbounds double, double* %5, i64 %idxprom4
+  store double %conv, double* %arrayidx5, align 8
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %7 = load i32, i32* %j, align 4
+  %inc = add nsw i32 %7, 1
+  store i32 %inc, i32* %j, align 4
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  %8 = load double*, double** %B.addr, align 8
+  %9 = load i32, i32* %i, align 4
+  %idxprom6 = sext i32 %9 to i64
+  %arrayidx7 = getelementptr inbounds double, double* %8, i64 %idxprom6
+  %10 = load double, double* %arrayidx7, align 8
+  %11 = load double*, double** %A.addr, align 8
+  %12 = load i32, i32* %i, align 4
+  %idxprom8 = sext i32 %12 to i64
+  %arrayidx9 = getelementptr inbounds double, double* %11, i64 %idxprom8
+  store double %10, double* %arrayidx9, align 8
+  br label %for.inc10
+
+for.inc10:                                        ; preds = %for.end
+  %13 = load i32, i32* %i, align 4
+  %inc11 = add nsw i32 %13, 1
+  store i32 %inc11, i32* %i, align 4
+  br label %for.cond
+
+for.end12:                                        ; preds = %for.cond
+  %14 = load double, double* %tmp, align 8
+  ret double %14
+}

Added: polly/trunk/test/MaximalStaticExpansion/working_expansion.ll
URL: http://llvm.org/viewvc/llvm-project/polly/trunk/test/MaximalStaticExpansion/working_expansion.ll?rev=310304&view=auto
==============================================================================
--- polly/trunk/test/MaximalStaticExpansion/working_expansion.ll (added)
+++ polly/trunk/test/MaximalStaticExpansion/working_expansion.ll Mon Aug  7 13:54:20 2017
@@ -0,0 +1,101 @@
+; RUN: opt -polly-canonicalize %loadPolly -polly-mse -analyze < %s | FileCheck %s
+;
+; Verify that the accesses are correctly expanded
+;
+; Original source code :
+;
+; #define Ni 2000
+; #define Nj 3000
+; 
+; double mse(double A[Ni], double B[Nj]) {
+;   int i;
+;   double tmp = 6;
+;   for (i = 0; i < Ni; i++) {
+;     for (int j = 0; j<Nj; j++) {
+;       B[j] = j;
+;     }
+;     A[i] = B[i]; 
+;   }
+;   return tmp;
+; }
+;
+; Check if the expanded SAI are created
+;
+; CHECK: double MemRef_B_Stmt_for_body3_expanded[2000][3000]; // Element size 8
+;
+; Check if the memory accesses are modified
+;
+; CHECK: new: { Stmt_for_body3[i0, i1] -> MemRef_B_Stmt_for_body3_expanded[i0, i1] };
+; CHECK: new: { Stmt_for_end[i0] -> MemRef_B_Stmt_for_body3_expanded[i0, i0] };
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+; Function Attrs: noinline nounwind uwtable
+define double @mse(double* %A, double* %B) {
+entry:
+  %A.addr = alloca double*, align 8
+  %B.addr = alloca double*, align 8
+  %i = alloca i32, align 4
+  %tmp = alloca double, align 8
+  %j = alloca i32, align 4
+  store double* %A, double** %A.addr, align 8
+  store double* %B, double** %B.addr, align 8
+  store double 6.000000e+00, double* %tmp, align 8
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc8, %entry
+  %0 = load i32, i32* %i, align 4
+  %cmp = icmp slt i32 %0, 2000
+  br i1 %cmp, label %for.body, label %for.end10
+
+for.body:                                         ; preds = %for.cond
+  store i32 0, i32* %j, align 4
+  br label %for.cond1
+
+for.cond1:                                        ; preds = %for.inc, %for.body
+  %1 = load i32, i32* %j, align 4
+  %cmp2 = icmp slt i32 %1, 3000
+  br i1 %cmp2, label %for.body3, label %for.end
+
+for.body3:                                        ; preds = %for.cond1
+  %2 = load i32, i32* %j, align 4
+  %conv = sitofp i32 %2 to double
+  %3 = load double*, double** %B.addr, align 8
+  %4 = load i32, i32* %j, align 4
+  %idxprom = sext i32 %4 to i64
+  %arrayidx = getelementptr inbounds double, double* %3, i64 %idxprom
+  store double %conv, double* %arrayidx, align 8
+  br label %for.inc
+
+for.inc:                                          ; preds = %for.body3
+  %5 = load i32, i32* %j, align 4
+  %inc = add nsw i32 %5, 1
+  store i32 %inc, i32* %j, align 4
+  br label %for.cond1
+
+for.end:                                          ; preds = %for.cond1
+  %6 = load double*, double** %B.addr, align 8
+  %7 = load i32, i32* %i, align 4
+  %idxprom4 = sext i32 %7 to i64
+  %arrayidx5 = getelementptr inbounds double, double* %6, i64 %idxprom4
+  %8 = load double, double* %arrayidx5, align 8
+  %9 = load double*, double** %A.addr, align 8
+  %10 = load i32, i32* %i, align 4
+  %idxprom6 = sext i32 %10 to i64
+  %arrayidx7 = getelementptr inbounds double, double* %9, i64 %idxprom6
+  store double %8, double* %arrayidx7, align 8
+  br label %for.inc8
+
+for.inc8:                                         ; preds = %for.end
+  %11 = load i32, i32* %i, align 4
+  %inc9 = add nsw i32 %11, 1
+  store i32 %inc9, i32* %i, align 4
+  br label %for.cond
+
+for.end10:                                        ; preds = %for.cond
+  %12 = load double, double* %tmp, align 8
+  ret double %12
+}
+




More information about the llvm-commits mailing list