Skip to content

Commit

Permalink
Introduce the ScopArrayInfo class.
Browse files Browse the repository at this point in the history
  This class allows to store information about the arrays in the SCoP.
  For each base pointer in the SCoP one object is created storing the
  type and dimension sizes of the array. The objects can be obtained via
  the SCoP, a MemoryAccess or the isl_id associated with the output
  dimension of a MemoryAccess (the description of what is accessed).

  So far we use the information in the IslExprBuilder to create the
  right base type before indexing into the base array. This fixes the
  bug http://llvm.org/bugs/show_bug.cgi?id=21113 (both test cases are
  included). On top of that we can now build runtime alias checks for
  delinearized arrays as the dimension sizes are also part of the
  ScopArrayInfo objects.

Differential Revision: http://reviews.llvm.org/D5613

llvm-svn: 219077
  • Loading branch information
Johannes Doerfert committed Oct 5, 2014
1 parent a00381f commit 1a28a89
Show file tree
Hide file tree
Showing 12 changed files with 287 additions and 46 deletions.
87 changes: 82 additions & 5 deletions polly/include/polly/ScopInfo.h
Expand Up @@ -59,7 +59,70 @@ class TempScop;
class SCEVAffFunc;
class Comparison;

//===----------------------------------------------------------------------===//
/// @brief A class to store information about arrays in the SCoP.
///
/// Objects are accessible via the ScoP, MemoryAccess or the id associated with
/// the MemoryAccess access function.
///
class ScopArrayInfo {
public:
/// @brief Construct a ScopArrayInfo object.
///
/// @param BasePtr The array base pointer.
/// @param AccessType The type used to access this array.
/// @param IslCtx The isl context used to create the base pointer id.
/// @param DimensionSizes A vector containing the size of each dimension.
ScopArrayInfo(Value *BasePtr, Type *AccessType, isl_ctx *IslCtx,
const SmallVector<const SCEV *, 4> &DimensionSizes);

/// @brief Destructor to free the isl id of the base pointer.
~ScopArrayInfo();

/// @brief Return the base pointer.
Value *getBasePtr() const { return BasePtr; }

/// @brief Return the number of dimensions.
unsigned getNumberOfDimensions() const { return DimensionSizes.size(); }

/// @brief Return the size of dimension @p dim.
const SCEV *getDimensionSize(unsigned dim) const {
assert(dim < getNumberOfDimensions() && "Invalid dimension");
return DimensionSizes[dim];
}

/// @brief Return the type used to access this array in the SCoP.
Type *getType() const { return AccessType; }

/// @brief Return the isl id for the base pointer.
__isl_give isl_id *getBasePtrId() const;

/// @brief Dump a readable representation to stderr.
void dump() const;

/// @brief Print a readable representation to @p OS.
void print(raw_ostream &OS) const;

/// @brief Access the ScopArrayInfo associated with an access function.
static const ScopArrayInfo *
getFromAccessFunction(__isl_keep isl_pw_multi_aff *PMA);

/// @brief Access the ScopArrayInfo associated with an isl Id.
static const ScopArrayInfo *getFromId(__isl_take isl_id *Id);

private:
/// @brief The base pointer.
Value *BasePtr;

/// @brief The type used to access this array.
Type *AccessType;

/// @brief The isl id for the base pointer.
isl_id *Id;

/// @brief The sizes of each dimension.
SmallVector<const SCEV *, 4> DimensionSizes;
};

