Merge TempScopInfo.{cpp|h} into ScopInfo.{cpp|h}

This prepares for a series of patches that merges TempScopInfo into ScopInfo to
reduce Polly's code complexity. Only ScopInfo.{cpp|h} will be left thereafter.
Moving the code of TempScopInfo in one commit makes the mains diffs simpler to
understand.

In detail, merging the following classes is planned:
TempScopInfo into ScopInfo
TempScop into Scop
IRAccess into MemoryAccess

Only moving code, no functional changes intended.

Differential Version: http://reviews.llvm.org/D12693

llvm-svn: 247274
This commit is contained in:
Michael Kruse 2015-09-10 12:46:52 +00:00
parent 6a43c00ebd
commit 7bf3944d23
8 changed files with 662 additions and 741 deletions

View File

@ -67,6 +67,36 @@ class TempScop;
class Comparison;
class SCEVAffFunc;
class Comparison {
const SCEV *LHS;
const SCEV *RHS;
ICmpInst::Predicate Pred;
public:
Comparison(const SCEV *LHS, const SCEV *RHS, ICmpInst::Predicate Pred)
: LHS(LHS), RHS(RHS), Pred(Pred) {}
const SCEV *getLHS() const { return LHS; }
const SCEV *getRHS() const { return RHS; }
ICmpInst::Predicate getPred() const { return Pred; }
void print(raw_ostream &OS) const;
};
//===---------------------------------------------------------------------===//
/// Maps from a loop to the affine function expressing its backedge taken count.
/// The backedge taken count already enough to express iteration domain as we
/// only allow loops with canonical induction variable.
/// A canonical induction variable is:
/// an integer recurrence that starts at 0 and increments by one each time
/// through the loop.
typedef std::map<const Loop *, const SCEV *> LoopBoundMapType;
typedef std::vector<std::pair<IRAccess, Instruction *>> AccFuncSetType;
typedef std::map<const BasicBlock *, AccFuncSetType> AccFuncMapType;
/// @brief A class to store information about arrays in the SCoP.
///
/// Objects are accessible via the ScoP, MemoryAccess or the id associated with
@ -184,6 +214,78 @@ private:
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,
SmallVector<const SCEV *, 4> Subscripts,
SmallVector<const SCEV *, 4> Sizes, Value *AccessValue)
: BaseAddress(BaseAddress), AccessValue(AccessValue), Offset(Offset),
ElemBytes(elemBytes), Type(Type), IsAffine(Affine), IsPHI(false),
Subscripts(Subscripts), Sizes(Sizes) {}
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.
class MemoryAccess {
public:
@ -1275,6 +1377,171 @@ static inline raw_ostream &operator<<(raw_ostream &O, const Scop &scop) {
return O;
}
//===---------------------------------------------------------------------===//
/// @brief Scop represent with llvm objects.
///
/// A helper class for remembering the parameter number and the max depth in
/// this Scop, and others context.
class TempScop {
// The Region.
Region &R;
// Access function of bbs.
AccFuncMapType &AccFuncMap;
friend class TempScopInfo;
explicit TempScop(Region &r, AccFuncMapType &accFuncMap)
: R(r), AccFuncMap(accFuncMap) {}
public:
~TempScop();
/// @brief Get the maximum Region contained by this Scop.
///
/// @return The maximum Region contained by this Scop.
Region &getMaxRegion() const { return R; }
/// @brief Get all access functions in a BasicBlock
///
/// @param BB The BasicBlock that containing the access functions.
///
/// @return All access functions in BB
///
AccFuncSetType *getAccessFunctions(const BasicBlock *BB) {
AccFuncMapType::iterator at = AccFuncMap.find(BB);
return at != AccFuncMap.end() ? &(at->second) : 0;
}
//@}
/// @brief Print the Temporary Scop information.
///
/// @param OS The output stream the access functions is printed to.
/// @param SE The ScalarEvolution that help printing Temporary Scop
/// information.
/// @param LI The LoopInfo that help printing the access functions.
void print(raw_ostream &OS, ScalarEvolution *SE, LoopInfo *LI) const;
/// @brief Print the access functions and loop bounds in this Scop.
///
/// @param OS The output stream the access functions is printed to.
/// @param SE The ScalarEvolution that help printing the access functions.
/// @param LI The LoopInfo that help printing the access functions.
void printDetail(raw_ostream &OS, ScalarEvolution *SE, LoopInfo *LI,
const Region *Reg, unsigned ind) const;
};
typedef std::map<const Region *, TempScop *> TempScopMapType;
//===----------------------------------------------------------------------===//
/// @brief The Function Pass to extract temporary information for Static control
/// part in llvm function.
///
class TempScopInfo : public RegionPass {
//===-------------------------------------------------------------------===//
TempScopInfo(const TempScopInfo &) = delete;
const TempScopInfo &operator=(const TempScopInfo &) = delete;
// The ScalarEvolution to help building Scop.
ScalarEvolution *SE;
// LoopInfo for information about loops
LoopInfo *LI;
// The AliasAnalysis to build AliasSetTracker.
AliasAnalysis *AA;
// Valid Regions for Scop
ScopDetection *SD;
// Target data for element size computing.
const DataLayout *TD;
// Access function of statements (currently BasicBlocks) .
AccFuncMapType AccFuncMap;
// Pre-created zero for the scalar accesses, with it we do not need create a
// zero scev every time when we need it.
const SCEV *ZeroOffset;
// The TempScop for this region.
TempScop *TempScopOfRegion;
// Clear the context.
void clear();
// Build the temprory information of Region R, where R must be a valid part
// of Scop.
TempScop *buildTempScop(Region &R);
/// @brief Build an instance of IRAccess from the Load/Store instruction.
///
/// @param Inst The Load/Store instruction that access the memory
/// @param L The parent loop of the instruction
/// @param R The region on which we are going to build a TempScop
/// @param BoxedLoops The set of loops that are overapproximated in @p R.
///
/// @return The IRAccess to describe the access function of the
/// instruction.
IRAccess buildIRAccess(Instruction *Inst, Loop *L, Region *R,
const ScopDetection::BoxedLoopsSetTy *BoxedLoops);
/// @brief Analyze and extract the cross-BB scalar dependences (or,
/// dataflow dependencies) of an instruction.
///
/// @param Inst The instruction to be analyzed
/// @param R The SCoP region
/// @param NonAffineSubRegion The non affine sub-region @p Inst is in.
///
/// @return True if the Instruction is used in other BB and a scalar write
/// Access is required.
bool buildScalarDependences(Instruction *Inst, Region *R,
Region *NonAffineSubRegio);
/// @brief Create IRAccesses for the given PHI node in the given region.
///
/// @param PHI The PHI node to be handled
/// @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 IsExitBlock Flag to indicate that @p PHI is in the exit BB.
void buildPHIAccesses(PHINode *PHI, Region &R, AccFuncSetType &Functions,
Region *NonAffineSubRegion, bool IsExitBlock = false);
/// @brief Build the access functions for the subregion @p SR.
///
/// @param R The SCoP region.
/// @param SR A subregion of @p R.
void buildAccessFunctions(Region &R, Region &SR);
/// @brief Build the access functions for the basic block @p BB
///
/// @param R The SCoP region.
/// @param BB A basic block in @p R.
/// @param NonAffineSubRegion The non affine sub-region @p BB is in.
/// @param IsExitBlock Flag to indicate that @p BB is in the exit BB.
void buildAccessFunctions(Region &R, BasicBlock &BB,
Region *NonAffineSubRegion = nullptr,
bool IsExitBlock = false);
public:
static char ID;
explicit TempScopInfo() : RegionPass(ID), TempScopOfRegion(nullptr) {}
~TempScopInfo();
/// @brief Get the temporay Scop information in LLVM IR for this region.
///
/// @return The Scop information in LLVM IR represent.
TempScop *getTempScop() const;
/// @name RegionPass interface
//@{
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
virtual void releaseMemory() { clear(); }
virtual bool runOnRegion(Region *R, RGPassManager &RGM);
virtual void print(raw_ostream &OS, const Module *) const;
//@}
};
///===---------------------------------------------------------------------===//
/// @brief Build the Polly IR (Scop and ScopStmt) on a Region.
///
@ -1326,6 +1593,7 @@ public:
namespace llvm {
class PassRegistry;
void initializeTempScopInfoPass(llvm::PassRegistry &);
void initializeScopInfoPass(llvm::PassRegistry &);
}

View File

@ -1,305 +0,0 @@
//===-------- polly/TempScopInfo.h - Extract TempScops ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Collect information about the control flow regions detected by the Scop
// detection, such that this information can be translated info its polyhedral
// representation.
//
//===----------------------------------------------------------------------===//
#ifndef POLLY_TEMP_SCOP_EXTRACTION_H
#define POLLY_TEMP_SCOP_EXTRACTION_H
#include "polly/ScopDetection.h"
#include "llvm/Analysis/RegionPass.h"
#include "llvm/IR/Instructions.h"
namespace llvm {
class DataLayout;
}
using namespace llvm;
namespace polly {
//===---------------------------------------------------------------------===//
/// @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,
SmallVector<const SCEV *, 4> Subscripts,
SmallVector<const SCEV *, 4> Sizes, Value *AccessValue)
: BaseAddress(BaseAddress), AccessValue(AccessValue), Offset(Offset),
ElemBytes(elemBytes), Type(Type), IsAffine(Affine), IsPHI(false),
Subscripts(Subscripts), Sizes(Sizes) {}
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;
};
class Comparison {
const SCEV *LHS;
const SCEV *RHS;
ICmpInst::Predicate Pred;
public:
Comparison(const SCEV *LHS, const SCEV *RHS, ICmpInst::Predicate Pred)
: LHS(LHS), RHS(RHS), Pred(Pred) {}
const SCEV *getLHS() const { return LHS; }
const SCEV *getRHS() const { return RHS; }
ICmpInst::Predicate getPred() const { return Pred; }
void print(raw_ostream &OS) const;
};
//===---------------------------------------------------------------------===//
/// Maps from a loop to the affine function expressing its backedge taken count.
/// The backedge taken count already enough to express iteration domain as we
/// only allow loops with canonical induction variable.
/// A canonical induction variable is:
/// an integer recurrence that starts at 0 and increments by one each time
/// through the loop.
typedef std::map<const Loop *, const SCEV *> LoopBoundMapType;
typedef std::vector<std::pair<IRAccess, Instruction *>> AccFuncSetType;
typedef std::map<const BasicBlock *, AccFuncSetType> AccFuncMapType;
//===---------------------------------------------------------------------===//
/// @brief Scop represent with llvm objects.
///
/// A helper class for remembering the parameter number and the max depth in
/// this Scop, and others context.
class TempScop {
// The Region.
Region &R;
// Access function of bbs.
AccFuncMapType &AccFuncMap;
friend class TempScopInfo;
explicit TempScop(Region &r, AccFuncMapType &accFuncMap)
: R(r), AccFuncMap(accFuncMap) {}
public:
~TempScop();
/// @brief Get the maximum Region contained by this Scop.
///
/// @return The maximum Region contained by this Scop.
Region &getMaxRegion() const { return R; }
/// @brief Get all access functions in a BasicBlock
///
/// @param BB The BasicBlock that containing the access functions.
///
/// @return All access functions in BB
///
AccFuncSetType *getAccessFunctions(const BasicBlock *BB) {
AccFuncMapType::iterator at = AccFuncMap.find(BB);
return at != AccFuncMap.end() ? &(at->second) : 0;
}
//@}
/// @brief Print the Temporary Scop information.
///
/// @param OS The output stream the access functions is printed to.
/// @param SE The ScalarEvolution that help printing Temporary Scop
/// information.
/// @param LI The LoopInfo that help printing the access functions.
void print(raw_ostream &OS, ScalarEvolution *SE, LoopInfo *LI) const;
/// @brief Print the access functions and loop bounds in this Scop.
///
/// @param OS The output stream the access functions is printed to.
/// @param SE The ScalarEvolution that help printing the access functions.
/// @param LI The LoopInfo that help printing the access functions.
void printDetail(raw_ostream &OS, ScalarEvolution *SE, LoopInfo *LI,
const Region *Reg, unsigned ind) const;
};
typedef std::map<const Region *, TempScop *> TempScopMapType;
//===----------------------------------------------------------------------===//
/// @brief The Function Pass to extract temporary information for Static control
/// part in llvm function.
///
class TempScopInfo : public RegionPass {
//===-------------------------------------------------------------------===//
TempScopInfo(const TempScopInfo &) = delete;
const TempScopInfo &operator=(const TempScopInfo &) = delete;
// The ScalarEvolution to help building Scop.
ScalarEvolution *SE;
// LoopInfo for information about loops
LoopInfo *LI;
// The AliasAnalysis to build AliasSetTracker.
AliasAnalysis *AA;
// Valid Regions for Scop
ScopDetection *SD;
// Target data for element size computing.
const DataLayout *TD;
// Access function of statements (currently BasicBlocks) .
AccFuncMapType AccFuncMap;
// Pre-created zero for the scalar accesses, with it we do not need create a
// zero scev every time when we need it.
const SCEV *ZeroOffset;
// The TempScop for this region.
TempScop *TempScopOfRegion;
// Clear the context.
void clear();
// Build the temprory information of Region R, where R must be a valid part
// of Scop.
TempScop *buildTempScop(Region &R);
/// @brief Build an instance of IRAccess from the Load/Store instruction.
///
/// @param Inst The Load/Store instruction that access the memory
/// @param L The parent loop of the instruction
/// @param R The region on which we are going to build a TempScop
/// @param BoxedLoops The set of loops that are overapproximated in @p R.
///
/// @return The IRAccess to describe the access function of the
/// instruction.
IRAccess buildIRAccess(Instruction *Inst, Loop *L, Region *R,
const ScopDetection::BoxedLoopsSetTy *BoxedLoops);
/// @brief Analyze and extract the cross-BB scalar dependences (or,
/// dataflow dependencies) of an instruction.
///
/// @param Inst The instruction to be analyzed
/// @param R The SCoP region
/// @param NonAffineSubRegion The non affine sub-region @p Inst is in.
///
/// @return True if the Instruction is used in other BB and a scalar write
/// Access is required.
bool buildScalarDependences(Instruction *Inst, Region *R,
Region *NonAffineSubRegio);
/// @brief Create IRAccesses for the given PHI node in the given region.
///
/// @param PHI The PHI node to be handled
/// @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 IsExitBlock Flag to indicate that @p PHI is in the exit BB.
void buildPHIAccesses(PHINode *PHI, Region &R, AccFuncSetType &Functions,
Region *NonAffineSubRegion, bool IsExitBlock = false);
/// @brief Build the access functions for the subregion @p SR.
///
/// @param R The SCoP region.
/// @param SR A subregion of @p R.
void buildAccessFunctions(Region &R, Region &SR);
/// @brief Build the access functions for the basic block @p BB
///
/// @param R The SCoP region.
/// @param BB A basic block in @p R.
/// @param NonAffineSubRegion The non affine sub-region @p BB is in.
/// @param IsExitBlock Flag to indicate that @p BB is in the exit BB.
void buildAccessFunctions(Region &R, BasicBlock &BB,
Region *NonAffineSubRegion = nullptr,
bool IsExitBlock = false);
public:
static char ID;
explicit TempScopInfo() : RegionPass(ID), TempScopOfRegion(nullptr) {}
~TempScopInfo();
/// @brief Get the temporay Scop information in LLVM IR for this region.
///
/// @return The Scop information in LLVM IR represent.
TempScop *getTempScop() const;
/// @name RegionPass interface
//@{
virtual void getAnalysisUsage(AnalysisUsage &AU) const;
virtual void releaseMemory() { clear(); }
virtual bool runOnRegion(Region *R, RGPassManager &RGM);
virtual void print(raw_ostream &OS, const Module *) const;
//@}
};
} // end namespace polly
namespace llvm {
class PassRegistry;
void initializeTempScopInfoPass(llvm::PassRegistry &);
}
#endif

