blob: 3d7ff725e0ee5cc84b912e38f40dfd196536cbea [file] [log] [blame]
//===------ polly/ScopInfo.h - Create Scops from LLVM IR --------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Create a polyhedral description for a static control flow region.
//
// The pass creates a polyhedral description of the Scops detected by the Scop
// detection derived from their LLVM-IR code.
//
// This represantation is shared among several tools in the polyhedral
// community, which are e.g. CLooG, Pluto, Loopo, Graphite.
//
//===----------------------------------------------------------------------===//
#ifndef POLLY_SCOP_INFO_H
#define POLLY_SCOP_INFO_H
#include "polly/ScopDetection.h"
#include "llvm/Analysis/RegionPass.h"
#include "isl/ctx.h"
using namespace llvm;
namespace llvm {
class Loop;
class LoopInfo;
class PHINode;
class ScalarEvolution;
class SCEV;
class SCEVAddRecExpr;
class Type;
}
struct isl_ctx;
struct isl_map;
struct isl_basic_map;
struct isl_id;
struct isl_set;
struct isl_union_set;
struct isl_space;
struct isl_constraint;
namespace polly {
class IRAccess;
class Scop;
class ScopStmt;
class ScopInfo;
class TempScop;
class SCEVAffFunc;
class Comparison;
//===----------------------------------------------------------------------===//
/// @brief Represent memory accesses in statements.
class MemoryAccess {
// DO NOT IMPLEMENT
MemoryAccess(const MemoryAccess &);
// DO NOT IMPLEMENT
const MemoryAccess &operator=(const MemoryAccess &);
public:
/// @brief The access type of a memory access
///
/// There are three kind of access types:
///
/// * A read access
///
/// A certain set of memory locations are read and may be used for internal
/// calculations.
///
/// * A write access
///
/// A certain set of memory locactions is definitely written. The old value is
/// replaced by a newly calculated value. The old value is not read or used at
/// all.
///
/// * A may write access
///
/// A certain set of memory locactions may be written. The memory location may
/// contain a new value if there is actually a write or the old value may
/// remain, if no write happens.
enum AccessType {
Read,
Write,
MayWrite
};
private:
isl_map *AccessRelation;
enum AccessType Type;
const Value* BaseAddr;
std::string BaseName;
isl_basic_map *createBasicAccessMap(ScopStmt *Statement);
void setBaseName();
ScopStmt *statement;
/// Updated access relation read from JSCOP file.
isl_map *newAccessRelation;
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.
MemoryAccess(const IRAccess &Access, ScopStmt *Statement);
// @brief Create a memory access that reads a complete memory object.
//
// @param BaseAddress The base address of the memory object.
// @param Statement The statement that contains this access.
MemoryAccess(const Value *BaseAddress, ScopStmt *Statement);
~MemoryAccess();
/// @brief Is this a read memory access?
bool isRead() const { return Type == MemoryAccess::Read; }
isl_map *getAccessRelation() const;
/// @brief Get an isl string representing this access function.
std::string getAccessRelationStr() const;
const Value *getBaseAddr() const {
return BaseAddr;
}
const std::string &getBaseName() const {
return BaseName;
}
/// @brief Get the new access function imported from JSCOP file
isl_map *getNewAccessRelation() const;
/// @brief Get the stride of this memory access in the specified domain
/// subset.
isl_set *getStride(__isl_take const isl_set *domainSubset) const;
/// @brief Is the stride of the access equal to a certain width.
bool isStrideX(__isl_take const isl_set *DomainSubset, int StrideWidth) const;
/// @brief Is consecutive memory accessed for a given
/// statement instance set?
bool isStrideOne(__isl_take const isl_set *domainSubset) const;
/// @brief Is always the same memory accessed for a given
/// statement instance set?
bool isStrideZero(__isl_take const isl_set *domainSubset) const;
/// @brief Get the statement that contains this memory access.
ScopStmt *getStatement() const { return statement; }
/// @brief Set the updated access relation read from JSCOP file.
void setNewAccessRelation(isl_map *newAccessRelation);
/// @brief Align the parameters in the access relation to the scop context
void realignParams();
/// @brief Print the MemoryAccess.
///
/// @param OS The output stream the MemoryAccess is printed to.
void print(raw_ostream &OS) const;
/// @brief Print the MemoryAccess to stderr.
void dump() const;
};
//===----------------------------------------------------------------------===//
/// @brief Statement of the Scop
///
/// A Scop statement represents an instruction in the Scop.
///
/// It is further described by its iteration domain, its schedule and its data
/// accesses.
/// At the moment every statement represents a single basic block of LLVM-IR.
class ScopStmt {
//===-------------------------------------------------------------------===//
// DO NOT IMPLEMENT
ScopStmt(const ScopStmt &);
// DO NOT IMPLEMENT
const ScopStmt &operator=(const ScopStmt &);
/// Polyhedral description
//@{
/// The Scop containing this ScopStmt
Scop &Parent;
/// The iteration domain describes the set of iterations for which this
/// statement is executed.
///
/// Example:
/// for (i = 0; i < 100 + b; ++i)
/// for (j = 0; j < i; ++j)
/// S(i,j);
///
/// 'S' is executed for different values of i and j. A vector of all
/// induction variables around S (i, j) is called iteration vector.
/// The domain describes the set of possible iteration vectors.
///
/// In this case it is:
///
/// Domain: 0 <= i <= 100 + b
/// 0 <= j <= i
///
/// A pair of statment and iteration vector (S, (5,3)) is called statment
/// instance.
isl_set *Domain;
/// The scattering map describes the execution order of the statement
/// instances.
///
/// A statement and its iteration domain do not give any information about the
/// order in time in which the different statement instances are executed.
/// This information is provided by the scattering.
///
/// The scattering maps every instance of each statement into a multi
/// dimensional scattering space. This space can be seen as a multi
/// dimensional clock.
///
/// Example:
///
/// <S,(5,4)> may be mapped to (5,4) by this scattering:
///
/// s0 = i (Year of execution)
/// s1 = j (Day of execution)
///
/// or to (9, 20) by this scattering:
///
/// s0 = i + j (Year of execution)
/// s1 = 20 (Day of execution)
///
/// The order statement instances are executed is defined by the
/// scattering vectors they are mapped to. A statement instance
/// <A, (i, j, ..)> is executed before a statement instance <B, (i', ..)>, if
/// the scattering vector of A is lexicographic smaller than the scattering
/// vector of B.
isl_map *Scattering;
/// The memory accesses of this statement.
///
/// The only side effects of a statement are its memory accesses.
typedef SmallVector<MemoryAccess*, 8> MemoryAccessVec;
MemoryAccessVec MemAccs;
std::map<const Instruction*, MemoryAccess*> InstructionToAccess;
//@}
/// The BasicBlock represented by this statement.
BasicBlock *BB;
/// @brief The loop induction variables surrounding the statement.
///
/// This information is only needed for final code generation.
std::vector<std::pair<PHINode*, Loop*> > IVS;
std::string BaseName;
/// Build the statment.
//@{
__isl_give isl_set *buildConditionSet(const Comparison &Cmp);
__isl_give isl_set *addConditionsToDomain(__isl_take isl_set *Domain,
TempScop &tempScop,
const Region &CurRegion);
__isl_give isl_set *addLoopBoundsToDomain(__isl_take isl_set *Domain,
TempScop &tempScop);
__isl_give isl_set *buildDomain(TempScop &tempScop,
const Region &CurRegion);
void buildScattering(SmallVectorImpl<unsigned> &Scatter);
void buildAccesses(TempScop &tempScop, const Region &CurRegion);
//@}
/// Create the ScopStmt from a BasicBlock.
ScopStmt(Scop &parent, TempScop &tempScop, const Region &CurRegion,
BasicBlock &bb, SmallVectorImpl<Loop*> &NestLoops,
SmallVectorImpl<unsigned> &Scatter);
friend class Scop;
public:
~ScopStmt();
/// @brief Get an isl_ctx pointer.
isl_ctx *getIslCtx() const;
/// @brief Get the iteration domain of this ScopStmt.
///
/// @return The iteration domain of this ScopStmt.
isl_set *getDomain() const;
/// @brief Get the space of the iteration domain
///
/// @return The space of the iteration domain
isl_space *getDomainSpace() const;
/// @brief Get an isl string representing this domain.
std::string getDomainStr() const;
/// @brief Get the scattering function of this ScopStmt.
///
/// @return The scattering function of this ScopStmt.
isl_map *getScattering() const;
void setScattering(isl_map *scattering);
/// @brief Get an isl string representing this scattering.
std::string getScatteringStr() const;
/// @brief Get the BasicBlock represented by this ScopStmt.
///
/// @return The BasicBlock represented by this ScopStmt.
BasicBlock *getBasicBlock() const { return BB; }
MemoryAccess &getAccessFor(const Instruction *Inst) {
return *InstructionToAccess[Inst];
}
void setBasicBlock(BasicBlock *Block) { BB = Block; }
typedef MemoryAccessVec::iterator memacc_iterator;
memacc_iterator memacc_begin() { return MemAccs.begin(); }
memacc_iterator memacc_end() { return MemAccs.end(); }
unsigned getNumParams() const;
unsigned getNumIterators() const;
unsigned getNumScattering() const;
Scop *getParent() { return &Parent; }
const Scop *getParent() const { return &Parent; }
const char *getBaseName() const;
/// @brief Get the induction variable for a dimension.
///
/// @param Dimension The dimension of the induction variable
/// @return The induction variable at a certain dimension.
const PHINode *getInductionVariableForDimension(unsigned Dimension) const;
/// @brief Get the loop for a dimension.
///
/// @param Dimension The dimension of the induction variable
/// @return The loop at a certain dimension.
const Loop *getLoopForDimension(unsigned Dimension) const;
/// @brief Return the SCEV for a loop dimension.
const SCEVAddRecExpr *getSCEVForDimension(unsigned Dimension) const;
/// @brief Align the parameters in the statement to the scop context
void realignParams();
/// @brief Print the ScopStmt.
///
/// @param OS The output stream the ScopStmt is printed to.
void print(raw_ostream &OS) const;
/// @brief Print the ScopStmt to stderr.
void dump() const;
};
/// @brief Print ScopStmt S to raw_ostream O.
static inline raw_ostream& operator<<(raw_ostream &O, const ScopStmt &S) {
S.print(O);
return O;
}
//===----------------------------------------------------------------------===//
/// @brief Static Control Part
///
/// A Scop is the polyhedral representation of a control flow region detected
/// by the Scop detection. It is generated by translating the LLVM-IR and
/// abstracting its effects.
///
/// A Scop consists of a set of:
///
/// * A set of statements executed in the Scop.
///
/// * A set of global parameters
/// Those parameters are scalar integer values, which are constant during
/// execution.
///
/// * A context
/// This context contains information about the values the parameters
/// can take and relations between different parameters.
class Scop {
//===-------------------------------------------------------------------===//
// DO NOT IMPLEMENT
Scop(const Scop &);
// DO NOT IMPLEMENT
const Scop &operator=(const Scop &);
ScalarEvolution *SE;
/// The underlying Region.
Region &R;
/// Max loop depth.
unsigned MaxLoopDepth;
typedef std::vector<ScopStmt*> StmtSet;
/// The Statments in this Scop.
StmtSet Stmts;
/// Parameters of this Scop
typedef SmallVector<const SCEV*, 8> ParamVecType;
ParamVecType Parameters;
/// The isl_ids that are used to represent the parameters
typedef std::map<const SCEV*, int> ParamIdType;
ParamIdType ParameterIds;
// Isl context.
isl_ctx *IslCtx;
/// Constraints on parameters.
isl_set *Context;
/// Create the static control part with a region, max loop depth of this
/// region and parameters used in this region.
Scop(TempScop &TempScop, LoopInfo &LI, ScalarEvolution &SE, isl_ctx *ctx);
/// @brief Check if a basic block is trivial.
///
/// A trivial basic block does not contain any useful calculation. Therefore,
/// it does not need to be represented as a polyhedral statement.
///
/// @param BB The basic block to check
/// @param tempScop TempScop returning further information regarding the Scop.
///
/// @return True if the basic block is trivial, otherwise false.
static bool isTrivialBB(BasicBlock *BB, TempScop &tempScop);
/// @brief Build the Context of the Scop.
void buildContext();
/// Build the Scop and Statement with precalculate scop information.
void buildScop(TempScop &TempScop, const Region &CurRegion,
// Loops in Scop containing CurRegion
SmallVectorImpl<Loop*> &NestLoops,
// The scattering numbers
SmallVectorImpl<unsigned> &Scatter,
LoopInfo &LI);
/// Helper function for printing the Scop.
void printContext(raw_ostream &OS) const;
void printStatements(raw_ostream &OS) const;
friend class ScopInfo;
public:
~Scop();
ScalarEvolution *getSE() const;
/// @brief Get the count of parameters used in this Scop.
///
/// @return The count of parameters used in this Scop.
inline ParamVecType::size_type getNumParams() const {
return Parameters.size();
}
/// @brief Get a set containing the parameters used in this Scop
///
/// @return The set containing the parameters used in this Scop.
inline const ParamVecType &getParams() const { return Parameters; }
/// @brief Take a list of parameters and add the new ones to the scop.
void addParams(std::vector<const SCEV*> NewParameters);
/// @brief Return the isl_id that represents a certain parameter.
///
/// @param Parameter A SCEV that was recognized as a Parameter.
///
/// @return The corresponding isl_id or NULL otherwise.
isl_id *getIdForParam(const SCEV *Parameter) const;
/// @name Parameter Iterators
///
/// These iterators iterate over all parameters of this Scop.
//@{
typedef ParamVecType::iterator param_iterator;
typedef ParamVecType::const_iterator const_param_iterator;
param_iterator param_begin() { return Parameters.begin(); }
param_iterator param_end() { return Parameters.end(); }
const_param_iterator param_begin() const { return Parameters.begin(); }
const_param_iterator param_end() const { return Parameters.end(); }
//@}
/// @brief Get the maximum region of this static control part.
///
/// @return The maximum region of this static control part.
inline const Region &getRegion() const { return R; }
inline Region &getRegion() { return R; }
/// @brief Get the maximum depth of the loop.
///
/// @return The maximum depth of the loop.
inline unsigned getMaxLoopDepth() const { return MaxLoopDepth; }
/// @brief Get the scattering dimension number of this Scop.
///
/// @return The scattering dimension number of this Scop.
inline unsigned getScatterDim() const {
unsigned maxScatterDim = 0;
for (const_iterator SI = begin(), SE = end(); SI != SE; ++SI)
maxScatterDim = std::max(maxScatterDim, (*SI)->getNumScattering());
return maxScatterDim;
}
/// @brief Get the name of this Scop.
std::string getNameStr() const;
/// @brief Get the constraint on parameter of this Scop.
///
/// @return The constraint on parameter of this Scop.
__isl_give isl_set *getContext() const;
__isl_give isl_space *getParamSpace() const;
/// @brief Get an isl string representing the context.
std::string getContextStr() const;
/// @name Statements Iterators
///
/// These iterators iterate over all statements of this Scop.
//@{
typedef StmtSet::iterator iterator;
typedef StmtSet::const_iterator const_iterator;
iterator begin() { return Stmts.begin(); }
iterator end() { return Stmts.end(); }
const_iterator begin() const { return Stmts.begin(); }
const_iterator end() const { return Stmts.end(); }
typedef StmtSet::reverse_iterator reverse_iterator;
typedef StmtSet::const_reverse_iterator const_reverse_iterator;
reverse_iterator rbegin() { return Stmts.rbegin(); }
reverse_iterator rend() { return Stmts.rend(); }
const_reverse_iterator rbegin() const { return Stmts.rbegin(); }
const_reverse_iterator rend() const { return Stmts.rend(); }
//@}
void setContext(isl_set* NewContext);
/// @brief Align the parameters in the statement to the scop context
void realignParams();
/// @brief Print the static control part.
///
/// @param OS The output stream the static control part is printed to.
void print(raw_ostream &OS) const;
/// @brief Print the ScopStmt to stderr.
void dump() const;
/// @brief Get the isl context of this static control part.
///
/// @return The isl context of this static control part.
isl_ctx *getIslCtx() const;
/// @brief Get a union set containing the iteration domains of all statements.
__isl_give isl_union_set *getDomains();
};
/// @brief Print Scop scop to raw_ostream O.
static inline raw_ostream& operator<<(raw_ostream &O, const Scop &scop) {
scop.print(O);
return O;
}
//===---------------------------------------------------------------------===//
/// @brief Build the Polly IR (Scop and ScopStmt) on a Region.
///
class ScopInfo : public RegionPass {
//===-------------------------------------------------------------------===//
// DO NOT IMPLEMENT
ScopInfo(const ScopInfo &);
// DO NOT IMPLEMENT
const ScopInfo &operator=(const ScopInfo &);
// The Scop
Scop *scop;
isl_ctx *ctx;
void clear() {
if (scop) {
delete scop;
scop = 0;
}
}
public:
static char ID;
explicit ScopInfo();
~ScopInfo();
/// @brief Try to build the Polly IR of static control part on the current
/// SESE-Region.
///
/// @return If the current region is a valid for a static control part,
/// return the Polly IR representing this static control part,
/// return null otherwise.
Scop *getScop() { return scop; }
const Scop *getScop() const { return scop; }
/// @name RegionPass interface
//@{
virtual bool runOnRegion(Region *R, RGPassManager &RGM);
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
virtual void releaseMemory() { clear(); }
virtual void print(raw_ostream &OS, const Module *) const {
if (scop)
scop->print(OS);
else
OS << "Invalid Scop!\n";
}
//@}
};
} //end namespace polly
namespace llvm {
class PassRegistry;
void initializeScopInfoPass(llvm::PassRegistry&);
}
#endif