Skip to content

Commit 795fa9e

Browse files
Bound ISL operations during pre-vectorization (#165204)
Bound ISL operations during pre-vectorization to prevent indefinite compilation. The MaxOpGuard previously used for schedule computation is now extended to also guard pre-vectorization optimizations. This patch includes a reduced test case derived from the original bug report. --------- Co-authored-by: Michael Kruse <[email protected]>
1 parent 8bd7fc7 commit 795fa9e

File tree

3 files changed

+78
-17
lines changed

3 files changed

+78
-17
lines changed

polly/lib/Transform/ScheduleOptimizer.cpp

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ struct OptimizerAdditionalInfoTy {
237237
bool Postopts;
238238
bool Prevect;
239239
bool &DepsChanged;
240+
IslMaxOperationsGuard &MaxOpGuard;
240241
};
241242

242243
class ScheduleTreeOptimizer final {
@@ -381,6 +382,8 @@ class ScheduleTreeOptimizer final {
381382
isl::schedule_node
382383
ScheduleTreeOptimizer::isolateFullPartialTiles(isl::schedule_node Node,
383384
int VectorWidth) {
385+
if (Node.is_null())
386+
return {};
384387
assert(isl_schedule_node_get_type(Node.get()) == isl_schedule_node_band);
385388
Node = Node.child(0).child(0);
386389
isl::union_map SchedRelUMap = Node.get_prefix_schedule_relation();
@@ -391,6 +394,8 @@ ScheduleTreeOptimizer::isolateFullPartialTiles(isl::schedule_node Node,
391394
isl::union_set IsolateOption = getIsolateOptions(IsolateDomain, 1);
392395
Node = Node.parent().parent();
393396
isl::union_set Options = IsolateOption.unite(AtomicOption);
397+
if (Node.is_null())
398+
return {};
394399
isl::schedule_node_band Result =
395400
Node.as<isl::schedule_node_band>().set_ast_build_options(Options);
396401
return Result;
@@ -411,9 +416,13 @@ struct InsertSimdMarkers final : ScheduleNodeRewriter<InsertSimdMarkers> {
411416

412417
isl::schedule_node ScheduleTreeOptimizer::prevectSchedBand(
413418
isl::schedule_node Node, unsigned DimToVectorize, int VectorWidth) {
419+
if (Node.is_null())
420+
return {};
414421
assert(isl_schedule_node_get_type(Node.get()) == isl_schedule_node_band);
415422

416423
auto Space = isl::manage(isl_schedule_node_band_get_space(Node.get()));
424+
if (Space.is_null())
425+
return {};
417426
unsigned ScheduleDimensions = unsignedFromIslSize(Space.dim(isl::dim::set));
418427
assert(DimToVectorize < ScheduleDimensions);
419428

@@ -439,12 +448,15 @@ isl::schedule_node ScheduleTreeOptimizer::prevectSchedBand(
439448
// Sink the inner loop into the smallest possible statements to make them
440449
// represent a single vector instruction if possible.
441450
Node = isl::manage(isl_schedule_node_band_sink(Node.release()));
451+
if (Node.is_null())
452+
return {};
442453

443454
// Add SIMD markers to those vector statements.
444455
InsertSimdMarkers SimdMarkerInserter;
445456
Node = SimdMarkerInserter.visit(Node);
446457

447-
PrevectOpts++;
458+
if (!Node.is_null())
459+
PrevectOpts++;
448460
return Node.parent();
449461
}
450462

@@ -535,6 +547,8 @@ ScheduleTreeOptimizer::applyTileBandOpt(isl::schedule_node Node) {
535547
isl::schedule_node
536548
ScheduleTreeOptimizer::applyPrevectBandOpt(isl::schedule_node Node) {
537549
auto Space = isl::manage(isl_schedule_node_band_get_space(Node.get()));
550+
if (Space.is_null())
551+
return {};
538552
int Dims = unsignedFromIslSize(Space.dim(isl::dim::set));
539553

540554
for (int i = Dims - 1; i >= 0; i--)
@@ -572,9 +586,14 @@ ScheduleTreeOptimizer::optimizeBand(__isl_take isl_schedule_node *NodeArg,
572586
Node = applyTileBandOpt(Node);
573587

574588
if (OAI->Prevect) {
589+
IslQuotaScope MaxScope = OAI->MaxOpGuard.enter();
590+
575591
// FIXME: Prevectorization requirements are different from those checked by
576592
// isTileableBandNode.
577593
Node = applyPrevectBandOpt(Node);
594+
595+
if (OAI->MaxOpGuard.hasQuotaExceeded() || Node.is_null())
596+
return (isl::schedule_node()).release();
578597
}
579598

580599
return Node.release();
@@ -771,6 +790,10 @@ static void runIslScheduleOptimizer(
771790
return;
772791
}
773792

793+
isl_ctx *Ctx = S.getIslCtx().get();
794+
IslMaxOperationsGuard MaxOpGuard(Ctx, ScheduleComputeOut,
795+
/*AutoEnter=*/false);
796+
774797
// Apply ISL's algorithm only if not overridden by the user. Note that
775798
// post-rescheduling optimizations (tiling, pattern-based, prevectorization)
776799
// rely on the coincidence/permutable annotations on schedule tree bands that
@@ -853,8 +876,6 @@ static void runIslScheduleOptimizer(
853876
IslOuterCoincidence = 0;
854877
}
855878

856-
isl_ctx *Ctx = S.getIslCtx().get();
857-
858879
isl_options_set_schedule_outer_coincidence(Ctx, IslOuterCoincidence);
859880
isl_options_set_schedule_maximize_band_depth(Ctx, IslMaximizeBands);
860881
isl_options_set_schedule_max_constant_term(Ctx, MaxConstantTerm);
@@ -870,28 +891,20 @@ static void runIslScheduleOptimizer(
870891
SC = SC.set_coincidence(Validity);
871892

872893
{
873-
IslMaxOperationsGuard MaxOpGuard(Ctx, ScheduleComputeOut);
894+
IslQuotaScope MaxOpScope = MaxOpGuard.enter();
874895
Schedule = SC.compute_schedule();
875-
876-
if (MaxOpGuard.hasQuotaExceeded())
877-
POLLY_DEBUG(
878-
dbgs() << "Schedule optimizer calculation exceeds ISL quota\n");
879896
}
880897

881898
isl_options_set_on_error(Ctx, OnErrorStatus);
882899

883-
ScopsRescheduled++;
900+
if (!Schedule.is_null())
901+
ScopsRescheduled++;
884902
POLLY_DEBUG(printSchedule(dbgs(), Schedule, "After rescheduling"));
885903
}
886904

887905
walkScheduleTreeForStatistics(Schedule, 1);
888906

889-
// In cases the scheduler is not able to optimize the code, we just do not
890-
// touch the schedule.
891-
if (Schedule.is_null())
892-
return;
893-
894-
if (GreedyFusion) {
907+
if (GreedyFusion && !Schedule.is_null()) {
895908
isl::union_map Validity = D.getDependences(
896909
Dependences::TYPE_RAW | Dependences::TYPE_WAR | Dependences::TYPE_WAW);
897910
Schedule = applyGreedyFusion(Schedule, Validity);
@@ -905,14 +918,20 @@ static void runIslScheduleOptimizer(
905918
/*PatternOpts=*/!HasUserTransformation && PMBasedOpts,
906919
/*Postopts=*/!HasUserTransformation && EnablePostopts,
907920
/*Prevect=*/PollyVectorizerChoice != VECTORIZER_NONE,
908-
DepsChanged};
909-
if (OAI.PatternOpts || OAI.Postopts || OAI.Prevect) {
921+
DepsChanged,
922+
MaxOpGuard};
923+
if (!Schedule.is_null() && (OAI.PatternOpts || OAI.Postopts || OAI.Prevect)) {
910924
Schedule = ScheduleTreeOptimizer::optimizeSchedule(Schedule, &OAI);
911925
Schedule = hoistExtensionNodes(Schedule);
912926
POLLY_DEBUG(printSchedule(dbgs(), Schedule, "After post-optimizations"));
913927
walkScheduleTreeForStatistics(Schedule, 2);
914928
}
915929

930+
if (MaxOpGuard.hasQuotaExceeded()) {
931+
POLLY_DEBUG(dbgs() << "Schedule optimizer calculation exceeds ISL quota\n");
932+
return;
933+
}
934+
916935
// Skip profitability check if user transformation(s) have been applied.
917936
if (!HasUserTransformation &&
918937
!ScheduleTreeOptimizer::isProfitableSchedule(S, Schedule))

polly/lib/Transform/ScheduleTreeTransform.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,9 @@ BandAttr *polly::getBandAttr(isl::schedule_node MarkOrBand) {
972972
}
973973

974974
isl::schedule polly::hoistExtensionNodes(isl::schedule Sched) {
975+
if (Sched.is_null())
976+
return {};
977+
975978
// If there is no extension node in the first place, return the original
976979
// schedule tree.
977980
if (!containsExtensionNode(Sched))
@@ -1126,6 +1129,8 @@ isl::set polly::getPartialTilePrefixes(isl::set ScheduleRange,
11261129

11271130
isl::union_set polly::getIsolateOptions(isl::set IsolateDomain,
11281131
unsigned OutDimsNum) {
1132+
if (IsolateDomain.is_null())
1133+
return {};
11291134
unsigned Dims = unsignedFromIslSize(IsolateDomain.tuple_dim());
11301135
assert(OutDimsNum <= Dims &&
11311136
"The isl::set IsolateDomain is used to describe the range of schedule "
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
; RUN: opt %loadNPMPolly -S -polly-vectorizer=stripmine -passes=polly-opt-isl -polly-debug -disable-output < %s 2>&1 | FileCheck %s
2+
; REQUIRES: asserts
3+
4+
define void @ham(ptr %arg, ptr %arg1, i32 %arg2, i32 %arg3, ptr %arg4, i32 %arg5, i32 %arg6) {
5+
bb:
6+
%getelementptr = getelementptr [7 x float], ptr null, i32 0, i32 %arg3
7+
br label %bb7
8+
9+
bb7: ; preds = %bb11, %bb
10+
%phi = phi i32 [ 0, %bb ], [ %add16, %bb11 ]
11+
br label %bb8
12+
13+
bb8: ; preds = %bb8, %bb7
14+
%phi9 = phi i32 [ 0, %bb7 ], [ %add, %bb8 ]
15+
%getelementptr10 = getelementptr [7 x float], ptr null, i32 0, i32 %phi9
16+
store float 0.000000e+00, ptr %getelementptr10, align 4
17+
%add = add i32 %phi9, 1
18+
%icmp = icmp eq i32 %phi9, 0
19+
br i1 %icmp, label %bb8, label %bb11
20+
21+
bb11: ; preds = %bb8
22+
%load = load float, ptr %getelementptr, align 4
23+
store float %load, ptr %arg4, align 4
24+
%getelementptr12 = getelementptr [7 x float], ptr null, i32 0, i32 %arg5
25+
%load13 = load float, ptr %getelementptr12, align 4
26+
store float %load13, ptr %arg, align 4
27+
%getelementptr14 = getelementptr [7 x float], ptr null, i32 0, i32 %arg6
28+
%load15 = load float, ptr %getelementptr14, align 4
29+
store float %load15, ptr %arg1, align 4
30+
%add16 = add i32 %phi, 1
31+
%icmp17 = icmp ne i32 %phi, %arg2
32+
br i1 %icmp17, label %bb7, label %bb18
33+
34+
bb18: ; preds = %bb11
35+
ret void
36+
}
37+
; CHECK:Schedule optimizer calculation exceeds ISL quota

0 commit comments

Comments
 (0)