Make the dimension sizes of in ScopArrayInfo available as isl_pw_affs
authorTobias Grosser <tobias@grosser.es>
Wed, 12 Aug 2015 15:27:16 +0000 (15:27 +0000)
committerTobias Grosser <tobias@grosser.es>
Wed, 12 Aug 2015 15:27:16 +0000 (15:27 +0000)
This makes it easier to reason about the size of an array dimension with isl.

llvm-svn: 244757

polly/include/polly/ScopInfo.h
polly/include/polly/Support/GICHelper.h
polly/include/polly/Support/SCEVAffinator.h
polly/lib/Analysis/ScopInfo.cpp
polly/lib/Support/SCEVAffinator.cpp
polly/test/ScopInfo/multidim_3d_parametric_array_static_loop_bounds.ll
polly/test/ScopInfo/multidim_only_ivs_3d_cast.ll

index 58710b4..ffc2b32 100644 (file)
@@ -80,8 +80,10 @@ public:
   /// @param IslCtx         The isl context used to create the base pointer id.
   /// @param DimensionSizes A vector containing the size of each dimension.
   /// @param IsPHI          Is this a PHI node specific array info object.
+  /// @param S              The scop this array object belongs to.
   ScopArrayInfo(Value *BasePtr, Type *ElementType, isl_ctx *IslCtx,
-                const SmallVector<const SCEV *, 4> &DimensionSizes, bool IsPHI);
+                const SmallVector<const SCEV *, 4> &DimensionSizes, bool IsPHI,
+                Scop *S);
 
   /// @brief Destructor to free the isl id of the base pointer.
   ~ScopArrayInfo();
@@ -92,12 +94,18 @@ public:
   /// @brief Return the number of dimensions.
   unsigned getNumberOfDimensions() const { return DimensionSizes.size(); }
 
-  /// @brief Return the size of dimension @p dim.
+  /// @brief Return the size of dimension @p dim as SCEV*.
   const SCEV *getDimensionSize(unsigned dim) const {
     assert(dim < getNumberOfDimensions() && "Invalid dimension");
     return DimensionSizes[dim];
   }
 
+  /// @brief Return the size of dimension @p dim as isl_pw_aff.
+  const isl_pw_aff *getDimensionSizePw(unsigned dim) const {
+    assert(dim < getNumberOfDimensions() && "Invalid dimension");
+    return DimensionSizesPw[dim - 1];
+  }
+
   /// @brief Get the type of the elements stored in this array.
   Type *getElementType() const { return ElementType; }
 
@@ -126,7 +134,9 @@ public:
   void dump() const;
 
   /// @brief Print a readable representation to @p OS.
-  void print(raw_ostream &OS) const;
+  ///
+  /// @param SizeAsPwAff Print the size as isl_pw_aff
+  void print(raw_ostream &OS, bool SizeAsPwAff = false) const;
 
   /// @brief Access the ScopArrayInfo associated with an access function.
   static const ScopArrayInfo *
@@ -145,9 +155,12 @@ private:
   /// @brief The isl id for the base pointer.
   isl_id *Id;
 
-  /// @brief The sizes of each dimension.
+  /// @brief The sizes of each dimension as SCEV*.
   SmallVector<const SCEV *, 4> DimensionSizes;
 
+  /// @brief The sizes of each dimension as isl_pw_aff.
+  SmallVector<isl_pw_aff *, 4> DimensionSizesPw;
+
   /// @brief Is this PHI node specific storage?
   bool IsPHI;
 };
@@ -1112,8 +1125,13 @@ public:
   /// @return The isl context of this static control part.
   isl_ctx *getIslCtx() const;
 
-  /// @brief Compute the isl representation for the SCEV @p E in @p Stmt.
-  __isl_give isl_pw_aff *getPwAff(const SCEV *E, ScopStmt *Stmt);
+  /// @brief Compute the isl representation for the SCEV @p
+  ///
+  ///
+  /// @param Stmt An (optional) statement for which the isl_pw_aff is
+  ///             computed. SCEVs known to not reference any loops in the
+  ///             scop can be passed without a statement.
+  __isl_give isl_pw_aff *getPwAff(const SCEV *E, ScopStmt *Stmt = nullptr);
 
   /// @brief Get a union set containing the iteration domains of all statements.
   __isl_give isl_union_set *getDomains() const;