/// @brief Represent memory accesses in statements.
class MemoryAccess {
public:
Expand Down Expand Up @@ -148,11 +211,12 @@ class MemoryAccess {
public:
/// @brief Create a memory access from an access in LLVM-IR.
///
/// @param Access The memory access.
/// @param Statement The statement that contains the access.
/// @param SE The ScalarEvolution analysis.
/// @param Access The memory access.
/// @param AccInst The access instruction.
/// @param Statement The statement that contains the access.
/// @param SAI The ScopArrayInfo object for this base pointer.
MemoryAccess(const IRAccess &Access, Instruction *AccInst,
ScopStmt *Statement);
ScopStmt *Statement, const ScopArrayInfo *SAI);

~MemoryAccess();

Expand Down Expand Up @@ -188,6 +252,9 @@ class MemoryAccess {
/// @brief Get the base array isl_id for this access.
__isl_give isl_id *getArrayId() const;

/// @brief Get the ScopArrayInfo object for the base address.
const ScopArrayInfo *getScopArrayInfo() const;

/// @brief Return a string representation of the accesse's reduction type.
const std::string getReductionOperatorStr() const;

Expand Down Expand Up @@ -534,6 +601,9 @@ class Scop {
/// Constraints on parameters.
isl_set *Context;

/// @brief A map to remember ScopArrayInfo objects for all base pointers.
DenseMap<const Value *, const ScopArrayInfo *> ScopArrayInfoMap;

/// @brief The assumptions under which this scop was built.
///
/// When constructing a scop sometimes the exact representation of a statement
Expand Down Expand Up @@ -728,6 +798,13 @@ class Scop {
const_reverse_iterator rend() const { return Stmts.rend(); }
//@}

/// @brief Return the (possibly new) ScopArrayInfo object for @p Access.
const ScopArrayInfo *getOrCreateScopArrayInfo(const IRAccess &Access,
Instruction *AccessInst);

/// @brief Return the cached ScopArrayInfo object for @p BasePtr.
const ScopArrayInfo *getScopArrayInfo(Value *BasePtr);

void setContext(isl_set *NewContext);

/// @brief Align the parameters in the statement to the scop context
Expand Down
89 changes: 82 additions & 7 deletions polly/lib/Analysis/ScopInfo.cpp
Expand Up @@ -278,6 +278,43 @@ int SCEVAffinator::getLoopDepth(const Loop *L) {
return L->getLoopDepth() - outerLoop->getLoopDepth();
}

ScopArrayInfo::ScopArrayInfo(Value *BasePtr, Type *AccessType, isl_ctx *Ctx,
const SmallVector<const SCEV *, 4> &DimensionSizes)
: BasePtr(BasePtr), AccessType(AccessType), DimensionSizes(DimensionSizes) {
const std::string BasePtrName = getIslCompatibleName("MemRef_", BasePtr, "");
Id = isl_id_alloc(Ctx, BasePtrName.c_str(), this);
}

ScopArrayInfo::~ScopArrayInfo() { isl_id_free(Id); }

isl_id *ScopArrayInfo::getBasePtrId() const { return isl_id_copy(Id); }

void ScopArrayInfo::dump() const { print(errs()); }

void ScopArrayInfo::print(raw_ostream &OS) const {
OS << "ScopArrayInfo:\n";
OS << " Base: " << *getBasePtr() << "\n";
OS << " Type: " << *getType() << "\n";
OS << " Dimension Sizes:\n";
for (unsigned u = 0; u < getNumberOfDimensions(); u++)
OS << " " << u << ") " << *DimensionSizes[u] << "\n";
OS << "\n";
}

const ScopArrayInfo *
ScopArrayInfo::getFromAccessFunction(__isl_keep isl_pw_multi_aff *PMA) {
isl_id *Id = isl_pw_multi_aff_get_tuple_id(PMA, isl_dim_out);
assert(Id && "Output dimension didn't have an ID");
return getFromId(Id);
}

const ScopArrayInfo *ScopArrayInfo::getFromId(isl_id *Id) {
void *User = isl_id_get_user(Id);
const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User);
isl_id_free(Id);
return SAI;
}

const std::string
MemoryAccess::getReductionOperatorStr(MemoryAccess::ReductionType RT) {
switch (RT) {
Expand Down Expand Up @@ -348,6 +385,14 @@ static MemoryAccess::AccessType getMemoryAccessType(const IRAccess &Access) {
llvm_unreachable("Unknown IRAccess type!");
}

const ScopArrayInfo *MemoryAccess::getScopArrayInfo() const {
isl_id *ArrayId = getArrayId();
void *User = isl_id_get_user(ArrayId);
const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User);
isl_id_free(ArrayId);
return SAI;
}

isl_id *MemoryAccess::getArrayId() const {
return isl_map_get_tuple_id(AccessRelation, isl_dim_out);
}
Expand Down Expand Up @@ -433,14 +478,15 @@ void MemoryAccess::assumeNoOutOfBound(const IRAccess &Access) {
}

MemoryAccess::MemoryAccess(const IRAccess &Access, Instruction *AccInst,
ScopStmt *Statement)
ScopStmt *Statement, const ScopArrayInfo *SAI)
: Type(getMemoryAccessType(Access)), Statement(Statement), Inst(AccInst),
newAccessRelation(nullptr) {

isl_ctx *Ctx = Statement->getIslCtx();
BaseAddr = Access.getBase();
BaseName = getIslCompatibleName("MemRef_", getBaseAddr(), "");
isl_id *BaseAddrId = isl_id_alloc(Ctx, getBaseName().c_str(), nullptr);

isl_id *BaseAddrId = SAI->getBasePtrId();

if (!Access.isAffine()) {
// We overapproximate non-affine accesses with a possible access to the
Expand Down Expand Up @@ -666,18 +712,23 @@ void ScopStmt::buildScattering(SmallVectorImpl<unsigned> &Scatter) {
}

void ScopStmt::buildAccesses(TempScop &tempScop, const Region &CurRegion) {
for (auto &&Access : *tempScop.getAccessFunctions(BB)) {
MemAccs.push_back(new MemoryAccess(Access.first, Access.second, this));
for (const auto &AccessPair : *tempScop.getAccessFunctions(BB)) {
const IRAccess &Access = AccessPair.first;
Instruction *AccessInst = AccessPair.second;

const ScopArrayInfo *SAI =
getParent()->getOrCreateScopArrayInfo(Access, AccessInst);
MemAccs.push_back(new MemoryAccess(Access, AccessInst, this, SAI));

// We do not track locations for scalar memory accesses at the moment.
//
// We do not have a use for this information at the moment. If we need this
// at some point, the "instruction -> access" mapping needs to be enhanced
// as a single instruction could then possibly perform multiple accesses.
if (!Access.first.isScalar()) {
assert(!InstructionToAccess.count(Access.second) &&
if (!Access.isScalar()) {
assert(!InstructionToAccess.count(AccessInst) &&
"Unexpected 1-to-N mapping on instruction to access map!");
InstructionToAccess[Access.second] = MemAccs.back();
InstructionToAccess[AccessInst] = MemAccs.back();
}
}
}
Expand Down Expand Up @@ -1373,6 +1424,10 @@ Scop::~Scop() {
for (ScopStmt *Stmt : *this)
delete Stmt;

// Free the ScopArrayInfo objects.
for (auto &ScopArrayInfoPair : ScopArrayInfoMap)
delete ScopArrayInfoPair.second;

// Free the alias groups
for (MinMaxVectorTy *MinMaxAccesses : MinMaxAliasGroups) {
for (MinMaxAccessTy &MMA : *MinMaxAccesses) {
Expand All @@ -1383,6 +1438,26 @@ Scop::~Scop() {
}
}

const ScopArrayInfo *Scop::getOrCreateScopArrayInfo(const IRAccess &Access,
Instruction *AccessInst) {
Value *BasePtr = Access.getBase();
const ScopArrayInfo *&SAI = ScopArrayInfoMap[BasePtr];
if (!SAI) {
Type *AccessType = getPointerOperand(*AccessInst)->getType();
SAI = new ScopArrayInfo(BasePtr, AccessType, getIslCtx(), Access.Sizes);
}
return SAI;
}

const ScopArrayInfo *Scop::getScopArrayInfo(Value *BasePtr) {
const SCEV *PtrSCEV = SE->getSCEV(BasePtr);
const SCEVUnknown *PtrBaseSCEV =
cast<SCEVUnknown>(SE->getPointerBase(PtrSCEV));
const ScopArrayInfo *SAI = ScopArrayInfoMap[PtrBaseSCEV->getValue()];
assert(SAI && "No ScopArrayInfo available for this base pointer");
return SAI;
}

std::string Scop::getContextStr() const { return stringFromIslObj(Context); }
std::string Scop::getAssumedContextStr() const {
return stringFromIslObj(AssumedContext);
Expand Down
1 change: 0 additions & 1 deletion polly/lib/CodeGen/IslCodeGeneration.cpp
Expand Up @@ -23,7 +23,6 @@
#include "polly/CodeGen/BlockGenerators.h"
#include "polly/CodeGen/CodeGeneration.h"
#include "polly/CodeGen/IslAst.h"
#include "polly/CodeGen/IslExprBuilder.h"
#include "polly/CodeGen/LoopGenerators.h"
#include "polly/CodeGen/Utils.h"
#include "polly/Dependences.h"
Expand Down
42 changes: 16 additions & 26 deletions polly/lib/CodeGen/IslExprBuilder.cpp
Expand Up @@ -11,6 +11,7 @@

#include "polly/CodeGen/IslExprBuilder.h"

#include "polly/ScopInfo.h"
#include "polly/Support/GICHelper.h"

#include "llvm/Support/Debug.h"
Expand Down Expand Up @@ -103,39 +104,28 @@ Value *IslExprBuilder::createAccessAddress(isl_ast_expr *Expr) {
assert(isl_ast_expr_get_op_n_arg(Expr) == 2 &&
"Multidimensional access functions are not supported yet");

Value *Base, *IndexOp, *Zero, *Access;
SmallVector<Value *, 4> Indices;
Type *PtrElTy;
Value *Base, *IndexOp, *Access;
isl_ast_expr *BaseExpr;
isl_id *BaseId;

Base = create(isl_ast_expr_get_op_arg(Expr, 0));
BaseExpr = isl_ast_expr_get_op_arg(Expr, 0);
BaseId = isl_ast_expr_get_id(BaseExpr);
isl_ast_expr_free(BaseExpr);

const ScopArrayInfo *SAI = ScopArrayInfo::getFromId(BaseId);
Base = SAI->getBasePtr();
assert(Base->getType()->isPointerTy() && "Access base should be a pointer");
const Twine &BaseName = Base->getName();

if (Base->getType() != SAI->getType())
Base = Builder.CreateBitCast(Base, SAI->getType(),
"polly.access.cast." + BaseName);

IndexOp = create(isl_ast_expr_get_op_arg(Expr, 1));
assert(IndexOp->getType()->isIntegerTy() &&
"Access index should be an integer");
Zero = ConstantInt::getNullValue(IndexOp->getType());

// If base is a array type like,
// int A[N][M][K];
// we have to adjust the GEP. The easiest way is to transform accesses like,
// A[i][j][k]
// into equivalent ones like,
// A[0][0][ i*N*M + j*M + k]
// because SCEV already folded the "peudo dimensions" into one. Thus our index
// operand will be 'i*N*M + j*M + k' anyway.
PtrElTy = Base->getType()->getPointerElementType();
while (PtrElTy->isArrayTy()) {
Indices.push_back(Zero);
PtrElTy = PtrElTy->getArrayElementType();
}

Indices.push_back(IndexOp);
assert((PtrElTy->isIntOrIntVectorTy() || PtrElTy->isFPOrFPVectorTy() ||
PtrElTy->isPtrOrPtrVectorTy()) &&
"We do not yet change the type of the access base during code "
"generation.");

Access = Builder.CreateGEP(Base, Indices, "polly.access." + Base->getName());
Access = Builder.CreateGEP(Base, IndexOp, "polly.access." + BaseName);

isl_ast_expr_free(Expr);
return Access;
Expand Down
3 changes: 3 additions & 0 deletions polly/lib/Exchange/JSONExporter.cpp
Expand Up @@ -277,6 +277,9 @@ bool JSONImporter::runOnScop(Scop &scop) {
return false;
}

isl_id *OutId = isl_map_get_tuple_id(currentAccessMap, isl_dim_out);
newAccessMap = isl_map_set_tuple_id(newAccessMap, isl_dim_out, OutId);

// We keep the old alignment, thus we cannot allow accesses to memory
// locations that were not accessed before.
isl_set *newAccessSet = isl_map_range(isl_map_copy(newAccessMap));
Expand Down
Expand Up @@ -40,4 +40,4 @@ for.inc: ; preds = %for.body
for.end: ; preds = %for.cond
ret i32 0
}
; CHECK: load i32* getelementptr inbounds ([100 x i32]* @A, i64 0, i64 10)
; CHECK: load i32* getelementptr inbounds ([100 x i32]* @A, i{{(32|64)}} 0, i{{(32|64)}} 10)
2 changes: 1 addition & 1 deletion polly/test/Isl/CodeGen/MemAccess/codegen_simple.ll
Expand Up @@ -40,4 +40,4 @@ for.inc: ; preds = %for.body
for.end: ; preds = %for.cond
ret i32 0
}
; CHECK: load i32* getelementptr inbounds ([100 x i32]* @A, i64 0, i64 0)
; CHECK: load i32* getelementptr inbounds ([100 x i32]* @A, i{{(32|64)}} 0, i{{(32|64)}} 0)
2 changes: 1 addition & 1 deletion polly/test/Isl/CodeGen/MemAccess/codegen_simple_float.ll
Expand Up @@ -38,4 +38,4 @@ for.inc: ; preds = %for.body
for.end: ; preds = %for.cond
ret i32 0
}
; CHECK: load float* getelementptr inbounds ([100 x float]* @A, i64 0, i64 0)
; CHECK: load float* getelementptr inbounds ([100 x float]* @A, i{{(32|64)}} 0, i{{(32|64)}} 0)
4 changes: 2 additions & 2 deletions polly/test/Isl/CodeGen/MemAccess/codegen_simple_md.ll
Expand Up @@ -63,13 +63,13 @@ for.end6: ; preds = %for.cond
; WITHCONST: %[[MUL2:[._a-zA-Z0-9]+]] = mul nsw i64 2, %[[IVIn]]
; WITHCONST: %[[SUM1:[._a-zA-Z0-9]+]] = add nsw i64 %[[MUL1]], %[[MUL2]]
; WITHCONST: %[[SUM2:[._a-zA-Z0-9]+]] = add nsw i64 %[[SUM1]], 5
; WITHCONST: %[[ACC:[._a-zA-Z0-9]*]] = getelementptr [1040 x i32]* @A, i64 0, i64 %[[SUM2]]
; WITHCONST: %[[ACC:[._a-zA-Z0-9]*]] = getelementptr i32* getelementptr inbounds ([1040 x i32]* @A, i{{(32|64)}} 0, i{{(32|64)}} 0), i64 %[[SUM2]]
; WITHCONST: store i32 100, i32* %[[ACC]]

; WITHOUTCONST: %[[IVOut:polly.indvar[0-9]*]] = phi i64 [ 0, %polly.loop_preheader{{[0-9]*}} ], [ %polly.indvar_next{{[0-9]*}}, %polly.{{[._a-zA-Z0-9]*}} ]
; WITHOUTCONST: %[[IVIn:polly.indvar[0-9]*]] = phi i64 [ 0, %polly.loop_preheader{{[0-9]*}} ], [ %polly.indvar_next{{[0-9]*}}, %polly.{{[._a-zA-Z0-9]*}} ]
; WITHOUTCONST: %[[MUL1:[._a-zA-Z0-9]+]] = mul nsw i64 16, %[[IVOut]]
; WITHOUTCONST: %[[MUL2:[._a-zA-Z0-9]+]] = mul nsw i64 2, %[[IVIn]]
; WITHOUTCONST: %[[SUM1:[._a-zA-Z0-9]+]] = add nsw i64 %[[MUL1]], %[[MUL2]]
; WITHOUTCONST: %[[ACC:[._a-zA-Z0-9]*]] = getelementptr [1040 x i32]* @A, i64 0, i64 %[[SUM1]]
; WITHOUTCONST: %[[ACC:[._a-zA-Z0-9]*]] = getelementptr i32* getelementptr inbounds ([1040 x i32]* @A, i{{(32|64)}} 0, i{{(32|64)}} 0), i64 %[[SUM1]]
; WITHOUTCONST: store i32 100, i32* %[[ACC]]
4 changes: 2 additions & 2 deletions polly/test/Isl/CodeGen/MemAccess/codegen_simple_md_float.ll
Expand Up @@ -59,13 +59,13 @@ for.end6: ; preds = %for.cond
; WITHCONST: %[[MUL2:[._a-zA-Z0-9]+]] = mul nsw i64 2, %[[IVIn]]
; WITHCONST: %[[SUM1:[._a-zA-Z0-9]+]] = add nsw i64 %[[MUL1]], %[[MUL2]]
; WITHCONST: %[[SUM2:[._a-zA-Z0-9]+]] = add nsw i64 %[[SUM1]], 5
; WITHCONST: %[[ACC:[._a-zA-Z0-9]*]] = getelementptr [1040 x float]* @A, i64 0, i64 %[[SUM2]]
; WITHCONST: %[[ACC:[._a-zA-Z0-9]*]] = getelementptr float* getelementptr inbounds ([1040 x float]* @A, i{{(32|64)}} 0, i{{(32|64)}} 0), i64 %[[SUM2]]
; WITHCONST: store float 1.000000e+02, float* %[[ACC]]

; WITHOUTCONST: %[[IVOut:polly.indvar[0-9]*]] = phi i64 [ 0, %polly.loop_preheader{{[0-9]*}} ], [ %polly.indvar_next{{[0-9]*}}, %polly.{{[._a-zA-Z0-9]*}} ]
; WITHOUTCONST: %[[IVIn:polly.indvar[0-9]*]] = phi i64 [ 0, %polly.loop_preheader{{[0-9]*}} ], [ %polly.indvar_next{{[0-9]*}}, %polly.{{[._a-zA-Z0-9]*}} ]
; WITHOUTCONST: %[[MUL1:[._a-zA-Z0-9]+]] = mul nsw i64 16, %[[IVOut]]
; WITHOUTCONST: %[[MUL2:[._a-zA-Z0-9]+]] = mul nsw i64 2, %[[IVIn]]
; WITHOUTCONST: %[[SUM1:[._a-zA-Z0-9]+]] = add nsw i64 %[[MUL1]], %[[MUL2]]
; WITHOUTCONST: %[[ACC:[._a-zA-Z0-9]*]] = getelementptr [1040 x float]* @A, i64 0, i64 %[[SUM1]]
; WITHOUTCONST: %[[ACC:[._a-zA-Z0-9]*]] = getelementptr float* getelementptr inbounds ([1040 x float]* @A, i{{(32|64)}} 0, i{{(32|64)}} 0), i64 %[[SUM1]]
; WITHOUTCONST: store float 1.000000e+02, float* %[[ACC]]

0 comments on commit 1a28a89

Please sign in to comment.