This makes it easier to reason about the size of an array dimension with isl.
llvm-svn: 244757
/// @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();
/// @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; }
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 *
/// @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;
};
/// @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;
}
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;
/// @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.
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); }
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";
}
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();
}
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 {
__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));
; }
; 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:
; 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