index 608dfd8..0896940 100644 (file)
@@ -65,6 +65,12 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
 }
 
 inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+                                     __isl_keep isl_pw_aff *Map) {
+  OS << polly::stringFromIslObj(Map);
+  return OS;
+}
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
                                      __isl_keep isl_pw_multi_aff *PMA) {
   OS << polly::stringFromIslObj(PMA);
   return OS;
index edc3522..519e974 100644 (file)
@@ -50,10 +50,12 @@ public:
   /// @brief Translate a SCEV to an isl_pw_aff.
   ///
   /// @param E    The expression that is translated.
-  /// @param Stmt The SCoP statement surrounding @p E.
+  /// @param Stmt The SCoP statement surrounding @p E or nullptr, if no
+  ///             loop induction variables inside the scop are referenced.
   ///
   /// @returns The isl representation of the SCEV @p E in @p Stmt.
-  __isl_give isl_pw_aff *getPwAff(const llvm::SCEV *E, const ScopStmt *Stmt);
+  __isl_give isl_pw_aff *getPwAff(const llvm::SCEV *E,
+                                  const ScopStmt *Stmt = nullptr);
 
 private:
   /// @brief Key to identify cached expressions.
index 5d65687..8b561b5 100644 (file)
@@ -116,15 +116,23 @@ static __isl_give isl_set *addRangeBoundsToSet(__isl_take isl_set *S,
 
 ScopArrayInfo::ScopArrayInfo(Value *BasePtr, Type *ElementType, isl_ctx *Ctx,
                              const SmallVector<const SCEV *, 4> &DimensionSizes,
-                             bool IsPHI)
+                             bool IsPHI, Scop *S)
     : BasePtr(BasePtr), ElementType(ElementType),
       DimensionSizes(DimensionSizes), IsPHI(IsPHI) {
   std::string BasePtrName =
       getIslCompatibleName("MemRef_", BasePtr, IsPHI ? "__phi" : "");
   Id = isl_id_alloc(Ctx, BasePtrName.c_str(), this);
+  for (const SCEV *Expr : DimensionSizes) {
+    isl_pw_aff *Size = S->getPwAff(Expr);
+    DimensionSizesPw.push_back(Size);
+  }
 }
 
-ScopArrayInfo::~ScopArrayInfo() { isl_id_free(Id); }
+ScopArrayInfo::~ScopArrayInfo() {
+  isl_id_free(Id);
+  for (isl_pw_aff *Size : DimensionSizesPw)
+    isl_pw_aff_free(Size);
+}
 
 std::string ScopArrayInfo::getName() const { return isl_id_get_name(Id); }
 
@@ -136,10 +144,19 @@ isl_id *ScopArrayInfo::getBasePtrId() const { return isl_id_copy(Id); }
 
 void ScopArrayInfo::dump() const { print(errs()); }
 
-void ScopArrayInfo::print(raw_ostream &OS) const {
+void ScopArrayInfo::print(raw_ostream &OS, bool SizeAsPwAff) const {
   OS.indent(8) << *getElementType() << " " << getName() << "[*]";
-  for (unsigned u = 0; u < getNumberOfDimensions(); u++)
-    OS << "[" << *DimensionSizes[u] << "]";
+  for (unsigned u = 0; u < getNumberOfDimensions(); u++) {
+    OS << "[";
+
+    if (SizeAsPwAff)
+      OS << " " << DimensionSizesPw[u] << " ";
+    else
+      OS << *DimensionSizes[u];
+
+    OS << "]";
+  }
+
   OS << " // Element size " << getElemSizeInBytes() << "\n";
 }
 
@@ -1502,8 +1519,8 @@ Scop::getOrCreateScopArrayInfo(Value *BasePtr, Type *AccessType,
                                bool IsPHI) {
   auto &SAI = ScopArrayInfoMap[std::make_pair(BasePtr, IsPHI)];
   if (!SAI)
-    SAI.reset(
-        new ScopArrayInfo(BasePtr, AccessType, getIslCtx(), Sizes, IsPHI));
+    SAI.reset(new ScopArrayInfo(BasePtr, AccessType, getIslCtx(), Sizes, IsPHI,
+                                this));
   return SAI.get();
 }
 
@@ -1628,6 +1645,13 @@ void Scop::printArrayInfo(raw_ostream &OS) const {
     Array.second->print(OS);
 
   OS.indent(4) << "}\n";
+
+  OS.indent(4) << "Arrays (Bounds as pw_affs) {\n";
+
+  for (auto &Array : arrays())
+    Array.second->print(OS, /* SizeAsPwAff */ true);
+
+  OS.indent(4) << "}\n";
 }
 
 void Scop::print(raw_ostream &OS) const {
index 06d7672..b6b237d 100644 (file)
@@ -37,7 +37,11 @@ SCEVAffinator::~SCEVAffinator() {
 __isl_give isl_pw_aff *SCEVAffinator::getPwAff(const SCEV *Expr,
                                                const ScopStmt *Stmt) {
   this->Stmt = Stmt;
-  NumIterators = Stmt->getNumIterators();
+
+  if (Stmt)
+    NumIterators = Stmt->getNumIterators();
+  else
+    NumIterators = 0;
 
   S->addParams(getParamsInAffineExpr(&R, Expr, SE));
 
index e0271c4..6ff616d 100644 (file)
@@ -10,21 +10,21 @@ target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f3
 ; }
 
 ; CHECK:   Assumed Context:
-; CHECK:   [o, m] -> {  :
+; CHECK:   [m, o] -> {  :
 ; CHECK-DAG:               m >= 150
 ; CHECK-DAG:               and
 ; CHECK-DAG:               o >= 200
 ; CHECK:             }
-; CHECK:   p0: %o
-; CHECK:   p1: %m
+; CHECK:   p0: %m
+; CHECK:   p1: %o
 ; CHECK:   Statements {
 ; CHECK:     Stmt_for_k
 ; CHECK:           Domain :=
-; CHECK:               [o, m] -> { Stmt_for_k[i0, i1, i2] : i0 >= 0 and i0 <= 99 and i1 >= 0 and i1 <= 149 and i2 >= 0 and i2 <= 199 };
+; CHECK:               [m, o] -> { Stmt_for_k[i0, i1, i2] : i0 >= 0 and i0 <= 99 and i1 >= 0 and i1 <= 149 and i2 >= 0 and i2 <= 199 };
 ; CHECK:           Schedule :=
-; CHECK:               [o, m] -> { Stmt_for_k[i0, i1, i2] -> [i0, i1, i2] };
+; CHECK:               [m, o] -> { Stmt_for_k[i0, i1, i2] -> [i0, i1, i2] };
 ; CHECK:           MustWriteAccess := [Reduction Type: NONE]
-; CHECK:               [o, m] -> { Stmt_for_k[i0, i1, i2] -> MemRef_A[i0, i1, i2] };
+; CHECK:               [m, o] -> { Stmt_for_k[i0, i1, i2] -> MemRef_A[i0, i1, i2] };
 
 define void @foo(i64 %n, i64 %m, i64 %o, double* %A) {
 entry:
index 62b72c3..38390c2 100644 (file)
 
 ; CHECK: Assumed Context:
 ; CHECK:  [n, m, o, p_3, p_4] -> { :
-; CHECK-DAG: p_3 >= o
-; CHECK-DAG: p_4 >= m
+; CHECK-DAG: p_3 >= m
+; CHECK-DAG: p_4 >= o
 ; CHECK:  }
 ; CHECK: p0: %n
 ; CHECK: p1: %m
 ; CHECK: p2: %o
-; CHECK: p3: (zext i32 %o to i64)
-; CHECK: p4: (zext i32 %m to i64)
+; CHECK: p3: (zext i32 %m to i64)
+; CHECK: p4: (zext i32 %o to i64)
 ; CHECK-NOT: p5
 
+; CHECK: Arrays {
+; CHECK: double MemRef_A[*][(zext i32 %m to i64)][(zext i32 %o to i64)][8] // Element size 8
+; CHECK: }
+; CHECK: Arrays (Bounds as pw_affs) {
+; CHECK: double MemRef_A[*][ [p_3] -> { [] -> [(p_3)] } ][ [p_4] -> { [] -> [(p_4)] } ][ { [] -> [(8)] } ] // Element size 8
+; CHECK: }
+
+
 ; CHECK: Domain
 ; CHECK:   [n, m, o, p_3, p_4] -> { Stmt_for_k[i0, i1, i2] : i0 >= 0 and i0 <= -1 + n and i1 >= 0 and i1 <= -1 + m and i2 >= 0 and i2 <= -1 + o };
 ; CHECK: Schedule