forked from OSchip/llvm-project
Merge IRAccess into MemoryAccess
All MemoryAccess objects will be owned by ScopInfo::AccFuncMap which
previously stored the IRAccess objects. Instead of creating new
MemoryAccess objects, the already created ones are reused, but their
order might be different now. Some fields of IRAccess and MemoryAccess
had the same meaning and are merged.
This is the last step of fusioning TempScopInfo.{h|cpp} and
ScopInfo.{h.cpp}. Some refactoring might still make sense.
Differential Revision: http://reviews.llvm.org/D12843
llvm-svn: 248024
This commit is contained in:
parent
92191730f8
commit
e2bccbbfb2
|
|
@ -59,7 +59,7 @@ struct isl_schedule;
|
||||||
|
|
||||||
namespace polly {
|
namespace polly {
|
||||||
|
|
||||||
class IRAccess;
|
class MemoryAccess;
|
||||||
class Scop;
|
class Scop;
|
||||||
class ScopStmt;
|
class ScopStmt;
|
||||||
class ScopInfo;
|
class ScopInfo;
|
||||||
|
|
@ -93,7 +93,7 @@ public:
|
||||||
/// through the loop.
|
/// through the loop.
|
||||||
typedef std::map<const Loop *, const SCEV *> LoopBoundMapType;
|
typedef std::map<const Loop *, const SCEV *> LoopBoundMapType;
|
||||||
|
|
||||||
typedef std::vector<std::pair<IRAccess, Instruction *>> AccFuncSetType;
|
typedef std::deque<MemoryAccess> AccFuncSetType;
|
||||||
typedef std::map<const BasicBlock *, AccFuncSetType> AccFuncMapType;
|
typedef std::map<const BasicBlock *, AccFuncSetType> AccFuncMapType;
|
||||||
|
|
||||||
/// @brief A class to store information about arrays in the SCoP.
|
/// @brief A class to store information about arrays in the SCoP.
|
||||||
|
|
@ -212,81 +212,11 @@ private:
|
||||||
bool IsPHI;
|
bool IsPHI;
|
||||||
};
|
};
|
||||||
|
|
||||||
//===---------------------------------------------------------------------===//
|
|
||||||
/// @brief A memory access described by a SCEV expression and the access type.
|
|
||||||
class IRAccess {
|
|
||||||
public:
|
|
||||||
Value *BaseAddress;
|
|
||||||
Value *AccessValue;
|
|
||||||
|
|
||||||
const SCEV *Offset;
|
|
||||||
|
|
||||||
// The type of the scev affine function
|
|
||||||
enum TypeKind {
|
|
||||||
READ = 0x1,
|
|
||||||
MUST_WRITE = 0x2,
|
|
||||||
MAY_WRITE = 0x3,
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
unsigned ElemBytes;
|
|
||||||
TypeKind Type;
|
|
||||||
bool IsAffine;
|
|
||||||
|
|
||||||
/// @brief Is this IRAccess modeling special PHI node accesses?
|
|
||||||
bool IsPHI;
|
|
||||||
|
|
||||||
public:
|
|
||||||
SmallVector<const SCEV *, 4> Subscripts, Sizes;
|
|
||||||
|
|
||||||
/// @brief Create a new IRAccess
|
|
||||||
///
|
|
||||||
/// @param IsPHI Are we modeling special PHI node accesses?
|
|
||||||
explicit IRAccess(TypeKind Type, Value *BaseAddress, const SCEV *Offset,
|
|
||||||
unsigned elemBytes, bool Affine, Value *AccessValue,
|
|
||||||
bool IsPHI = false)
|
|
||||||
: BaseAddress(BaseAddress), AccessValue(AccessValue), Offset(Offset),
|
|
||||||
ElemBytes(elemBytes), Type(Type), IsAffine(Affine), IsPHI(IsPHI) {}
|
|
||||||
|
|
||||||
explicit IRAccess(TypeKind Type, Value *BaseAddress, const SCEV *Offset,
|
|
||||||
unsigned elemBytes, bool Affine,
|
|
||||||
ArrayRef<const SCEV *> Subscripts,
|
|
||||||
ArrayRef<const SCEV *> Sizes, Value *AccessValue)
|
|
||||||
: BaseAddress(BaseAddress), AccessValue(AccessValue), Offset(Offset),
|
|
||||||
ElemBytes(elemBytes), Type(Type), IsAffine(Affine), IsPHI(false),
|
|
||||||
Subscripts(Subscripts.begin(), Subscripts.end()),
|
|
||||||
Sizes(Sizes.begin(), Sizes.end()) {}
|
|
||||||
|
|
||||||
enum TypeKind getType() const { return Type; }
|
|
||||||
|
|
||||||
Value *getBase() const { return BaseAddress; }
|
|
||||||
|
|
||||||
Value *getAccessValue() const { return AccessValue; }
|
|
||||||
|
|
||||||
const SCEV *getOffset() const { return Offset; }
|
|
||||||
|
|
||||||
unsigned getElemSizeInBytes() const { return ElemBytes; }
|
|
||||||
|
|
||||||
bool isAffine() const { return IsAffine; }
|
|
||||||
|
|
||||||
bool isRead() const { return Type == READ; }
|
|
||||||
|
|
||||||
bool isWrite() const { return Type == MUST_WRITE; }
|
|
||||||
|
|
||||||
void setMayWrite() { Type = MAY_WRITE; }
|
|
||||||
|
|
||||||
bool isMayWrite() const { return Type == MAY_WRITE; }
|
|
||||||
|
|
||||||
bool isScalar() const { return Subscripts.size() == 0; }
|
|
||||||
|
|
||||||
// @brief Is this IRAccess modeling special PHI node accesses?
|
|
||||||
bool isPHI() const { return IsPHI; }
|
|
||||||
|
|
||||||
void print(raw_ostream &OS) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// @brief Represent memory accesses in statements.
|
/// @brief Represent memory accesses in statements.
|
||||||
class MemoryAccess {
|
class MemoryAccess {
|
||||||
|
friend class Scop;
|
||||||
|
friend class ScopStmt;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// @brief The access type of a memory access
|
/// @brief The access type of a memory access
|
||||||
///
|
///
|
||||||
|
|
@ -308,7 +238,11 @@ public:
|
||||||
/// A certain set of memory locations may be written. The memory location may
|
/// A certain set of memory locations may be written. The memory location may
|
||||||
/// contain a new value if there is actually a write or the old value may
|
/// contain a new value if there is actually a write or the old value may
|
||||||
/// remain, if no write happens.
|
/// remain, if no write happens.
|
||||||
enum AccessType { READ, MUST_WRITE, MAY_WRITE };
|
enum AccessType {
|
||||||
|
READ = 0x1,
|
||||||
|
MUST_WRITE = 0x2,
|
||||||
|
MAY_WRITE = 0x3,
|
||||||
|
};
|
||||||
|
|
||||||
/// @brief Reduction access type
|
/// @brief Reduction access type
|
||||||
///
|
///
|
||||||
|
|
@ -326,16 +260,19 @@ private:
|
||||||
MemoryAccess(const MemoryAccess &) = delete;
|
MemoryAccess(const MemoryAccess &) = delete;
|
||||||
const MemoryAccess &operator=(const MemoryAccess &) = delete;
|
const MemoryAccess &operator=(const MemoryAccess &) = delete;
|
||||||
|
|
||||||
isl_map *AccessRelation;
|
/// @brief A unique identifier for this memory access.
|
||||||
|
///
|
||||||
|
/// The identifier is unique between all memory accesses belonging to the same
|
||||||
|
/// scop statement.
|
||||||
|
isl_id *Id;
|
||||||
|
|
||||||
|
/// @brief Is this MemoryAccess modeling special PHI node accesses?
|
||||||
|
bool IsPHI;
|
||||||
|
|
||||||
|
/// @brief Whether it a reading or writing access, and if writing, whether it
|
||||||
|
/// is conditional (MAY_WRITE).
|
||||||
enum AccessType AccType;
|
enum AccessType AccType;
|
||||||
|
|
||||||
/// @brief The base address (e.g., A for A[i+j]).
|
|
||||||
Value *BaseAddr;
|
|
||||||
|
|
||||||
std::string BaseName;
|
|
||||||
__isl_give isl_basic_map *createBasicAccessMap(ScopStmt *Statement);
|
|
||||||
ScopStmt *Statement;
|
|
||||||
|
|
||||||
/// @brief Reduction type for reduction like accesses, RT_NONE otherwise
|
/// @brief Reduction type for reduction like accesses, RT_NONE otherwise
|
||||||
///
|
///
|
||||||
/// An access is reduction like if it is part of a load-store chain in which
|
/// An access is reduction like if it is part of a load-store chain in which
|
||||||
|
|
@ -362,6 +299,29 @@ private:
|
||||||
/// could allow us to handle the above example.
|
/// could allow us to handle the above example.
|
||||||
ReductionType RedType = RT_NONE;
|
ReductionType RedType = RT_NONE;
|
||||||
|
|
||||||
|
/// @brief Parent ScopStmt of this access.
|
||||||
|
ScopStmt *Statement;
|
||||||
|
|
||||||
|
// Properties describing the accessed array.
|
||||||
|
// TODO: It might be possible to move them to ScopArrayInfo.
|
||||||
|
// @{
|
||||||
|
|
||||||
|
/// @brief The base address (e.g., A for A[i+j]).
|
||||||
|
Value *BaseAddr;
|
||||||
|
|
||||||
|
/// @brief An unique name of the accessed array.
|
||||||
|
std::string BaseName;
|
||||||
|
|
||||||
|
/// @brief Size in bytes of a single array element.
|
||||||
|
unsigned ElemBytes;
|
||||||
|
|
||||||
|
/// @brief Size of each dimension of the accessed array.
|
||||||
|
SmallVector<const SCEV *, 4> Sizes;
|
||||||
|
// @}
|
||||||
|
|
||||||
|
// Properties describing the accessed element.
|
||||||
|
// @{
|
||||||
|
|
||||||
/// @brief The access instruction of this memory access.
|
/// @brief The access instruction of this memory access.
|
||||||
Instruction *AccessInstruction;
|
Instruction *AccessInstruction;
|
||||||
|
|
||||||
|
|
@ -373,16 +333,38 @@ private:
|
||||||
///
|
///
|
||||||
Value *AccessValue;
|
Value *AccessValue;
|
||||||
|
|
||||||
/// Updated access relation read from JSCOP file.
|
/// @brief Accessed element relative to the base pointer (in bytes).
|
||||||
isl_map *NewAccessRelation;
|
|
||||||
|
|
||||||
/// @brief A unique identifier for this memory access.
|
|
||||||
///
|
///
|
||||||
/// The identifier is unique between all memory accesses belonging to the same
|
/// Currently only used by printIR.
|
||||||
/// scop statement.
|
const SCEV *Offset;
|
||||||
isl_id *Id;
|
|
||||||
|
|
||||||
void assumeNoOutOfBound(const IRAccess &Access);
|
/// @brief Are all the subscripts affine expression?
|
||||||
|
bool IsAffine;
|
||||||
|
|
||||||
|
/// @brief Subscript expression for each dimension.
|
||||||
|
SmallVector<const SCEV *, 4> Subscripts;
|
||||||
|
|
||||||
|
/// @brief Relation from statment instances to the accessed array elements.
|
||||||
|
isl_map *AccessRelation;
|
||||||
|
|
||||||
|
/// @brief Updated access relation read from JSCOP file.
|
||||||
|
isl_map *NewAccessRelation;
|
||||||
|
// @}
|
||||||
|
|
||||||
|
unsigned getElemSizeInBytes() const { return ElemBytes; }
|
||||||
|
|
||||||
|
bool isAffine() const { return IsAffine; }
|
||||||
|
|
||||||
|
/// @brief Is this MemoryAccess modeling special PHI node accesses?
|
||||||
|
bool isPHI() const { return IsPHI; }
|
||||||
|
|
||||||
|
void printIR(raw_ostream &OS) const;
|
||||||
|
|
||||||
|
void setStatement(ScopStmt *Stmt) { this->Statement = Stmt; }
|
||||||
|
|
||||||
|
__isl_give isl_basic_map *createBasicAccessMap(ScopStmt *Statement);
|
||||||
|
|
||||||
|
void assumeNoOutOfBound();
|
||||||
|
|
||||||
/// @brief Compute bounds on an over approximated access relation.
|
/// @brief Compute bounds on an over approximated access relation.
|
||||||
///
|
///
|
||||||
|
|
@ -426,22 +408,37 @@ private:
|
||||||
/// The introduction of different cases necessarily complicates the memory
|
/// The introduction of different cases necessarily complicates the memory
|
||||||
/// access function, but cases that can be statically proven to not happen
|
/// access function, but cases that can be statically proven to not happen
|
||||||
/// will be eliminated later on.
|
/// will be eliminated later on.
|
||||||
__isl_give isl_map *foldAccess(const IRAccess &Access,
|
__isl_give isl_map *foldAccess(__isl_take isl_map *AccessRelation,
|
||||||
__isl_take isl_map *AccessRelation,
|
|
||||||
ScopStmt *Statement);
|
ScopStmt *Statement);
|
||||||
|
|
||||||
public:
|
/// @brief Assemble the access relation from all availbale information.
|
||||||
/// @brief Create a memory access from an access in LLVM-IR.
|
|
||||||
///
|
///
|
||||||
/// @param Access The memory access.
|
/// In particular, used the information passes in the constructor and the
|
||||||
/// @param AccInst The access instruction.
|
/// parent ScopStmt set by setStatment().
|
||||||
/// @param Statement The statement that contains the access.
|
///
|
||||||
/// @param SAI The ScopArrayInfo object for this base pointer.
|
/// @param SAI Info object for the accessed array.
|
||||||
/// @param Identifier An identifier that is unique for all memory accesses
|
void buildAccessRelation(const ScopArrayInfo *SAI);
|
||||||
/// belonging to the same scop statement.
|
|
||||||
MemoryAccess(const IRAccess &Access, Instruction *AccInst,
|
|
||||||
ScopStmt *Statement, const ScopArrayInfo *SAI, int Identifier);
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// @brief Create a new MemoryAccess.
|
||||||
|
///
|
||||||
|
/// @param AccessInst The instruction doing the access.
|
||||||
|
/// @param Id Identifier that is guranteed to be unique within the
|
||||||
|
/// same ScopStmt.
|
||||||
|
/// @param BaseAddr The accessed array's address.
|
||||||
|
/// @param Offset Accessed memoray location relative to @p BaseAddr.
|
||||||
|
/// @param ElemBytes Number of accessed bytes.
|
||||||
|
/// @param AccType Whether read or write access.
|
||||||
|
/// @param IsAffine Whether the subscripts are affine expressions.
|
||||||
|
/// @param IsPHI Are we modeling special PHI node accesses?
|
||||||
|
/// @param Subscripts Subscipt expressions
|
||||||
|
/// @param Sizes Dimension lengths of the accessed array.
|
||||||
|
/// @param BaseName Name of the acessed array.
|
||||||
|
MemoryAccess(Instruction *AccessInst, __isl_take isl_id *Id, AccessType Type,
|
||||||
|
Value *BaseAddress, const SCEV *Offset, unsigned ElemBytes,
|
||||||
|
bool Affine, ArrayRef<const SCEV *> Subscripts,
|
||||||
|
ArrayRef<const SCEV *> Sizes, Value *AccessValue, bool IsPHI,
|
||||||
|
StringRef BaseName);
|
||||||
~MemoryAccess();
|
~MemoryAccess();
|
||||||
|
|
||||||
/// @brief Get the type of a memory access.
|
/// @brief Get the type of a memory access.
|
||||||
|
|
@ -582,7 +579,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
|
||||||
class ScopStmt {
|
class ScopStmt {
|
||||||
public:
|
public:
|
||||||
/// @brief List to hold all (scalar) memory accesses mapped to an instruction.
|
/// @brief List to hold all (scalar) memory accesses mapped to an instruction.
|
||||||
using MemoryAccessList = std::forward_list<MemoryAccess>;
|
using MemoryAccessList = std::forward_list<MemoryAccess *>;
|
||||||
|
|
||||||
ScopStmt(const ScopStmt &) = delete;
|
ScopStmt(const ScopStmt &) = delete;
|
||||||
const ScopStmt &operator=(const ScopStmt &) = delete;
|
const ScopStmt &operator=(const ScopStmt &) = delete;
|
||||||
|
|
@ -784,8 +781,7 @@ public:
|
||||||
/// @brief Return the __first__ (scalar) memory access for @p Inst if any.
|
/// @brief Return the __first__ (scalar) memory access for @p Inst if any.
|
||||||
MemoryAccess *lookupAccessFor(const Instruction *Inst) const {
|
MemoryAccess *lookupAccessFor(const Instruction *Inst) const {
|
||||||
auto It = InstructionToAccess.find(Inst);
|
auto It = InstructionToAccess.find(Inst);
|
||||||
return It == InstructionToAccess.end() ? nullptr
|
return It == InstructionToAccess.end() ? nullptr : It->getSecond()->front();
|
||||||
: &It->getSecond()->front();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBasicBlock(BasicBlock *Block) {
|
void setBasicBlock(BasicBlock *Block) {
|
||||||
|
|
@ -1437,6 +1433,9 @@ class ScopInfo : public RegionPass {
|
||||||
const DataLayout *TD;
|
const DataLayout *TD;
|
||||||
|
|
||||||
// Access function of statements (currently BasicBlocks) .
|
// Access function of statements (currently BasicBlocks) .
|
||||||
|
//
|
||||||
|
// This owns all the MemoryAccess objects of the Scop created in this pass. It
|
||||||
|
// must live until #scop is deleted.
|
||||||
AccFuncMapType AccFuncMap;
|
AccFuncMapType AccFuncMap;
|
||||||
|
|
||||||
// Pre-created zero for the scalar accesses, with it we do not need create a
|
// Pre-created zero for the scalar accesses, with it we do not need create a
|
||||||
|
|
@ -1453,16 +1452,13 @@ class ScopInfo : public RegionPass {
|
||||||
// Build the SCoP for Region @p R.
|
// Build the SCoP for Region @p R.
|
||||||
Scop *buildScop(Region &R, DominatorTree &DT);
|
Scop *buildScop(Region &R, DominatorTree &DT);
|
||||||
|
|
||||||
/// @brief Build an instance of IRAccess from the Load/Store instruction.
|
/// @brief Build an instance of MemoryAccess from the Load/Store instruction.
|
||||||
///
|
///
|
||||||
/// @param Inst The Load/Store instruction that access the memory
|
/// @param Inst The Load/Store instruction that access the memory
|
||||||
/// @param L The parent loop of the instruction
|
/// @param L The parent loop of the instruction
|
||||||
/// @param R The region on which to build the data access dictionary.
|
/// @param R The region on which to build the data access dictionary.
|
||||||
/// @param BoxedLoops The set of loops that are overapproximated in @p R.
|
/// @param BoxedLoops The set of loops that are overapproximated in @p R.
|
||||||
///
|
void buildMemoryAccess(Instruction *Inst, Loop *L, Region *R,
|
||||||
/// @return The IRAccess to describe the access function of the
|
|
||||||
/// instruction.
|
|
||||||
IRAccess buildIRAccess(Instruction *Inst, Loop *L, Region *R,
|
|
||||||
const ScopDetection::BoxedLoopsSetTy *BoxedLoops);
|
const ScopDetection::BoxedLoopsSetTy *BoxedLoops);
|
||||||
|
|
||||||
/// @brief Analyze and extract the cross-BB scalar dependences (or,
|
/// @brief Analyze and extract the cross-BB scalar dependences (or,
|
||||||
|
|
@ -1477,15 +1473,14 @@ class ScopInfo : public RegionPass {
|
||||||
bool buildScalarDependences(Instruction *Inst, Region *R,
|
bool buildScalarDependences(Instruction *Inst, Region *R,
|
||||||
Region *NonAffineSubRegio);
|
Region *NonAffineSubRegio);
|
||||||
|
|
||||||
/// @brief Create IRAccesses for the given PHI node in the given region.
|
/// @brief Create MemoryAccesses for the given PHI node in the given region.
|
||||||
///
|
///
|
||||||
/// @param PHI The PHI node to be handled
|
/// @param PHI The PHI node to be handled
|
||||||
/// @param R The SCoP region
|
/// @param R The SCoP region
|
||||||
/// @param Functions The access functions of the current BB
|
|
||||||
/// @param NonAffineSubRegion The non affine sub-region @p PHI is in.
|
/// @param NonAffineSubRegion The non affine sub-region @p PHI is in.
|
||||||
/// @param IsExitBlock Flag to indicate that @p PHI is in the exit BB.
|
/// @param IsExitBlock Flag to indicate that @p PHI is in the exit BB.
|
||||||
void buildPHIAccesses(PHINode *PHI, Region &R, AccFuncSetType &Functions,
|
void buildPHIAccesses(PHINode *PHI, Region &R, Region *NonAffineSubRegion,
|
||||||
Region *NonAffineSubRegion, bool IsExitBlock = false);
|
bool IsExitBlock = false);
|
||||||
|
|
||||||
/// @brief Build the access functions for the subregion @p SR.
|
/// @brief Build the access functions for the subregion @p SR.
|
||||||
///
|
///
|
||||||
|
|
@ -1503,6 +1498,44 @@ class ScopInfo : public RegionPass {
|
||||||
Region *NonAffineSubRegion = nullptr,
|
Region *NonAffineSubRegion = nullptr,
|
||||||
bool IsExitBlock = false);
|
bool IsExitBlock = false);
|
||||||
|
|
||||||
|
/// @brief Create a new MemoryAccess object and add it to #AccFuncMap.
|
||||||
|
///
|
||||||
|
/// @param BB The block where the access takes place.
|
||||||
|
/// @param Inst The instruction doing the access. It is not necessarily
|
||||||
|
/// inside @p BB.
|
||||||
|
/// @param Type The kind of access.
|
||||||
|
/// @param BaseAddress The accessed array's base address.
|
||||||
|
/// @param Offset Accessed location relative to @p BaseAddress.
|
||||||
|
/// @param ElemBytes Size of accessed array element.
|
||||||
|
/// @param Affine Whether all subscripts are affine expressions.
|
||||||
|
/// @param AccessValue Value read or written.
|
||||||
|
/// @param Subscripts Access subscripts per dimension.
|
||||||
|
/// @param Sizes The array diminsion's sizes.
|
||||||
|
/// @param IsPHI Whether this is an emulated PHI node.
|
||||||
|
void addMemoryAccess(BasicBlock *BB, Instruction *Inst,
|
||||||
|
MemoryAccess::AccessType Type, Value *BaseAddress,
|
||||||
|
const SCEV *Offset, unsigned ElemBytes, bool Affine,
|
||||||
|
Value *AccessValue, ArrayRef<const SCEV *> Subscripts,
|
||||||
|
ArrayRef<const SCEV *> Sizes, bool IsPHI);
|
||||||
|
|
||||||
|
void addMemoryAccess(BasicBlock *BB, Instruction *Inst,
|
||||||
|
MemoryAccess::AccessType Type, Value *BaseAddress,
|
||||||
|
const SCEV *Offset, unsigned ElemBytes, bool Affine,
|
||||||
|
Value *AccessValue, bool IsPHI = false) {
|
||||||
|
addMemoryAccess(BB, Inst, Type, BaseAddress, Offset, ElemBytes, Affine,
|
||||||
|
AccessValue, ArrayRef<const SCEV *>(),
|
||||||
|
ArrayRef<const SCEV *>(), IsPHI);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addMemoryAccess(BasicBlock *BB, Instruction *Inst,
|
||||||
|
MemoryAccess::AccessType Type, Value *BaseAddress,
|
||||||
|
const SCEV *Offset, unsigned ElemBytes, bool Affine,
|
||||||
|
ArrayRef<const SCEV *> Subscripts,
|
||||||
|
ArrayRef<const SCEV *> Sizes, Value *AccessValue) {
|
||||||
|
addMemoryAccess(BB, Inst, Type, BaseAddress, Offset, ElemBytes, Affine,
|
||||||
|
AccessValue, Subscripts, Sizes, false);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static char ID;
|
static char ID;
|
||||||
explicit ScopInfo();
|
explicit ScopInfo();
|
||||||
|
|
|
||||||
|
|
@ -227,7 +227,7 @@ const ScopArrayInfo *ScopArrayInfo::getFromId(isl_id *Id) {
|
||||||
return SAI;
|
return SAI;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAccess::print(raw_ostream &OS) const {
|
void MemoryAccess::printIR(raw_ostream &OS) const {
|
||||||
if (isRead())
|
if (isRead())
|
||||||
OS << "Read ";
|
OS << "Read ";
|
||||||
else {
|
else {
|
||||||
|
|
@ -235,7 +235,7 @@ void IRAccess::print(raw_ostream &OS) const {
|
||||||
OS << "May";
|
OS << "May";
|
||||||
OS << "Write ";
|
OS << "Write ";
|
||||||
}
|
}
|
||||||
OS << BaseAddress->getName() << '[' << *Offset << "]\n";
|
OS << BaseAddr->getName() << '[' << *Offset << "]\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string
|
const std::string
|
||||||
|
|
@ -290,8 +290,6 @@ static MemoryAccess::ReductionType getReductionType(const BinaryOperator *BinOp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
|
||||||
|
|
||||||
/// @brief Derive the individual index expressions from a GEP instruction
|
/// @brief Derive the individual index expressions from a GEP instruction
|
||||||
///
|
///
|
||||||
/// This function optimistically assumes the GEP references into a fixed size
|
/// This function optimistically assumes the GEP references into a fixed size
|
||||||
|
|
@ -359,18 +357,6 @@ MemoryAccess::~MemoryAccess() {
|
||||||
isl_map_free(NewAccessRelation);
|
isl_map_free(NewAccessRelation);
|
||||||
}
|
}
|
||||||
|
|
||||||
static MemoryAccess::AccessType getMemoryAccessType(const IRAccess &Access) {
|
|
||||||
switch (Access.getType()) {
|
|
||||||
case IRAccess::READ:
|
|
||||||
return MemoryAccess::READ;
|
|
||||||
case IRAccess::MUST_WRITE:
|
|
||||||
return MemoryAccess::MUST_WRITE;
|
|
||||||
case IRAccess::MAY_WRITE:
|
|
||||||
return MemoryAccess::MAY_WRITE;
|
|
||||||
}
|
|
||||||
llvm_unreachable("Unknown IRAccess type!");
|
|
||||||
}
|
|
||||||
|
|
||||||
const ScopArrayInfo *MemoryAccess::getScopArrayInfo() const {
|
const ScopArrayInfo *MemoryAccess::getScopArrayInfo() const {
|
||||||
isl_id *ArrayId = getArrayId();
|
isl_id *ArrayId = getArrayId();
|
||||||
void *User = isl_id_get_user(ArrayId);
|
void *User = isl_id_get_user(ArrayId);
|
||||||
|
|
@ -446,10 +432,10 @@ MemoryAccess::createBasicAccessMap(ScopStmt *Statement) {
|
||||||
// possibly yield out of bound memory accesses. The complement of these
|
// possibly yield out of bound memory accesses. The complement of these
|
||||||
// constraints is the set of constraints that needs to be assumed to ensure such
|
// constraints is the set of constraints that needs to be assumed to ensure such
|
||||||
// statement instances are never executed.
|
// statement instances are never executed.
|
||||||
void MemoryAccess::assumeNoOutOfBound(const IRAccess &Access) {
|
void MemoryAccess::assumeNoOutOfBound() {
|
||||||
isl_space *Space = isl_space_range(getOriginalAccessRelationSpace());
|
isl_space *Space = isl_space_range(getOriginalAccessRelationSpace());
|
||||||
isl_set *Outside = isl_set_empty(isl_space_copy(Space));
|
isl_set *Outside = isl_set_empty(isl_space_copy(Space));
|
||||||
for (int i = 1, Size = Access.Subscripts.size(); i < Size; ++i) {
|
for (int i = 1, Size = Subscripts.size(); i < Size; ++i) {
|
||||||
isl_local_space *LS = isl_local_space_from_space(isl_space_copy(Space));
|
isl_local_space *LS = isl_local_space_from_space(isl_space_copy(Space));
|
||||||
isl_pw_aff *Var =
|
isl_pw_aff *Var =
|
||||||
isl_pw_aff_var_on_domain(isl_local_space_copy(LS), isl_dim_set, i);
|
isl_pw_aff_var_on_domain(isl_local_space_copy(LS), isl_dim_set, i);
|
||||||
|
|
@ -458,7 +444,7 @@ void MemoryAccess::assumeNoOutOfBound(const IRAccess &Access) {
|
||||||
isl_set *DimOutside;
|
isl_set *DimOutside;
|
||||||
|
|
||||||
DimOutside = isl_pw_aff_lt_set(isl_pw_aff_copy(Var), Zero);
|
DimOutside = isl_pw_aff_lt_set(isl_pw_aff_copy(Var), Zero);
|
||||||
isl_pw_aff *SizeE = Statement->getPwAff(Access.Sizes[i - 1]);
|
isl_pw_aff *SizeE = Statement->getPwAff(Sizes[i - 1]);
|
||||||
|
|
||||||
SizeE = isl_pw_aff_drop_dims(SizeE, isl_dim_in, 0,
|
SizeE = isl_pw_aff_drop_dims(SizeE, isl_dim_in, 0,
|
||||||
Statement->getNumIterators());
|
Statement->getNumIterators());
|
||||||
|
|
@ -519,15 +505,14 @@ void MemoryAccess::computeBoundsOnAccessRelation(unsigned ElementSize) {
|
||||||
AccessRelation = isl_map_intersect_range(AccessRelation, AccessRange);
|
AccessRelation = isl_map_intersect_range(AccessRelation, AccessRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
__isl_give isl_map *MemoryAccess::foldAccess(const IRAccess &Access,
|
__isl_give isl_map *MemoryAccess::foldAccess(__isl_take isl_map *AccessRelation,
|
||||||
__isl_take isl_map *AccessRelation,
|
|
||||||
ScopStmt *Statement) {
|
ScopStmt *Statement) {
|
||||||
int Size = Access.Subscripts.size();
|
int Size = Subscripts.size();
|
||||||
|
|
||||||
for (int i = Size - 2; i >= 0; --i) {
|
for (int i = Size - 2; i >= 0; --i) {
|
||||||
isl_space *Space;
|
isl_space *Space;
|
||||||
isl_map *MapOne, *MapTwo;
|
isl_map *MapOne, *MapTwo;
|
||||||
isl_pw_aff *DimSize = Statement->getPwAff(Access.Sizes[i]);
|
isl_pw_aff *DimSize = Statement->getPwAff(Sizes[i]);
|
||||||
|
|
||||||
isl_space *SpaceSize = isl_pw_aff_get_space(DimSize);
|
isl_space *SpaceSize = isl_pw_aff_get_space(DimSize);
|
||||||
isl_pw_aff_free(DimSize);
|
isl_pw_aff_free(DimSize);
|
||||||
|
|
@ -570,23 +555,13 @@ __isl_give isl_map *MemoryAccess::foldAccess(const IRAccess &Access,
|
||||||
return AccessRelation;
|
return AccessRelation;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryAccess::MemoryAccess(const IRAccess &Access, Instruction *AccInst,
|
void MemoryAccess::buildAccessRelation(const ScopArrayInfo *SAI) {
|
||||||
ScopStmt *Statement, const ScopArrayInfo *SAI,
|
assert(!AccessRelation && "AccessReltation already built");
|
||||||
int Identifier)
|
|
||||||
: AccType(getMemoryAccessType(Access)), Statement(Statement),
|
|
||||||
AccessInstruction(AccInst), AccessValue(Access.getAccessValue()),
|
|
||||||
NewAccessRelation(nullptr) {
|
|
||||||
|
|
||||||
isl_ctx *Ctx = Statement->getIslCtx();
|
|
||||||
BaseAddr = Access.getBase();
|
|
||||||
BaseName = getIslCompatibleName("MemRef_", getBaseAddr(), "");
|
|
||||||
|
|
||||||
|
isl_ctx *Ctx = isl_id_get_ctx(Id);
|
||||||
isl_id *BaseAddrId = SAI->getBasePtrId();
|
isl_id *BaseAddrId = SAI->getBasePtrId();
|
||||||
|
|
||||||
auto IdName = "__polly_array_ref_" + std::to_string(Identifier);
|
if (!isAffine()) {
|
||||||
Id = isl_id_alloc(Ctx, IdName.c_str(), nullptr);
|
|
||||||
|
|
||||||
if (!Access.isAffine()) {
|
|
||||||
// We overapproximate non-affine accesses with a possible access to the
|
// We overapproximate non-affine accesses with a possible access to the
|
||||||
// whole array. For read accesses it does not make a difference, if an
|
// whole array. For read accesses it does not make a difference, if an
|
||||||
// access must or may happen. However, for write accesses it is important to
|
// access must or may happen. However, for write accesses it is important to
|
||||||
|
|
@ -595,15 +570,15 @@ MemoryAccess::MemoryAccess(const IRAccess &Access, Instruction *AccInst,
|
||||||
AccessRelation =
|
AccessRelation =
|
||||||
isl_map_set_tuple_id(AccessRelation, isl_dim_out, BaseAddrId);
|
isl_map_set_tuple_id(AccessRelation, isl_dim_out, BaseAddrId);
|
||||||
|
|
||||||
computeBoundsOnAccessRelation(Access.getElemSizeInBytes());
|
computeBoundsOnAccessRelation(getElemSizeInBytes());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
isl_space *Space = isl_space_alloc(Ctx, 0, Statement->getNumIterators(), 0);
|
isl_space *Space = isl_space_alloc(Ctx, 0, Statement->getNumIterators(), 0);
|
||||||
AccessRelation = isl_map_universe(Space);
|
AccessRelation = isl_map_universe(Space);
|
||||||
|
|
||||||
for (int i = 0, Size = Access.Subscripts.size(); i < Size; ++i) {
|
for (int i = 0, Size = Subscripts.size(); i < Size; ++i) {
|
||||||
isl_pw_aff *Affine = Statement->getPwAff(Access.Subscripts[i]);
|
isl_pw_aff *Affine = Statement->getPwAff(Subscripts[i]);
|
||||||
|
|
||||||
if (Size == 1) {
|
if (Size == 1) {
|
||||||
// For the non delinearized arrays, divide the access function of the last
|
// For the non delinearized arrays, divide the access function of the last
|
||||||
|
|
@ -614,7 +589,7 @@ MemoryAccess::MemoryAccess(const IRAccess &Access, Instruction *AccInst,
|
||||||
// two subsequent values of 'i' index two values that are stored next to
|
// two subsequent values of 'i' index two values that are stored next to
|
||||||
// each other in memory. By this division we make this characteristic
|
// each other in memory. By this division we make this characteristic
|
||||||
// obvious again.
|
// obvious again.
|
||||||
isl_val *v = isl_val_int_from_si(Ctx, Access.getElemSizeInBytes());
|
isl_val *v = isl_val_int_from_si(Ctx, getElemSizeInBytes());
|
||||||
Affine = isl_pw_aff_scale_down_val(Affine, v);
|
Affine = isl_pw_aff_scale_down_val(Affine, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -623,8 +598,8 @@ MemoryAccess::MemoryAccess(const IRAccess &Access, Instruction *AccInst,
|
||||||
AccessRelation = isl_map_flat_range_product(AccessRelation, SubscriptMap);
|
AccessRelation = isl_map_flat_range_product(AccessRelation, SubscriptMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Access.Sizes.size() > 1 && !isa<SCEVConstant>(Access.Sizes[0]))
|
if (Sizes.size() > 1 && !isa<SCEVConstant>(Sizes[0]))
|
||||||
AccessRelation = foldAccess(Access, AccessRelation, Statement);
|
AccessRelation = foldAccess(AccessRelation, Statement);
|
||||||
|
|
||||||
Space = Statement->getDomainSpace();
|
Space = Statement->getDomainSpace();
|
||||||
AccessRelation = isl_map_set_tuple_id(
|
AccessRelation = isl_map_set_tuple_id(
|
||||||
|
|
@ -632,11 +607,24 @@ MemoryAccess::MemoryAccess(const IRAccess &Access, Instruction *AccInst,
|
||||||
AccessRelation =
|
AccessRelation =
|
||||||
isl_map_set_tuple_id(AccessRelation, isl_dim_out, BaseAddrId);
|
isl_map_set_tuple_id(AccessRelation, isl_dim_out, BaseAddrId);
|
||||||
|
|
||||||
assumeNoOutOfBound(Access);
|
assumeNoOutOfBound();
|
||||||
AccessRelation = isl_map_gist_domain(AccessRelation, Statement->getDomain());
|
AccessRelation = isl_map_gist_domain(AccessRelation, Statement->getDomain());
|
||||||
isl_space_free(Space);
|
isl_space_free(Space);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MemoryAccess::MemoryAccess(Instruction *AccessInst, __isl_take isl_id *Id,
|
||||||
|
AccessType Type, Value *BaseAddress,
|
||||||
|
const SCEV *Offset, unsigned ElemBytes, bool Affine,
|
||||||
|
ArrayRef<const SCEV *> Subscripts,
|
||||||
|
ArrayRef<const SCEV *> Sizes, Value *AccessValue,
|
||||||
|
bool IsPHI, StringRef BaseName)
|
||||||
|
: Id(Id), IsPHI(IsPHI), AccType(Type), RedType(RT_NONE), Statement(nullptr),
|
||||||
|
BaseAddr(BaseAddress), BaseName(BaseName), ElemBytes(ElemBytes),
|
||||||
|
Sizes(Sizes.begin(), Sizes.end()), AccessInstruction(AccessInst),
|
||||||
|
AccessValue(AccessValue), Offset(Offset), IsAffine(Affine),
|
||||||
|
Subscripts(Subscripts.begin(), Subscripts.end()), AccessRelation(nullptr),
|
||||||
|
NewAccessRelation(nullptr) {}
|
||||||
|
|
||||||
void MemoryAccess::realignParams() {
|
void MemoryAccess::realignParams() {
|
||||||
isl_space *ParamSpace = Statement->getParent()->getParamSpace();
|
isl_space *ParamSpace = Statement->getParent()->getParamSpace();
|
||||||
AccessRelation = isl_map_align_params(AccessRelation, ParamSpace);
|
AccessRelation = isl_map_align_params(AccessRelation, ParamSpace);
|
||||||
|
|
@ -808,22 +796,23 @@ void ScopStmt::buildAccesses(BasicBlock *Block, bool isApproximated) {
|
||||||
if (!AFS)
|
if (!AFS)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (auto &AccessPair : *AFS) {
|
for (auto &Access : *AFS) {
|
||||||
IRAccess &Access = AccessPair.first;
|
Instruction *AccessInst = Access.getAccessInstruction();
|
||||||
Instruction *AccessInst = AccessPair.second;
|
|
||||||
Type *ElementType = Access.getAccessValue()->getType();
|
Type *ElementType = Access.getAccessValue()->getType();
|
||||||
|
|
||||||
const ScopArrayInfo *SAI = getParent()->getOrCreateScopArrayInfo(
|
const ScopArrayInfo *SAI = getParent()->getOrCreateScopArrayInfo(
|
||||||
Access.getBase(), ElementType, Access.Sizes, Access.isPHI());
|
Access.getBaseAddr(), ElementType, Access.Sizes, Access.isPHI());
|
||||||
|
|
||||||
if (isApproximated && Access.isWrite())
|
if (isApproximated && Access.isMustWrite())
|
||||||
Access.setMayWrite();
|
Access.AccType = MemoryAccess::MAY_WRITE;
|
||||||
|
|
||||||
MemoryAccessList *&MAL = InstructionToAccess[AccessInst];
|
MemoryAccessList *&MAL = InstructionToAccess[AccessInst];
|
||||||
if (!MAL)
|
if (!MAL)
|
||||||
MAL = new MemoryAccessList();
|
MAL = new MemoryAccessList();
|
||||||
MAL->emplace_front(Access, AccessInst, this, SAI, MemAccs.size());
|
Access.setStatement(this);
|
||||||
MemAccs.push_back(&MAL->front());
|
Access.buildAccessRelation(SAI);
|
||||||
|
MAL->emplace_front(&Access);
|
||||||
|
MemAccs.push_back(MAL->front());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2741,7 +2730,7 @@ void Scop::printIRAccessesDetail(raw_ostream &OS, ScalarEvolution *SE,
|
||||||
|
|
||||||
for (access_iterator AI = AccFuncs.begin(), AE = AccFuncs.end(); AI != AE;
|
for (access_iterator AI = AccFuncs.begin(), AE = AccFuncs.end(); AI != AE;
|
||||||
++AI)
|
++AI)
|
||||||
AI->first.print(OS.indent(ind + 2));
|
AI->printIR(OS.indent(ind + 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2754,7 +2743,6 @@ int Scop::getRelativeLoopDepth(const Loop *L) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScopInfo::buildPHIAccesses(PHINode *PHI, Region &R,
|
void ScopInfo::buildPHIAccesses(PHINode *PHI, Region &R,
|
||||||
AccFuncSetType &Functions,
|
|
||||||
Region *NonAffineSubRegion, bool IsExitBlock) {
|
Region *NonAffineSubRegion, bool IsExitBlock) {
|
||||||
|
|
||||||
// PHI nodes that are in the exit block of the region, hence if IsExitBlock is
|
// PHI nodes that are in the exit block of the region, hence if IsExitBlock is
|
||||||
|
|
@ -2792,11 +2780,10 @@ void ScopInfo::buildPHIAccesses(PHINode *PHI, Region &R,
|
||||||
// we have to insert a scalar dependence from the definition of OpI to
|
// we have to insert a scalar dependence from the definition of OpI to
|
||||||
// OpBB if the definition is not in OpBB.
|
// OpBB if the definition is not in OpBB.
|
||||||
if (OpIBB != OpBB) {
|
if (OpIBB != OpBB) {
|
||||||
IRAccess ScalarRead(IRAccess::READ, OpI, ZeroOffset, 1, true, OpI);
|
addMemoryAccess(OpBB, PHI, MemoryAccess::READ, OpI, ZeroOffset, 1, true,
|
||||||
AccFuncMap[OpBB].push_back(std::make_pair(ScalarRead, PHI));
|
OpI);
|
||||||
IRAccess ScalarWrite(IRAccess::MUST_WRITE, OpI, ZeroOffset, 1, true,
|
addMemoryAccess(OpIBB, OpI, MemoryAccess::MUST_WRITE, OpI, ZeroOffset,
|
||||||
OpI);
|
1, true, OpI);
|
||||||
AccFuncMap[OpIBB].push_back(std::make_pair(ScalarWrite, OpI));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2804,15 +2791,14 @@ void ScopInfo::buildPHIAccesses(PHINode *PHI, Region &R,
|
||||||
// instruction.
|
// instruction.
|
||||||
OpI = OpBB->getTerminator();
|
OpI = OpBB->getTerminator();
|
||||||
|
|
||||||
IRAccess ScalarAccess(IRAccess::MUST_WRITE, PHI, ZeroOffset, 1, true, Op,
|
addMemoryAccess(OpBB, OpI, MemoryAccess::MUST_WRITE, PHI, ZeroOffset, 1,
|
||||||
/* IsPHI */ !IsExitBlock);
|
true, Op, /* IsPHI */ !IsExitBlock);
|
||||||
AccFuncMap[OpBB].push_back(std::make_pair(ScalarAccess, OpI));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!OnlyNonAffineSubRegionOperands) {
|
if (!OnlyNonAffineSubRegionOperands) {
|
||||||
IRAccess ScalarAccess(IRAccess::READ, PHI, ZeroOffset, 1, true, PHI,
|
addMemoryAccess(PHI->getParent(), PHI, MemoryAccess::READ, PHI, ZeroOffset,
|
||||||
/* IsPHI */ !IsExitBlock);
|
1, true, PHI,
|
||||||
Functions.push_back(std::make_pair(ScalarAccess, PHI));
|
/* IsPHI */ !IsExitBlock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2866,10 +2852,10 @@ bool ScopInfo::buildScalarDependences(Instruction *Inst, Region *R,
|
||||||
AnyCrossStmtUse = true;
|
AnyCrossStmtUse = true;
|
||||||
|
|
||||||
// Do not build a read access that is not in the current SCoP
|
// Do not build a read access that is not in the current SCoP
|
||||||
// Use the def instruction as base address of the IRAccess, so that it will
|
// Use the def instruction as base address of the MemoryAccess, so that it
|
||||||
// become the name of the scalar access in the polyhedral form.
|
// will become the name of the scalar access in the polyhedral form.
|
||||||
IRAccess ScalarAccess(IRAccess::READ, Inst, ZeroOffset, 1, true, Inst);
|
addMemoryAccess(UseParent, UI, MemoryAccess::READ, Inst, ZeroOffset, 1,
|
||||||
AccFuncMap[UseParent].push_back(std::make_pair(ScalarAccess, UI));
|
true, Inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ModelReadOnlyScalars) {
|
if (ModelReadOnlyScalars) {
|
||||||
|
|
@ -2884,9 +2870,8 @@ bool ScopInfo::buildScalarDependences(Instruction *Inst, Region *R,
|
||||||
if (isa<Constant>(Op))
|
if (isa<Constant>(Op))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
IRAccess ScalarAccess(IRAccess::READ, Op, ZeroOffset, 1, true, Op);
|
addMemoryAccess(Inst->getParent(), Inst, MemoryAccess::READ, Op,
|
||||||
AccFuncMap[Inst->getParent()].push_back(
|
ZeroOffset, 1, true, Op);
|
||||||
std::make_pair(ScalarAccess, Inst));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2895,24 +2880,24 @@ bool ScopInfo::buildScalarDependences(Instruction *Inst, Region *R,
|
||||||
|
|
||||||
extern MapInsnToMemAcc InsnToMemAcc;
|
extern MapInsnToMemAcc InsnToMemAcc;
|
||||||
|
|
||||||
IRAccess
|
void ScopInfo::buildMemoryAccess(
|
||||||
ScopInfo::buildIRAccess(Instruction *Inst, Loop *L, Region *R,
|
Instruction *Inst, Loop *L, Region *R,
|
||||||
const ScopDetection::BoxedLoopsSetTy *BoxedLoops) {
|
const ScopDetection::BoxedLoopsSetTy *BoxedLoops) {
|
||||||
unsigned Size;
|
unsigned Size;
|
||||||
Type *SizeType;
|
Type *SizeType;
|
||||||
Value *Val;
|
Value *Val;
|
||||||
enum IRAccess::TypeKind Type;
|
enum MemoryAccess::AccessType Type;
|
||||||
|
|
||||||
if (LoadInst *Load = dyn_cast<LoadInst>(Inst)) {
|
if (LoadInst *Load = dyn_cast<LoadInst>(Inst)) {
|
||||||
SizeType = Load->getType();
|
SizeType = Load->getType();
|
||||||
Size = TD->getTypeStoreSize(SizeType);
|
Size = TD->getTypeStoreSize(SizeType);
|
||||||
Type = IRAccess::READ;
|
Type = MemoryAccess::READ;
|
||||||
Val = Load;
|
Val = Load;
|
||||||
} else {
|
} else {
|
||||||
StoreInst *Store = cast<StoreInst>(Inst);
|
StoreInst *Store = cast<StoreInst>(Inst);
|
||||||
SizeType = Store->getValueOperand()->getType();
|
SizeType = Store->getValueOperand()->getType();
|
||||||
Size = TD->getTypeStoreSize(SizeType);
|
Size = TD->getTypeStoreSize(SizeType);
|
||||||
Type = IRAccess::MUST_WRITE;
|
Type = MemoryAccess::MUST_WRITE;
|
||||||
Val = Store->getValueOperand();
|
Val = Store->getValueOperand();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2957,17 +2942,20 @@ ScopInfo::buildIRAccess(Instruction *Inst, Loop *L, Region *R,
|
||||||
SizesSCEV.push_back(SE->getSCEV(ConstantInt::get(
|
SizesSCEV.push_back(SE->getSCEV(ConstantInt::get(
|
||||||
IntegerType::getInt64Ty(BasePtr->getContext()), Size)));
|
IntegerType::getInt64Ty(BasePtr->getContext()), Size)));
|
||||||
|
|
||||||
return IRAccess(Type, BasePointer->getValue(), AccessFunction, Size,
|
addMemoryAccess(Inst->getParent(), Inst, Type, BasePointer->getValue(),
|
||||||
true, Subscripts, SizesSCEV, Val);
|
AccessFunction, Size, true, Subscripts, SizesSCEV, Val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto AccItr = InsnToMemAcc.find(Inst);
|
auto AccItr = InsnToMemAcc.find(Inst);
|
||||||
if (PollyDelinearize && AccItr != InsnToMemAcc.end())
|
if (PollyDelinearize && AccItr != InsnToMemAcc.end()) {
|
||||||
return IRAccess(Type, BasePointer->getValue(), AccessFunction, Size, true,
|
addMemoryAccess(Inst->getParent(), Inst, Type, BasePointer->getValue(),
|
||||||
|
AccessFunction, Size, true,
|
||||||
AccItr->second.DelinearizedSubscripts,
|
AccItr->second.DelinearizedSubscripts,
|
||||||
AccItr->second.Shape->DelinearizedSizes, Val);
|
AccItr->second.Shape->DelinearizedSizes, Val);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the access depends on a loop contained in a non-affine subregion.
|
// Check if the access depends on a loop contained in a non-affine subregion.
|
||||||
bool isVariantInNonAffineLoop = false;
|
bool isVariantInNonAffineLoop = false;
|
||||||
|
|
@ -2986,11 +2974,11 @@ ScopInfo::buildIRAccess(Instruction *Inst, Loop *L, Region *R,
|
||||||
Subscripts.push_back(AccessFunction);
|
Subscripts.push_back(AccessFunction);
|
||||||
Sizes.push_back(SE->getConstant(ZeroOffset->getType(), Size));
|
Sizes.push_back(SE->getConstant(ZeroOffset->getType(), Size));
|
||||||
|
|
||||||
if (!IsAffine && Type == IRAccess::MUST_WRITE)
|
if (!IsAffine && Type == MemoryAccess::MUST_WRITE)
|
||||||
Type = IRAccess::MAY_WRITE;
|
Type = MemoryAccess::MAY_WRITE;
|
||||||
|
|
||||||
return IRAccess(Type, BasePointer->getValue(), AccessFunction, Size, IsAffine,
|
addMemoryAccess(Inst->getParent(), Inst, Type, BasePointer->getValue(),
|
||||||
Subscripts, Sizes, Val);
|
AccessFunction, Size, IsAffine, Subscripts, Sizes, Val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScopInfo::buildAccessFunctions(Region &R, Region &SR) {
|
void ScopInfo::buildAccessFunctions(Region &R, Region &SR) {
|
||||||
|
|
@ -3011,7 +2999,6 @@ void ScopInfo::buildAccessFunctions(Region &R, Region &SR) {
|
||||||
void ScopInfo::buildAccessFunctions(Region &R, BasicBlock &BB,
|
void ScopInfo::buildAccessFunctions(Region &R, BasicBlock &BB,
|
||||||
Region *NonAffineSubRegion,
|
Region *NonAffineSubRegion,
|
||||||
bool IsExitBlock) {
|
bool IsExitBlock) {
|
||||||
AccFuncSetType Functions;
|
|
||||||
Loop *L = LI->getLoopFor(&BB);
|
Loop *L = LI->getLoopFor(&BB);
|
||||||
|
|
||||||
// The set of loops contained in non-affine subregions that are part of R.
|
// The set of loops contained in non-affine subregions that are part of R.
|
||||||
|
|
@ -3022,35 +3009,42 @@ void ScopInfo::buildAccessFunctions(Region &R, BasicBlock &BB,
|
||||||
|
|
||||||
PHINode *PHI = dyn_cast<PHINode>(Inst);
|
PHINode *PHI = dyn_cast<PHINode>(Inst);
|
||||||
if (PHI)
|
if (PHI)
|
||||||
buildPHIAccesses(PHI, R, Functions, NonAffineSubRegion, IsExitBlock);
|
buildPHIAccesses(PHI, R, NonAffineSubRegion, IsExitBlock);
|
||||||
|
|
||||||
// For the exit block we stop modeling after the last PHI node.
|
// For the exit block we stop modeling after the last PHI node.
|
||||||
if (!PHI && IsExitBlock)
|
if (!PHI && IsExitBlock)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst))
|
if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst))
|
||||||
Functions.push_back(
|
buildMemoryAccess(Inst, L, &R, BoxedLoops);
|
||||||
std::make_pair(buildIRAccess(Inst, L, &R, BoxedLoops), Inst));
|
|
||||||
|
|
||||||
if (isIgnoredIntrinsic(Inst))
|
if (isIgnoredIntrinsic(Inst))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (buildScalarDependences(Inst, &R, NonAffineSubRegion)) {
|
if (buildScalarDependences(Inst, &R, NonAffineSubRegion)) {
|
||||||
// If the Instruction is used outside the statement, we need to build the
|
if (!isa<StoreInst>(Inst))
|
||||||
// write access.
|
addMemoryAccess(&BB, Inst, MemoryAccess::MUST_WRITE, Inst, ZeroOffset,
|
||||||
if (!isa<StoreInst>(Inst)) {
|
1, true, Inst);
|
||||||
IRAccess ScalarAccess(IRAccess::MUST_WRITE, Inst, ZeroOffset, 1, true,
|
|
||||||
Inst);
|
|
||||||
Functions.push_back(std::make_pair(ScalarAccess, Inst));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Functions.empty())
|
void ScopInfo::addMemoryAccess(
|
||||||
return;
|
BasicBlock *BB, Instruction *Inst, MemoryAccess::AccessType Type,
|
||||||
|
Value *BaseAddress, const SCEV *Offset, unsigned ElemBytes, bool Affine,
|
||||||
|
Value *AccessValue, ArrayRef<const SCEV *> Subscripts,
|
||||||
|
ArrayRef<const SCEV *> Sizes, bool IsPHI = false) {
|
||||||
|
AccFuncSetType &AccList = AccFuncMap[BB];
|
||||||
|
size_t Identifier = AccList.size();
|
||||||
|
|
||||||
AccFuncSetType &Accs = AccFuncMap[&BB];
|
Value *BaseAddr = BaseAddress;
|
||||||
Accs.insert(Accs.end(), Functions.begin(), Functions.end());
|
std::string BaseName = getIslCompatibleName("MemRef_", BaseAddr, "");
|
||||||
|
|
||||||
|
std::string IdName = "__polly_array_ref_" + std::to_string(Identifier);
|
||||||
|
isl_id *Id = isl_id_alloc(ctx, IdName.c_str(), nullptr);
|
||||||
|
|
||||||
|
AccList.emplace_back(Inst, Id, Type, BaseAddress, Offset, ElemBytes, Affine,
|
||||||
|
Subscripts, Sizes, AccessValue, IsPHI, BaseName);
|
||||||
}
|
}
|
||||||
|
|
||||||
Scop *ScopInfo::buildScop(Region &R, DominatorTree &DT) {
|
Scop *ScopInfo::buildScop(Region &R, DominatorTree &DT) {
|
||||||
|
|
|
||||||
|
|
@ -406,12 +406,12 @@ void BlockGenerator::generateScalarLoads(ScopStmt &Stmt,
|
||||||
if (!MAL)
|
if (!MAL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (MemoryAccess &MA : *MAL) {
|
for (MemoryAccess *MA : *MAL) {
|
||||||
if (!MA.isScalar() || !MA.isRead())
|
if (!MA->isScalar() || !MA->isRead())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto *Address = getOrCreateAlloca(MA);
|
auto *Address = getOrCreateAlloca(*MA);
|
||||||
BBMap[MA.getBaseAddr()] =
|
BBMap[MA->getBaseAddr()] =
|
||||||
Builder.CreateLoad(Address, Address->getName() + ".reload");
|
Builder.CreateLoad(Address, Address->getName() + ".reload");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,8 +73,8 @@ do.end45: ; preds = %do.cond42
|
||||||
|
|
||||||
|
|
||||||
; MEMORY: RAW dependences:
|
; MEMORY: RAW dependences:
|
||||||
; MEMORY: { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, o2] : i0 <= 35 and i0 >= 0 and i1 <= 35 and i1 >= 0 and i2 >= 0 and o2 >= 1 + i2 and o2 <= 35 and o2 >= 0 }
|
; MEMORY: { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, o2] : i0 <= 35 and i0 >= 0 and i1 <= 35 and i1 >= 0 and i2 >= 0 and o2 >= 1 + i2 and o2 <= 35 }
|
||||||
; MEMORY: WAR dependences:
|
; MEMORY: WAR dependences:
|
||||||
; MEMORY: { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, o2] : i0 <= 35 and i0 >= 0 and i1 <= 35 and i1 >= 0 and i2 >= 0 and o2 >= 1 + i2 and o2 <= 35 and o2 >= 0 }
|
; MEMORY: { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, o2] : i0 <= 35 and i0 >= 0 and i1 <= 35 and i1 >= 0 and i2 >= 0 and o2 >= 1 + i2 and o2 <= 35 }
|
||||||
; MEMORY: WAW dependences:
|
; MEMORY: WAW dependences:
|
||||||
; MEMORY: { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, o2] : i0 <= 35 and i0 >= 0 and i1 <= 35 and i1 >= 0 and i2 >= 0 and o2 >= 1 + i2 and o2 <= 35 and o2 >= 0 }
|
; MEMORY: { Stmt_do_body2[i0, i1, i2] -> Stmt_do_body2[i0, i1, o2] : i0 <= 35 and i0 >= 0 and i1 <= 35 and i1 >= 0 and i2 >= 0 and o2 >= 1 + i2 and o2 <= 35 }
|
||||||
|
|
|
||||||
|
|
@ -53,10 +53,10 @@ bb2: ; preds = %bb, %entry
|
||||||
; CHECK: [n] -> { Stmt_bb[i0] -> [i0] };
|
; CHECK: [n] -> { Stmt_bb[i0] -> [i0] };
|
||||||
; CHECK: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1]
|
; CHECK: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1]
|
||||||
; CHECK: [n] -> { Stmt_bb[i0] -> MemRef_1__phi[] };
|
; CHECK: [n] -> { Stmt_bb[i0] -> MemRef_1__phi[] };
|
||||||
; CHECK: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1]
|
|
||||||
; CHECK: [n] -> { Stmt_bb[i0] -> MemRef_k_05__phi[] };
|
|
||||||
; CHECK: ReadAccess := [Reduction Type: NONE] [Scalar: 1]
|
; CHECK: ReadAccess := [Reduction Type: NONE] [Scalar: 1]
|
||||||
; CHECK: [n] -> { Stmt_bb[i0] -> MemRef_1__phi[] };
|
; CHECK: [n] -> { Stmt_bb[i0] -> MemRef_1__phi[] };
|
||||||
|
; CHECK: MustWriteAccess := [Reduction Type: NONE] [Scalar: 1]
|
||||||
|
; CHECK: [n] -> { Stmt_bb[i0] -> MemRef_k_05__phi[] };
|
||||||
; CHECK: ReadAccess := [Reduction Type: NONE] [Scalar: 1]
|
; CHECK: ReadAccess := [Reduction Type: NONE] [Scalar: 1]
|
||||||
; CHECK: [n] -> { Stmt_bb[i0] -> MemRef_k_05__phi[] };
|
; CHECK: [n] -> { Stmt_bb[i0] -> MemRef_k_05__phi[] };
|
||||||
; CHECK: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0]
|
; CHECK: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue