diff --git a/polly/include/polly/ScopBuilder.h b/polly/include/polly/ScopBuilder.h --- a/polly/include/polly/ScopBuilder.h +++ b/polly/include/polly/ScopBuilder.h @@ -61,6 +61,18 @@ // The Scop std::unique_ptr scop; + /// Collection to hold taken assumptions. + /// + /// There are two reasons why we want to record assumptions first before we + /// add them to the assumed/invalid context: + /// 1) If the SCoP is not profitable or otherwise invalid without the + /// assumed/invalid context we do not have to compute it. + /// 2) Information about the context are gathered rather late in the SCoP + /// construction (basically after we know all parameters), thus the user + /// might see overly complicated assumptions to be taken while they will + /// only be simplified later on. + RecordedAssumptionsTy RecordedAssumptions; + // Methods for pattern matching against Fortran code generated by dragonegg. // @{ diff --git a/polly/include/polly/ScopInfo.h b/polly/include/polly/ScopInfo.h --- a/polly/include/polly/ScopInfo.h +++ b/polly/include/polly/ScopInfo.h @@ -19,6 +19,7 @@ #include "polly/ScopDetection.h" #include "polly/Support/SCEVAffinator.h" +#include "polly/Support/ScopHelper.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SetVector.h" @@ -54,23 +55,6 @@ // are also unlikely to result in good code. extern int const MaxDisjunctsInDomain; -/// Enumeration of assumptions Polly can take. -enum AssumptionKind { - ALIASING, - INBOUNDS, - WRAPPING, - UNSIGNED, - PROFITABLE, - ERRORBLOCK, - COMPLEXITY, - INFINITELOOP, - INVARIANTLOAD, - DELINEARIZATION, -}; - -/// Enum to distinguish between assumptions and restrictions. -enum AssumptionSign { AS_ASSUMPTION, AS_RESTRICTION }; - /// The different memory kinds used in Polly. /// /// We distinguish between arrays and various scalar memory objects. We use @@ -479,6 +463,8 @@ RT_BAND, ///< Bitwise And }; + using SubscriptsTy = SmallVector; + private: /// A unique identifier for this memory access. /// @@ -590,7 +576,7 @@ bool IsAffine = true; /// Subscript expression for each dimension. - SmallVector Subscripts; + SubscriptsTy Subscripts; /// Relation from statement instances to the accessed array elements. /// @@ -633,7 +619,7 @@ isl::basic_map createBasicAccessMap(ScopStmt *Statement); - void assumeNoOutOfBound(); + isl::set assumeNoOutOfBound(); /// Compute bounds on an over approximated access relation. /// @@ -894,6 +880,11 @@ /// Return the access instruction of this memory access. Instruction *getAccessInstruction() const { return AccessInstruction; } + /// Return an iterator range containing the subscripts. + iterator_range subscripts() const { + return make_range(Subscripts.begin(), Subscripts.end()); + } + /// Return the number of access function subscript. unsigned getNumSubscripts() const { return Subscripts.size(); } @@ -1624,24 +1615,6 @@ /// Print ScopStmt S to raw_ostream OS. raw_ostream &operator<<(raw_ostream &OS, const ScopStmt &S); -/// Helper struct to remember assumptions. -struct Assumption { - /// The kind of the assumption (e.g., WRAPPING). - AssumptionKind Kind; - - /// Flag to distinguish assumptions and restrictions. - AssumptionSign Sign; - - /// The valid/invalid context if this is an assumption/restriction. - isl::set Set; - - /// The location that caused this assumption. - DebugLoc Loc; - - /// An optional block whose domain can simplify the assumption. - BasicBlock *BB; -}; - /// Build the conditions sets for the branch condition @p Condition in /// the @p Domain. /// @@ -1838,19 +1811,6 @@ /// need to be "false". Otherwise they behave the same. isl::set InvalidContext; - using RecordedAssumptionsTy = SmallVector; - /// Collection to hold taken assumptions. - /// - /// There are two reasons why we want to record assumptions first before we - /// add them to the assumed/invalid context: - /// 1) If the SCoP is not profitable or otherwise invalid without the - /// assumed/invalid context we do not have to compute it. - /// 2) Information about the context are gathered rather late in the SCoP - /// construction (basically after we know all parameters), thus the user - /// might see overly complicated assumptions to be taken while they will - /// only be simplified later on. - RecordedAssumptionsTy RecordedAssumptions; - /// The schedule of the SCoP /// /// The schedule of the SCoP describes the execution order of the statements @@ -2129,12 +2089,6 @@ InvariantEquivClasses.end()); } - /// Return an iterator range containing hold assumptions. - iterator_range - recorded_assumptions() const { - return make_range(RecordedAssumptions.begin(), RecordedAssumptions.end()); - } - /// Return an iterator range containing all the MemoryAccess objects of the /// Scop. iterator_range access_functions() { @@ -2297,9 +2251,6 @@ /// @returns True if the optimized SCoP can be executed. bool hasFeasibleRuntimeContext() const; - /// Clear assumptions which have been already processed. - void clearRecordedAssumptions() { return RecordedAssumptions.clear(); } - /// Check if the assumption in @p Set is trivial or not. /// /// @param Set The relations between parameters that are assumed to hold. @@ -2347,24 +2298,6 @@ void addAssumption(AssumptionKind Kind, isl::set Set, DebugLoc Loc, AssumptionSign Sign, BasicBlock *BB); - /// Record an assumption for later addition to the assumed context. - /// - /// This function will add the assumption to the RecordedAssumptions. This - /// collection will be added (@see addAssumption) to the assumed context once - /// all paramaters are known and the context is fully built. - /// - /// @param Kind The assumption kind describing the underlying cause. - /// @param Set The relations between parameters that are assumed to hold. - /// @param Loc The location in the source that caused this assumption. - /// @param Sign Enum to indicate if the assumptions in @p Set are positive - /// (needed/assumptions) or negative (invalid/restrictions). - /// @param BB The block in which this assumption was taken. If it is - /// set, the domain of that block will be used to simplify the - /// actual assumption in @p Set once it is added. This is useful - /// if the assumption was created prior to the domain. - void recordAssumption(AssumptionKind Kind, isl::set Set, DebugLoc Loc, - AssumptionSign Sign, BasicBlock *BB = nullptr); - /// Mark the scop as invalid. /// /// This method adds an assumption to the scop that is always invalid. As a @@ -2504,7 +2437,7 @@ /// /// @returns The ScopArrayInfo pointer or NULL if no such pointer is /// available. - const ScopArrayInfo *getScopArrayInfoOrNull(Value *BasePtr, MemoryKind Kind); + ScopArrayInfo *getScopArrayInfoOrNull(Value *BasePtr, MemoryKind Kind); /// Return the cached ScopArrayInfo object for @p BasePtr. /// @@ -2513,7 +2446,7 @@ /// /// @returns The ScopArrayInfo pointer (may assert if no such pointer is /// available). - const ScopArrayInfo *getScopArrayInfo(Value *BasePtr, MemoryKind Kind); + ScopArrayInfo *getScopArrayInfo(Value *BasePtr, MemoryKind Kind); /// Invalidate ScopArrayInfo object for base address. /// @@ -2589,13 +2522,16 @@ /// a dummy value of appropriate dimension is returned. This allows to bail /// for complex cases without "error handling code" needed on the users side. PWACtx getPwAff(const SCEV *E, BasicBlock *BB = nullptr, - bool NonNegative = false); + bool NonNegative = false, + RecordedAssumptionsTy *RecordedAssumptions = nullptr); /// Compute the isl representation for the SCEV @p E /// /// This function is like @see Scop::getPwAff() but strips away the invalid /// domain part associated with the piecewise affine function. - isl::pw_aff getPwAffOnly(const SCEV *E, BasicBlock *BB = nullptr); + isl::pw_aff + getPwAffOnly(const SCEV *E, BasicBlock *BB = nullptr, + RecordedAssumptionsTy *RecordedAssumptions = nullptr); /// Check if an AddRec for the loop L is cached. bool hasNSWAddRecForLoop(Loop *L) { return Affinator.hasNSWAddRecForLoop(L); } diff --git a/polly/include/polly/Support/SCEVAffinator.h b/polly/include/polly/Support/SCEVAffinator.h --- a/polly/include/polly/Support/SCEVAffinator.h +++ b/polly/include/polly/Support/SCEVAffinator.h @@ -13,6 +13,7 @@ #ifndef POLLY_SCEV_AFFINATOR_H #define POLLY_SCEV_AFFINATOR_H +#include "polly/Support/ScopHelper.h" #include "llvm/Analysis/ScalarEvolutionExpressions.h" #include "isl/isl-noexceptions.h" @@ -36,10 +37,12 @@ /// @param BB The block in which @p E is executed. /// /// @returns The isl representation of the SCEV @p E in @p Domain. - PWACtx getPwAff(const llvm::SCEV *E, llvm::BasicBlock *BB = nullptr); + PWACtx getPwAff(const llvm::SCEV *E, llvm::BasicBlock *BB = nullptr, + RecordedAssumptionsTy *RecordedAssumptions = nullptr); /// Take the assumption that @p PWAC is non-negative. - void takeNonNegativeAssumption(PWACtx &PWAC); + void takeNonNegativeAssumption( + PWACtx &PWAC, RecordedAssumptionsTy *RecordedAssumptions = nullptr); /// Interpret the PWA in @p PWAC as an unsigned value. void interpretAsUnsigned(PWACtx &PWAC, unsigned Width); @@ -63,6 +66,7 @@ llvm::ScalarEvolution &SE; llvm::LoopInfo &LI; llvm::BasicBlock *BB; + RecordedAssumptionsTy *RecordedAssumptions = nullptr; /// Target data for element size computing. const llvm::DataLayout &TD; diff --git a/polly/include/polly/Support/ScopHelper.h b/polly/include/polly/Support/ScopHelper.h --- a/polly/include/polly/Support/ScopHelper.h +++ b/polly/include/polly/Support/ScopHelper.h @@ -17,6 +17,7 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/ValueHandle.h" +#include "isl/isl-noexceptions.h" namespace llvm { class LoopInfo; @@ -34,6 +35,63 @@ class Scop; class ScopStmt; +/// Enumeration of assumptions Polly can take. +enum AssumptionKind { + ALIASING, + INBOUNDS, + WRAPPING, + UNSIGNED, + PROFITABLE, + ERRORBLOCK, + COMPLEXITY, + INFINITELOOP, + INVARIANTLOAD, + DELINEARIZATION, +}; + +/// Enum to distinguish between assumptions and restrictions. +enum AssumptionSign { AS_ASSUMPTION, AS_RESTRICTION }; + +/// Helper struct to remember assumptions. +struct Assumption { + /// The kind of the assumption (e.g., WRAPPING). + AssumptionKind Kind; + + /// Flag to distinguish assumptions and restrictions. + AssumptionSign Sign; + + /// The valid/invalid context if this is an assumption/restriction. + isl::set Set; + + /// The location that caused this assumption. + llvm::DebugLoc Loc; + + /// An optional block whose domain can simplify the assumption. + llvm::BasicBlock *BB; +}; + +using RecordedAssumptionsTy = llvm::SmallVector; + +/// Record an assumption for later addition to the assumed context. +/// +/// This function will add the assumption to the RecordedAssumptions. This +/// collection will be added (@see addAssumption) to the assumed context once +/// all paramaters are known and the context is fully built. +/// +/// @param RecordedAssumption container which keeps all recorded assumptions. +/// @param Kind The assumption kind describing the underlying cause. +/// @param Set The relations between parameters that are assumed to hold. +/// @param Loc The location in the source that caused this assumption. +/// @param Sign Enum to indicate if the assumptions in @p Set are positive +/// (needed/assumptions) or negative (invalid/restrictions). +/// @param BB The block in which this assumption was taken. If it is +/// set, the domain of that block will be used to simplify the +/// actual assumption in @p Set once it is added. This is useful +/// if the assumption was created prior to the domain. +void recordAssumption(RecordedAssumptionsTy *RecordedAssumptions, + AssumptionKind Kind, isl::set Set, llvm::DebugLoc Loc, + AssumptionSign Sign, llvm::BasicBlock *BB = nullptr); + /// Type to remap values. using ValueMapT = llvm::DenseMap, llvm::AssertingVH>; diff --git a/polly/lib/Analysis/ScopBuilder.cpp b/polly/lib/Analysis/ScopBuilder.cpp --- a/polly/lib/Analysis/ScopBuilder.cpp +++ b/polly/lib/Analysis/ScopBuilder.cpp @@ -96,6 +96,11 @@ " their loads. "), cl::Hidden, cl::init(false), cl::cat(PollyCategory)); +static cl::opt + PollyIgnoreInbounds("polly-ignore-inbounds", + cl::desc("Do not take inbounds assumptions at all"), + cl::Hidden, cl::init(false), cl::cat(PollyCategory)); + static cl::opt RunTimeChecksMaxArraysPerGroup( "polly-rtc-max-arrays-per-group", cl::desc("The maximal number of arrays to compare in each alias group."), @@ -344,7 +349,7 @@ ScopBuilder::getPwAff(BasicBlock *BB, DenseMap &InvalidDomainMap, const SCEV *E, bool NonNegative) { - PWACtx PWAC = scop->getPwAff(E, BB, NonNegative); + PWACtx PWAC = scop->getPwAff(E, BB, NonNegative, &RecordedAssumptions); InvalidDomainMap[BB] = InvalidDomainMap[BB].unite(PWAC.second); return PWAC.first.release(); } @@ -796,9 +801,8 @@ return true; isl::set UnboundedCtx = Parts.first.params(); - scop->recordAssumption(INFINITELOOP, UnboundedCtx, - HeaderBB->getTerminator()->getDebugLoc(), - AS_RESTRICTION); + recordAssumption(&RecordedAssumptions, INFINITELOOP, UnboundedCtx, + HeaderBB->getTerminator()->getDebugLoc(), AS_RESTRICTION); return true; } @@ -1019,9 +1023,8 @@ } else { InvalidDomain = Domain; isl::set DomPar = Domain.params(); - scop->recordAssumption(ERRORBLOCK, DomPar, - BB->getTerminator()->getDebugLoc(), - AS_RESTRICTION); + recordAssumption(&RecordedAssumptions, ERRORBLOCK, DomPar, + BB->getTerminator()->getDebugLoc(), AS_RESTRICTION); Domain = isl::set::empty(Domain.get_space()); } @@ -1488,7 +1491,7 @@ } void ScopBuilder::addRecordedAssumptions() { - for (auto &AS : llvm::reverse(scop->recorded_assumptions())) { + for (auto &AS : llvm::reverse(RecordedAssumptions)) { if (!AS.BB) { scop->addAssumption(AS.Kind, AS.Set, AS.Loc, AS.Sign, @@ -1518,7 +1521,6 @@ scop->addAssumption(AS.Kind, isl::manage(S), AS.Loc, AS_RESTRICTION, AS.BB); } - scop->clearRecordedAssumptions(); } void ScopBuilder::addUserAssumptions( @@ -2502,9 +2504,17 @@ } void ScopBuilder::assumeNoOutOfBounds() { + if (PollyIgnoreInbounds) + return; for (auto &Stmt : *scop) - for (auto &Access : Stmt) - Access->assumeNoOutOfBound(); + for (auto &Access : Stmt) { + isl::set Outside = Access->assumeNoOutOfBound(); + const auto &Loc = Access->getAccessInstruction() + ? Access->getAccessInstruction()->getDebugLoc() + : DebugLoc(); + recordAssumption(&RecordedAssumptions, INBOUNDS, Outside, Loc, + AS_ASSUMPTION); + } } void ScopBuilder::ensureValueWrite(Instruction *Inst) { @@ -2959,8 +2969,8 @@ // Even if the statement is not modeled precisely we can hoist the load if it // does not involve any parameters that might have been specialized by the // statement domain. - for (unsigned u = 0, e = MA->getNumSubscripts(); u < e; u++) - if (!isa(MA->getSubscript(u))) + for (const SCEV *Subscript : MA->subscripts()) + if (!isa(Subscript)) return false; return true; } @@ -3214,8 +3224,26 @@ else Ty = MemoryKind::Array; + // Create isl::pw_aff for SCEVs which describe sizes. Collect all + // assumptions which are taken. isl::pw_aff objects are cached internally + // and they are used later by scop. + for (const SCEV *Size : Access->Sizes) { + if (!Size) + continue; + scop->getPwAff(Size, nullptr, false, &RecordedAssumptions); + } auto *SAI = scop->getOrCreateScopArrayInfo(Access->getOriginalBaseAddr(), ElementType, Access->Sizes, Ty); + + // Create isl::pw_aff for SCEVs which describe subscripts. Collect all + // assumptions which are taken. isl::pw_aff objects are cached internally + // and they are used later by scop. + for (const SCEV *Subscript : Access->subscripts()) { + if (!Access->isAffine() || !Subscript) + continue; + scop->getPwAff(Subscript, Stmt.getEntryBlock(), false, + &RecordedAssumptions); + } Access->buildAccessRelation(SAI); scop->addAccessData(Access); } @@ -3768,6 +3796,7 @@ InfeasibleScops++; Msg = "SCoP ends here but was dismissed."; LLVM_DEBUG(dbgs() << "SCoP detected but dismissed\n"); + RecordedAssumptions.clear(); scop.reset(); } else { Msg = "SCoP ends here."; diff --git a/polly/lib/Analysis/ScopInfo.cpp b/polly/lib/Analysis/ScopInfo.cpp --- a/polly/lib/Analysis/ScopInfo.cpp +++ b/polly/lib/Analysis/ScopInfo.cpp @@ -133,11 +133,6 @@ cl::desc("Take more precise inbounds assumptions (do not scale well)"), cl::Hidden, cl::init(false), cl::cat(PollyCategory)); -static cl::opt - PollyIgnoreInbounds("polly-ignore-inbounds", - cl::desc("Do not take inbounds assumptions at all"), - cl::Hidden, cl::init(false), cl::cat(PollyCategory)); - static cl::opt PollyIgnoreParamBounds( "polly-ignore-parameter-bounds", cl::desc( @@ -662,9 +657,7 @@ // possibly yield out of bound memory accesses. The complement of these // constraints is the set of constraints that needs to be assumed to ensure such // statement instances are never executed. -void MemoryAccess::assumeNoOutOfBound() { - if (PollyIgnoreInbounds) - return; +isl::set MemoryAccess::assumeNoOutOfBound() { auto *SAI = getScopArrayInfo(); isl::space Space = getOriginalAccessRelationSpace().range(); isl::set Outside = isl::set::empty(Space); @@ -692,13 +685,10 @@ // bail out more often than strictly necessary. Outside = Outside.remove_divs(); Outside = Outside.complement(); - const auto &Loc = getAccessInstruction() - ? getAccessInstruction()->getDebugLoc() - : DebugLoc(); + if (!PollyPreciseInbounds) Outside = Outside.gist_params(Statement->getDomain().params()); - Statement->getParent()->recordAssumption(INBOUNDS, Outside, Loc, - AS_ASSUMPTION); + return Outside; } void MemoryAccess::buildMemIntrinsicAccessRelation() { @@ -1856,13 +1846,12 @@ return SAI; } -const ScopArrayInfo *Scop::getScopArrayInfoOrNull(Value *BasePtr, - MemoryKind Kind) { +ScopArrayInfo *Scop::getScopArrayInfoOrNull(Value *BasePtr, MemoryKind Kind) { auto *SAI = ScopArrayInfoMap[std::make_pair(BasePtr, Kind)].get(); return SAI; } -const ScopArrayInfo *Scop::getScopArrayInfo(Value *BasePtr, MemoryKind Kind) { +ScopArrayInfo *Scop::getScopArrayInfo(Value *BasePtr, MemoryKind Kind) { auto *SAI = getScopArrayInfoOrNull(BasePtr, Kind); assert(SAI && "No ScopArrayInfo available for this base pointer"); return SAI; @@ -2117,13 +2106,6 @@ InvalidContext = InvalidContext.unite(Set).coalesce(); } -void Scop::recordAssumption(AssumptionKind Kind, isl::set Set, DebugLoc Loc, - AssumptionSign Sign, BasicBlock *BB) { - assert((Set.is_params() || BB) && - "Assumptions without a basic block must be parameter sets"); - RecordedAssumptions.push_back({Kind, Sign, Set, Loc, BB}); -} - void Scop::invalidate(AssumptionKind Kind, DebugLoc Loc, BasicBlock *BB) { LLVM_DEBUG(dbgs() << "Invalidate SCoP because of reason " << Kind << "\n"); addAssumption(Kind, isl::set::empty(getParamSpace()), Loc, AS_ASSUMPTION, BB); @@ -2241,13 +2223,14 @@ isl::ctx Scop::getIslCtx() const { return IslCtx.get(); } __isl_give PWACtx Scop::getPwAff(const SCEV *E, BasicBlock *BB, - bool NonNegative) { + bool NonNegative, + RecordedAssumptionsTy *RecordedAssumptions) { // First try to use the SCEVAffinator to generate a piecewise defined // affine function from @p E in the context of @p BB. If that tasks becomes to // complex the affinator might return a nullptr. In such a case we invalidate // the SCoP and return a dummy value. This way we do not need to add error // handling code to all users of this function. - auto PWAC = Affinator.getPwAff(E, BB); + auto PWAC = Affinator.getPwAff(E, BB, RecordedAssumptions); if (PWAC.first) { // TODO: We could use a heuristic and either use: // SCEVAffinator::takeNonNegativeAssumption @@ -2255,13 +2238,13 @@ // SCEVAffinator::interpretAsUnsigned // to deal with unsigned or "NonNegative" SCEVs. if (NonNegative) - Affinator.takeNonNegativeAssumption(PWAC); + Affinator.takeNonNegativeAssumption(PWAC, RecordedAssumptions); return PWAC; } auto DL = BB ? BB->getTerminator()->getDebugLoc() : DebugLoc(); invalidate(COMPLEXITY, DL, BB); - return Affinator.getPwAff(SE->getZero(E->getType()), BB); + return Affinator.getPwAff(SE->getZero(E->getType()), BB, RecordedAssumptions); } isl::union_set Scop::getDomains() const { @@ -2274,8 +2257,9 @@ return isl::manage(Domain); } -isl::pw_aff Scop::getPwAffOnly(const SCEV *E, BasicBlock *BB) { - PWACtx PWAC = getPwAff(E, BB); +isl::pw_aff Scop::getPwAffOnly(const SCEV *E, BasicBlock *BB, + RecordedAssumptionsTy *RecordedAssumptions) { + PWACtx PWAC = getPwAff(E, BB, RecordedAssumptions); return PWAC.first; } diff --git a/polly/lib/Support/SCEVAffinator.cpp b/polly/lib/Support/SCEVAffinator.cpp --- a/polly/lib/Support/SCEVAffinator.cpp +++ b/polly/lib/Support/SCEVAffinator.cpp @@ -95,23 +95,28 @@ NonNegPWA, isl_pw_aff_add(PWAC.first.release(), ExpPWA))); } -void SCEVAffinator::takeNonNegativeAssumption(PWACtx &PWAC) { +void SCEVAffinator::takeNonNegativeAssumption( + PWACtx &PWAC, RecordedAssumptionsTy *RecordedAssumptions) { + this->RecordedAssumptions = RecordedAssumptions; + auto *NegPWA = isl_pw_aff_neg(PWAC.first.copy()); auto *NegDom = isl_pw_aff_pos_set(NegPWA); PWAC.second = isl::manage(isl_set_union(PWAC.second.release(), isl_set_copy(NegDom))); auto *Restriction = BB ? NegDom : isl_set_params(NegDom); auto DL = BB ? BB->getTerminator()->getDebugLoc() : DebugLoc(); - S->recordAssumption(UNSIGNED, isl::manage(Restriction), DL, AS_RESTRICTION, - BB); + recordAssumption(RecordedAssumptions, UNSIGNED, isl::manage(Restriction), DL, + AS_RESTRICTION, BB); } PWACtx SCEVAffinator::getPWACtxFromPWA(isl::pw_aff PWA) { return std::make_pair(PWA, isl::set::empty(isl::space(Ctx, 0, NumIterators))); } -PWACtx SCEVAffinator::getPwAff(const SCEV *Expr, BasicBlock *BB) { +PWACtx SCEVAffinator::getPwAff(const SCEV *Expr, BasicBlock *BB, + RecordedAssumptionsTy *RecordedAssumptions) { this->BB = BB; + this->RecordedAssumptions = RecordedAssumptions; if (BB) { auto *DC = S->getDomainConditions(BB).release(); @@ -145,7 +150,8 @@ NotEqualSet = NotEqualSet.coalesce(); if (!NotEqualSet.is_empty()) - S->recordAssumption(WRAPPING, NotEqualSet, Loc, AS_RESTRICTION, BB); + recordAssumption(RecordedAssumptions, WRAPPING, NotEqualSet, Loc, + AS_RESTRICTION, BB); return PWAC; } @@ -289,8 +295,8 @@ OutOfBoundsDom = isl_set_params(OutOfBoundsDom); } - S->recordAssumption(UNSIGNED, isl::manage(OutOfBoundsDom), DebugLoc(), - AS_RESTRICTION, BB); + recordAssumption(RecordedAssumptions, UNSIGNED, isl::manage(OutOfBoundsDom), + DebugLoc(), AS_RESTRICTION, BB); return OpPWAC; } @@ -344,7 +350,7 @@ // If the width is to big we assume the negative part does not occur. if (!computeModuloForExpr(Op)) { - takeNonNegativeAssumption(OpPWAC); + takeNonNegativeAssumption(OpPWAC, RecordedAssumptions); return OpPWAC; } @@ -485,7 +491,7 @@ // precise but therefor a heuristic is needed. // Assume a non-negative dividend. - takeNonNegativeAssumption(DividendPWAC); + takeNonNegativeAssumption(DividendPWAC, RecordedAssumptions); DividendPWAC = combine(DividendPWAC, DivisorPWAC, isl_pw_aff_div); DividendPWAC.first = DividendPWAC.first.floor(); diff --git a/polly/lib/Support/ScopHelper.cpp b/polly/lib/Support/ScopHelper.cpp --- a/polly/lib/Support/ScopHelper.cpp +++ b/polly/lib/Support/ScopHelper.cpp @@ -221,6 +221,16 @@ polly::splitEntryBlockForAlloca(EntryBlock, DT, LI, RI); } +void polly::recordAssumption(polly::RecordedAssumptionsTy *RecordedAssumptions, + polly::AssumptionKind Kind, isl::set Set, + DebugLoc Loc, polly::AssumptionSign Sign, + BasicBlock *BB) { + assert((Set.is_params() || BB) && + "Assumptions without a basic block must be parameter sets"); + if (RecordedAssumptions) + RecordedAssumptions->push_back({Kind, Sign, Set, Loc, BB}); +} + /// The SCEVExpander will __not__ generate any code for an existing SDiv/SRem /// instruction but just use it, if it is referenced as a SCEVUnknown. We want /// however to generate new code if the instruction is in the analyzed region