View File

@ -23,7 +23,7 @@
#include "polly/Support/GICHelper.h"
#include "polly/Support/SCEVValidator.h"
#include "polly/Support/ScopHelper.h"
#include "polly/TempScopInfo.h"
#include "polly/CodeGen/BlockGenerators.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/Statistic.h"
@ -59,6 +59,11 @@ using namespace polly;
STATISTIC(ScopFound, "Number of valid Scops");
STATISTIC(RichScopFound, "Number of Scops containing a loop");
static cl::opt<bool> ModelReadOnlyScalars(
"polly-analyze-read-only-scalars",
cl::desc("Model read-only scalar values in the scop description"),
cl::Hidden, cl::ZeroOrMore, cl::init(true), cl::cat(PollyCategory));
// Multiplicative reductions can be disabled separately as these kind of
// operations can overflow easily. Additive reductions and bit operations
// are in contrast pretty stable.
@ -86,6 +91,13 @@ static cl::opt<bool> DetectReductions("polly-detect-reductions",
cl::Hidden, cl::ZeroOrMore,
cl::init(true), cl::cat(PollyCategory));
//===----------------------------------------------------------------------===//
/// Helper Classes
void Comparison::print(raw_ostream &OS) const {
// Not yet implemented.
}
// Create a sequence of two schedules. Either argument may be null and is
// interpreted as the empty schedule. Can also return null if both schedules are
// empty.
@ -213,6 +225,17 @@ const ScopArrayInfo *ScopArrayInfo::getFromId(isl_id *Id) {
return SAI;
}
void IRAccess::print(raw_ostream &OS) const {
if (isRead())
OS << "Read ";
else {
if (isMayWrite())
OS << "May";
OS << "Write ";
}
OS << BaseAddress->getName() << '[' << *Offset << "]\n";
}
const std::string
MemoryAccess::getReductionOperatorStr(MemoryAccess::ReductionType RT) {
switch (RT) {
@ -2328,6 +2351,36 @@ ScopStmt *Scop::getStmtForBasicBlock(BasicBlock *BB) const {
return StmtMapIt->second;
}
//===----------------------------------------------------------------------===//
// TempScop implementation
TempScop::~TempScop() {}
void TempScop::print(raw_ostream &OS, ScalarEvolution *SE, LoopInfo *LI) const {
OS << "Scop: " << R.getNameStr() << "\n";
printDetail(OS, SE, LI, &R, 0);
}
void TempScop::printDetail(raw_ostream &OS, ScalarEvolution *SE, LoopInfo *LI,
const Region *CurR, unsigned ind) const {
// FIXME: Print other details rather than memory accesses.
for (const auto &CurBlock : CurR->blocks()) {
AccFuncMapType::const_iterator AccSetIt = AccFuncMap.find(CurBlock);
// Ignore trivial blocks that do not contain any memory access.
if (AccSetIt == AccFuncMap.end())
continue;
OS.indent(ind) << "BB: " << CurBlock->getName() << '\n';
typedef AccFuncSetType::const_iterator access_iterator;
const AccFuncSetType &AccFuncs = AccSetIt->second;
for (access_iterator AI = AccFuncs.begin(), AE = AccFuncs.end(); AI != AE;
++AI)
AI->first.print(OS.indent(ind + 2));
}
}
int Scop::getRelativeLoopDepth(const Loop *L) const {
Loop *OuterLoop =
L ? R.outermostLoopInRegion(const_cast<Loop *>(L)) : nullptr;
@ -2336,6 +2389,346 @@ int Scop::getRelativeLoopDepth(const Loop *L) const {
return L->getLoopDepth() - OuterLoop->getLoopDepth();
}
void TempScopInfo::buildPHIAccesses(PHINode *PHI, Region &R,
AccFuncSetType &Functions,
Region *NonAffineSubRegion,
bool IsExitBlock) {
// PHI nodes that are in the exit block of the region, hence if IsExitBlock is
// true, are not modeled as ordinary PHI nodes as they are not part of the
// region. However, we model the operands in the predecessor blocks that are
// part of the region as regular scalar accesses.
// If we can synthesize a PHI we can skip it, however only if it is in
// the region. If it is not it can only be in the exit block of the region.
// In this case we model the operands but not the PHI itself.
if (!IsExitBlock && canSynthesize(PHI, LI, SE, &R))
return;
// PHI nodes are modeled as if they had been demoted prior to the SCoP
// detection. Hence, the PHI is a load of a new memory location in which the
// incoming value was written at the end of the incoming basic block.
bool OnlyNonAffineSubRegionOperands = true;
for (unsigned u = 0; u < PHI->getNumIncomingValues(); u++) {
Value *Op = PHI->getIncomingValue(u);
BasicBlock *OpBB = PHI->getIncomingBlock(u);
// Do not build scalar dependences inside a non-affine subregion.
if (NonAffineSubRegion && NonAffineSubRegion->contains(OpBB))
continue;
OnlyNonAffineSubRegionOperands = false;
if (!R.contains(OpBB))
continue;
Instruction *OpI = dyn_cast<Instruction>(Op);
if (OpI) {
BasicBlock *OpIBB = OpI->getParent();
// As we pretend there is a use (or more precise a write) of OpI in OpBB
// we have to insert a scalar dependence from the definition of OpI to
// OpBB if the definition is not in OpBB.
if (OpIBB != OpBB) {
IRAccess ScalarRead(IRAccess::READ, OpI, ZeroOffset, 1, true, OpI);
AccFuncMap[OpBB].push_back(std::make_pair(ScalarRead, PHI));
IRAccess ScalarWrite(IRAccess::MUST_WRITE, OpI, ZeroOffset, 1, true,
OpI);
AccFuncMap[OpIBB].push_back(std::make_pair(ScalarWrite, OpI));
}
}
// Always use the terminator of the incoming basic block as the access
// instruction.
OpI = OpBB->getTerminator();
IRAccess ScalarAccess(IRAccess::MUST_WRITE, PHI, ZeroOffset, 1, true, Op,
/* IsPHI */ !IsExitBlock);
AccFuncMap[OpBB].push_back(std::make_pair(ScalarAccess, OpI));
}
if (!OnlyNonAffineSubRegionOperands) {
IRAccess ScalarAccess(IRAccess::READ, PHI, ZeroOffset, 1, true, PHI,
/* IsPHI */ !IsExitBlock);
Functions.push_back(std::make_pair(ScalarAccess, PHI));
}
}
bool TempScopInfo::buildScalarDependences(Instruction *Inst, Region *R,
Region *NonAffineSubRegion) {
bool canSynthesizeInst = canSynthesize(Inst, LI, SE, R);
if (isIgnoredIntrinsic(Inst))
return false;
bool AnyCrossStmtUse = false;
BasicBlock *ParentBB = Inst->getParent();
for (User *U : Inst->users()) {
Instruction *UI = dyn_cast<Instruction>(U);
// Ignore the strange user
if (UI == 0)
continue;
BasicBlock *UseParent = UI->getParent();
// Ignore the users in the same BB (statement)
if (UseParent == ParentBB)
continue;
// Do not build scalar dependences inside a non-affine subregion.
if (NonAffineSubRegion && NonAffineSubRegion->contains(UseParent))
continue;
// Check whether or not the use is in the SCoP.
if (!R->contains(UseParent)) {
AnyCrossStmtUse = true;
continue;
}
// If the instruction can be synthesized and the user is in the region
// we do not need to add scalar dependences.
if (canSynthesizeInst)
continue;
// No need to translate these scalar dependences into polyhedral form,
// because synthesizable scalars can be generated by the code generator.
if (canSynthesize(UI, LI, SE, R))
continue;
// Skip PHI nodes in the region as they handle their operands on their own.
if (isa<PHINode>(UI))
continue;
// Now U is used in another statement.
AnyCrossStmtUse = true;
// 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
// become the name of the scalar access in the polyhedral form.
IRAccess ScalarAccess(IRAccess::READ, Inst, ZeroOffset, 1, true, Inst);
AccFuncMap[UseParent].push_back(std::make_pair(ScalarAccess, UI));
}
if (ModelReadOnlyScalars) {
for (Value *Op : Inst->operands()) {
if (canSynthesize(Op, LI, SE, R))
continue;
if (Instruction *OpInst = dyn_cast<Instruction>(Op))
if (R->contains(OpInst))
continue;
if (isa<Constant>(Op))
continue;
IRAccess ScalarAccess(IRAccess::READ, Op, ZeroOffset, 1, true, Op);
AccFuncMap[Inst->getParent()].push_back(
std::make_pair(ScalarAccess, Inst));
}
}
return AnyCrossStmtUse;
}
extern MapInsnToMemAcc InsnToMemAcc;
IRAccess
TempScopInfo::buildIRAccess(Instruction *Inst, Loop *L, Region *R,
const ScopDetection::BoxedLoopsSetTy *BoxedLoops) {
unsigned Size;
Type *SizeType;
Value *Val;
enum IRAccess::TypeKind Type;
if (LoadInst *Load = dyn_cast<LoadInst>(Inst)) {
SizeType = Load->getType();
Size = TD->getTypeStoreSize(SizeType);
Type = IRAccess::READ;
Val = Load;
} else {
StoreInst *Store = cast<StoreInst>(Inst);
SizeType = Store->getValueOperand()->getType();
Size = TD->getTypeStoreSize(SizeType);
Type = IRAccess::MUST_WRITE;
Val = Store->getValueOperand();
}
const SCEV *AccessFunction = SE->getSCEVAtScope(getPointerOperand(*Inst), L);
const SCEVUnknown *BasePointer =
dyn_cast<SCEVUnknown>(SE->getPointerBase(AccessFunction));
assert(BasePointer && "Could not find base pointer");
AccessFunction = SE->getMinusSCEV(AccessFunction, BasePointer);
auto AccItr = InsnToMemAcc.find(Inst);
if (PollyDelinearize && AccItr != InsnToMemAcc.end())
return IRAccess(Type, BasePointer->getValue(), AccessFunction, Size, true,
AccItr->second.DelinearizedSubscripts,
AccItr->second.Shape->DelinearizedSizes, Val);
// Check if the access depends on a loop contained in a non-affine subregion.
bool isVariantInNonAffineLoop = false;
if (BoxedLoops) {
SetVector<const Loop *> Loops;
findLoops(AccessFunction, Loops);
for (const Loop *L : Loops)
if (BoxedLoops->count(L))
isVariantInNonAffineLoop = true;
}
bool IsAffine = !isVariantInNonAffineLoop &&
isAffineExpr(R, AccessFunction, *SE, BasePointer->getValue());
SmallVector<const SCEV *, 4> Subscripts, Sizes;
Subscripts.push_back(AccessFunction);
Sizes.push_back(SE->getConstant(ZeroOffset->getType(), Size));
if (!IsAffine && Type == IRAccess::MUST_WRITE)
Type = IRAccess::MAY_WRITE;
return IRAccess(Type, BasePointer->getValue(), AccessFunction, Size, IsAffine,
Subscripts, Sizes, Val);
}
void TempScopInfo::buildAccessFunctions(Region &R, Region &SR) {
if (SD->isNonAffineSubRegion(&SR, &R)) {
for (BasicBlock *BB : SR.blocks())
buildAccessFunctions(R, *BB, &SR);
return;
}
for (auto I = SR.element_begin(), E = SR.element_end(); I != E; ++I)
if (I->isSubRegion())
buildAccessFunctions(R, *I->getNodeAs<Region>());
else
buildAccessFunctions(R, *I->getNodeAs<BasicBlock>());
}
void TempScopInfo::buildAccessFunctions(Region &R, BasicBlock &BB,
Region *NonAffineSubRegion,
bool IsExitBlock) {
AccFuncSetType Functions;
Loop *L = LI->getLoopFor(&BB);
// The set of loops contained in non-affine subregions that are part of R.
const ScopDetection::BoxedLoopsSetTy *BoxedLoops = SD->getBoxedLoops(&R);
for (BasicBlock::iterator I = BB.begin(), E = --BB.end(); I != E; ++I) {
Instruction *Inst = I;
PHINode *PHI = dyn_cast<PHINode>(Inst);
if (PHI)
buildPHIAccesses(PHI, R, Functions, NonAffineSubRegion, IsExitBlock);
// For the exit block we stop modeling after the last PHI node.
if (!PHI && IsExitBlock)
break;
if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst))
Functions.push_back(
std::make_pair(buildIRAccess(Inst, L, &R, BoxedLoops), Inst));
if (isIgnoredIntrinsic(Inst))
continue;
if (buildScalarDependences(Inst, &R, NonAffineSubRegion)) {
// If the Instruction is used outside the statement, we need to build the
// write access.
if (!isa<StoreInst>(Inst)) {
IRAccess ScalarAccess(IRAccess::MUST_WRITE, Inst, ZeroOffset, 1, true,
Inst);
Functions.push_back(std::make_pair(ScalarAccess, Inst));
}
}
}
if (Functions.empty())
return;
AccFuncSetType &Accs = AccFuncMap[&BB];
Accs.insert(Accs.end(), Functions.begin(), Functions.end());
}
TempScop *TempScopInfo::buildTempScop(Region &R) {
TempScop *TScop = new TempScop(R, AccFuncMap);
buildAccessFunctions(R, R);
// In case the region does not have an exiting block we will later (during
// code generation) split the exit block. This will move potential PHI nodes
// from the current exit block into the new region exiting block. Hence, PHI
// nodes that are at this point not part of the region will be.
// To handle these PHI nodes later we will now model their operands as scalar
// accesses. Note that we do not model anything in the exit block if we have
// an exiting block in the region, as there will not be any splitting later.
if (!R.getExitingBlock())
buildAccessFunctions(R, *R.getExit(), nullptr, /* IsExitBlock */ true);
return TScop;
}
TempScop *TempScopInfo::getTempScop() const { return TempScopOfRegion; }
void TempScopInfo::print(raw_ostream &OS, const Module *) const {
if (TempScopOfRegion)
TempScopOfRegion->print(OS, SE, LI);
}
bool TempScopInfo::runOnRegion(Region *R, RGPassManager &RGM) {
SD = &getAnalysis<ScopDetection>();
if (!SD->isMaxRegionInScop(*R))
return false;
Function *F = R->getEntry()->getParent();
SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
TD = &F->getParent()->getDataLayout();
ZeroOffset = SE->getConstant(TD->getIntPtrType(F->getContext()), 0);
assert(!TempScopOfRegion && "Build the TempScop only once");
TempScopOfRegion = buildTempScop(*R);
return false;
}
void TempScopInfo::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequiredTransitive<LoopInfoWrapperPass>();
AU.addRequiredTransitive<ScalarEvolutionWrapperPass>();
AU.addRequiredTransitive<ScopDetection>();
AU.addRequiredID(IndependentBlocksID);
AU.addRequired<AAResultsWrapperPass>();
AU.setPreservesAll();
}
TempScopInfo::~TempScopInfo() { clear(); }
void TempScopInfo::clear() {
AccFuncMap.clear();
if (TempScopOfRegion)
delete TempScopOfRegion;
TempScopOfRegion = nullptr;
}
//===----------------------------------------------------------------------===//
// TempScop information extraction pass implement
char TempScopInfo::ID = 0;
Pass *polly::createTempScopInfoPass() { return new TempScopInfo(); }
INITIALIZE_PASS_BEGIN(TempScopInfo, "polly-analyze-ir",
"Polly - Analyse the LLVM-IR in the detected regions",
false, false);
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass);
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass);
INITIALIZE_PASS_DEPENDENCY(RegionInfoPass);
INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass);
INITIALIZE_PASS_END(TempScopInfo, "polly-analyze-ir",
"Polly - Analyse the LLVM-IR in the detected regions",
false, false)
//===----------------------------------------------------------------------===//
ScopInfo::ScopInfo() : RegionPass(ID), scop(0) {
ctx = isl_ctx_alloc();

View File

@ -1,431 +0,0 @@
//===---------- TempScopInfo.cpp - Extract TempScops ---------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Collect information about the control flow regions detected by the Scop
// detection, such that this information can be translated info its polyhedral
// representation.
//
//===----------------------------------------------------------------------===//
#include "polly/TempScopInfo.h"
#include "polly/Options.h"
#include "polly/CodeGen/BlockGenerators.h"
#include "polly/LinkAllPasses.h"
#include "polly/ScopDetection.h"
#include "polly/Support/GICHelper.h"
#include "polly/Support/SCEVValidator.h"
#include "polly/Support/ScopHelper.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/Analysis/RegionIterator.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
using namespace llvm;
using namespace polly;
static cl::opt<bool> ModelReadOnlyScalars(
"polly-analyze-read-only-scalars",
cl::desc("Model read-only scalar values in the scop description"),
cl::Hidden, cl::ZeroOrMore, cl::init(true), cl::cat(PollyCategory));
#define DEBUG_TYPE "polly-analyze-ir"
//===----------------------------------------------------------------------===//
/// Helper Classes
void IRAccess::print(raw_ostream &OS) const {
if (isRead())
OS << "Read ";
else {
if (isMayWrite())
OS << "May";
OS << "Write ";
}
OS << BaseAddress->getName() << '[' << *Offset << "]\n";
}
void Comparison::print(raw_ostream &OS) const {
// Not yet implemented.
}
//===----------------------------------------------------------------------===//
// TempScop implementation
TempScop::~TempScop() {}
void TempScop::print(raw_ostream &OS, ScalarEvolution *SE, LoopInfo *LI) const {
OS << "Scop: " << R.getNameStr() << "\n";
printDetail(OS, SE, LI, &R, 0);
}
void TempScop::printDetail(raw_ostream &OS, ScalarEvolution *SE, LoopInfo *LI,
const Region *CurR, unsigned ind) const {
// FIXME: Print other details rather than memory accesses.
for (const auto &CurBlock : CurR->blocks()) {
AccFuncMapType::const_iterator AccSetIt = AccFuncMap.find(CurBlock);
// Ignore trivial blocks that do not contain any memory access.
if (AccSetIt == AccFuncMap.end())
continue;
OS.indent(ind) << "BB: " << CurBlock->getName() << '\n';
typedef AccFuncSetType::const_iterator access_iterator;
const AccFuncSetType &AccFuncs = AccSetIt->second;
for (access_iterator AI = AccFuncs.begin(), AE = AccFuncs.end(); AI != AE;
++AI)
AI->first.print(OS.indent(ind + 2));
}
}
void TempScopInfo::buildPHIAccesses(PHINode *PHI, Region &R,
AccFuncSetType &Functions,
Region *NonAffineSubRegion,
bool IsExitBlock) {
// PHI nodes that are in the exit block of the region, hence if IsExitBlock is
// true, are not modeled as ordinary PHI nodes as they are not part of the
// region. However, we model the operands in the predecessor blocks that are
// part of the region as regular scalar accesses.
// If we can synthesize a PHI we can skip it, however only if it is in
// the region. If it is not it can only be in the exit block of the region.
// In this case we model the operands but not the PHI itself.
if (!IsExitBlock && canSynthesize(PHI, LI, SE, &R))
return;
// PHI nodes are modeled as if they had been demoted prior to the SCoP
// detection. Hence, the PHI is a load of a new memory location in which the
// incoming value was written at the end of the incoming basic block.
bool OnlyNonAffineSubRegionOperands = true;
for (unsigned u = 0; u < PHI->getNumIncomingValues(); u++) {
Value *Op = PHI->getIncomingValue(u);
BasicBlock *OpBB = PHI->getIncomingBlock(u);
// Do not build scalar dependences inside a non-affine subregion.
if (NonAffineSubRegion && NonAffineSubRegion->contains(OpBB))
continue;
OnlyNonAffineSubRegionOperands = false;
if (!R.contains(OpBB))
continue;
Instruction *OpI = dyn_cast<Instruction>(Op);
if (OpI) {
BasicBlock *OpIBB = OpI->getParent();
// As we pretend there is a use (or more precise a write) of OpI in OpBB
// we have to insert a scalar dependence from the definition of OpI to
// OpBB if the definition is not in OpBB.
if (OpIBB != OpBB) {
IRAccess ScalarRead(IRAccess::READ, OpI, ZeroOffset, 1, true, OpI);
AccFuncMap[OpBB].push_back(std::make_pair(ScalarRead, PHI));
IRAccess ScalarWrite(IRAccess::MUST_WRITE, OpI, ZeroOffset, 1, true,
OpI);
AccFuncMap[OpIBB].push_back(std::make_pair(ScalarWrite, OpI));
}
}
// Always use the terminator of the incoming basic block as the access
// instruction.
OpI = OpBB->getTerminator();
IRAccess ScalarAccess(IRAccess::MUST_WRITE, PHI, ZeroOffset, 1, true, Op,
/* IsPHI */ !IsExitBlock);
AccFuncMap[OpBB].push_back(std::make_pair(ScalarAccess, OpI));
}
if (!OnlyNonAffineSubRegionOperands) {
IRAccess ScalarAccess(IRAccess::READ, PHI, ZeroOffset, 1, true, PHI,
/* IsPHI */ !IsExitBlock);
Functions.push_back(std::make_pair(ScalarAccess, PHI));
}
}
bool TempScopInfo::buildScalarDependences(Instruction *Inst, Region *R,
Region *NonAffineSubRegion) {
bool canSynthesizeInst = canSynthesize(Inst, LI, SE, R);
if (isIgnoredIntrinsic(Inst))
return false;
bool AnyCrossStmtUse = false;
BasicBlock *ParentBB = Inst->getParent();
for (User *U : Inst->users()) {
Instruction *UI = dyn_cast<Instruction>(U);
// Ignore the strange user
if (UI == 0)
continue;
BasicBlock *UseParent = UI->getParent();
// Ignore the users in the same BB (statement)
if (UseParent == ParentBB)
continue;
// Do not build scalar dependences inside a non-affine subregion.
if (NonAffineSubRegion && NonAffineSubRegion->contains(UseParent))
continue;
// Check whether or not the use is in the SCoP.
if (!R->contains(UseParent)) {
AnyCrossStmtUse = true;
continue;
}
// If the instruction can be synthesized and the user is in the region
// we do not need to add scalar dependences.
if (canSynthesizeInst)
continue;
// No need to translate these scalar dependences into polyhedral form,
// because synthesizable scalars can be generated by the code generator.
if (canSynthesize(UI, LI, SE, R))
continue;
// Skip PHI nodes in the region as they handle their operands on their own.
if (isa<PHINode>(UI))
continue;
// Now U is used in another statement.
AnyCrossStmtUse = true;
// 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
// become the name of the scalar access in the polyhedral form.
IRAccess ScalarAccess(IRAccess::READ, Inst, ZeroOffset, 1, true, Inst);
AccFuncMap[UseParent].push_back(std::make_pair(ScalarAccess, UI));
}
if (ModelReadOnlyScalars) {
for (Value *Op : Inst->operands()) {
if (canSynthesize(Op, LI, SE, R))
continue;
if (Instruction *OpInst = dyn_cast<Instruction>(Op))
if (R->contains(OpInst))
continue;
if (isa<Constant>(Op))
continue;
IRAccess ScalarAccess(IRAccess::READ, Op, ZeroOffset, 1, true, Op);
AccFuncMap[Inst->getParent()].push_back(
std::make_pair(ScalarAccess, Inst));
}
}
return AnyCrossStmtUse;
}
extern MapInsnToMemAcc InsnToMemAcc;
IRAccess
TempScopInfo::buildIRAccess(Instruction *Inst, Loop *L, Region *R,
const ScopDetection::BoxedLoopsSetTy *BoxedLoops) {
unsigned Size;
Type *SizeType;
Value *Val;
enum IRAccess::TypeKind Type;
if (LoadInst *Load = dyn_cast<LoadInst>(Inst)) {
SizeType = Load->getType();
Size = TD->getTypeStoreSize(SizeType);
Type = IRAccess::READ;
Val = Load;
} else {
StoreInst *Store = cast<StoreInst>(Inst);
SizeType = Store->getValueOperand()->getType();
Size = TD->getTypeStoreSize(SizeType);
Type = IRAccess::MUST_WRITE;
Val = Store->getValueOperand();
}
const SCEV *AccessFunction = SE->getSCEVAtScope(getPointerOperand(*Inst), L);
const SCEVUnknown *BasePointer =
dyn_cast<SCEVUnknown>(SE->getPointerBase(AccessFunction));
assert(BasePointer && "Could not find base pointer");
AccessFunction = SE->getMinusSCEV(AccessFunction, BasePointer);
auto AccItr = InsnToMemAcc.find(Inst);
if (PollyDelinearize && AccItr != InsnToMemAcc.end())
return IRAccess(Type, BasePointer->getValue(), AccessFunction, Size, true,
AccItr->second.DelinearizedSubscripts,
AccItr->second.Shape->DelinearizedSizes, Val);
// Check if the access depends on a loop contained in a non-affine subregion.
bool isVariantInNonAffineLoop = false;
if (BoxedLoops) {
SetVector<const Loop *> Loops;
findLoops(AccessFunction, Loops);
for (const Loop *L : Loops)
if (BoxedLoops->count(L))
isVariantInNonAffineLoop = true;
}
bool IsAffine = !isVariantInNonAffineLoop &&
isAffineExpr(R, AccessFunction, *SE, BasePointer->getValue());
SmallVector<const SCEV *, 4> Subscripts, Sizes;
Subscripts.push_back(AccessFunction);
Sizes.push_back(SE->getConstant(ZeroOffset->getType(), Size));
if (!IsAffine && Type == IRAccess::MUST_WRITE)
Type = IRAccess::MAY_WRITE;
return IRAccess(Type, BasePointer->getValue(), AccessFunction, Size, IsAffine,
Subscripts, Sizes, Val);
}
void TempScopInfo::buildAccessFunctions(Region &R, Region &SR) {
if (SD->isNonAffineSubRegion(&SR, &R)) {
for (BasicBlock *BB : SR.blocks())
buildAccessFunctions(R, *BB, &SR);
return;
}
for (auto I = SR.element_begin(), E = SR.element_end(); I != E; ++I)
if (I->isSubRegion())
buildAccessFunctions(R, *I->getNodeAs<Region>());
else
buildAccessFunctions(R, *I->getNodeAs<BasicBlock>());
}
void TempScopInfo::buildAccessFunctions(Region &R, BasicBlock &BB,
Region *NonAffineSubRegion,
bool IsExitBlock) {
AccFuncSetType Functions;
Loop *L = LI->getLoopFor(&BB);
// The set of loops contained in non-affine subregions that are part of R.
const ScopDetection::BoxedLoopsSetTy *BoxedLoops = SD->getBoxedLoops(&R);
for (BasicBlock::iterator I = BB.begin(), E = --BB.end(); I != E; ++I) {
Instruction *Inst = I;
PHINode *PHI = dyn_cast<PHINode>(Inst);
if (PHI)
buildPHIAccesses(PHI, R, Functions, NonAffineSubRegion, IsExitBlock);
// For the exit block we stop modeling after the last PHI node.
if (!PHI && IsExitBlock)
break;
if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst))
Functions.push_back(
std::make_pair(buildIRAccess(Inst, L, &R, BoxedLoops), Inst));
if (isIgnoredIntrinsic(Inst))
continue;
if (buildScalarDependences(Inst, &R, NonAffineSubRegion)) {
// If the Instruction is used outside the statement, we need to build the
// write access.
if (!isa<StoreInst>(Inst)) {
IRAccess ScalarAccess(IRAccess::MUST_WRITE, Inst, ZeroOffset, 1, true,
Inst);
Functions.push_back(std::make_pair(ScalarAccess, Inst));
}
}
}
if (Functions.empty())
return;
AccFuncSetType &Accs = AccFuncMap[&BB];
Accs.insert(Accs.end(), Functions.begin(), Functions.end());
}
TempScop *TempScopInfo::buildTempScop(Region &R) {
TempScop *TScop = new TempScop(R, AccFuncMap);
buildAccessFunctions(R, R);
// In case the region does not have an exiting block we will later (during
// code generation) split the exit block. This will move potential PHI nodes
// from the current exit block into the new region exiting block. Hence, PHI
// nodes that are at this point not part of the region will be.
// To handle these PHI nodes later we will now model their operands as scalar
// accesses. Note that we do not model anything in the exit block if we have
// an exiting block in the region, as there will not be any splitting later.
if (!R.getExitingBlock())
buildAccessFunctions(R, *R.getExit(), nullptr, /* IsExitBlock */ true);
return TScop;
}
TempScop *TempScopInfo::getTempScop() const { return TempScopOfRegion; }
void TempScopInfo::print(raw_ostream &OS, const Module *) const {
if (TempScopOfRegion)
TempScopOfRegion->print(OS, SE, LI);
}
bool TempScopInfo::runOnRegion(Region *R, RGPassManager &RGM) {
SD = &getAnalysis<ScopDetection>();
if (!SD->isMaxRegionInScop(*R))
return false;
Function *F = R->getEntry()->getParent();
SE = &getAnalysis<ScalarEvolutionWrapperPass>().getSE();
LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
TD = &F->getParent()->getDataLayout();
ZeroOffset = SE->getConstant(TD->getIntPtrType(F->getContext()), 0);
assert(!TempScopOfRegion && "Build the TempScop only once");
TempScopOfRegion = buildTempScop(*R);
return false;
}
void TempScopInfo::getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequiredTransitive<LoopInfoWrapperPass>();
AU.addRequiredTransitive<ScalarEvolutionWrapperPass>();
AU.addRequiredTransitive<ScopDetection>();
AU.addRequiredID(IndependentBlocksID);
AU.addRequired<AAResultsWrapperPass>();
AU.setPreservesAll();
}
TempScopInfo::~TempScopInfo() { clear(); }
void TempScopInfo::clear() {
AccFuncMap.clear();
if (TempScopOfRegion)
delete TempScopOfRegion;
TempScopOfRegion = nullptr;
}
//===----------------------------------------------------------------------===//
// TempScop information extraction pass implement
char TempScopInfo::ID = 0;
Pass *polly::createTempScopInfoPass() { return new TempScopInfo(); }
INITIALIZE_PASS_BEGIN(TempScopInfo, "polly-analyze-ir",
"Polly - Analyse the LLVM-IR in the detected regions",
false, false);
INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass);
INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass);
INITIALIZE_PASS_DEPENDENCY(RegionInfoPass);
INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass);
INITIALIZE_PASS_END(TempScopInfo, "polly-analyze-ir",
"Polly - Analyse the LLVM-IR in the detected regions",
false, false)

View File

@ -275,7 +275,6 @@ add_polly_library(Polly
Analysis/ScopInfo.cpp
Analysis/ScopGraphPrinter.cpp
Analysis/ScopPass.cpp
Analysis/TempScopInfo.cpp
CodeGen/BlockGenerators.cpp
${ISL_CODEGEN_FILES}
CodeGen/LoopGenerators.cpp

View File

@ -26,7 +26,6 @@
#include "polly/LinkAllPasses.h"
#include "polly/ScopInfo.h"
#include "polly/Support/ScopHelper.h"
#include "polly/TempScopInfo.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/Debug.h"

View File

@ -26,7 +26,6 @@
#include "polly/Support/GICHelper.h"
#include "polly/Support/SCEVValidator.h"
#include "polly/Support/ScopHelper.h"
#include "polly/TempScopInfo.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Analysis/LoopInfo.h"

View File

@ -27,7 +27,6 @@
#include "polly/Options.h"
#include "polly/ScopDetection.h"
#include "polly/ScopInfo.h"
#include "polly/TempScopInfo.h"
#include "llvm/Analysis/CFGPrinter.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"