[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
This commit is contained in:
Michael Kruse 2016-10-10 11:45:54 +00:00
parent 1eb779b5ae
commit 8bfba1ff46
2 changed files with 128 additions and 69 deletions

View File

@ -19,6 +19,7 @@
#include "isl/aff.h" #include "isl/aff.h"
#include "isl/ctx.h" #include "isl/ctx.h"
#include "isl/map.h" #include "isl/map.h"
#include "isl/options.h"
#include "isl/set.h" #include "isl/set.h"
#include "isl/union_map.h" #include "isl/union_map.h"
#include "isl/union_set.h" #include "isl/union_set.h"
@ -425,6 +426,70 @@ isl_stat foreachPieceWithBreak(
NonowningIslPtr<isl_pw_aff> PwAff, NonowningIslPtr<isl_pw_aff> PwAff,
const std::function<isl_stat(IslPtr<isl_set>, IslPtr<isl_aff>)> &F); const std::function<isl_stat(IslPtr<isl_set>, IslPtr<isl_aff>)> &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 } // end namespace polly
#endif #endif

View File

@ -370,74 +370,71 @@ void Dependences::calculateDependences(Scop &S) {
} }
} }
long MaxOpsOld = isl_ctx_get_max_operations(IslCtx.get()); {
if (OptComputeOut) { IslMaxOperationsGuard MaxOpGuard(IslCtx.get(), OptComputeOut);
isl_ctx_reset_operations(IslCtx.get());
isl_ctx_set_max_operations(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) { if (isl_ctx_last_error(IslCtx.get()) == isl_error_quota) {
isl_union_map_free(RAW); isl_union_map_free(RAW);
isl_union_map_free(WAW); isl_union_map_free(WAW);
@ -445,9 +442,6 @@ void Dependences::calculateDependences(Scop &S) {
RAW = WAW = WAR = nullptr; RAW = WAW = WAR = nullptr;
isl_ctx_reset_error(IslCtx.get()); 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 // Drop out early, as the remaining computations are only needed for
// reduction dependences or dependences that are finer than statement // reduction dependences or dependences that are finer than statement