Polly 24.0.0git
ScheduleOptimizer.cpp
Go to the documentation of this file.
1//===- ScheduleOptimizer.cpp - Calculate an optimized schedule ------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This pass generates an entirely new schedule tree from the data dependences
10// and iteration domains. The new schedule tree is computed in two steps:
11//
12// 1) The isl scheduling optimizer is run
13//
14// The isl scheduling optimizer creates a new schedule tree that maximizes
15// parallelism and tileability and minimizes data-dependence distances. The
16// algorithm used is a modified version of the ``Pluto'' algorithm:
17//
18// U. Bondhugula, A. Hartono, J. Ramanujam, and P. Sadayappan.
19// A Practical Automatic Polyhedral Parallelizer and Locality Optimizer.
20// In Proceedings of the 2008 ACM SIGPLAN Conference On Programming Language
21// Design and Implementation, PLDI ’08, pages 101–113. ACM, 2008.
22//
23// 2) A set of post-scheduling transformations is applied on the schedule tree.
24//
25// These optimizations include:
26//
27// - Tiling of the innermost tilable bands
28// - Prevectorization - The choice of a possible outer loop that is strip-mined
29// to the innermost level to enable inner-loop
30// vectorization.
31// - Some optimizations for spatial locality are also planned.
32//
33// For a detailed description of the schedule tree itself please see section 6
34// of:
35//
36// Polyhedral AST generation is more than scanning polyhedra
37// Tobias Grosser, Sven Verdoolaege, Albert Cohen
38// ACM Transactions on Programming Languages and Systems (TOPLAS),
39// 37(4), July 2015
40// http://www.grosser.es/#pub-polyhedral-AST-generation
41//
42// This publication also contains a detailed discussion of the different options
43// for polyhedral loop unrolling, full/partial tile separation and other uses
44// of the schedule tree.
45//
46//===----------------------------------------------------------------------===//
47
53#include "polly/Options.h"
55#include "polly/ScopInfo.h"
58#include "llvm/ADT/Sequence.h"
59#include "llvm/ADT/Statistic.h"
60#include "llvm/Analysis/OptimizationRemarkEmitter.h"
61#include "llvm/Support/CommandLine.h"
62#include "isl/options.h"
63
64using namespace llvm;
65using namespace polly;
66
67namespace llvm {
68class Loop;
69class Module;
70} // namespace llvm
71
73#define DEBUG_TYPE "polly-opt-isl"
74
75static cl::opt<std::string>
76 OptimizeDeps("polly-opt-optimize-only",
77 cl::desc("Only a certain kind of dependences (all/raw)"),
78 cl::Hidden, cl::init("all"), cl::cat(PollyCategory));
79
80static cl::opt<std::string>
81 SimplifyDeps("polly-opt-simplify-deps",
82 cl::desc("Dependences should be simplified (yes/no)"),
83 cl::Hidden, cl::init("yes"), cl::cat(PollyCategory));
84
85static cl::opt<int> MaxConstantTerm(
86 "polly-opt-max-constant-term",
87 cl::desc("The maximal constant term allowed (-1 is unlimited)"), cl::Hidden,
88 cl::init(20), cl::cat(PollyCategory));
89
90static cl::opt<int> MaxCoefficient(
91 "polly-opt-max-coefficient",
92 cl::desc("The maximal coefficient allowed (-1 is unlimited)"), cl::Hidden,
93 cl::init(20), cl::cat(PollyCategory));
94
95static cl::opt<std::string>
96 MaximizeBandDepth("polly-opt-maximize-bands",
97 cl::desc("Maximize the band depth (yes/no)"), cl::Hidden,
98 cl::init("yes"), cl::cat(PollyCategory));
99
100static cl::opt<int>
101 ScheduleComputeOut("polly-schedule-computeout",
102 cl::desc("Bound the scheduler by maximal amount"
103 "of computational steps. "),
104 cl::Hidden, cl::init(300000), cl::cat(PollyCategory));
105
106static cl::opt<bool>
107 GreedyFusion("polly-loopfusion-greedy",
108 cl::desc("Aggressively try to fuse everything"), cl::Hidden,
109 cl::cat(PollyCategory));
110
111static cl::opt<std::string> OuterCoincidence(
112 "polly-opt-outer-coincidence",
113 cl::desc("Try to construct schedules where the outer member of each band "
114 "satisfies the coincidence constraints (yes/no)"),
115 cl::Hidden, cl::init("no"), cl::cat(PollyCategory));
116
117static cl::opt<int> PrevectorWidth(
118 "polly-prevect-width",
119 cl::desc(
120 "The number of loop iterations to strip-mine for pre-vectorization"),
121 cl::Hidden, cl::init(4), cl::cat(PollyCategory));
122
123static cl::opt<bool> FirstLevelTiling("polly-tiling",
124 cl::desc("Enable loop tiling"),
125 cl::init(true), cl::cat(PollyCategory));
126
127static cl::opt<int> FirstLevelDefaultTileSize(
128 "polly-default-tile-size",
129 cl::desc("The default tile size (if not enough were provided by"
130 " --polly-tile-sizes)"),
131 cl::Hidden, cl::init(32), cl::cat(PollyCategory));
132
133static cl::list<int>
134 FirstLevelTileSizes("polly-tile-sizes",
135 cl::desc("A tile size for each loop dimension, filled "
136 "with --polly-default-tile-size"),
137 cl::Hidden, cl::CommaSeparated, cl::cat(PollyCategory));
138
139static cl::opt<bool>
140 SecondLevelTiling("polly-2nd-level-tiling",
141 cl::desc("Enable a 2nd level loop of loop tiling"),
142 cl::cat(PollyCategory));
143
144static cl::opt<int> SecondLevelDefaultTileSize(
145 "polly-2nd-level-default-tile-size",
146 cl::desc("The default 2nd-level tile size (if not enough were provided by"
147 " --polly-2nd-level-tile-sizes)"),
148 cl::Hidden, cl::init(16), cl::cat(PollyCategory));
149
150static cl::list<int>
151 SecondLevelTileSizes("polly-2nd-level-tile-sizes",
152 cl::desc("A tile size for each loop dimension, filled "
153 "with --polly-default-tile-size"),
154 cl::Hidden, cl::CommaSeparated,
155 cl::cat(PollyCategory));
156
157static cl::opt<bool> RegisterTiling("polly-register-tiling",
158 cl::desc("Enable register tiling"),
159 cl::cat(PollyCategory));
160
161static cl::opt<int> RegisterDefaultTileSize(
162 "polly-register-tiling-default-tile-size",
163 cl::desc("The default register tile size (if not enough were provided by"
164 " --polly-register-tile-sizes)"),
165 cl::Hidden, cl::init(2), cl::cat(PollyCategory));
166
167static cl::list<int>
168 RegisterTileSizes("polly-register-tile-sizes",
169 cl::desc("A tile size for each loop dimension, filled "
170 "with --polly-register-tile-size"),
171 cl::Hidden, cl::CommaSeparated, cl::cat(PollyCategory));
172
173static cl::opt<bool> PragmaBasedOpts(
174 "polly-pragma-based-opts",
175 cl::desc("Apply user-directed transformation from metadata"),
176 cl::init(true), cl::cat(PollyCategory));
177
178static cl::opt<bool> EnableReschedule("polly-reschedule",
179 cl::desc("Optimize SCoPs using ISL"),
180 cl::init(true), cl::cat(PollyCategory));
181
182static cl::opt<bool>
183 PMBasedOpts("polly-pattern-matching-based-opts",
184 cl::desc("Perform optimizations based on pattern matching"),
185 cl::init(true), cl::cat(PollyCategory));
186
187static cl::opt<bool>
188 EnablePostopts("polly-postopts",
189 cl::desc("Apply post-rescheduling optimizations such as "
190 "tiling (requires -polly-reschedule)"),
191 cl::init(true), cl::cat(PollyCategory));
192
193static cl::opt<bool> OptimizedScops(
194 "polly-optimized-scops",
195 cl::desc("Polly - Dump polyhedral description of Scops optimized with "
196 "the isl scheduling optimizer and the set of post-scheduling "
197 "transformations is applied on the schedule tree"),
198 cl::cat(PollyCategory));
199
200static cl::opt<bool> PollyPrintOptIsl("polly-print-opt-isl",
201 cl::desc("A polly pass"),
202 cl::cat(PollyCategory));
203
204STATISTIC(ScopsProcessed, "Number of scops processed");
205STATISTIC(ScopsRescheduled, "Number of scops rescheduled");
206STATISTIC(ScopsOptimized, "Number of scops optimized");
207
208STATISTIC(NumAffineLoopsOptimized, "Number of affine loops optimized");
209STATISTIC(NumBoxedLoopsOptimized, "Number of boxed loops optimized");
210
211#define THREE_STATISTICS(VARNAME, DESC) \
212 static Statistic VARNAME[3] = { \
213 {DEBUG_TYPE, #VARNAME "0", DESC " (original)"}, \
214 {DEBUG_TYPE, #VARNAME "1", DESC " (after scheduler)"}, \
215 {DEBUG_TYPE, #VARNAME "2", DESC " (after optimizer)"}}
216
217THREE_STATISTICS(NumBands, "Number of bands");
218THREE_STATISTICS(NumBandMembers, "Number of band members");
219THREE_STATISTICS(NumCoincident, "Number of coincident band members");
220THREE_STATISTICS(NumPermutable, "Number of permutable bands");
221THREE_STATISTICS(NumFilters, "Number of filter nodes");
222THREE_STATISTICS(NumExtension, "Number of extension nodes");
223
224STATISTIC(FirstLevelTileOpts, "Number of first level tiling applied");
225STATISTIC(SecondLevelTileOpts, "Number of second level tiling applied");
226STATISTIC(RegisterTileOpts, "Number of register tiling applied");
227STATISTIC(PrevectOpts, "Number of strip-mining for prevectorization applied");
228STATISTIC(MatMulOpts,
229 "Number of matrix multiplication patterns detected and optimized");
230
231namespace {
232/// Additional parameters of the schedule optimizer.
233///
234/// Target Transform Info and the SCoP dependencies used by the schedule
235/// optimizer.
236struct OptimizerAdditionalInfoTy {
237 const llvm::TargetTransformInfo *TTI;
238 const Dependences *D;
239 bool PatternOpts;
240 bool Postopts;
241 bool Prevect;
242 bool &DepsChanged;
243 IslMaxOperationsGuard &MaxOpGuard;
244};
245
246class ScheduleTreeOptimizer final {
247public:
248 /// Apply schedule tree transformations.
249 ///
250 /// This function takes an (possibly already optimized) schedule tree and
251 /// applies a set of additional optimizations on the schedule tree. The
252 /// transformations applied include:
253 ///
254 /// - Pattern-based optimizations
255 /// - Tiling
256 /// - Prevectorization
257 ///
258 /// @param Schedule The schedule object the transformations will be applied
259 /// to.
260 /// @param OAI Target Transform Info and the SCoP dependencies.
261 /// @returns The transformed schedule.
262 static isl::schedule
263 optimizeSchedule(isl::schedule Schedule,
264 const OptimizerAdditionalInfoTy *OAI = nullptr);
265
266 /// Apply schedule tree transformations.
267 ///
268 /// This function takes a node in an (possibly already optimized) schedule
269 /// tree and applies a set of additional optimizations on this schedule tree
270 /// node and its descendants. The transformations applied include:
271 ///
272 /// - Pattern-based optimizations
273 /// - Tiling
274 /// - Prevectorization
275 ///
276 /// @param Node The schedule object post-transformations will be applied to.
277 /// @param OAI Target Transform Info and the SCoP dependencies.
278 /// @returns The transformed schedule.
279 static isl::schedule_node
280 optimizeScheduleNode(isl::schedule_node Node,
281 const OptimizerAdditionalInfoTy *OAI = nullptr);
282
283 /// Decide if the @p NewSchedule is profitable for @p S.
284 ///
285 /// @param S The SCoP we optimize.
286 /// @param NewSchedule The new schedule we computed.
287 ///
288 /// @return True, if we believe @p NewSchedule is an improvement for @p S.
289 static bool isProfitableSchedule(polly::Scop &S, isl::schedule NewSchedule);
290
291 /// Isolate a set of partial tile prefixes.
292 ///
293 /// This set should ensure that it contains only partial tile prefixes that
294 /// have exactly VectorWidth iterations.
295 ///
296 /// @param Node A schedule node band, which is a parent of a band node,
297 /// that contains a vector loop.
298 /// @return Modified isl_schedule_node.
299 static isl::schedule_node isolateFullPartialTiles(isl::schedule_node Node,
300 int VectorWidth);
301
302private:
303 /// Check if this node is a band node we want to tile.
304 ///
305 /// We look for innermost band nodes where individual dimensions are marked as
306 /// permutable.
307 ///
308 /// @param Node The node to check.
309 static bool isTileableBandNode(isl::schedule_node Node);
310
311 /// Check if this node is a band node we want to transform using pattern
312 /// matching.
313 ///
314 /// We look for innermost band nodes where individual dimensions are marked as
315 /// permutable. There is no restriction on the number of individual
316 /// dimensions.
317 ///
318 /// @param Node The node to check.
319 static bool isPMOptimizableBandNode(isl::schedule_node Node);
320
321 /// Pre-vectorizes one scheduling dimension of a schedule band.
322 ///
323 /// prevectSchedBand splits out the dimension DimToVectorize, tiles it and
324 /// sinks the resulting point loop.
325 ///
326 /// Example (DimToVectorize=0, VectorWidth=4):
327 ///
328 /// | Before transformation:
329 /// |
330 /// | A[i,j] -> [i,j]
331 /// |
332 /// | for (i = 0; i < 128; i++)
333 /// | for (j = 0; j < 128; j++)
334 /// | A(i,j);
335 ///
336 /// | After transformation:
337 /// |
338 /// | for (it = 0; it < 32; it+=1)
339 /// | for (j = 0; j < 128; j++)
340 /// | for (ip = 0; ip <= 3; ip++)
341 /// | A(4 * it + ip,j);
342 ///
343 /// The goal of this transformation is to create a trivially vectorizable
344 /// loop. This means a parallel loop at the innermost level that has a
345 /// constant number of iterations corresponding to the target vector width.
346 ///
347 /// This transformation creates a loop at the innermost level. The loop has
348 /// a constant number of iterations, if the number of loop iterations at
349 /// DimToVectorize can be divided by VectorWidth. The default VectorWidth is
350 /// currently constant and not yet target specific. This function does not
351 /// reason about parallelism.
352 static isl::schedule_node prevectSchedBand(isl::schedule_node Node,
353 unsigned DimToVectorize,
354 int VectorWidth);
355
356 /// Apply additional optimizations on the bands in the schedule tree.
357 ///
358 /// We are looking for an innermost band node and apply the following
359 /// transformations:
360 ///
361 /// - Tile the band
362 /// - if the band is tileable
363 /// - if the band has more than one loop dimension
364 ///
365 /// - Prevectorize the schedule of the band (or the point loop in case of
366 /// tiling).
367 /// - if vectorization is enabled
368 ///
369 /// @param Node The schedule node to (possibly) optimize.
370 /// @param User A pointer to forward some use information
371 /// (currently unused).
372 static isl_schedule_node *optimizeBand(isl_schedule_node *Node, void *User);
373
374 /// Apply tiling optimizations on the bands in the schedule tree.
375 ///
376 /// @param Node The schedule node to (possibly) optimize.
377 static isl::schedule_node applyTileBandOpt(isl::schedule_node Node);
378
379 /// Apply prevectorization on the bands in the schedule tree.
380 ///
381 /// @param Node The schedule node to (possibly) prevectorize.
382 static isl::schedule_node applyPrevectBandOpt(isl::schedule_node Node);
383};
384
385isl::schedule_node
386ScheduleTreeOptimizer::isolateFullPartialTiles(isl::schedule_node Node,
387 int VectorWidth) {
388 if (Node.is_null())
389 return {};
391 Node = Node.child(0).child(0);
392 isl::union_map SchedRelUMap = Node.get_prefix_schedule_relation();
393 isl::union_set ScheduleRangeUSet = SchedRelUMap.range();
394 isl::set ScheduleRange{ScheduleRangeUSet};
395 isl::set IsolateDomain = getPartialTilePrefixes(ScheduleRange, VectorWidth);
396 auto AtomicOption = getDimOptions(IsolateDomain.ctx(), "atomic");
397 isl::union_set IsolateOption = getIsolateOptions(IsolateDomain, 1);
398 Node = Node.parent().parent();
399 isl::union_set Options = IsolateOption.unite(AtomicOption);
400 if (Node.is_null())
401 return {};
402 isl::schedule_node_band Result =
403 Node.as<isl::schedule_node_band>().set_ast_build_options(Options);
404 return Result;
405}
406
407struct InsertSimdMarkers final : ScheduleNodeRewriter<InsertSimdMarkers> {
408 isl::schedule_node visitBand(isl::schedule_node_band Band) {
409 isl::schedule_node Node = visitChildren(Band);
410
411 // Only add SIMD markers to innermost bands.
412 if (!Node.first_child().isa<isl::schedule_node_leaf>())
413 return Node;
414
415 isl::id LoopMarker = isl::id::alloc(Band.ctx(), "SIMD", nullptr);
416 return Band.insert_mark(LoopMarker);
417 }
418};
419
420isl::schedule_node ScheduleTreeOptimizer::prevectSchedBand(
421 isl::schedule_node Node, unsigned DimToVectorize, int VectorWidth) {
422 if (Node.is_null())
423 return {};
425
427 if (Space.is_null())
428 return {};
429 unsigned ScheduleDimensions = unsignedFromIslSize(Space.dim(isl::dim::set));
430 assert(DimToVectorize < ScheduleDimensions);
431
432 if (DimToVectorize > 0) {
433 Node = isl::manage(
434 isl_schedule_node_band_split(Node.release(), DimToVectorize));
435 Node = Node.child(0);
436 }
437 if (DimToVectorize < ScheduleDimensions - 1)
440 auto Sizes = isl::multi_val::zero(Space);
441 Sizes = Sizes.set_val(0, isl::val(Node.ctx(), VectorWidth));
442 Node =
443 isl::manage(isl_schedule_node_band_tile(Node.release(), Sizes.release()));
444 Node = isolateFullPartialTiles(Node, VectorWidth);
445 Node = Node.child(0);
446 // Make sure the "trivially vectorizable loop" is not unrolled. Otherwise,
447 // we will have troubles to match it in the backend.
448 Node = Node.as<isl::schedule_node_band>().set_ast_build_options(
449 isl::union_set(Node.ctx(), "{ unroll[x]: 1 = 0 }"));
450
451 // Sink the inner loop into the smallest possible statements to make them
452 // represent a single vector instruction if possible.
454 if (Node.is_null())
455 return {};
456
457 // Add SIMD markers to those vector statements.
458 InsertSimdMarkers SimdMarkerInserter;
459 Node = SimdMarkerInserter.visit(Node);
460
461 if (!Node.is_null())
462 PrevectOpts++;
463 return Node.parent();
464}
465
466static bool isSimpleInnermostBand(const isl::schedule_node &Node) {
469
470 auto ChildType = isl_schedule_node_get_type(Node.child(0).get());
471
472 if (ChildType == isl_schedule_node_leaf)
473 return true;
474
475 if (ChildType != isl_schedule_node_sequence)
476 return false;
477
478 auto Sequence = Node.child(0);
479
480 for (int c = 0, nc = isl_schedule_node_n_children(Sequence.get()); c < nc;
481 ++c) {
482 auto Child = Sequence.child(c);
484 return false;
485 if (isl_schedule_node_get_type(Child.child(0).get()) !=
487 return false;
488 }
489 return true;
490}
491
492/// Check if this node is a band node, which has only one child.
493///
494/// @param Node The node to check.
495static bool isOneTimeParentBandNode(isl::schedule_node Node) {
497 return false;
498
499 if (isl_schedule_node_n_children(Node.get()) != 1)
500 return false;
501
502 return true;
503}
504
505bool ScheduleTreeOptimizer::isTileableBandNode(isl::schedule_node Node) {
506 if (!isOneTimeParentBandNode(Node))
507 return false;
508
510 return false;
511
513
514 if (unsignedFromIslSize(Space.dim(isl::dim::set)) <= 1u)
515 return false;
516
517 return isSimpleInnermostBand(Node);
518}
519
520bool ScheduleTreeOptimizer::isPMOptimizableBandNode(isl::schedule_node Node) {
521 if (!isOneTimeParentBandNode(Node))
522 return false;
523
524 return Node.child(0).isa<isl::schedule_node_leaf>();
525}
526
527__isl_give isl::schedule_node
528ScheduleTreeOptimizer::applyTileBandOpt(isl::schedule_node Node) {
529 if (FirstLevelTiling) {
530 Node = tileNode(Node, "1st level tiling", FirstLevelTileSizes,
532 FirstLevelTileOpts++;
533 }
534
535 if (SecondLevelTiling) {
536 Node = tileNode(Node, "2nd level tiling", SecondLevelTileSizes,
538 SecondLevelTileOpts++;
539 }
540
541 if (RegisterTiling) {
542 Node =
544 RegisterTileOpts++;
545 }
546
547 return Node;
548}
549
550isl::schedule_node
551ScheduleTreeOptimizer::applyPrevectBandOpt(isl::schedule_node Node) {
553 if (Space.is_null())
554 return {};
555 int Dims = unsignedFromIslSize(Space.dim(isl::dim::set));
556
557 for (int i = Dims - 1; i >= 0; i--)
558 if (Node.as<isl::schedule_node_band>().member_get_coincident(i)) {
559 Node = prevectSchedBand(Node, i, PrevectorWidth);
560 break;
561 }
562
563 return Node;
564}
565
567ScheduleTreeOptimizer::optimizeBand(__isl_take isl_schedule_node *NodeArg,
568 void *User) {
569 const OptimizerAdditionalInfoTy *OAI =
570 static_cast<const OptimizerAdditionalInfoTy *>(User);
571 assert(OAI && "Expecting optimization options");
572
573 isl::schedule_node Node = isl::manage(NodeArg);
574
575 if (OAI->PatternOpts && isPMOptimizableBandNode(Node)) {
576 isl::schedule_node PatternOptimizedSchedule =
577 tryOptimizeMatMulPattern(Node, OAI->TTI, OAI->D);
578 if (!PatternOptimizedSchedule.is_null()) {
579 MatMulOpts++;
580 OAI->DepsChanged = true;
581 return PatternOptimizedSchedule.release();
582 }
583 }
584
585 if (!isTileableBandNode(Node))
586 return Node.release();
587
588 if (OAI->Postopts)
589 Node = applyTileBandOpt(Node);
590
591 if (OAI->Prevect) {
592 IslQuotaScope MaxScope = OAI->MaxOpGuard.enter();
593
594 // FIXME: Prevectorization requirements are different from those checked by
595 // isTileableBandNode.
596 Node = applyPrevectBandOpt(Node);
597
598 if (OAI->MaxOpGuard.hasQuotaExceeded() || Node.is_null())
599 return (isl::schedule_node()).release();
600 }
601
602 return Node.release();
603}
604
605isl::schedule
606ScheduleTreeOptimizer::optimizeSchedule(isl::schedule Schedule,
607 const OptimizerAdditionalInfoTy *OAI) {
608 auto Root = Schedule.get_root();
609 Root = optimizeScheduleNode(Root, OAI);
610 return Root.get_schedule();
611}
612
613isl::schedule_node ScheduleTreeOptimizer::optimizeScheduleNode(
614 isl::schedule_node Node, const OptimizerAdditionalInfoTy *OAI) {
616 Node.release(), optimizeBand,
617 const_cast<void *>(static_cast<const void *>(OAI))));
618 return Node;
619}
620
621bool ScheduleTreeOptimizer::isProfitableSchedule(Scop &S,
622 isl::schedule NewSchedule) {
623 // To understand if the schedule has been optimized we check if the schedule
624 // has changed at all.
625 // TODO: We can improve this by tracking if any necessarily beneficial
626 // transformations have been performed. This can e.g. be tiling, loop
627 // interchange, or ...) We can track this either at the place where the
628 // transformation has been performed or, in case of automatic ILP based
629 // optimizations, by comparing (yet to be defined) performance metrics
630 // before/after the scheduling optimizer
631 // (e.g., #stride-one accesses)
632 // FIXME: A schedule tree whose union_map-conversion is identical to the
633 // original schedule map may still allow for parallelization, i.e. can still
634 // be profitable.
635 auto NewScheduleMap = NewSchedule.get_map();
636 auto OldSchedule = S.getSchedule();
637 assert(!OldSchedule.is_null() &&
638 "Only IslScheduleOptimizer can insert extension nodes "
639 "that make Scop::getSchedule() return nullptr.");
640 bool changed = !OldSchedule.is_equal(NewScheduleMap);
641 return changed;
642}
643
644#ifndef NDEBUG
645static void printSchedule(llvm::raw_ostream &OS, const isl::schedule &Schedule,
646 StringRef Desc) {
647 isl::ctx Ctx = Schedule.ctx();
650 P = isl_printer_print_schedule(P, Schedule.get());
651 char *Str = isl_printer_get_str(P);
652 OS << Desc << ": \n" << Str << "\n";
653 free(Str);
655}
656#endif
657
658/// Return whether the dependence distances of @p Map, which relates instances
659/// of the same statement, are bounded.
660static bool hasBoundedDistances(const isl::map &Map) {
661 isl::set Deltas = Map.deltas();
662 return !Deltas.is_null() && Deltas.is_bounded().is_true();
663}
664
665/// Undo the simplification of the proximity dependences of a statement on
666/// itself where it made their distances unbounded.
667///
668/// The scheduler looks for schedule rows that bound the distance of every
669/// proximity dependence. If the simplification drops the constraints of the
670/// domain that bound the distance of a dependence, such as a value that is
671/// read by all later iterations of a loop, then every row that advances along
672/// that loop has an unbounded distance, and the scheduler falls back to
673/// carrying dependences one row at a time instead of forming a permutable
674/// band.
675///
676/// @param Simplified The simplified proximity dependences.
677/// @param Exact The proximity dependences before simplification.
678static isl::union_map keepBoundedDistances(const isl::union_map &Simplified,
679 const isl::union_map &Exact) {
680 isl::union_map Result = isl::union_map::empty(Simplified.ctx());
681 for (isl::map Map : Simplified.get_map_list()) {
682 isl::space Space = Map.get_space();
683 if (Space.domain().is_equal(Space.range()) && !hasBoundedDistances(Map)) {
684 // Only add the constraints that bound the distances before the
685 // simplification rather than restoring all constraints of the exact
686 // dependence: preferably the hull of the exact distances, which is a
687 // single convex set, otherwise the exact distances themselves.
688 isl::set ExactDeltas = Exact.extract_map(Space).deltas();
689 isl::map Bounded = Map.intersect(ExactDeltas.simple_hull().translation());
690 if (!hasBoundedDistances(Bounded))
691 Bounded = Map.intersect(ExactDeltas.translation());
692 if (hasBoundedDistances(Bounded))
693 Map = Bounded;
694 }
695 Result = Result.unite(isl::union_map(Map));
696 }
697 return Result;
698}
699
700/// Collect statistics for the schedule tree.
701///
702/// @param Schedule The schedule tree to analyze. If not a schedule tree it is
703/// ignored.
704/// @param Version The version of the schedule tree that is analyzed.
705/// 0 for the original schedule tree before any transformation.
706/// 1 for the schedule tree after isl's rescheduling.
707/// 2 for the schedule tree after optimizations are applied
708/// (tiling, pattern matching)
709static void walkScheduleTreeForStatistics(isl::schedule Schedule, int Version) {
710 auto Root = Schedule.get_root();
711 if (Root.is_null())
712 return;
713
715 Root.get(),
716 [](__isl_keep isl_schedule_node *nodeptr, void *user) -> isl_bool {
717 isl::schedule_node Node = isl::manage_copy(nodeptr);
718 int Version = *static_cast<int *>(user);
719
720 switch (isl_schedule_node_get_type(Node.get())) {
721 case isl_schedule_node_band: {
722 NumBands[Version]++;
723 if (isl_schedule_node_band_get_permutable(Node.get()) ==
724 isl_bool_true)
725 NumPermutable[Version]++;
726
727 int CountMembers = isl_schedule_node_band_n_member(Node.get());
728 NumBandMembers[Version] += CountMembers;
729 for (int i = 0; i < CountMembers; i += 1) {
730 if (Node.as<isl::schedule_node_band>().member_get_coincident(i))
731 NumCoincident[Version]++;
732 }
733 break;
734 }
735
736 case isl_schedule_node_filter:
737 NumFilters[Version]++;
738 break;
739
740 case isl_schedule_node_extension:
741 NumExtension[Version]++;
742 break;
743
744 default:
745 break;
746 }
747
748 return isl_bool_true;
749 },
750 &Version);
751}
752
753static void runIslScheduleOptimizerImpl(
754 Scop &S,
755 function_ref<const Dependences &(Dependences::AnalysisLevel)> GetDeps,
756 TargetTransformInfo *TTI, OptimizationRemarkEmitter *ORE,
757 isl::schedule &LastSchedule, bool &DepsChanged) {
758 // Skip empty SCoPs but still allow code generation as it will delete the
759 // loops present but not needed.
760 if (S.getSize() == 0) {
761 S.markAsOptimized();
762 return;
763 }
764
765 ScopsProcessed++;
766
767 // Schedule without optimizations.
768 isl::schedule Schedule = S.getScheduleTree();
769 walkScheduleTreeForStatistics(S.getScheduleTree(), 0);
770 POLLY_DEBUG(printSchedule(dbgs(), Schedule, "Original schedule tree"));
771
772 bool HasUserTransformation = false;
773 if (PragmaBasedOpts) {
774 isl::schedule ManuallyTransformed = applyManualTransformations(
775 &S, Schedule, GetDeps(Dependences::AL_Statement), ORE);
776 if (ManuallyTransformed.is_null()) {
777 POLLY_DEBUG(dbgs() << "Error during manual optimization\n");
778 return;
779 }
780
781 if (ManuallyTransformed.get() != Schedule.get()) {
782 // User transformations have precedence over other transformations.
783 HasUserTransformation = true;
784 Schedule = std::move(ManuallyTransformed);
786 printSchedule(dbgs(), Schedule, "After manual transformations"));
787 }
788 }
789
790 // Only continue if either manual transformations have been applied or we are
791 // allowed to apply heuristics.
792 // TODO: Detect disabled heuristics and no user-directed transformation
793 // metadata earlier in ScopDetection.
794 if (!HasUserTransformation && S.hasDisableHeuristicsHint()) {
795 POLLY_DEBUG(dbgs() << "Heuristic optimizations disabled by metadata\n");
796 return;
797 }
798
799 // Get dependency analysis.
800 const Dependences &D = GetDeps(Dependences::AL_Statement);
801 if (D.getSharedIslCtx() != S.getSharedIslCtx()) {
802 POLLY_DEBUG(dbgs() << "DependenceInfo for another SCoP/isl_ctx\n");
803 return;
804 }
805 if (!D.hasValidDependences()) {
806 POLLY_DEBUG(dbgs() << "Dependency information not available\n");
807 return;
808 }
809
810 isl_ctx *Ctx = S.getIslCtx().get();
812 /*AutoEnter=*/false);
813
814 // Apply ISL's algorithm only if not overridden by the user. Note that
815 // post-rescheduling optimizations (tiling, pattern-based, prevectorization)
816 // rely on the coincidence/permutable annotations on schedule tree bands that
817 // are added by the rescheduling analyzer. Therefore, disabling the
818 // rescheduler implicitly also disables these optimizations.
819 if (!EnableReschedule) {
820 POLLY_DEBUG(dbgs() << "Skipping rescheduling due to command line option\n");
821 } else if (HasUserTransformation) {
823 dbgs() << "Skipping rescheduling due to manual transformation\n");
824 } else {
825 // Build input data.
826 int ValidityKinds =
828 int ProximityKinds;
829
830 if (OptimizeDeps == "all")
831 ProximityKinds =
833 else if (OptimizeDeps == "raw")
834 ProximityKinds = Dependences::TYPE_RAW;
835 else {
836 errs() << "Do not know how to optimize for '" << OptimizeDeps << "'"
837 << " Falling back to optimizing all dependences.\n";
838 ProximityKinds =
840 }
841
842 isl::union_set Domain = S.getDomains();
843
844 if (Domain.is_null())
845 return;
846
847 isl::union_map Validity = D.getDependences(ValidityKinds);
848 isl::union_map Proximity = D.getDependences(ProximityKinds);
849
850 // Simplify the dependences by removing the constraints introduced by the
851 // domains. This can speed up the scheduling time significantly, as large
852 // constant coefficients will be removed from the dependences. The
853 // introduction of some additional dependences reduces the possible
854 // transformations, but in most cases, such transformation do not seem to be
855 // interesting anyway. In some cases this option may stop the scheduler to
856 // find any schedule.
857 if (SimplifyDeps == "yes") {
858 isl::union_map ExactProximity = Proximity;
859 Validity = Validity.gist_domain(Domain);
860 Validity = Validity.gist_range(Domain);
861 Proximity = Proximity.gist_domain(Domain);
862 Proximity = Proximity.gist_range(Domain);
863 Proximity = keepBoundedDistances(Proximity, ExactProximity);
864 } else if (SimplifyDeps != "no") {
865 errs()
866 << "warning: Option -polly-opt-simplify-deps should either be 'yes' "
867 "or 'no'. Falling back to default: 'yes'\n";
868 }
869
870 POLLY_DEBUG(dbgs() << "\n\nCompute schedule from: ");
871 POLLY_DEBUG(dbgs() << "Domain := " << Domain << ";\n");
872 POLLY_DEBUG(dbgs() << "Proximity := " << Proximity << ";\n");
873 POLLY_DEBUG(dbgs() << "Validity := " << Validity << ";\n");
874
875 int IslMaximizeBands;
876 if (MaximizeBandDepth == "yes") {
877 IslMaximizeBands = 1;
878 } else if (MaximizeBandDepth == "no") {
879 IslMaximizeBands = 0;
880 } else {
881 errs()
882 << "warning: Option -polly-opt-maximize-bands should either be 'yes'"
883 " or 'no'. Falling back to default: 'yes'\n";
884 IslMaximizeBands = 1;
885 }
886
887 int IslOuterCoincidence;
888 if (OuterCoincidence == "yes") {
889 IslOuterCoincidence = 1;
890 } else if (OuterCoincidence == "no") {
891 IslOuterCoincidence = 0;
892 } else {
893 errs() << "warning: Option -polly-opt-outer-coincidence should either be "
894 "'yes' or 'no'. Falling back to default: 'no'\n";
895 IslOuterCoincidence = 0;
896 }
897
903
904 auto OnErrorStatus = isl_options_get_on_error(Ctx);
906
908 SC = SC.set_proximity(Proximity);
909 SC = SC.set_validity(Validity);
910 SC = SC.set_coincidence(Validity);
911
912 {
913 IslQuotaScope MaxOpScope = MaxOpGuard.enter();
914 Schedule = SC.compute_schedule();
915 }
916
917 isl_options_set_on_error(Ctx, OnErrorStatus);
918
919 if (!Schedule.is_null())
920 ScopsRescheduled++;
921 POLLY_DEBUG(printSchedule(dbgs(), Schedule, "After rescheduling"));
922 }
923
924 walkScheduleTreeForStatistics(Schedule, 1);
925
926 if (GreedyFusion && !Schedule.is_null()) {
927 isl::union_map Validity = D.getDependences(
929 Schedule = applyGreedyFusion(Schedule, Validity);
930 assert(!Schedule.is_null());
931 }
932
933 // Apply post-rescheduling optimizations (if enabled) and/or prevectorization.
934 const OptimizerAdditionalInfoTy OAI = {
935 TTI,
936 const_cast<Dependences *>(&D),
937 /*PatternOpts=*/!HasUserTransformation && PMBasedOpts,
938 /*Postopts=*/!HasUserTransformation && EnablePostopts,
940 DepsChanged,
941 MaxOpGuard};
942 if (!Schedule.is_null() && (OAI.PatternOpts || OAI.Postopts || OAI.Prevect)) {
943 Schedule = ScheduleTreeOptimizer::optimizeSchedule(Schedule, &OAI);
944 Schedule = hoistExtensionNodes(Schedule);
945 POLLY_DEBUG(printSchedule(dbgs(), Schedule, "After post-optimizations"));
946 walkScheduleTreeForStatistics(Schedule, 2);
947 }
948
949 // Check for why any computation could have failed
950 if (MaxOpGuard.hasQuotaExceeded()) {
951 POLLY_DEBUG(dbgs() << "Schedule optimizer calculation exceeds ISL quota\n");
952 return;
953 } else if (isl_ctx_last_error(Ctx) != isl_error_none) {
955 const char *File = isl_ctx_last_error_file(Ctx);
956 int Line = isl_ctx_last_error_line(Ctx);
957 const char *Msg = isl_ctx_last_error_msg(Ctx);
958 dbgs() << "ISL reported an error during the computation of a new "
959 "schedule at "
960 << File << ":" << Line << ": " << Msg;
961 });
963 return;
964 } else if (Schedule.is_null()) {
965 POLLY_DEBUG(dbgs() << "Schedule optimizer did not compute a new schedule "
966 "for unknown reasons\n");
967 return;
968 }
969
970 // Skip profitability check if user transformation(s) have been applied.
971 if (!HasUserTransformation &&
972 !ScheduleTreeOptimizer::isProfitableSchedule(S, Schedule))
973 return;
974
975 auto ScopStats = S.getStatistics();
976 ScopsOptimized++;
977 NumAffineLoopsOptimized += ScopStats.NumAffineLoops;
978 NumBoxedLoopsOptimized += ScopStats.NumBoxedLoops;
979 LastSchedule = Schedule;
980
981 S.setScheduleTree(Schedule);
982 S.markAsOptimized();
983
984 if (OptimizedScops)
985 errs() << S;
986}
987
988static void runScheduleOptimizerPrinter(raw_ostream &OS,
989 isl::schedule LastSchedule) {
990 isl_printer *p;
991 char *ScheduleStr;
992
993 OS << "Calculated schedule:\n";
994
995 if (LastSchedule.is_null()) {
996 OS << "n/a\n";
997 return;
998 }
999
1000 p = isl_printer_to_str(LastSchedule.ctx().get());
1002 p = isl_printer_print_schedule(p, LastSchedule.get());
1003 ScheduleStr = isl_printer_get_str(p);
1005
1006 OS << ScheduleStr << "\n";
1007
1008 free(ScheduleStr);
1009}
1010
1011} // namespace
1012
1013void polly::runIslScheduleOptimizer(Scop &S, TargetTransformInfo *TTI,
1015 auto GetDeps = [&Deps](Dependences::AnalysisLevel) -> const Dependences & {
1017 };
1018 OptimizationRemarkEmitter ORE(&S.getFunction());
1019 isl::schedule LastSchedule;
1020 bool DepsChanged = false;
1021 runIslScheduleOptimizerImpl(S, GetDeps, TTI, &ORE, LastSchedule, DepsChanged);
1022 if (DepsChanged)
1023 Deps.abandonDependences();
1024
1025 if (PollyPrintOptIsl) {
1026 outs()
1027 << "Printing analysis 'Polly - Optimize schedule of SCoP' for region: '"
1028 << S.getName() << "' in function '" << S.getFunction().getName()
1029 << "':\n";
1030 runScheduleOptimizerPrinter(outs(), LastSchedule);
1031 }
1032}
unsigned unsignedFromIslSize(const isl::size &Size)
Check that Size is valid (only on debug builds) and cast it to unsigned.
Definition ISLTools.h:40
llvm::cl::OptionCategory PollyCategory
#define POLLY_DEBUG(X)
Definition PollyDebug.h:23
static cl::opt< bool > PragmaBasedOpts("polly-pragma-based-opts", cl::desc("Apply user-directed transformation from metadata"), cl::init(true), cl::cat(PollyCategory))
static cl::opt< int > MaxCoefficient("polly-opt-max-coefficient", cl::desc("The maximal coefficient allowed (-1 is unlimited)"), cl::Hidden, cl::init(20), cl::cat(PollyCategory))
static cl::opt< bool > PollyPrintOptIsl("polly-print-opt-isl", cl::desc("A polly pass"), cl::cat(PollyCategory))
static cl::opt< int > MaxConstantTerm("polly-opt-max-constant-term", cl::desc("The maximal constant term allowed (-1 is unlimited)"), cl::Hidden, cl::init(20), cl::cat(PollyCategory))
static cl::opt< int > PrevectorWidth("polly-prevect-width", cl::desc("The number of loop iterations to strip-mine for pre-vectorization"), cl::Hidden, cl::init(4), cl::cat(PollyCategory))
static cl::opt< std::string > MaximizeBandDepth("polly-opt-maximize-bands", cl::desc("Maximize the band depth (yes/no)"), cl::Hidden, cl::init("yes"), cl::cat(PollyCategory))
static cl::opt< int > ScheduleComputeOut("polly-schedule-computeout", cl::desc("Bound the scheduler by maximal amount" "of computational steps. "), cl::Hidden, cl::init(300000), cl::cat(PollyCategory))
static cl::opt< int > SecondLevelDefaultTileSize("polly-2nd-level-default-tile-size", cl::desc("The default 2nd-level tile size (if not enough were provided by" " --polly-2nd-level-tile-sizes)"), cl::Hidden, cl::init(16), cl::cat(PollyCategory))
static cl::opt< int > RegisterDefaultTileSize("polly-register-tiling-default-tile-size", cl::desc("The default register tile size (if not enough were provided by" " --polly-register-tile-sizes)"), cl::Hidden, cl::init(2), cl::cat(PollyCategory))
static cl::opt< int > FirstLevelDefaultTileSize("polly-default-tile-size", cl::desc("The default tile size (if not enough were provided by" " --polly-tile-sizes)"), cl::Hidden, cl::init(32), cl::cat(PollyCategory))
static cl::opt< bool > OptimizedScops("polly-optimized-scops", cl::desc("Polly - Dump polyhedral description of Scops optimized with " "the isl scheduling optimizer and the set of post-scheduling " "transformations is applied on the schedule tree"), cl::cat(PollyCategory))
static cl::opt< bool > PMBasedOpts("polly-pattern-matching-based-opts", cl::desc("Perform optimizations based on pattern matching"), cl::init(true), cl::cat(PollyCategory))
static cl::opt< bool > EnablePostopts("polly-postopts", cl::desc("Apply post-rescheduling optimizations such as " "tiling (requires -polly-reschedule)"), cl::init(true), cl::cat(PollyCategory))
static cl::opt< bool > FirstLevelTiling("polly-tiling", cl::desc("Enable loop tiling"), cl::init(true), cl::cat(PollyCategory))
static cl::list< int > FirstLevelTileSizes("polly-tile-sizes", cl::desc("A tile size for each loop dimension, filled " "with --polly-default-tile-size"), cl::Hidden, cl::CommaSeparated, cl::cat(PollyCategory))
static cl::opt< bool > GreedyFusion("polly-loopfusion-greedy", cl::desc("Aggressively try to fuse everything"), cl::Hidden, cl::cat(PollyCategory))
static cl::opt< bool > RegisterTiling("polly-register-tiling", cl::desc("Enable register tiling"), cl::cat(PollyCategory))
static cl::opt< std::string > SimplifyDeps("polly-opt-simplify-deps", cl::desc("Dependences should be simplified (yes/no)"), cl::Hidden, cl::init("yes"), cl::cat(PollyCategory))
static cl::opt< bool > EnableReschedule("polly-reschedule", cl::desc("Optimize SCoPs using ISL"), cl::init(true), cl::cat(PollyCategory))
STATISTIC(ScopsProcessed, "Number of scops processed")
static cl::opt< bool > SecondLevelTiling("polly-2nd-level-tiling", cl::desc("Enable a 2nd level loop of loop tiling"), cl::cat(PollyCategory))
static cl::opt< std::string > OptimizeDeps("polly-opt-optimize-only", cl::desc("Only a certain kind of dependences (all/raw)"), cl::Hidden, cl::init("all"), cl::cat(PollyCategory))
static cl::list< int > RegisterTileSizes("polly-register-tile-sizes", cl::desc("A tile size for each loop dimension, filled " "with --polly-register-tile-size"), cl::Hidden, cl::CommaSeparated, cl::cat(PollyCategory))
#define THREE_STATISTICS(VARNAME, DESC)
static cl::list< int > SecondLevelTileSizes("polly-2nd-level-tile-sizes", cl::desc("A tile size for each loop dimension, filled " "with --polly-default-tile-size"), cl::Hidden, cl::CommaSeparated, cl::cat(PollyCategory))
static cl::opt< std::string > OuterCoincidence("polly-opt-outer-coincidence", cl::desc("Try to construct schedules where the outer member of each band " "satisfies the coincidence constraints (yes/no)"), cl::Hidden, cl::init("no"), cl::cat(PollyCategory))
isl_ctx * get()
isl::checked::set deltas() const
isl::checked::space get_space() const
isl::checked::map intersect(isl::checked::map map2) const
isl::checked::ctx ctx() const
isl::checked::ctx ctx() const
isl::checked::schedule_node child(int pos) const
__isl_give isl_schedule_node * release()
isl::checked::schedule_node parent() const
isl::checked::schedule_node first_child() const
isl::checked::schedule_node insert_mark(isl::checked::id mark) const
__isl_keep isl_schedule_node * get() const
__isl_keep isl_schedule * get() const
isl::checked::schedule_node get_root() const
isl::checked::union_map get_map() const
isl::checked::ctx ctx() const
isl::checked::ctx ctx() const
isl::checked::map translation() const
bool is_null() const
isl::checked::space domain() const
isl::checked::space range() const
boolean is_equal(const isl::checked::space &space2) const
isl::checked::union_set range() const
isl::checked::union_map unite(isl::checked::union_map umap2) const
isl::checked::map extract_map(isl::checked::space space) const
isl::checked::map_list get_map_list() const
isl::checked::ctx ctx() const
isl::checked::union_map gist_range(isl::checked::union_set uset) const
isl::checked::union_map gist_domain(isl::checked::union_set uset) const
isl::checked::union_set unite(isl::checked::union_set uset2) const
static isl::id alloc(isl::ctx ctx, const std::string &name, void *user)
static isl::multi_val zero(isl::space space)
static isl::schedule_constraints on_domain(isl::union_set domain)
static isl::union_map empty(isl::ctx ctx)
The accumulated dependence information for a SCoP.
bool hasValidDependences() const
Report if valid dependences are available.
const std::shared_ptr< isl_ctx > & getSharedIslCtx() const
isl::union_map getDependences(int Kinds) const
Get the dependences of type Kinds.
Scoped limit of ISL operations.
Definition GICHelper.h:424
bool hasQuotaExceeded() const
Return whether the current quota has exceeded.
Definition GICHelper.h:483
IslQuotaScope enter(bool AllowReturnNull=true)
Enter a scope that can handle out-of-quota errors.
Definition GICHelper.h:477
Scope guard for code that allows arbitrary isl function to return an error if the max-operations quot...
Definition GICHelper.h:357
Static Control Part.
Definition ScopInfo.h:1627
#define __isl_take
Definition ctx.h:23
const char * isl_ctx_last_error_file(isl_ctx *ctx)
Definition isl_ctx.c:347
enum isl_error isl_ctx_last_error(isl_ctx *ctx)
Definition isl_ctx.c:333
#define __isl_give
Definition ctx.h:20
@ isl_error_none
Definition ctx.h:76
void isl_ctx_reset_error(isl_ctx *ctx)
Definition isl_ctx.c:359
#define __isl_keep
Definition ctx.h:26
int isl_ctx_last_error_line(isl_ctx *ctx)
Definition isl_ctx.c:354
const char * isl_ctx_last_error_msg(isl_ctx *ctx)
Definition isl_ctx.c:340
isl_bool
Definition ctx.h:90
@ isl_bool_true
Definition ctx.h:93
isl_stat isl_stat void * user
Definition hmap.h:39
#define S(TYPE, NAME)
enum isl_schedule_node_type isl_schedule_node_get_type(__isl_keep isl_schedule_node *node)
const char * p
Definition isl_test.c:8397
#define assert(exp)
boolean manage(isl_bool val)
Definition cpp-checked.h:98
isl::schedule applyManualTransformations(Scop *S, isl::schedule Sched, const Dependences &D, llvm::OptimizationRemarkEmitter *ORE)
Apply loop-transformation metadata.
@ VECTORIZER_NONE
VectorizerChoice PollyVectorizerChoice
isl::schedule_node applyRegisterTiling(isl::schedule_node Node, llvm::ArrayRef< int > TileSizes, int DefaultTileSize)
Tile a schedule node and unroll point loops.
isl::schedule applyGreedyFusion(isl::schedule Sched, const isl::union_map &Deps)
Apply greedy fusion.
isl::schedule_node tryOptimizeMatMulPattern(isl::schedule_node Node, const llvm::TargetTransformInfo *TTI, const Dependences *D)
Apply the BLIS matmul optimization pattern if possible.
isl::union_set getIsolateOptions(isl::set IsolateDomain, unsigned OutDimsNum)
Create an isl::union_set, which describes the isolate option based on IsolateDomain.
void runIslScheduleOptimizer(Scop &S, llvm::TargetTransformInfo *TTI, DependenceAnalysis::Result &Deps)
isl::schedule_node tileNode(isl::schedule_node Node, const char *Identifier, llvm::ArrayRef< int > TileSizes, int DefaultTileSize)
Tile a schedule node.
isl::union_set getDimOptions(isl::ctx Ctx, const char *Option)
Create an isl::union_set, which describes the specified option for the dimension of the current node.
isl::schedule hoistExtensionNodes(isl::schedule Sched)
Hoist all domains from extension into the root domain node, such that there are no more extension nod...
isl::set getPartialTilePrefixes(isl::set ScheduleRange, int VectorWidth)
Build the desired set of partial tile prefixes.
isl_stat isl_options_set_on_error(isl_ctx *ctx, int val)
int isl_options_get_on_error(isl_ctx *ctx)
#define ISL_ON_ERROR_CONTINUE
Definition options.h:30
__isl_null isl_printer * isl_printer_free(__isl_take isl_printer *printer)
__isl_give char * isl_printer_get_str(__isl_keep isl_printer *printer)
#define ISL_YAML_STYLE_BLOCK
Definition printer.h:38
__isl_give isl_printer * isl_printer_set_yaml_style(__isl_take isl_printer *p, int yaml_style)
__isl_give isl_printer * isl_printer_to_str(isl_ctx *ctx)
struct isl_printer isl_printer
Definition printer_type.h:9
isl_stat isl_options_set_schedule_outer_coincidence(isl_ctx *ctx, int val)
isl_stat isl_options_set_schedule_maximize_band_depth(isl_ctx *ctx, int val)
__isl_give isl_printer * isl_printer_print_schedule(__isl_take isl_printer *p, __isl_keep isl_schedule *schedule)
isl_stat isl_options_set_schedule_max_constant_term(isl_ctx *ctx, int val)
isl_stat isl_options_set_schedule_max_coefficient(isl_ctx *ctx, int val)
__isl_give isl_schedule_node * isl_schedule_node_band_sink(__isl_take isl_schedule_node *node)
__isl_export __isl_give isl_schedule_node * isl_schedule_node_band_split(__isl_take isl_schedule_node *node, int pos)
__isl_export isl_size isl_schedule_node_n_children(__isl_keep isl_schedule_node *node)
__isl_export __isl_give isl_schedule_node * isl_schedule_node_band_tile(__isl_take isl_schedule_node *node, __isl_take isl_multi_val *sizes)
__isl_export isl_stat isl_schedule_node_foreach_descendant_top_down(__isl_keep isl_schedule_node *node, isl_bool(*fn)(__isl_keep isl_schedule_node *node, void *user), void *user)
__isl_give isl_space * isl_schedule_node_band_get_space(__isl_keep isl_schedule_node *node)
__isl_export __isl_give isl_schedule_node * isl_schedule_node_map_descendant_bottom_up(__isl_take isl_schedule_node *node, __isl_give isl_schedule_node *(*fn)(__isl_take isl_schedule_node *node, void *user), void *user)
isl_stat isl_options_set_tile_scale_tile_loops(isl_ctx *ctx, int val)
__isl_export isl_bool isl_schedule_node_band_get_permutable(__isl_keep isl_schedule_node *node)
struct isl_schedule_node isl_schedule_node
@ isl_schedule_node_filter
@ isl_schedule_node_band
@ isl_schedule_node_sequence
@ isl_schedule_node_leaf
const Dependences & getDependences(Dependences::AnalysisLevel Level)
Return the dependence information for the current SCoP.
void abandonDependences()
Invalidate the dependence information and recompute it when needed again.
static TupleKindPtr Domain("Domain")
static TupleKindPtr Str
static TupleKindPtr Ctx