forked from OSchip/llvm-project
[Polly] Introduce caching for the isErrorBlock function. NFC.
Compilation of the file insn-attrtab.c of the SPEC CPU 2017 502.gcc_r benchmark takes excessive time (> 30min) with Polly enabled. Most time is spent in the isErrorBlock function querying the DominatorTree. The isErrorBlock is invoked redundantly over the course of ScopDetection and ScopBuilder. This patch introduces a caching mechanism for its result. Instead of a free function, isErrorBlock is moved to ScopDetection where its cache map resides. This also means that many functions directly or indirectly calling isErrorBlock are not "const" anymore. The DetectionContextMap was marked as "mutable", but IMHO it never should have been since it stores the detection result. 502.gcc_r only takes excessive time with the new pass manager. The reason seeams to be that it invalidates the ScopDetection analysis more often than the legacy pass manager, for unknown reasons.
This commit is contained in:
parent
cc7bcef3e3
commit
58e4e71fc8
|
@ -214,7 +214,11 @@ private:
|
|||
/// Map to remember detection contexts for all regions.
|
||||
using DetectionContextMapTy =
|
||||
DenseMap<BBPair, std::unique_ptr<DetectionContext>>;
|
||||
mutable DetectionContextMapTy DetectionContextMap;
|
||||
DetectionContextMapTy DetectionContextMap;
|
||||
|
||||
/// Cache for the isErrorBlock function.
|
||||
DenseMap<std::tuple<const BasicBlock *, const Region *>, bool>
|
||||
ErrorBlockCache;
|
||||
|
||||
/// Remove cached results for @p R.
|
||||
void removeCachedResults(const Region &R);
|
||||
|
@ -305,7 +309,7 @@ private:
|
|||
/// @param Context The context of scop detection.
|
||||
///
|
||||
/// @return True if all blocks in R are valid, false otherwise.
|
||||
bool allBlocksValid(DetectionContext &Context) const;
|
||||
bool allBlocksValid(DetectionContext &Context);
|
||||
|
||||
/// Check if a region has sufficient compute instructions.
|
||||
///
|
||||
|
@ -347,7 +351,7 @@ private:
|
|||
/// @param Context The context of scop detection.
|
||||
///
|
||||
/// @return True if R is a Scop, false otherwise.
|
||||
bool isValidRegion(DetectionContext &Context) const;
|
||||
bool isValidRegion(DetectionContext &Context);
|
||||
|
||||
/// Check if an intrinsic call can be part of a Scop.
|
||||
///
|
||||
|
@ -420,7 +424,7 @@ private:
|
|||
/// @param Context The context of scop detection.
|
||||
///
|
||||
/// @return True if the instruction is valid, false otherwise.
|
||||
bool isValidInstruction(Instruction &Inst, DetectionContext &Context) const;
|
||||
bool isValidInstruction(Instruction &Inst, DetectionContext &Context);
|
||||
|
||||
/// Check if the switch @p SI with condition @p Condition is valid.
|
||||
///
|
||||
|
@ -444,7 +448,7 @@ private:
|
|||
///
|
||||
/// @return True if the branch @p BI is valid.
|
||||
bool isValidBranch(BasicBlock &BB, BranchInst *BI, Value *Condition,
|
||||
bool IsLoopBranch, DetectionContext &Context) const;
|
||||
bool IsLoopBranch, DetectionContext &Context);
|
||||
|
||||
/// Check if the SCEV @p S is affine in the current @p Context.
|
||||
///
|
||||
|
@ -472,7 +476,7 @@ private:
|
|||
///
|
||||
/// @return True if the BB contains only valid control flow.
|
||||
bool isValidCFG(BasicBlock &BB, bool IsLoopBranch, bool AllowUnreachable,
|
||||
DetectionContext &Context) const;
|
||||
DetectionContext &Context);
|
||||
|
||||
/// Is a loop valid with respect to a given region.
|
||||
///
|
||||
|
@ -480,7 +484,7 @@ private:
|
|||
/// @param Context The context of scop detection.
|
||||
///
|
||||
/// @return True if the loop is valid in the region.
|
||||
bool isValidLoop(Loop *L, DetectionContext &Context) const;
|
||||
bool isValidLoop(Loop *L, DetectionContext &Context);
|
||||
|
||||
/// Count the number of loops and the maximal loop depth in @p L.
|
||||
///
|
||||
|
@ -505,7 +509,7 @@ private:
|
|||
/// @param Context The context of scop detection.
|
||||
///
|
||||
/// @return True if ISL can compute the trip count of the loop.
|
||||
bool canUseISLTripCount(Loop *L, DetectionContext &Context) const;
|
||||
bool canUseISLTripCount(Loop *L, DetectionContext &Context);
|
||||
|
||||
/// Print the locations of all detected scops.
|
||||
void printLocations(Function &F);
|
||||
|
@ -550,7 +554,7 @@ public:
|
|||
/// referenced by a Scop that is still to be processed.
|
||||
///
|
||||
/// @return Return true if R is the maximum Region in a Scop, false otherwise.
|
||||
bool isMaxRegionInScop(const Region &R, bool Verify = true) const;
|
||||
bool isMaxRegionInScop(const Region &R, bool Verify = true);
|
||||
|
||||
/// Return the detection context for @p R, nullptr if @p R was invalid.
|
||||
DetectionContext *getDetectionContext(const Region *R) const;
|
||||
|
@ -596,12 +600,12 @@ public:
|
|||
|
||||
/// Verify if all valid Regions in this Function are still valid
|
||||
/// after some transformations.
|
||||
void verifyAnalysis() const;
|
||||
void verifyAnalysis();
|
||||
|
||||
/// Verify if R is still a valid part of Scop after some transformations.
|
||||
///
|
||||
/// @param R The Region to verify.
|
||||
void verifyRegion(const Region &R) const;
|
||||
void verifyRegion(const Region &R);
|
||||
|
||||
/// Count the number of loops and the maximal loop depth in @p R.
|
||||
///
|
||||
|
@ -615,6 +619,24 @@ public:
|
|||
countBeneficialLoops(Region *R, ScalarEvolution &SE, LoopInfo &LI,
|
||||
unsigned MinProfitableTrips);
|
||||
|
||||
/// Check if the block is a error block.
|
||||
///
|
||||
/// A error block is currently any block that fulfills at least one of
|
||||
/// the following conditions:
|
||||
///
|
||||
/// - It is terminated by an unreachable instruction
|
||||
/// - It contains a call to a non-pure function that is not immediately
|
||||
/// dominated by a loop header and that does not dominate the region exit.
|
||||
/// This is a heuristic to pick only error blocks that are conditionally
|
||||
/// executed and can be assumed to be not executed at all without the
|
||||
/// domains being available.
|
||||
///
|
||||
/// @param BB The block to check.
|
||||
/// @param R The analyzed region.
|
||||
///
|
||||
/// @return True if the block is a error block, false otherwise.
|
||||
bool isErrorBlock(llvm::BasicBlock &BB, const llvm::Region &R);
|
||||
|
||||
private:
|
||||
/// OptimizationRemarkEmitter object used to emit diagnostic remarks
|
||||
OptimizationRemarkEmitter &ORE;
|
||||
|
@ -652,8 +674,7 @@ struct ScopDetectionWrapperPass : public FunctionPass {
|
|||
void print(raw_ostream &OS, const Module *) const override;
|
||||
//@}
|
||||
|
||||
ScopDetection &getSD() { return *Result; }
|
||||
const ScopDetection &getSD() const { return *Result; }
|
||||
ScopDetection &getSD() const { return *Result; }
|
||||
};
|
||||
} // namespace polly
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ class SCEVConstant;
|
|||
} // namespace llvm
|
||||
|
||||
namespace polly {
|
||||
class ScopDetection;
|
||||
|
||||
/// Check if a call is side-effect free and has only constant arguments.
|
||||
///
|
||||
|
@ -94,17 +95,14 @@ extractConstantFactor(const llvm::SCEV *M, llvm::ScalarEvolution &SE);
|
|||
/// conditions that seemed non-affine before are now in fact affine.
|
||||
const llvm::SCEV *tryForwardThroughPHI(const llvm::SCEV *Expr, llvm::Region &R,
|
||||
llvm::ScalarEvolution &SE,
|
||||
llvm::LoopInfo &LI,
|
||||
const llvm::DominatorTree &DT);
|
||||
ScopDetection *SD);
|
||||
|
||||
/// Return a unique non-error block incoming value for @p PHI if available.
|
||||
///
|
||||
/// @param R The region to run our code on.
|
||||
/// @param LI The loopinfo tree
|
||||
/// @param DT The dominator tree
|
||||
/// @param SD The ScopDetection
|
||||
llvm::Value *getUniqueNonErrorValue(llvm::PHINode *PHI, llvm::Region *R,
|
||||
llvm::LoopInfo &LI,
|
||||
const llvm::DominatorTree &DT);
|
||||
ScopDetection *SD);
|
||||
} // namespace polly
|
||||
|
||||
#endif
|
||||
|
|
|
@ -413,27 +413,6 @@ llvm::Value *expandCodeFor(Scop &S, llvm::ScalarEvolution &SE,
|
|||
llvm::Instruction *IP, ValueMapT *VMap,
|
||||
llvm::BasicBlock *RTCBB);
|
||||
|
||||
/// Check if the block is a error block.
|
||||
///
|
||||
/// A error block is currently any block that fulfills at least one of
|
||||
/// the following conditions:
|
||||
///
|
||||
/// - It is terminated by an unreachable instruction
|
||||
/// - It contains a call to a non-pure function that is not immediately
|
||||
/// dominated by a loop header and that does not dominate the region exit.
|
||||
/// This is a heuristic to pick only error blocks that are conditionally
|
||||
/// executed and can be assumed to be not executed at all without the domains
|
||||
/// being available.
|
||||
///
|
||||
/// @param BB The block to check.
|
||||
/// @param R The analyzed region.
|
||||
/// @param LI The loop info analysis.
|
||||
/// @param DT The dominator tree of the function.
|
||||
///
|
||||
/// @return True if the block is a error block, false otherwise.
|
||||
bool isErrorBlock(llvm::BasicBlock &BB, const llvm::Region &R,
|
||||
llvm::LoopInfo &LI, const llvm::DominatorTree &DT);
|
||||
|
||||
/// Return the condition for the terminator @p TI.
|
||||
///
|
||||
/// For unconditional branches the "i1 true" condition will be returned.
|
||||
|
|
|
@ -180,12 +180,12 @@ getRegionNodeSuccessor(RegionNode *RN, Instruction *TI, unsigned idx) {
|
|||
return TI->getSuccessor(idx);
|
||||
}
|
||||
|
||||
static bool containsErrorBlock(RegionNode *RN, const Region &R, LoopInfo &LI,
|
||||
const DominatorTree &DT) {
|
||||
static bool containsErrorBlock(RegionNode *RN, const Region &R,
|
||||
ScopDetection *SD) {
|
||||
if (!RN->isSubRegion())
|
||||
return isErrorBlock(*RN->getNodeAs<BasicBlock>(), R, LI, DT);
|
||||
return SD->isErrorBlock(*RN->getNodeAs<BasicBlock>(), R);
|
||||
for (BasicBlock *BB : RN->getNodeAs<Region>()->blocks())
|
||||
if (isErrorBlock(*BB, R, LI, DT))
|
||||
if (SD->isErrorBlock(*BB, R))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
@ -448,7 +448,7 @@ bool ScopBuilder::buildConditionSets(
|
|||
.release();
|
||||
} else if (auto *PHI = dyn_cast<PHINode>(Condition)) {
|
||||
auto *Unique = dyn_cast<ConstantInt>(
|
||||
getUniqueNonErrorValue(PHI, &scop->getRegion(), LI, DT));
|
||||
getUniqueNonErrorValue(PHI, &scop->getRegion(), &SD));
|
||||
|
||||
if (Unique->isZero())
|
||||
ConsequenceCondSet = isl_set_empty(isl_set_get_space(Domain));
|
||||
|
@ -497,8 +497,8 @@ bool ScopBuilder::buildConditionSets(
|
|||
const SCEV *LeftOperand = SE.getSCEVAtScope(ICond->getOperand(0), L),
|
||||
*RightOperand = SE.getSCEVAtScope(ICond->getOperand(1), L);
|
||||
|
||||
LeftOperand = tryForwardThroughPHI(LeftOperand, R, SE, LI, DT);
|
||||
RightOperand = tryForwardThroughPHI(RightOperand, R, SE, LI, DT);
|
||||
LeftOperand = tryForwardThroughPHI(LeftOperand, R, SE, &SD);
|
||||
RightOperand = tryForwardThroughPHI(RightOperand, R, SE, &SD);
|
||||
|
||||
switch (ICond->getPredicate()) {
|
||||
case ICmpInst::ICMP_ULT:
|
||||
|
@ -844,7 +844,7 @@ bool ScopBuilder::buildDomains(
|
|||
scop->setDomain(EntryBB, Domain);
|
||||
|
||||
if (IsOnlyNonAffineRegion)
|
||||
return !containsErrorBlock(R->getNode(), *R, LI, DT);
|
||||
return !containsErrorBlock(R->getNode(), *R, &SD);
|
||||
|
||||
if (!buildDomainsWithBranchConstraints(R, InvalidDomainMap))
|
||||
return false;
|
||||
|
@ -897,7 +897,7 @@ bool ScopBuilder::buildDomainsWithBranchConstraints(
|
|||
}
|
||||
}
|
||||
|
||||
if (containsErrorBlock(RN, scop->getRegion(), LI, DT))
|
||||
if (containsErrorBlock(RN, scop->getRegion(), &SD))
|
||||
scop->notifyErrorBlock();
|
||||
;
|
||||
|
||||
|
@ -1013,7 +1013,7 @@ bool ScopBuilder::propagateInvalidStmtDomains(
|
|||
}
|
||||
}
|
||||
|
||||
bool ContainsErrorBlock = containsErrorBlock(RN, scop->getRegion(), LI, DT);
|
||||
bool ContainsErrorBlock = containsErrorBlock(RN, scop->getRegion(), &SD);
|
||||
BasicBlock *BB = getRegionNodeBasicBlock(RN);
|
||||
isl::set &Domain = scop->getOrInitEmptyDomain(BB);
|
||||
assert(!Domain.is_null() && "Cannot propagate a nullptr");
|
||||
|
@ -2257,7 +2257,7 @@ void ScopBuilder::buildAccessFunctions(ScopStmt *Stmt, BasicBlock &BB,
|
|||
|
||||
// We do not build access functions for error blocks, as they may contain
|
||||
// instructions we can not model.
|
||||
if (isErrorBlock(BB, scop->getRegion(), LI, DT))
|
||||
if (SD.isErrorBlock(BB, scop->getRegion()))
|
||||
return;
|
||||
|
||||
auto BuildAccessesForInst = [this, Stmt,
|
||||
|
@ -3673,7 +3673,7 @@ void ScopBuilder::buildScop(Region &R, AssumptionCache &AC) {
|
|||
// created somewhere.
|
||||
const InvariantLoadsSetTy &RIL = scop->getRequiredInvariantLoads();
|
||||
for (BasicBlock *BB : scop->getRegion().blocks()) {
|
||||
if (isErrorBlock(*BB, scop->getRegion(), LI, DT))
|
||||
if (SD.isErrorBlock(*BB, scop->getRegion()))
|
||||
continue;
|
||||
|
||||
for (Instruction &Inst : *BB) {
|
||||
|
|
|
@ -226,6 +226,11 @@ static cl::opt<bool, true> XPollyInvariantLoadHoisting(
|
|||
cl::location(PollyInvariantLoadHoisting), cl::Hidden, cl::ZeroOrMore,
|
||||
cl::init(false), cl::cat(PollyCategory));
|
||||
|
||||
static cl::opt<bool> PollyAllowErrorBlocks(
|
||||
"polly-allow-error-blocks",
|
||||
cl::desc("Allow to speculate on the execution of 'error blocks'."),
|
||||
cl::Hidden, cl::init(true), cl::ZeroOrMore, cl::cat(PollyCategory));
|
||||
|
||||
/// The minimal trip count under which loops are considered unprofitable.
|
||||
static const unsigned MIN_LOOP_TRIP_COUNT = 8;
|
||||
|
||||
|
@ -410,7 +415,7 @@ inline bool ScopDetection::invalid(DetectionContext &Context, bool Assert,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ScopDetection::isMaxRegionInScop(const Region &R, bool Verify) const {
|
||||
bool ScopDetection::isMaxRegionInScop(const Region &R, bool Verify) {
|
||||
if (!ValidRegions.count(&R))
|
||||
return false;
|
||||
|
||||
|
@ -570,7 +575,7 @@ bool ScopDetection::isValidSwitch(BasicBlock &BB, SwitchInst *SI,
|
|||
|
||||
bool ScopDetection::isValidBranch(BasicBlock &BB, BranchInst *BI,
|
||||
Value *Condition, bool IsLoopBranch,
|
||||
DetectionContext &Context) const {
|
||||
DetectionContext &Context) {
|
||||
// Constant integer conditions are always affine.
|
||||
if (isa<ConstantInt>(Condition))
|
||||
return true;
|
||||
|
@ -587,7 +592,7 @@ bool ScopDetection::isValidBranch(BasicBlock &BB, BranchInst *BI,
|
|||
|
||||
if (auto PHI = dyn_cast<PHINode>(Condition)) {
|
||||
auto *Unique = dyn_cast_or_null<ConstantInt>(
|
||||
getUniqueNonErrorValue(PHI, &Context.CurRegion, LI, DT));
|
||||
getUniqueNonErrorValue(PHI, &Context.CurRegion, this));
|
||||
if (Unique && (Unique->isZero() || Unique->isOne()))
|
||||
return true;
|
||||
}
|
||||
|
@ -617,8 +622,8 @@ bool ScopDetection::isValidBranch(BasicBlock &BB, BranchInst *BI,
|
|||
const SCEV *LHS = SE.getSCEVAtScope(ICmp->getOperand(0), L);
|
||||
const SCEV *RHS = SE.getSCEVAtScope(ICmp->getOperand(1), L);
|
||||
|
||||
LHS = tryForwardThroughPHI(LHS, Context.CurRegion, SE, LI, DT);
|
||||
RHS = tryForwardThroughPHI(RHS, Context.CurRegion, SE, LI, DT);
|
||||
LHS = tryForwardThroughPHI(LHS, Context.CurRegion, SE, this);
|
||||
RHS = tryForwardThroughPHI(RHS, Context.CurRegion, SE, this);
|
||||
|
||||
// If unsigned operations are not allowed try to approximate the region.
|
||||
if (ICmp->isUnsigned() && !PollyAllowUnsignedOperations)
|
||||
|
@ -650,7 +655,7 @@ bool ScopDetection::isValidBranch(BasicBlock &BB, BranchInst *BI,
|
|||
|
||||
bool ScopDetection::isValidCFG(BasicBlock &BB, bool IsLoopBranch,
|
||||
bool AllowUnreachable,
|
||||
DetectionContext &Context) const {
|
||||
DetectionContext &Context) {
|
||||
Region &CurRegion = Context.CurRegion;
|
||||
|
||||
Instruction *TI = BB.getTerminator();
|
||||
|
@ -1210,14 +1215,14 @@ bool ScopDetection::isValidMemoryAccess(MemAccInst Inst,
|
|||
}
|
||||
|
||||
bool ScopDetection::isValidInstruction(Instruction &Inst,
|
||||
DetectionContext &Context) const {
|
||||
DetectionContext &Context) {
|
||||
for (auto &Op : Inst.operands()) {
|
||||
auto *OpInst = dyn_cast<Instruction>(&Op);
|
||||
|
||||
if (!OpInst)
|
||||
continue;
|
||||
|
||||
if (isErrorBlock(*OpInst->getParent(), Context.CurRegion, LI, DT)) {
|
||||
if (isErrorBlock(*OpInst->getParent(), Context.CurRegion)) {
|
||||
auto *PHI = dyn_cast<PHINode>(OpInst);
|
||||
if (PHI) {
|
||||
for (User *U : PHI->users()) {
|
||||
|
@ -1275,8 +1280,7 @@ static bool hasExitingBlocks(Loop *L) {
|
|||
return !ExitingBlocks.empty();
|
||||
}
|
||||
|
||||
bool ScopDetection::canUseISLTripCount(Loop *L,
|
||||
DetectionContext &Context) const {
|
||||
bool ScopDetection::canUseISLTripCount(Loop *L, DetectionContext &Context) {
|
||||
// Ensure the loop has valid exiting blocks as well as latches, otherwise we
|
||||
// need to overapproximate it as a boxed loop.
|
||||
SmallVector<BasicBlock *, 4> LoopControlBlocks;
|
||||
|
@ -1291,7 +1295,7 @@ bool ScopDetection::canUseISLTripCount(Loop *L,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ScopDetection::isValidLoop(Loop *L, DetectionContext &Context) const {
|
||||
bool ScopDetection::isValidLoop(Loop *L, DetectionContext &Context) {
|
||||
// Loops that contain part but not all of the blocks of a region cannot be
|
||||
// handled by the schedule generation. Such loop constructs can happen
|
||||
// because a region can contain BBs that have no path to the exit block
|
||||
|
@ -1405,6 +1409,70 @@ ScopDetection::countBeneficialLoops(Region *R, ScalarEvolution &SE,
|
|||
return {LoopNum, MaxLoopDepth};
|
||||
}
|
||||
|
||||
static bool isErrorBlockImpl(BasicBlock &BB, const Region &R, LoopInfo &LI,
|
||||
const DominatorTree &DT) {
|
||||
if (isa<UnreachableInst>(BB.getTerminator()))
|
||||
return true;
|
||||
|
||||
if (LI.isLoopHeader(&BB))
|
||||
return false;
|
||||
|
||||
// Basic blocks that are always executed are not considered error blocks,
|
||||
// as their execution can not be a rare event.
|
||||
bool DominatesAllPredecessors = true;
|
||||
if (R.isTopLevelRegion()) {
|
||||
for (BasicBlock &I : *R.getEntry()->getParent()) {
|
||||
if (isa<ReturnInst>(I.getTerminator()) && !DT.dominates(&BB, &I)) {
|
||||
DominatesAllPredecessors = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto Pred : predecessors(R.getExit())) {
|
||||
if (R.contains(Pred) && !DT.dominates(&BB, Pred)) {
|
||||
DominatesAllPredecessors = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DominatesAllPredecessors)
|
||||
return false;
|
||||
|
||||
for (Instruction &Inst : BB)
|
||||
if (CallInst *CI = dyn_cast<CallInst>(&Inst)) {
|
||||
if (isDebugCall(CI))
|
||||
continue;
|
||||
|
||||
if (isIgnoredIntrinsic(CI))
|
||||
continue;
|
||||
|
||||
// memset, memcpy and memmove are modeled intrinsics.
|
||||
if (isa<MemSetInst>(CI) || isa<MemTransferInst>(CI))
|
||||
continue;
|
||||
|
||||
if (!CI->doesNotAccessMemory())
|
||||
return true;
|
||||
if (CI->doesNotReturn())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ScopDetection::isErrorBlock(llvm::BasicBlock &BB, const llvm::Region &R) {
|
||||
if (!PollyAllowErrorBlocks)
|
||||
return false;
|
||||
|
||||
auto It = ErrorBlockCache.insert({{&BB, &R}, false});
|
||||
if (!It.second)
|
||||
return It.first->getSecond();
|
||||
|
||||
bool Result = isErrorBlockImpl(BB, R, LI, DT);
|
||||
It.first->second = Result;
|
||||
return Result;
|
||||
}
|
||||
|
||||
Region *ScopDetection::expandRegion(Region &R) {
|
||||
// Initial no valid region was found (greater than R)
|
||||
std::unique_ptr<Region> LastValidRegion;
|
||||
|
@ -1542,7 +1610,7 @@ void ScopDetection::findScops(Region &R) {
|
|||
}
|
||||
}
|
||||
|
||||
bool ScopDetection::allBlocksValid(DetectionContext &Context) const {
|
||||
bool ScopDetection::allBlocksValid(DetectionContext &Context) {
|
||||
Region &CurRegion = Context.CurRegion;
|
||||
|
||||
for (const BasicBlock *BB : CurRegion.blocks()) {
|
||||
|
@ -1563,7 +1631,7 @@ bool ScopDetection::allBlocksValid(DetectionContext &Context) const {
|
|||
}
|
||||
|
||||
for (BasicBlock *BB : CurRegion.blocks()) {
|
||||
bool IsErrorBlock = isErrorBlock(*BB, CurRegion, LI, DT);
|
||||
bool IsErrorBlock = isErrorBlock(*BB, CurRegion);
|
||||
|
||||
// Also check exception blocks (and possibly register them as non-affine
|
||||
// regions). Even though exception blocks are not modeled, we use them
|
||||
|
@ -1657,7 +1725,7 @@ bool ScopDetection::isProfitableRegion(DetectionContext &Context) const {
|
|||
return invalid<ReportUnprofitable>(Context, /*Assert=*/true, &CurRegion);
|
||||
}
|
||||
|
||||
bool ScopDetection::isValidRegion(DetectionContext &Context) const {
|
||||
bool ScopDetection::isValidRegion(DetectionContext &Context) {
|
||||
Region &CurRegion = Context.CurRegion;
|
||||
|
||||
LLVM_DEBUG(dbgs() << "Checking region: " << CurRegion.getNameStr() << "\n\t");
|
||||
|
@ -1857,14 +1925,14 @@ const RejectLog *ScopDetection::lookupRejectionLog(const Region *R) const {
|
|||
return DC ? &DC->Log : nullptr;
|
||||
}
|
||||
|
||||
void ScopDetection::verifyRegion(const Region &R) const {
|
||||
void ScopDetection::verifyRegion(const Region &R) {
|
||||
assert(isMaxRegionInScop(R) && "Expect R is a valid region.");
|
||||
|
||||
DetectionContext Context(const_cast<Region &>(R), AA, true /*verifying*/);
|
||||
isValidRegion(Context);
|
||||
}
|
||||
|
||||
void ScopDetection::verifyAnalysis() const {
|
||||
void ScopDetection::verifyAnalysis() {
|
||||
if (!VerifyScops)
|
||||
return;
|
||||
|
||||
|
|
|
@ -135,7 +135,7 @@ struct DOTGraphTraits<ScopDetectionWrapperPass *>
|
|||
|
||||
// Print the cluster of the subregions. This groups the single basic blocks
|
||||
// and adds a different background color for each group.
|
||||
static void printRegionCluster(const ScopDetection *SD, const Region *R,
|
||||
static void printRegionCluster(ScopDetection *SD, const Region *R,
|
||||
raw_ostream &O, unsigned depth = 0) {
|
||||
O.indent(2 * depth) << "subgraph cluster_" << static_cast<const void *>(R)
|
||||
<< " {\n";
|
||||
|
|
|
@ -777,8 +777,7 @@ extractConstantFactor(const SCEV *S, ScalarEvolution &SE) {
|
|||
}
|
||||
|
||||
const SCEV *tryForwardThroughPHI(const SCEV *Expr, Region &R,
|
||||
ScalarEvolution &SE, LoopInfo &LI,
|
||||
const DominatorTree &DT) {
|
||||
ScalarEvolution &SE, ScopDetection *SD) {
|
||||
if (auto *Unknown = dyn_cast<SCEVUnknown>(Expr)) {
|
||||
Value *V = Unknown->getValue();
|
||||
auto *PHI = dyn_cast<PHINode>(V);
|
||||
|
@ -789,7 +788,7 @@ const SCEV *tryForwardThroughPHI(const SCEV *Expr, Region &R,
|
|||
|
||||
for (unsigned i = 0; i < PHI->getNumIncomingValues(); i++) {
|
||||
BasicBlock *Incoming = PHI->getIncomingBlock(i);
|
||||
if (isErrorBlock(*Incoming, R, LI, DT) && R.contains(Incoming))
|
||||
if (SD->isErrorBlock(*Incoming, R) && R.contains(Incoming))
|
||||
continue;
|
||||
if (Final)
|
||||
return Expr;
|
||||
|
@ -802,12 +801,11 @@ const SCEV *tryForwardThroughPHI(const SCEV *Expr, Region &R,
|
|||
return Expr;
|
||||
}
|
||||
|
||||
Value *getUniqueNonErrorValue(PHINode *PHI, Region *R, LoopInfo &LI,
|
||||
const DominatorTree &DT) {
|
||||
Value *getUniqueNonErrorValue(PHINode *PHI, Region *R, ScopDetection *SD) {
|
||||
Value *V = nullptr;
|
||||
for (unsigned i = 0; i < PHI->getNumIncomingValues(); i++) {
|
||||
BasicBlock *BB = PHI->getIncomingBlock(i);
|
||||
if (!isErrorBlock(*BB, *R, LI, DT)) {
|
||||
if (!SD->isErrorBlock(*BB, *R)) {
|
||||
if (V)
|
||||
return nullptr;
|
||||
V = PHI->getIncomingValue(i);
|
||||
|
|
|
@ -27,11 +27,6 @@ using namespace polly;
|
|||
|
||||
#define DEBUG_TYPE "polly-scop-helper"
|
||||
|
||||
static cl::opt<bool> PollyAllowErrorBlocks(
|
||||
"polly-allow-error-blocks",
|
||||
cl::desc("Allow to speculate on the execution of 'error blocks'."),
|
||||
cl::Hidden, cl::init(true), cl::ZeroOrMore, cl::cat(PollyCategory));
|
||||
|
||||
static cl::list<std::string> DebugFunctions(
|
||||
"polly-debug-func",
|
||||
cl::desc("Allow calls to the specified functions in SCoPs even if their "
|
||||
|
@ -413,60 +408,6 @@ Value *polly::expandCodeFor(Scop &S, ScalarEvolution &SE, const DataLayout &DL,
|
|||
return Expander.expandCodeFor(E, Ty, IP);
|
||||
}
|
||||
|
||||
bool polly::isErrorBlock(BasicBlock &BB, const Region &R, LoopInfo &LI,
|
||||
const DominatorTree &DT) {
|
||||
if (!PollyAllowErrorBlocks)
|
||||
return false;
|
||||
|
||||
if (isa<UnreachableInst>(BB.getTerminator()))
|
||||
return true;
|
||||
|
||||
if (LI.isLoopHeader(&BB))
|
||||
return false;
|
||||
|
||||
// Basic blocks that are always executed are not considered error blocks,
|
||||
// as their execution can not be a rare event.
|
||||
bool DominatesAllPredecessors = true;
|
||||
if (R.isTopLevelRegion()) {
|
||||
for (BasicBlock &I : *R.getEntry()->getParent()) {
|
||||
if (isa<ReturnInst>(I.getTerminator()) && !DT.dominates(&BB, &I)) {
|
||||
DominatesAllPredecessors = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto Pred : predecessors(R.getExit())) {
|
||||
if (R.contains(Pred) && !DT.dominates(&BB, Pred)) {
|
||||
DominatesAllPredecessors = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DominatesAllPredecessors)
|
||||
return false;
|
||||
|
||||
for (Instruction &Inst : BB)
|
||||
if (CallInst *CI = dyn_cast<CallInst>(&Inst)) {
|
||||
if (isDebugCall(CI))
|
||||
continue;
|
||||
|
||||
if (isIgnoredIntrinsic(CI))
|
||||
continue;
|
||||
|
||||
// memset, memcpy and memmove are modeled intrinsics.
|
||||
if (isa<MemSetInst>(CI) || isa<MemTransferInst>(CI))
|
||||
continue;
|
||||
|
||||
if (!CI->doesNotAccessMemory())
|
||||
return true;
|
||||
if (CI->doesNotReturn())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Value *polly::getConditionFromTerminator(Instruction *TI) {
|
||||
if (BranchInst *BR = dyn_cast<BranchInst>(TI)) {
|
||||
if (BR->isUnconditional())
|
||||
|
|
Loading…
Reference in New Issue