Index: include/polly/CodeGen/IslNodeBuilder.h =================================================================== --- include/polly/CodeGen/IslNodeBuilder.h +++ include/polly/CodeGen/IslNodeBuilder.h @@ -412,6 +412,16 @@ /// ids to new access expressions. void generateCopyStmt(ScopStmt *Stmt, __isl_keep isl_id_to_ast_expr *NewAccesses); + + /// Materialize a canonical loop induction variable for `L`, which is a loop + /// that is *not* present in the Scop. + /// + /// Note that this is materialized at the point where the `Builder` is + /// currently pointing. + /// We also populate the `OutsideLoopIterations` map with `L`s SCEV to keep + /// track of the induction variable. + /// See [Code generation of induction variables of loops outside Scops] + Value *materializeNonScopLoopInductionVariable(const Loop *L); }; #endif // POLLY_ISL_NODE_BUILDER_H Index: lib/CodeGen/IslNodeBuilder.cpp =================================================================== --- lib/CodeGen/IslNodeBuilder.cpp +++ lib/CodeGen/IslNodeBuilder.cpp @@ -309,9 +309,17 @@ Values.remove_if([](const Value *V) { return isa(V); }); + /// Note: Code generation of induction variables of loops outside Scops + /// /// Remove loops that contain the scop or that are part of the scop, as they /// are considered local. This leaves only loops that are before the scop, but /// do not contain the scop itself. + /// We ignore loops perfectly contained in the Scop because these are already + /// generated at `IslNodeBuilder::addParameters`. These `Loops` are loops + /// whose induction variables are referred to by the Scop, but the Scop is not + /// fully contained in these Loops. Since there can be many of these, + /// we choose to codegen these on-demand. + /// @see IslNodeBuilder::materializeNonScopLoopInductionVariable. Loops.remove_if([this](const Loop *L) { return S.contains(L) || L->contains(S.getEntry()); }); @@ -627,13 +635,10 @@ // Create for all loops we depend on values that contain the current loop // iteration. These values are necessary to generate code for SCEVs that // depend on such loops. As a result we need to pass them to the subfunction. + // See [Code generation of induction variables of loops outside Scops] for (const Loop *L : Loops) { - const SCEV *OuterLIV = SE.getAddRecExpr(SE.getUnknown(Builder.getInt64(0)), - SE.getUnknown(Builder.getInt64(1)), - L, SCEV::FlagAnyWrap); - Value *V = generateSCEV(OuterLIV); - OutsideLoopIterations[L] = SE.getUnknown(V); - SubtreeValues.insert(V); + Value *LoopInductionVar = materializeNonScopLoopInductionVariable(L); + SubtreeValues.insert(LoopInductionVar); } ValueMapT NewValues; @@ -896,6 +901,17 @@ Builder.CreateStore(LoadValue, StoreAddr); } +Value *IslNodeBuilder::materializeNonScopLoopInductionVariable(const Loop *L) { + assert(OutsideLoopIterations.find(L) == OutsideLoopIterations.end() && + "trying to materialize loop induction variable twice"); + const SCEV *OuterLIV = SE.getAddRecExpr(SE.getUnknown(Builder.getInt64(0)), + SE.getUnknown(Builder.getInt64(1)), L, + SCEV::FlagAnyWrap); + Value *V = generateSCEV(OuterLIV); + OutsideLoopIterations[L] = SE.getUnknown(V); + return V; +} + void IslNodeBuilder::createUser(__isl_take isl_ast_node *User) { LoopToScevMapT LTS; isl_id *Id; @@ -1484,11 +1500,7 @@ L = L->getParentLoop(); while (L != nullptr) { - const SCEV *OuterLIV = SE.getAddRecExpr(SE.getUnknown(Builder.getInt64(0)), - SE.getUnknown(Builder.getInt64(1)), - L, SCEV::FlagAnyWrap); - Value *V = generateSCEV(OuterLIV); - OutsideLoopIterations[L] = SE.getUnknown(V); + materializeNonScopLoopInductionVariable(L); L = L->getParentLoop(); }