#include "polly/ScopBuilder.h"
#include "polly/Options.h"
#include "polly/ScopDetection.h"
#include "polly/ScopInfo.h"
#include "polly/Support/GICHelper.h"
#include "polly/Support/ISLTools.h"
#include "polly/Support/SCEVValidator.h"
#include "polly/Support/ScopHelper.h"
#include "polly/Support/VirtualInstruction.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/EquivalenceClasses.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/Delinearization.h"
#include "llvm/Analysis/Loads.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/RegionInfo.h"
#include "llvm/Analysis/RegionIterator.h"
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Use.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
usingnamespacellvm;
usingnamespacepolly;
#include "polly/Support/PollyDebug.h"
#define DEBUG_TYPE …
STATISTIC(ScopFound, "Number of valid Scops");
STATISTIC(RichScopFound, "Number of Scops containing a loop");
STATISTIC(InfeasibleScops,
"Number of SCoPs with statically infeasible context.");
bool polly::ModelReadOnlyScalars;
static unsigned const MaxDimensionsInAccessRange = …;
static cl::opt<bool, true> XModelReadOnlyScalars(
"polly-analyze-read-only-scalars",
cl::desc("Model read-only scalar values in the scop description"),
cl::location(ModelReadOnlyScalars), cl::Hidden, cl::init(true),
cl::cat(PollyCategory));
static cl::opt<int>
OptComputeOut("polly-analysis-computeout",
cl::desc("Bound the scop analysis by a maximal amount of "
"computational steps (0 means no bound)"),
cl::Hidden, cl::init(800000), cl::cat(PollyCategory));
static cl::opt<bool> PollyAllowDereferenceOfAllFunctionParams(
"polly-allow-dereference-of-all-function-parameters",
cl::desc(
"Treat all parameters to functions that are pointers as dereferencible."
" This is useful for invariant load hoisting, since we can generate"
" less runtime checks. This is only valid if all pointers to functions"
" are always initialized, so that Polly can choose to hoist"
" their loads. "),
cl::Hidden, cl::init(false), cl::cat(PollyCategory));
static cl::opt<bool>
PollyIgnoreInbounds("polly-ignore-inbounds",
cl::desc("Do not take inbounds assumptions at all"),
cl::Hidden, cl::init(false), cl::cat(PollyCategory));
static cl::opt<unsigned> RunTimeChecksMaxArraysPerGroup(
"polly-rtc-max-arrays-per-group",
cl::desc("The maximal number of arrays to compare in each alias group."),
cl::Hidden, cl::init(20), cl::cat(PollyCategory));
static cl::opt<unsigned> RunTimeChecksMaxAccessDisjuncts(
"polly-rtc-max-array-disjuncts",
cl::desc("The maximal number of disjunts allowed in memory accesses to "
"to build RTCs."),
cl::Hidden, cl::init(8), cl::cat(PollyCategory));
static cl::opt<unsigned> RunTimeChecksMaxParameters(
"polly-rtc-max-parameters",
cl::desc("The maximal number of parameters allowed in RTCs."), cl::Hidden,
cl::init(8), cl::cat(PollyCategory));
static cl::opt<bool> UnprofitableScalarAccs(
"polly-unprofitable-scalar-accs",
cl::desc("Count statements with scalar accesses as not optimizable"),
cl::Hidden, cl::init(false), cl::cat(PollyCategory));
static cl::opt<std::string> UserContextStr(
"polly-context", cl::value_desc("isl parameter set"),
cl::desc("Provide additional constraints on the context parameters"),
cl::init(""), cl::cat(PollyCategory));
static cl::opt<bool> DetectReductions("polly-detect-reductions",
cl::desc("Detect and exploit reductions"),
cl::Hidden, cl::init(true),
cl::cat(PollyCategory));
static cl::opt<bool> DisableMultiplicativeReductions(
"polly-disable-multiplicative-reductions",
cl::desc("Disable multiplicative reductions"), cl::Hidden,
cl::cat(PollyCategory));
enum class GranularityChoice { … };
static cl::opt<GranularityChoice> StmtGranularity(
"polly-stmt-granularity",
cl::desc(
"Algorithm to use for splitting basic blocks into multiple statements"),
cl::values(clEnumValN(GranularityChoice::BasicBlocks, "bb",
"One statement per basic block"),
clEnumValN(GranularityChoice::ScalarIndependence, "scalar-indep",
"Scalar independence heuristic"),
clEnumValN(GranularityChoice::Stores, "store",
"Store-level granularity")),
cl::init(GranularityChoice::ScalarIndependence), cl::cat(PollyCategory));
static inline BasicBlock *getRegionNodeBasicBlock(RegionNode *RN) { … }
static inline BasicBlock *
getRegionNodeSuccessor(RegionNode *RN, Instruction *TI, unsigned idx) { … }
static bool containsErrorBlock(RegionNode *RN, const Region &R,
ScopDetection *SD) { … }
static isl::map createNextIterationMap(isl::space SetSpace, unsigned Dim) { … }
static isl::set collectBoundedParts(isl::set S) { … }
static std::pair<isl::set, isl::set> partitionSetParts(isl::set S,
unsigned Dim) { … }
static isl::set buildConditionSet(ICmpInst::Predicate Pred, isl::pw_aff L,
isl::pw_aff R) { … }
isl::set ScopBuilder::adjustDomainDimensions(isl::set Dom, Loop *OldL,
Loop *NewL) { … }
__isl_give isl_pw_aff *
ScopBuilder::getPwAff(BasicBlock *BB,
DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
const SCEV *E, bool NonNegative) { … }
__isl_give isl_set *ScopBuilder::buildUnsignedConditionSets(
BasicBlock *BB, Value *Condition, __isl_keep isl_set *Domain,
const SCEV *SCEV_TestVal, const SCEV *SCEV_UpperBound,
DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
bool IsStrictUpperBound) { … }
bool ScopBuilder::buildConditionSets(
BasicBlock *BB, SwitchInst *SI, Loop *L, __isl_keep isl_set *Domain,
DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
SmallVectorImpl<__isl_give isl_set *> &ConditionSets) { … }
bool ScopBuilder::buildConditionSets(
BasicBlock *BB, Value *Condition, Instruction *TI, Loop *L,
__isl_keep isl_set *Domain,
DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
SmallVectorImpl<__isl_give isl_set *> &ConditionSets) { … }
bool ScopBuilder::buildConditionSets(
BasicBlock *BB, Instruction *TI, Loop *L, __isl_keep isl_set *Domain,
DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
SmallVectorImpl<__isl_give isl_set *> &ConditionSets) { … }
bool ScopBuilder::propagateDomainConstraints(
Region *R, DenseMap<BasicBlock *, isl::set> &InvalidDomainMap) { … }
void ScopBuilder::propagateDomainConstraintsToRegionExit(
BasicBlock *BB, Loop *BBLoop,
SmallPtrSetImpl<BasicBlock *> &FinishedExitBlocks,
DenseMap<BasicBlock *, isl::set> &InvalidDomainMap) { … }
isl::set ScopBuilder::getPredecessorDomainConstraints(BasicBlock *BB,
isl::set Domain) { … }
bool ScopBuilder::addLoopBoundsToHeaderDomain(
Loop *L, DenseMap<BasicBlock *, isl::set> &InvalidDomainMap) { … }
void ScopBuilder::buildInvariantEquivalenceClasses() { … }
bool ScopBuilder::buildDomains(
Region *R, DenseMap<BasicBlock *, isl::set> &InvalidDomainMap) { … }
bool ScopBuilder::buildDomainsWithBranchConstraints(
Region *R, DenseMap<BasicBlock *, isl::set> &InvalidDomainMap) { … }
bool ScopBuilder::propagateInvalidStmtDomains(
Region *R, DenseMap<BasicBlock *, isl::set> &InvalidDomainMap) { … }
void ScopBuilder::buildPHIAccesses(ScopStmt *PHIStmt, PHINode *PHI,
Region *NonAffineSubRegion,
bool IsExitBlock) { … }
void ScopBuilder::buildScalarDependences(ScopStmt *UserStmt,
Instruction *Inst) { … }
static isl::schedule combineInSequence(isl::schedule Prev, isl::schedule Succ) { … }
static isl::multi_union_pw_aff mapToDimension(isl::union_set USet, unsigned N) { … }
void ScopBuilder::buildSchedule() { … }
void ScopBuilder::buildSchedule(Region *R, LoopStackTy &LoopStack) { … }
void ScopBuilder::buildSchedule(RegionNode *RN, LoopStackTy &LoopStack) { … }
void ScopBuilder::buildEscapingDependences(Instruction *Inst) { … }
void ScopBuilder::addRecordedAssumptions() { … }
void ScopBuilder::addUserAssumptions(
AssumptionCache &AC, DenseMap<BasicBlock *, isl::set> &InvalidDomainMap) { … }
bool ScopBuilder::buildAccessMultiDimFixed(MemAccInst Inst, ScopStmt *Stmt) { … }
bool ScopBuilder::buildAccessMultiDimParam(MemAccInst Inst, ScopStmt *Stmt) { … }
bool ScopBuilder::buildAccessMemIntrinsic(MemAccInst Inst, ScopStmt *Stmt) { … }
bool ScopBuilder::buildAccessCallInst(MemAccInst Inst, ScopStmt *Stmt) { … }
bool ScopBuilder::buildAccessSingleDim(MemAccInst Inst, ScopStmt *Stmt) { … }
void ScopBuilder::buildMemoryAccess(MemAccInst Inst, ScopStmt *Stmt) { … }
void ScopBuilder::buildAccessFunctions() { … }
bool ScopBuilder::shouldModelInst(Instruction *Inst, Loop *L) { … }
static std::string makeStmtName(BasicBlock *BB, long BBIdx, int Count,
bool IsMain, bool IsLast = false) { … }
static std::string makeStmtName(Region *R, long RIdx) { … }
void ScopBuilder::buildSequentialBlockStmts(BasicBlock *BB, bool SplitOnStore) { … }
static bool isOrderedInstruction(Instruction *Inst) { … }
static void joinOperandTree(EquivalenceClasses<Instruction *> &UnionFind,
ArrayRef<Instruction *> ModeledInsts) { … }
static void
joinOrderedInstructions(EquivalenceClasses<Instruction *> &UnionFind,
ArrayRef<Instruction *> ModeledInsts) { … }
static void joinOrderedPHIs(EquivalenceClasses<Instruction *> &UnionFind,
ArrayRef<Instruction *> ModeledInsts) { … }
void ScopBuilder::buildEqivClassBlockStmts(BasicBlock *BB) { … }
void ScopBuilder::buildStmts(Region &SR) { … }
void ScopBuilder::buildAccessFunctions(ScopStmt *Stmt, BasicBlock &BB,
Region *NonAffineSubRegion) { … }
MemoryAccess *ScopBuilder::addMemoryAccess(
ScopStmt *Stmt, Instruction *Inst, MemoryAccess::AccessType AccType,
Value *BaseAddress, Type *ElementType, bool Affine, Value *AccessValue,
ArrayRef<const SCEV *> Subscripts, ArrayRef<const SCEV *> Sizes,
MemoryKind Kind) { … }
void ScopBuilder::addArrayAccess(ScopStmt *Stmt, MemAccInst MemAccInst,
MemoryAccess::AccessType AccType,
Value *BaseAddress, Type *ElementType,
bool IsAffine,
ArrayRef<const SCEV *> Subscripts,
ArrayRef<const SCEV *> Sizes,
Value *AccessValue) { … }
static bool isDivisible(const SCEV *Expr, unsigned Size, ScalarEvolution &SE) { … }
void ScopBuilder::foldSizeConstantsToRight() { … }
void ScopBuilder::finalizeAccesses() { … }
void ScopBuilder::updateAccessDimensionality() { … }
void ScopBuilder::foldAccessRelations() { … }
void ScopBuilder::assumeNoOutOfBounds() { … }
void ScopBuilder::ensureValueWrite(Instruction *Inst) { … }
void ScopBuilder::ensureValueRead(Value *V, ScopStmt *UserStmt) { … }
void ScopBuilder::ensurePHIWrite(PHINode *PHI, ScopStmt *IncomingStmt,
BasicBlock *IncomingBlock,
Value *IncomingValue, bool IsExitBlock) { … }
void ScopBuilder::addPHIReadAccess(ScopStmt *PHIStmt, PHINode *PHI) { … }
void ScopBuilder::buildDomain(ScopStmt &Stmt) { … }
void ScopBuilder::collectSurroundingLoops(ScopStmt &Stmt) { … }
static MemoryAccess::ReductionType
getReductionType(const BinaryOperator *BinOp) { … }
static MemoryAccess::ReductionType
combineReductionType(MemoryAccess::ReductionType RT0,
MemoryAccess::ReductionType RT1) { … }
bool hasIntersectingAccesses(isl::set AllAccs, MemoryAccess *LoadMA,
MemoryAccess *StoreMA, isl::set Domain,
SmallVector<MemoryAccess *, 8> &MemAccs) { … }
bool checkCandidatePairAccesses(MemoryAccess *LoadMA, MemoryAccess *StoreMA,
isl::set Domain,
SmallVector<MemoryAccess *, 8> &MemAccs) { … }
void ScopBuilder::checkForReductions(ScopStmt &Stmt) { … }
void ScopBuilder::verifyInvariantLoads() { … }
void ScopBuilder::hoistInvariantLoads() { … }
static bool isAccessRangeTooComplex(isl::set AccessRange) { … }
bool ScopBuilder::hasNonHoistableBasePtrInScop(MemoryAccess *MA,
isl::union_map Writes) { … }
void ScopBuilder::addUserContext() { … }
isl::set ScopBuilder::getNonHoistableCtx(MemoryAccess *Access,
isl::union_map Writes) { … }
static bool isAParameter(llvm::Value *maybeParam, const Function &F) { … }
bool ScopBuilder::canAlwaysBeHoisted(MemoryAccess *MA,
bool StmtInvalidCtxIsEmpty,
bool MAInvalidCtxIsEmpty,
bool NonHoistableCtxIsEmpty) { … }
void ScopBuilder::addInvariantLoads(ScopStmt &Stmt,
InvariantAccessesTy &InvMAs) { … }
static const ScopArrayInfo *findCanonicalArray(Scop &S,
MemoryAccessList &Accesses) { … }
static bool isUsedForIndirectHoistedLoad(Scop &S, const ScopArrayInfo *Array) { … }
static void replaceBasePtrArrays(Scop &S, const ScopArrayInfo *Old,
const ScopArrayInfo *New) { … }
void ScopBuilder::canonicalizeDynamicBasePtrs() { … }
void ScopBuilder::buildAccessRelations(ScopStmt &Stmt) { … }
static bool buildMinMaxAccess(isl::set Set,
Scop::MinMaxVectorTy &MinMaxAccesses, Scop &S) { … }
bool ScopBuilder::calculateMinMaxAccess(AliasGroupTy AliasGroup,
Scop::MinMaxVectorTy &MinMaxAccesses) { … }
static isl::set getAccessDomain(MemoryAccess *MA) { … }
bool ScopBuilder::buildAliasChecks() { … }
std::tuple<ScopBuilder::AliasGroupVectorTy, DenseSet<const ScopArrayInfo *>>
ScopBuilder::buildAliasGroupsForAccesses() { … }
bool ScopBuilder::buildAliasGroups() { … }
bool ScopBuilder::buildAliasGroup(
AliasGroupTy &AliasGroup, DenseSet<const ScopArrayInfo *> HasWriteAccess) { … }
void ScopBuilder::splitAliasGroupsByDomain(AliasGroupVectorTy &AliasGroups) { … }
#ifndef NDEBUG
static void verifyUse(Scop *S, Use &Op, LoopInfo &LI) {
auto PhysUse = VirtualUse::create(S, Op, &LI, false);
auto VirtUse = VirtualUse::create(S, Op, &LI, true);
assert(PhysUse.getKind() == VirtUse.getKind());
}
static void verifyUses(Scop *S, LoopInfo &LI, DominatorTree &DT) {
for (auto *BB : S->getRegion().blocks()) {
for (auto &Inst : *BB) {
auto *Stmt = S->getStmtFor(&Inst);
if (!Stmt)
continue;
if (isIgnoredIntrinsic(&Inst))
continue;
if (Inst.isTerminator() && Stmt->isBlockStmt())
continue;
for (auto &Op : Inst.operands())
verifyUse(S, Op, LI);
if (isa<StoreInst>(Inst))
continue;
auto VirtDef =
VirtualUse::create(S, Stmt, Stmt->getSurroundingLoop(), &Inst, true);
assert(VirtDef.getKind() == VirtualUse::Synthesizable ||
VirtDef.getKind() == VirtualUse::Intra ||
VirtDef.getKind() == VirtualUse::Hoisted);
}
}
if (S->hasSingleExitEdge())
return;
if (!S->getRegion().isTopLevelRegion()) {
for (auto &Inst : *S->getRegion().getExit()) {
if (!isa<PHINode>(Inst))
break;
for (auto &Op : Inst.operands())
verifyUse(S, Op, LI);
}
}
}
#endif
void ScopBuilder::buildScop(Region &R, AssumptionCache &AC) { … }
ScopBuilder::ScopBuilder(Region *R, AssumptionCache &AC, AAResults &AA,
const DataLayout &DL, DominatorTree &DT, LoopInfo &LI,
ScopDetection &SD, ScalarEvolution &SE,
OptimizationRemarkEmitter &ORE)
: … { … }