Index: polly/trunk/include/polly/ScopBuilder.h =================================================================== --- polly/trunk/include/polly/ScopBuilder.h +++ polly/trunk/include/polly/ScopBuilder.h @@ -375,6 +375,25 @@ /// ... void verifyInvariantLoads(); + /// Hoist invariant memory loads and check for required ones. + /// + /// We first identify "common" invariant loads, thus loads that are invariant + /// and can be hoisted. Then we check if all required invariant loads have + /// been identified as (common) invariant. A load is a required invariant load + /// if it was assumed to be invariant during SCoP detection, e.g., to assume + /// loop bounds to be affine or runtime alias checks to be placeable. In case + /// a required invariant load was not identified as (common) invariant we will + /// drop this SCoP. An example for both "common" as well as required invariant + /// loads is given below: + /// + /// for (int i = 1; i < *LB[0]; i++) + /// for (int j = 1; j < *LB[1]; j++) + /// A[i][j] += A[0][0] + (*V); + /// + /// Common inv. loads: V, A[0][0], LB[0], LB[1] + /// Required inv. loads: LB[0], LB[1], (V, if it may alias with A or LB) + void hoistInvariantLoads(); + /// Collect loads which might form a reduction chain with @p StoreMA. /// /// Check if the stored value for @p StoreMA is a binary operator with one or Index: polly/trunk/include/polly/ScopInfo.h =================================================================== --- polly/trunk/include/polly/ScopInfo.h +++ polly/trunk/include/polly/ScopInfo.h @@ -2031,42 +2031,11 @@ /// Check if the base ptr of @p MA is in the SCoP but not hoistable. bool hasNonHoistableBasePtrInScop(MemoryAccess *MA, isl::union_map Writes); - /// Return the context under which the access cannot be hoisted. - /// - /// @param Access The access to check. - /// @param Writes The set of all memory writes in the scop. - /// - /// @return Return the context under which the access cannot be hoisted or a - /// nullptr if it cannot be hoisted at all. - isl::set getNonHoistableCtx(MemoryAccess *Access, isl::union_map Writes); - - /// Hoist invariant memory loads and check for required ones. - /// - /// We first identify "common" invariant loads, thus loads that are invariant - /// and can be hoisted. Then we check if all required invariant loads have - /// been identified as (common) invariant. A load is a required invariant load - /// if it was assumed to be invariant during SCoP detection, e.g., to assume - /// loop bounds to be affine or runtime alias checks to be placeable. In case - /// a required invariant load was not identified as (common) invariant we will - /// drop this SCoP. An example for both "common" as well as required invariant - /// loads is given below: - /// - /// for (int i = 1; i < *LB[0]; i++) - /// for (int j = 1; j < *LB[1]; j++) - /// A[i][j] += A[0][0] + (*V); - /// - /// Common inv. loads: V, A[0][0], LB[0], LB[1] - /// Required inv. loads: LB[0], LB[1], (V, if it may alias with A or LB) - void hoistInvariantLoads(); - /// Check if @p MA can always be hoisted without execution context. bool canAlwaysBeHoisted(MemoryAccess *MA, bool StmtInvalidCtxIsEmpty, bool MAInvalidCtxIsEmpty, bool NonHoistableCtxIsEmpty); - /// Add invariant loads listed in @p InvMAs with the domain of @p Stmt. - void addInvariantLoads(ScopStmt &Stmt, InvariantAccessesTy &InvMAs); - /// Create an id for @p Param and store it in the ParameterIds map. void createParameterId(const SCEV *Param); @@ -2341,6 +2310,9 @@ InvEquivClassVMap[LoadInst] = ClassRep; } + /// Add invariant loads listed in @p InvMAs with the domain of @p Stmt. + void addInvariantLoads(ScopStmt &Stmt, InvariantAccessesTy &InvMAs); + /// Remove the metadata stored for @p Access. void removeAccessData(MemoryAccess *Access); @@ -2663,6 +2635,15 @@ return MinMaxAliasGroups; } + /// Return the context under which the access cannot be hoisted. + /// + /// @param Access The access to check. + /// @param Writes The set of all memory writes in the scop. + /// + /// @return Return the context under which the access cannot be hoisted or a + /// nullptr if it cannot be hoisted at all. + isl::set getNonHoistableCtx(MemoryAccess *Access, isl::union_map Writes); + /// Get an isl string representing the context. std::string getContextStr() const; Index: polly/trunk/lib/Analysis/ScopBuilder.cpp =================================================================== --- polly/trunk/lib/Analysis/ScopBuilder.cpp +++ polly/trunk/lib/Analysis/ScopBuilder.cpp @@ -1320,6 +1320,25 @@ } } +void ScopBuilder::hoistInvariantLoads() { + if (!PollyInvariantLoadHoisting) + return; + + isl::union_map Writes = scop->getWrites(); + for (ScopStmt &Stmt : *scop) { + InvariantAccessesTy InvariantAccesses; + + for (MemoryAccess *Access : Stmt) + if (isl::set NHCtx = scop->getNonHoistableCtx(Access, Writes)) + InvariantAccesses.push_back({Access, NHCtx}); + + // Transfer the memory access from the statement to the SCoP. + for (auto InvMA : InvariantAccesses) + Stmt.removeMemoryAccess(InvMA.MA); + scop->addInvariantLoads(Stmt, InvariantAccesses); + } +} + void ScopBuilder::collectCandidateReductionLoads( MemoryAccess *StoreMA, SmallVectorImpl &Loads) { ScopStmt *Stmt = StoreMA->getStatement(); @@ -1670,7 +1689,7 @@ return; } - scop->hoistInvariantLoads(); + hoistInvariantLoads(); canonicalizeDynamicBasePtrs(); verifyInvariantLoads(); scop->simplifySCoP(true); Index: polly/trunk/lib/Analysis/ScopInfo.cpp =================================================================== --- polly/trunk/lib/Analysis/ScopInfo.cpp +++ polly/trunk/lib/Analysis/ScopInfo.cpp @@ -3778,25 +3778,6 @@ return WrittenCtx; } -void Scop::hoistInvariantLoads() { - if (!PollyInvariantLoadHoisting) - return; - - isl::union_map Writes = getWrites(); - for (ScopStmt &Stmt : *this) { - InvariantAccessesTy InvariantAccesses; - - for (MemoryAccess *Access : Stmt) - if (isl::set NHCtx = getNonHoistableCtx(Access, Writes)) - InvariantAccesses.push_back({Access, NHCtx}); - - // Transfer the memory access from the statement to the SCoP. - for (auto InvMA : InvariantAccesses) - Stmt.removeMemoryAccess(InvMA.MA); - addInvariantLoads(Stmt, InvariantAccesses); - } -} - ScopArrayInfo *Scop::getOrCreateScopArrayInfo(Value *BasePtr, Type *ElementType, ArrayRef Sizes, MemoryKind Kind,