Index: include/polly/ScopInfo.h =================================================================== --- include/polly/ScopInfo.h +++ include/polly/ScopInfo.h @@ -34,6 +34,7 @@ using namespace llvm; namespace llvm { +class AssumptionCache; class Loop; class LoopInfo; class PHINode; @@ -1170,7 +1171,7 @@ unsigned MaxLoopDepth); /// @brief Initialize this ScopInfo . - void init(AliasAnalysis &AA); + void init(AliasAnalysis &AA, AssumptionCache &AC); /// @brief Add loop carried constraints to the header block of the loop @p L. /// @@ -1255,7 +1256,10 @@ /// @brief Build the BoundaryContext based on the wrapping of expressions. void buildBoundaryContext(); - /// @brief Add user provided parameter constraints to context. + /// @brief Add user provided parameter constraints to context (source code). + void addUserAssumptions(AssumptionCache &AC); + + /// @brief Add user provided parameter constraints to context (command line). void addUserContext(); /// @brief Add the bounds of the parameters to the context. @@ -1670,7 +1674,7 @@ void clear(); // Build the SCoP for Region @p R. - void buildScop(Region &R, DominatorTree &DT); + void buildScop(Region &R, DominatorTree &DT, AssumptionCache &AC); /// @brief Build an instance of MemoryAccess from the Load/Store instruction. /// Index: include/polly/Support/SCEVValidator.h =================================================================== --- include/polly/Support/SCEVValidator.h +++ include/polly/Support/SCEVValidator.h @@ -49,6 +49,12 @@ bool isAffineExpr(const llvm::Region *R, const llvm::SCEV *Expression, llvm::ScalarEvolution &SE, const llvm::Value *BaseAddress = 0, InvariantLoadsSetTy *ILS = nullptr); + +/// @brief Check if @p V describes an affine parameter constraint in @p R. +bool isAffineParameterConstraint(llvm::Value *V, const llvm::Region *R, + llvm::ScalarEvolution &SE, + std::vector &Params); + std::vector getParamsInAffineExpr(const llvm::Region *R, const llvm::SCEV *Expression, llvm::ScalarEvolution &SE, Index: lib/Analysis/ScopInfo.cpp =================================================================== --- lib/Analysis/ScopInfo.cpp +++ lib/Analysis/ScopInfo.cpp @@ -30,6 +30,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/LoopIterator.h" #include "llvm/Analysis/RegionIterator.h" @@ -1048,7 +1049,7 @@ "Condition of exiting branch was neither constant nor ICmp!"); ScalarEvolution &SE = *S.getSE(); - BasicBlock *BB = TI->getParent(); + BasicBlock *BB = TI ? TI->getParent() : nullptr; isl_pw_aff *LHS, *RHS; LHS = S.getPwAff(SE.getSCEVAtScope(ICond->getOperand(0), L), BB); RHS = S.getPwAff(SE.getSCEVAtScope(ICond->getOperand(1), L), BB); @@ -1056,6 +1057,10 @@ buildConditionSet(ICond->getPredicate(), LHS, RHS, Domain); } + // If no terminator was given we are only looking for parameter constraints. + if (!TI) + ConsequenceCondSet = isl_set_params(ConsequenceCondSet); + assert(ConsequenceCondSet); isl_set *AlternativeCondSet = isl_set_complement(isl_set_copy(ConsequenceCondSet)); @@ -1572,6 +1577,38 @@ trackAssumption(WRAPPING, BoundaryContext, DebugLoc()); } +void Scop::addUserAssumptions(AssumptionCache &AC) { + auto *R = &getRegion(); + auto &F = *R->getEntry()->getParent(); + for (auto &Assumption : AC.assumptions()) { + auto *CI = dyn_cast_or_null(Assumption); + if (!CI || CI->getNumArgOperands() != 1) + continue; + + auto *Val = CI->getArgOperand(0); + std::vector Params; + if (!isAffineParameterConstraint(Val, R, *SE, Params)) { + emitOptimizationRemarkAnalysis(F.getContext(), DEBUG_TYPE, F, + CI->getDebugLoc(), + "Non-affine user assumption."); + continue; + } + + addParams(Params); + + auto *L = LI.getLoopFor(CI->getParent()); + SmallVector ConditionSets; + buildConditionSets(*this, Val, nullptr, L, Context, ConditionSets); + + auto *AssumptionCtx = isl_set_params(ConditionSets[0]); + emitOptimizationRemarkAnalysis( + F.getContext(), DEBUG_TYPE, F, CI->getDebugLoc(), + "Use user assumption: " + stringFromIslObj(AssumptionCtx)); + Context = isl_set_intersect(Context, AssumptionCtx); + isl_set_free(ConditionSets[1]); + } +} + void Scop::addUserContext() { if (UserContextStr.empty()) return; @@ -2462,8 +2499,9 @@ IslCtx(Context), Context(nullptr), Affinator(this), AssumedContext(nullptr), BoundaryContext(nullptr), Schedule(nullptr) {} -void Scop::init(AliasAnalysis &AA) { +void Scop::init(AliasAnalysis &AA, AssumptionCache &AC) { buildContext(); + addUserAssumptions(AC); buildInvariantEquivalenceClasses(); buildDomains(&R); @@ -3753,7 +3791,7 @@ MemoryAccess::PHI); } -void ScopInfo::buildScop(Region &R, DominatorTree &DT) { +void ScopInfo::buildScop(Region &R, DominatorTree &DT, AssumptionCache &AC) { unsigned MaxLoopDepth = getMaxLoopDepthInRegion(R, *LI, *SD); scop = new Scop(R, AccFuncMap, *SD, *SE, DT, *LI, ctx, MaxLoopDepth); @@ -3770,7 +3808,7 @@ if (!R.getExitingBlock()) buildAccessFunctions(R, *R.getExit(), nullptr, /* IsExitBlock */ true); - scop->init(*AA); + scop->init(*AA, AC); } void ScopInfo::print(raw_ostream &OS, const Module *) const { @@ -3808,6 +3846,7 @@ AU.addRequiredTransitive(); AU.addRequiredTransitive(); AU.addRequired(); + AU.addRequired(); AU.setPreservesAll(); } @@ -3823,13 +3862,14 @@ AA = &getAnalysis().getAAResults(); TD = &F->getParent()->getDataLayout(); DominatorTree &DT = getAnalysis().getDomTree(); + auto &AC = getAnalysis().getAssumptionCache(*F); DebugLoc Beg, End; getDebugLocations(R, Beg, End); emitOptimizationRemarkAnalysis(F->getContext(), DEBUG_TYPE, *F, Beg, "SCoP begins here."); - buildScop(*R, DT); + buildScop(*R, DT, AC); emitOptimizationRemarkAnalysis(F->getContext(), DEBUG_TYPE, *F, End, "SCoP ends here."); @@ -3857,6 +3897,7 @@ "Polly - Create polyhedral description of Scops", false, false); INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass); +INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker); INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass); INITIALIZE_PASS_DEPENDENCY(RegionInfoPass); INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass); Index: lib/Support/SCEVValidator.cpp =================================================================== --- lib/Support/SCEVValidator.cpp +++ lib/Support/SCEVValidator.cpp @@ -587,6 +587,35 @@ return Result.isValid(); } +bool isAffineParameterConstraint(Value *V, const Region *R, ScalarEvolution &SE, + std::vector &Params) { + if (auto *ICmp = dyn_cast(V)) { + return isAffineParameterConstraint(ICmp->getOperand(0), R, SE, Params) && + isAffineParameterConstraint(ICmp->getOperand(1), R, SE, Params); + } else if (auto *BinOp = dyn_cast(V)) { + auto Opcode = BinOp->getOpcode(); + if (Opcode != Instruction::And && Opcode != Instruction::Or) + return false; + + return isAffineParameterConstraint(BinOp->getOperand(0), R, SE, Params) && + isAffineParameterConstraint(BinOp->getOperand(1), R, SE, Params); + } + + auto *E = SE.getSCEV(V); + if (isa(E)) + return false; + + SCEVValidator Validator(R, SE, nullptr, nullptr); + ValidatorResult Result = Validator.visit(E); + if (!Result.isConstant()) + return false; + + auto ResultParams = Result.getParameters(); + Params.insert(Params.end(), ResultParams.begin(), ResultParams.end()); + + return true; +} + std::vector getParamsInAffineExpr(const Region *R, const SCEV *Expr, ScalarEvolution &SE,