From 8bfba1ff4656c3e21b15de1f7c6a38a978b4bc9f Mon Sep 17 00:00:00 2001 From: Michael Kruse Date: Mon, 10 Oct 2016 11:45:54 +0000 Subject: [PATCH] [Support/DepInfo] Introduce IslMaxOperationsGuard and make DepInfo use it. NFC. IslMaxOperationsGuard defines a scope where ISL may abort operations because if it takes too many operations. Replace the call to the raw ISL interface by a use of the guard. IslMaxOperationsGuard provides a uniform way to define a maximal computation time for a code region in C++ using RAII. llvm-svn: 283744 --- polly/include/polly/Support/GICHelper.h | 65 ++++++++++++ polly/lib/Analysis/DependenceInfo.cpp | 132 +++++++++++------------- 2 files changed, 128 insertions(+), 69 deletions(-) diff --git a/polly/include/polly/Support/GICHelper.h b/polly/include/polly/Support/GICHelper.h index 5a587252bba5..380237e10b25 100644 --- a/polly/include/polly/Support/GICHelper.h +++ b/polly/include/polly/Support/GICHelper.h @@ -19,6 +19,7 @@ #include "isl/aff.h" #include "isl/ctx.h" #include "isl/map.h" +#include "isl/options.h" #include "isl/set.h" #include "isl/union_map.h" #include "isl/union_set.h" @@ -425,6 +426,70 @@ isl_stat foreachPieceWithBreak( NonowningIslPtr PwAff, const std::function, IslPtr)> &F); +/// Scoped limit of ISL operations. +/// +/// Limits the number of ISL operations during the lifetime of this object. The +/// idea is to use this as an RAII guard for the scope where the code is aware +/// that ISL can return errors even when all input is valid. After leaving the +/// scope, it will return to the error setting as it was before. That also means +/// that the error setting should not be changed while in that scope. +/// +/// Such scopes are not allowed to be nested because the previous operations +/// counter cannot be reset to the previous state, or one that adds the +/// operations while being in the nested scope. Use therefore is only allowed +/// while currently a no operations-limit is active. +class IslMaxOperationsGuard { +private: + /// The ISL context to set the operations limit. + /// + /// If set to nullptr, there is no need for any action at the end of the + /// scope. + isl_ctx *IslCtx; + + /// Old OnError setting; to reset to when the scope ends. + int OldOnError; + +public: + /// Enter a max operations scope. + /// + /// @param IslCtx The ISL context to set the operations limit for. + /// @param LocalMaxOps Maximum number of operations allowed in the + /// scope. If set to zero, no operations limit is enforced. + IslMaxOperationsGuard(isl_ctx *IslCtx, unsigned long LocalMaxOps) + : IslCtx(IslCtx) { + assert(IslCtx); + assert(isl_ctx_get_max_operations(IslCtx) == 0 && + "Nested max operations not supported"); + + if (LocalMaxOps == 0) { + // No limit on operations; also disable restoring on_error/max_operations. + this->IslCtx = nullptr; + return; + } + + // Save previous state. + OldOnError = isl_options_get_on_error(IslCtx); + + // Activate the new setting. + isl_ctx_set_max_operations(IslCtx, LocalMaxOps); + isl_ctx_reset_operations(IslCtx); + isl_options_set_on_error(IslCtx, ISL_ON_ERROR_CONTINUE); + } + + /// Leave the max operations scope. + ~IslMaxOperationsGuard() { + if (!IslCtx) + return; + + assert(isl_options_get_on_error(IslCtx) == ISL_ON_ERROR_CONTINUE && + "Unexpected change of the on_error setting"); + + // Return to the previous error setting. + isl_ctx_set_max_operations(IslCtx, 0); + isl_options_set_on_error(IslCtx, OldOnError); + } +}; + } // end namespace polly #endif diff --git a/polly/lib/Analysis/DependenceInfo.cpp b/polly/lib/Analysis/DependenceInfo.cpp index acf27f38735d..627ce7e23d72 100644 --- a/polly/lib/Analysis/DependenceInfo.cpp +++ b/polly/lib/Analysis/DependenceInfo.cpp @@ -370,74 +370,71 @@ void Dependences::calculateDependences(Scop &S) { } } - long MaxOpsOld = isl_ctx_get_max_operations(IslCtx.get()); - if (OptComputeOut) { - isl_ctx_reset_operations(IslCtx.get()); - isl_ctx_set_max_operations(IslCtx.get(), OptComputeOut); + { + IslMaxOperationsGuard MaxOpGuard(IslCtx.get(), OptComputeOut); + + DEBUG(dbgs() << "Read: " << Read << "\n"; + dbgs() << "Write: " << Write << "\n"; + dbgs() << "MayWrite: " << MayWrite << "\n"; + dbgs() << "Schedule: " << Schedule << "\n"); + + RAW = WAW = WAR = RED = nullptr; + + if (OptAnalysisType == VALUE_BASED_ANALYSIS) { + isl_union_flow *Flow; + + Flow = buildFlow(Read, Write, MayWrite, Schedule); + + RAW = isl_union_flow_get_must_dependence(Flow); + isl_union_flow_free(Flow); + + Flow = buildFlow(Write, Write, Read, Schedule); + + WAW = isl_union_flow_get_must_dependence(Flow); + WAR = isl_union_flow_get_may_dependence(Flow); + + // This subtraction is needed to obtain the same results as were given by + // isl_union_map_compute_flow. For large sets this may add some + // compile-time cost. As there does not seem to be a need to distinguish + // between WAW and WAR, refactoring Polly to only track general non-flow + // dependences may improve performance. + WAR = isl_union_map_subtract(WAR, isl_union_map_copy(WAW)); + + isl_union_flow_free(Flow); + isl_schedule_free(Schedule); + } else { + isl_union_flow *Flow; + + Write = isl_union_map_union(Write, isl_union_map_copy(MayWrite)); + + Flow = buildFlow(Read, nullptr, Write, Schedule); + + RAW = isl_union_flow_get_may_dependence(Flow); + isl_union_flow_free(Flow); + + Flow = buildFlow(Write, nullptr, Read, Schedule); + + WAR = isl_union_flow_get_may_dependence(Flow); + isl_union_flow_free(Flow); + + Flow = buildFlow(Write, nullptr, Write, Schedule); + + WAW = isl_union_flow_get_may_dependence(Flow); + isl_union_flow_free(Flow); + isl_schedule_free(Schedule); + } + + isl_union_map_free(MayWrite); + isl_union_map_free(Write); + isl_union_map_free(Read); + + RAW = isl_union_map_coalesce(RAW); + WAW = isl_union_map_coalesce(WAW); + WAR = isl_union_map_coalesce(WAR); + + // End of max_operations scope. } - auto OnErrorStatus = isl_options_get_on_error(IslCtx.get()); - isl_options_set_on_error(IslCtx.get(), ISL_ON_ERROR_CONTINUE); - - DEBUG(dbgs() << "Read: " << Read << "\n"; - dbgs() << "Write: " << Write << "\n"; - dbgs() << "MayWrite: " << MayWrite << "\n"; - dbgs() << "Schedule: " << Schedule << "\n"); - - RAW = WAW = WAR = RED = nullptr; - - if (OptAnalysisType == VALUE_BASED_ANALYSIS) { - isl_union_flow *Flow; - - Flow = buildFlow(Read, Write, MayWrite, Schedule); - - RAW = isl_union_flow_get_must_dependence(Flow); - isl_union_flow_free(Flow); - - Flow = buildFlow(Write, Write, Read, Schedule); - - WAW = isl_union_flow_get_must_dependence(Flow); - WAR = isl_union_flow_get_may_dependence(Flow); - - // This subtraction is needed to obtain the same results as were given by - // isl_union_map_compute_flow. For large sets this may add some compile-time - // cost. As there does not seem to be a need to distinguish between WAW and - // WAR, refactoring Polly to only track general non-flow dependences may - // improve performance. - WAR = isl_union_map_subtract(WAR, isl_union_map_copy(WAW)); - - isl_union_flow_free(Flow); - isl_schedule_free(Schedule); - } else { - isl_union_flow *Flow; - - Write = isl_union_map_union(Write, isl_union_map_copy(MayWrite)); - - Flow = buildFlow(Read, nullptr, Write, Schedule); - - RAW = isl_union_flow_get_may_dependence(Flow); - isl_union_flow_free(Flow); - - Flow = buildFlow(Write, nullptr, Read, Schedule); - - WAR = isl_union_flow_get_may_dependence(Flow); - isl_union_flow_free(Flow); - - Flow = buildFlow(Write, nullptr, Write, Schedule); - - WAW = isl_union_flow_get_may_dependence(Flow); - isl_union_flow_free(Flow); - isl_schedule_free(Schedule); - } - - isl_union_map_free(MayWrite); - isl_union_map_free(Write); - isl_union_map_free(Read); - - RAW = isl_union_map_coalesce(RAW); - WAW = isl_union_map_coalesce(WAW); - WAR = isl_union_map_coalesce(WAR); - if (isl_ctx_last_error(IslCtx.get()) == isl_error_quota) { isl_union_map_free(RAW); isl_union_map_free(WAW); @@ -445,9 +442,6 @@ void Dependences::calculateDependences(Scop &S) { RAW = WAW = WAR = nullptr; isl_ctx_reset_error(IslCtx.get()); } - isl_options_set_on_error(IslCtx.get(), OnErrorStatus); - isl_ctx_reset_operations(IslCtx.get()); - isl_ctx_set_max_operations(IslCtx.get(), MaxOpsOld); // Drop out early, as the remaining computations are only needed for // reduction dependences or dependences that are finer than statement