Index: include/polly/DependenceInfo.h =================================================================== --- include/polly/DependenceInfo.h +++ include/polly/DependenceInfo.h @@ -137,15 +137,15 @@ /// is able to call or modify a dependences struct. friend class DependenceInfo; -private: - /// @brief Create an empty dependences struct. - Dependences() - : RAW(nullptr), WAR(nullptr), WAW(nullptr), RED(nullptr), - TC_RED(nullptr) {} - /// @brief Destructor that will free internal objects. ~Dependences() { releaseMemory(); } +private: + /// @brief Create an empty dependences struct. + explicit Dependences(isl_ctx *IslCtx) + : RAW(nullptr), WAR(nullptr), WAW(nullptr), RED(nullptr), TC_RED(nullptr), + IslCtx(IslCtx) {} + /// @brief Calculate and add at the privatization dependences. void addPrivatizationDependences(); @@ -173,6 +173,9 @@ /// @brief Mapping from memory accesses to their reduction dependences. ReductionDependencesMapTy ReductionDependences; + + /// Isl context from the SCoP. + isl_ctx *IslCtx; }; class DependenceInfo : public ScopPass { @@ -183,7 +186,7 @@ DependenceInfo() : ScopPass(ID) {} /// @brief Return the dependence information for the current SCoP. - const Dependences &getDependences() { return D; } + const Dependences &getDependences() { return *D; } /// @brief Recompute dependences from schedule and memory accesses. void recomputeDependences(); @@ -192,10 +195,10 @@ bool runOnScop(Scop &S) override; /// @brief Print the dependences for the given SCoP to @p OS. - void printScop(raw_ostream &OS, Scop &) const override { D.print(OS); } + void printScop(raw_ostream &OS, Scop &) const override { D->print(OS); } /// @brief Release the internal memory. - void releaseMemory() override { D.releaseMemory(); } + void releaseMemory() override { D.reset(); } /// @brief Register all analyses and transformation required. void getAnalysisUsage(AnalysisUsage &AU) const override; @@ -204,7 +207,7 @@ Scop *S; /// @brief Dependences struct for the current SCoP. - Dependences D; + std::auto_ptr D; }; } // End polly namespace. Index: include/polly/ScopInfo.h =================================================================== --- include/polly/ScopInfo.h +++ include/polly/ScopInfo.h @@ -1273,6 +1273,12 @@ ParamIdType ParameterIds; /// Isl context. + /// + /// We need a shared_ptr with reference counter to delete the context when all + /// isl objects are deleted. We will distribute the shared_ptr to all objects + /// that use the context to create isl objects, and increase the reference + /// counter. By doing this, we guarantee that the context is deleted when we + /// delete the last object that creates isl objects with the context. isl_ctx *IslCtx; /// @brief A map from basic blocks to SCoP statements. @@ -1376,7 +1382,7 @@ InvariantEquivClassesTy InvariantEquivClasses; /// @brief Scop constructor; invoked from ScopInfo::buildScop. - Scop(Region &R, ScalarEvolution &SE, isl_ctx *ctx, unsigned MaxLoopDepth); + Scop(Region &R, ScalarEvolution &SE, unsigned MaxLoopDepth); /// @brief Get or create the access function set in a BasicBlock AccFuncSetType &getOrCreateAccessFunctions(const BasicBlock *BB) { @@ -2015,7 +2021,6 @@ // The Scop std::unique_ptr scop; - isl_ctx *ctx; // Clear the context. void clear(); Index: lib/Analysis/DependenceInfo.cpp =================================================================== --- lib/Analysis/DependenceInfo.cpp +++ lib/Analysis/DependenceInfo.cpp @@ -283,10 +283,10 @@ Write = isl_union_map_coalesce(Write); MayWrite = isl_union_map_coalesce(MayWrite); - long MaxOpsOld = isl_ctx_get_max_operations(S.getIslCtx()); + long MaxOpsOld = isl_ctx_get_max_operations(IslCtx); if (OptComputeOut) - isl_ctx_set_max_operations(S.getIslCtx(), OptComputeOut); - isl_options_set_on_error(S.getIslCtx(), ISL_ON_ERROR_CONTINUE); + isl_ctx_set_max_operations(IslCtx, OptComputeOut); + isl_options_set_on_error(IslCtx, ISL_ON_ERROR_CONTINUE); DEBUG(dbgs() << "Read: " << Read << "\n"; dbgs() << "Write: " << Write << "\n"; @@ -362,16 +362,16 @@ WAW = isl_union_map_coalesce(WAW); WAR = isl_union_map_coalesce(WAR); - if (isl_ctx_last_error(S.getIslCtx()) == isl_error_quota) { + if (isl_ctx_last_error(IslCtx) == isl_error_quota) { isl_union_map_free(RAW); isl_union_map_free(WAW); isl_union_map_free(WAR); RAW = WAW = WAR = nullptr; - isl_ctx_reset_error(S.getIslCtx()); + isl_ctx_reset_error(IslCtx); } - isl_options_set_on_error(S.getIslCtx(), ISL_ON_ERROR_ABORT); - isl_ctx_reset_operations(S.getIslCtx()); - isl_ctx_set_max_operations(S.getIslCtx(), MaxOpsOld); + isl_options_set_on_error(IslCtx, ISL_ON_ERROR_ABORT); + isl_ctx_reset_operations(IslCtx); + isl_ctx_set_max_operations(IslCtx, MaxOpsOld); isl_union_map *STMT_RAW, *STMT_WAW, *STMT_WAR; STMT_RAW = isl_union_map_intersect_domain( @@ -647,6 +647,8 @@ for (auto &ReductionDeps : ReductionDependences) isl_map_free(ReductionDeps.second); ReductionDependences.clear(); + + isl_ctx_free_if_no_ref(IslCtx); } isl_union_map *Dependences::getDependences(int Kinds) const { @@ -689,8 +691,8 @@ } void DependenceInfo::recomputeDependences() { - releaseMemory(); - D.calculateDependences(*S); + D.reset(new Dependences(S->getIslCtx())); + D->calculateDependences(*S); } bool DependenceInfo::runOnScop(Scop &ScopVar) { Index: lib/Analysis/ScopInfo.cpp =================================================================== --- lib/Analysis/ScopInfo.cpp +++ lib/Analysis/ScopInfo.cpp @@ -112,7 +112,6 @@ cl::Hidden, cl::ZeroOrMore, cl::init(false), cl::cat(PollyCategory)); //===----------------------------------------------------------------------===// - // Create a sequence of two schedules. Either argument may be null and is // interpreted as the empty schedule. Can also return null if both schedules are // empty. @@ -1788,7 +1787,8 @@ if (UserContextStr.empty()) return; - isl_set *UserContext = isl_set_read_from_str(IslCtx, UserContextStr.c_str()); + isl_set *UserContext = + isl_set_read_from_str(getIslCtx(), UserContextStr.c_str()); isl_space *Space = getParamSpace(); if (isl_space_dim(Space, isl_dim_param) != isl_set_dim(UserContext, isl_dim_param)) { @@ -1852,7 +1852,7 @@ } void Scop::buildContext() { - isl_space *Space = isl_space_params_alloc(IslCtx, 0); + isl_space *Space = isl_space_params_alloc(getIslCtx(), 0); Context = isl_set_universe(isl_space_copy(Space)); AssumedContext = isl_set_universe(Space); } @@ -1869,7 +1869,7 @@ void Scop::realignParams() { // Add all parameters into a common model. - isl_space *Space = isl_space_params_alloc(IslCtx, ParameterIds.size()); + isl_space *Space = isl_space_params_alloc(getIslCtx(), ParameterIds.size()); for (const auto &ParamID : ParameterIds) { const SCEV *Parameter = ParamID.first; @@ -2735,13 +2735,13 @@ return MaxLD - MinLD + 1; } -Scop::Scop(Region &R, ScalarEvolution &ScalarEvolution, isl_ctx *Context, - unsigned MaxLoopDepth) +Scop::Scop(Region &R, ScalarEvolution &ScalarEvolution, unsigned MaxLoopDepth) : SE(&ScalarEvolution), R(R), IsOptimized(false), HasSingleExitEdge(R.getExitingBlock()), HasErrorBlock(false), - MaxLoopDepth(MaxLoopDepth), IslCtx(Context), Context(nullptr), + MaxLoopDepth(MaxLoopDepth), IslCtx(isl_ctx_alloc()), Context(nullptr), Affinator(this), AssumedContext(nullptr), BoundaryContext(nullptr), Schedule(nullptr) { + isl_options_set_on_error(getIslCtx(), ISL_ON_ERROR_ABORT); buildContext(); } @@ -2802,6 +2802,14 @@ for (const auto &IAClass : InvariantEquivClasses) isl_set_free(std::get<2>(IAClass)); + + // Explicitly release all Scop objects and the underlying isl objects before + // we relase the isl context. + Stmts.clear(); + ScopArrayInfoMap.clear(); + AccFuncMap.clear(); + + isl_ctx_free_if_no_ref(IslCtx); } void Scop::updateAccessDimensionality() { @@ -4137,7 +4145,7 @@ void ScopInfo::buildScop(Region &R, AssumptionCache &AC) { unsigned MaxLoopDepth = getMaxLoopDepthInRegion(R, *LI, *SD); - scop.reset(new Scop(R, *SE, ctx, MaxLoopDepth)); + scop.reset(new Scop(R, *SE, MaxLoopDepth)); buildStmts(R, R); buildAccessFunctions(R, R, *SD->getInsnToMemAccMap(&R)); @@ -4168,15 +4176,9 @@ void ScopInfo::clear() { scop.reset(); } //===----------------------------------------------------------------------===// -ScopInfo::ScopInfo() : RegionPass(ID) { - ctx = isl_ctx_alloc(); - isl_options_set_on_error(ctx, ISL_ON_ERROR_ABORT); -} +ScopInfo::ScopInfo() : RegionPass(ID) {} -ScopInfo::~ScopInfo() { - clear(); - isl_ctx_free(ctx); -} +ScopInfo::~ScopInfo() { clear(); } void ScopInfo::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); Index: lib/CodeGen/IslAst.cpp =================================================================== --- lib/CodeGen/IslAst.cpp +++ lib/CodeGen/IslAst.cpp @@ -89,6 +89,7 @@ Scop *S; isl_ast_node *Root; isl_ast_expr *RunCondition; + isl_ctx *Ctx; IslAst(Scop *Scop); void init(const Dependences &D); @@ -377,7 +378,8 @@ return true; } -IslAst::IslAst(Scop *Scop) : S(Scop), Root(nullptr), RunCondition(nullptr) {} +IslAst::IslAst(Scop *Scop) + : S(Scop), Root(nullptr), RunCondition(nullptr), Ctx(Scop->getIslCtx()) {} void IslAst::init(const Dependences &D) { bool PerformParallelTest = PollyParallel || DetectParallel || @@ -425,6 +427,7 @@ IslAst::~IslAst() { isl_ast_node_free(Root); isl_ast_expr_free(RunCondition); + isl_ctx_free_if_no_ref(Ctx); } __isl_give isl_ast_node *IslAst::getAst() { return isl_ast_node_copy(Root); } Index: lib/External/isl/include/isl/ctx.h =================================================================== --- lib/External/isl/include/isl/ctx.h +++ lib/External/isl/include/isl/ctx.h @@ -161,6 +161,7 @@ void isl_ctx_ref(struct isl_ctx *ctx); void isl_ctx_deref(struct isl_ctx *ctx); void isl_ctx_free(isl_ctx *ctx); +void isl_ctx_free_if_no_ref(isl_ctx *ctx); void isl_ctx_abort(isl_ctx *ctx); void isl_ctx_resume(isl_ctx *ctx); Index: lib/External/isl/isl_ctx.c =================================================================== --- lib/External/isl/isl_ctx.c +++ lib/External/isl/isl_ctx.c @@ -261,6 +261,14 @@ free(ctx); } +void isl_ctx_free_if_no_ref(struct isl_ctx *ctx) +{ + if (!ctx || ctx->ref != 0) + return; + + isl_ctx_free(ctx); +} + struct isl_options *isl_ctx_options(isl_ctx *ctx) { if (!ctx)