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> IsolateCompleteTiles(
174 "polly-isolate-complete-tiles",
175 cl::desc("Separate the complete tiles of a tiled band from the partial "
176 "ones, so that the point loops of the complete tiles have "
177 "constant bounds"),
178 cl::Hidden, cl::init(false), cl::cat(PollyCategory));
179
180static cl::opt<int> IsolateCompleteTileDims(
181 "polly-isolate-complete-tile-dims",
182 cl::desc("Number of innermost tile dimensions that have to be complete for "
183 "a tile to be isolated (0: all of them). Requiring fewer of them "
184 "generates less code, but also gives fewer point loops a constant "
185 "bound"),
186 cl::Hidden, cl::init(0), cl::cat(PollyCategory));
187
188static cl::opt<bool> IsolateCompleteTiles2ndLevel(
189 "polly-isolate-complete-tiles-2nd-level",
190 cl::desc("Separate the complete tiles of the second level of tiling from "
191 "the partial ones"),
192 cl::Hidden, cl::init(false), cl::cat(PollyCategory));
193
194static cl::opt<bool> IsolateCompleteRegisterTiles(
195 "polly-isolate-complete-register-tiles",
196 cl::desc("Separate the complete register tiles from the partial ones, so "
197 "that their unrolled point loops need no guards"),
198 cl::Hidden, cl::init(false), cl::cat(PollyCategory));
199
200static cl::opt<bool> PragmaBasedOpts(
201 "polly-pragma-based-opts",
202 cl::desc("Apply user-directed transformation from metadata"),
203 cl::init(true), cl::cat(PollyCategory));
204
205static cl::opt<bool> EnableReschedule("polly-reschedule",
206 cl::desc("Optimize SCoPs using ISL"),
207 cl::init(true), cl::cat(PollyCategory));
208
209static cl::opt<bool>
210 PMBasedOpts("polly-pattern-matching-based-opts",
211 cl::desc("Perform optimizations based on pattern matching"),
212 cl::init(true), cl::cat(PollyCategory));
213
214static cl::opt<bool>
215 EnablePostopts("polly-postopts",
216 cl::desc("Apply post-rescheduling optimizations such as "
217 "tiling (requires -polly-reschedule)"),
218 cl::init(true), cl::cat(PollyCategory));
219
220static cl::opt<bool> OptimizedScops(
221 "polly-optimized-scops",
222 cl::desc("Polly - Dump polyhedral description of Scops optimized with "
223 "the isl scheduling optimizer and the set of post-scheduling "
224 "transformations is applied on the schedule tree"),
225 cl::cat(PollyCategory));
226
227static cl::opt<bool> PollyPrintOptIsl("polly-print-opt-isl",
228 cl::desc("A polly pass"),
229 cl::cat(PollyCategory));
230
231STATISTIC(ScopsProcessed, "Number of scops processed");
232STATISTIC(ScopsRescheduled, "Number of scops rescheduled");
233STATISTIC(ScopsOptimized, "Number of scops optimized");
234
235STATISTIC(NumAffineLoopsOptimized, "Number of affine loops optimized");
236STATISTIC(NumBoxedLoopsOptimized, "Number of boxed loops optimized");
237
238#define THREE_STATISTICS(VARNAME, DESC) \
239 static Statistic VARNAME[3] = { \
240 {DEBUG_TYPE, #VARNAME "0", DESC " (original)"}, \
241 {DEBUG_TYPE, #VARNAME "1", DESC " (after scheduler)"}, \
242 {DEBUG_TYPE, #VARNAME "2", DESC " (after optimizer)"}}
243
244THREE_STATISTICS(NumBands, "Number of bands");
245THREE_STATISTICS(NumBandMembers, "Number of band members");
246THREE_STATISTICS(NumCoincident, "Number of coincident band members");
247THREE_STATISTICS(NumPermutable, "Number of permutable bands");
248THREE_STATISTICS(NumFilters, "Number of filter nodes");
249THREE_STATISTICS(NumExtension, "Number of extension nodes");
250
251STATISTIC(FirstLevelTileOpts, "Number of first level tiling applied");
252STATISTIC(SecondLevelTileOpts, "Number of second level tiling applied");
253STATISTIC(RegisterTileOpts, "Number of register tiling applied");
254STATISTIC(PrevectOpts, "Number of strip-mining for prevectorization applied");
255STATISTIC(MatMulOpts,
256 "Number of matrix multiplication patterns detected and optimized");
257
258namespace {
259/// Additional parameters of the schedule optimizer.
260///
261/// Target Transform Info and the SCoP dependencies used by the schedule
262/// optimizer.
263struct OptimizerAdditionalInfoTy {
264 const llvm::TargetTransformInfo *TTI;
265 const Dependences *D;
266 bool PatternOpts;
267 bool Postopts;
268 bool Prevect;
269 bool &DepsChanged;
270 IslMaxOperationsGuard &MaxOpGuard;
271};
272
273class ScheduleTreeOptimizer final {
274public:
275 /// Apply schedule tree transformations.
276 ///
277 /// This function takes an (possibly already optimized) schedule tree and
278 /// applies a set of additional optimizations on the schedule tree. The
279 /// transformations applied include:
280 ///
281 /// - Pattern-based optimizations
282 /// - Tiling
283 /// - Prevectorization
284 ///
285 /// @param Schedule The schedule object the transformations will be applied
286 /// to.
287 /// @param OAI Target Transform Info and the SCoP dependencies.
288 /// @returns The transformed schedule.
289 static isl::schedule
290 optimizeSchedule(isl::schedule Schedule,
291 const OptimizerAdditionalInfoTy *OAI = nullptr);
292
293 /// Apply schedule tree transformations.
294 ///
295 /// This function takes a node in an (possibly already optimized) schedule
296 /// tree and applies a set of additional optimizations on this schedule tree
297 /// node and its descendants. The transformations applied include:
298 ///
299 /// - Pattern-based optimizations
300 /// - Tiling
301 /// - Prevectorization
302 ///
303 /// @param Node The schedule object post-transformations will be applied to.
304 /// @param OAI Target Transform Info and the SCoP dependencies.
305 /// @returns The transformed schedule.
306 static isl::schedule_node
307 optimizeScheduleNode(isl::schedule_node Node,
308 const OptimizerAdditionalInfoTy *OAI = nullptr);
309
310 /// Decide if the @p NewSchedule is profitable for @p S.
311 ///
312 /// @param S The SCoP we optimize.
313 /// @param NewSchedule The new schedule we computed.
314 ///
315 /// @return True, if we believe @p NewSchedule is an improvement for @p S.
316 static bool isProfitableSchedule(polly::Scop &S, isl::schedule NewSchedule);
317
318 /// Isolate a set of partial tile prefixes.
319 ///
320 /// This set should ensure that it contains only partial tile prefixes that
321 /// have exactly VectorWidth iterations.
322 ///
323 /// @param Node A schedule node band, which is a parent of a band node,
324 /// that contains a vector loop.
325 /// @return Modified isl_schedule_node.
326 static isl::schedule_node isolateFullPartialTiles(isl::schedule_node Node,
327 int VectorWidth);
328
329private:
330 /// Check if this node is a band node we want to tile.
331 ///
332 /// We look for innermost band nodes where individual dimensions are marked as
333 /// permutable.
334 ///
335 /// @param Node The node to check.
336 static bool isTileableBandNode(isl::schedule_node Node);
337
338 /// Check if this node is a band node we want to transform using pattern
339 /// matching.
340 ///
341 /// We look for innermost band nodes where individual dimensions are marked as
342 /// permutable. There is no restriction on the number of individual
343 /// dimensions.
344 ///
345 /// @param Node The node to check.
346 static bool isPMOptimizableBandNode(isl::schedule_node Node);
347
348 /// Pre-vectorizes one scheduling dimension of a schedule band.
349 ///
350 /// prevectSchedBand splits out the dimension DimToVectorize, tiles it and
351 /// sinks the resulting point loop.
352 ///
353 /// Example (DimToVectorize=0, VectorWidth=4):
354 ///
355 /// | Before transformation:
356 /// |
357 /// | A[i,j] -> [i,j]
358 /// |
359 /// | for (i = 0; i < 128; i++)
360 /// | for (j = 0; j < 128; j++)
361 /// | A(i,j);
362 ///
363 /// | After transformation:
364 /// |
365 /// | for (it = 0; it < 32; it+=1)
366 /// | for (j = 0; j < 128; j++)
367 /// | for (ip = 0; ip <= 3; ip++)
368 /// | A(4 * it + ip,j);
369 ///
370 /// The goal of this transformation is to create a trivially vectorizable
371 /// loop. This means a parallel loop at the innermost level that has a
372 /// constant number of iterations corresponding to the target vector width.
373 ///
374 /// This transformation creates a loop at the innermost level. The loop has
375 /// a constant number of iterations, if the number of loop iterations at
376 /// DimToVectorize can be divided by VectorWidth. The default VectorWidth is
377 /// currently constant and not yet target specific. This function does not
378 /// reason about parallelism.
379 static isl::schedule_node prevectSchedBand(isl::schedule_node Node,
380 unsigned DimToVectorize,
381 int VectorWidth);
382
383 /// Apply additional optimizations on the bands in the schedule tree.
384 ///
385 /// We are looking for an innermost band node and apply the following
386 /// transformations:
387 ///
388 /// - Tile the band
389 /// - if the band is tileable
390 /// - if the band has more than one loop dimension
391 ///
392 /// - Prevectorize the schedule of the band (or the point loop in case of
393 /// tiling).
394 /// - if vectorization is enabled
395 ///
396 /// @param Node The schedule node to (possibly) optimize.
397 /// @param User A pointer to forward some use information
398 /// (currently unused).
399 static isl_schedule_node *optimizeBand(isl_schedule_node *Node, void *User);
400
401 /// Apply tiling optimizations on the bands in the schedule tree.
402 ///
403 /// @param Node The schedule node to (possibly) optimize.
404 static isl::schedule_node applyTileBandOpt(isl::schedule_node Node);
405
406 /// Apply prevectorization on the bands in the schedule tree.
407 ///
408 /// @param Node The schedule node to (possibly) prevectorize.
409 static isl::schedule_node applyPrevectBandOpt(isl::schedule_node Node);
410};
411
412isl::schedule_node
413ScheduleTreeOptimizer::isolateFullPartialTiles(isl::schedule_node Node,
414 int VectorWidth) {
415 if (Node.is_null())
416 return {};
418 Node = Node.child(0).child(0);
419 isl::union_map SchedRelUMap = Node.get_prefix_schedule_relation();
420 isl::union_set ScheduleRangeUSet = SchedRelUMap.range();
421 isl::set ScheduleRange{ScheduleRangeUSet};
422 isl::set IsolateDomain = getPartialTilePrefixes(ScheduleRange, VectorWidth);
423 auto AtomicOption = getDimOptions(IsolateDomain.ctx(), "atomic");
424 isl::union_set IsolateOption = getIsolateOptions(IsolateDomain, 1);
425 Node = Node.parent().parent();
426 isl::union_set Options = IsolateOption.unite(AtomicOption);
427 if (Node.is_null())
428 return {};
429 isl::schedule_node_band Result =
430 Node.as<isl::schedule_node_band>().set_ast_build_options(Options);
431 return Result;
432}
433
434/// Separate the complete tiles of a tiled band from the partial ones.
435///
436/// The point loops of a complete tile run over the whole tile, so isolating
437/// those tiles gives them constant loop bounds instead of the min() expressions
438/// that a tiling of an iteration space which is not a multiple of the tile size
439/// produces. The partial tiles are left to a single atomic copy of the loop
440/// nest to keep the code growth bounded.
441///
442/// @param Node The point band of the tiling, as returned by tileNode.
443/// @param TileSizes The tile size of each tiled dimension.
444/// @return The point band of the modified tree.
445static isl::schedule_node isolateCompleteTiles(isl::schedule_node Node,
446 ArrayRef<int> TileSizes) {
448 "Expecting the point band that tileNode returned");
449
450 // Below the point band, the prefix schedule covers the outer dimensions
451 // followed by the tile and the point dimensions of this tiling.
452 isl::union_set ScheduleRangeUSet =
453 Node.child(0).get_prefix_schedule_relation().range();
454 isl::set ScheduleRange{ScheduleRangeUSet};
455 if (ScheduleRange.is_null())
456 return Node;
457
458 unsigned NumCompleteDims = TileSizes.size();
460 NumCompleteDims =
461 std::min<unsigned>(IsolateCompleteTileDims, TileSizes.size());
462
463 isl::set CompleteTilePrefixes =
464 getCompleteTilePrefixes(ScheduleRange, TileSizes, NumCompleteDims);
465 if (CompleteTilePrefixes.is_null())
466 return Node;
467
468 isl::union_set Options =
469 getIsolateOptions(CompleteTilePrefixes, TileSizes.size())
470 .unite(getDimOptions(Node.ctx(), "atomic"));
471
472 // The option describes the tile dimensions, so it belongs to the tile band,
473 // which sits above the marker separating it from the point band.
474 isl::schedule_node TileBand = Node.parent().parent();
475 if (!TileBand.isa<isl::schedule_node_band>())
476 return Node;
477
478 TileBand =
479 TileBand.as<isl::schedule_node_band>().set_ast_build_options(Options);
480 if (TileBand.is_null())
481 return Node;
482
483 return TileBand.child(0).child(0);
484}
485
486struct InsertSimdMarkers final : ScheduleNodeRewriter<InsertSimdMarkers> {
487 isl::schedule_node visitBand(isl::schedule_node_band Band) {
488 isl::schedule_node Node = visitChildren(Band);
489
490 // Only add SIMD markers to innermost bands.
491 if (!Node.first_child().isa<isl::schedule_node_leaf>())
492 return Node;
493
494 isl::id LoopMarker = isl::id::alloc(Band.ctx(), "SIMD", nullptr);
495 return Band.insert_mark(LoopMarker);
496 }
497};
498
499isl::schedule_node ScheduleTreeOptimizer::prevectSchedBand(
500 isl::schedule_node Node, unsigned DimToVectorize, int VectorWidth) {
501 if (Node.is_null())
502 return {};
504
506 if (Space.is_null())
507 return {};
508 unsigned ScheduleDimensions = unsignedFromIslSize(Space.dim(isl::dim::set));
509 assert(DimToVectorize < ScheduleDimensions);
510
511 if (DimToVectorize > 0) {
512 Node = isl::manage(
513 isl_schedule_node_band_split(Node.release(), DimToVectorize));
514 Node = Node.child(0);
515 }
516 if (DimToVectorize < ScheduleDimensions - 1)
519 auto Sizes = isl::multi_val::zero(Space);
520 Sizes = Sizes.set_val(0, isl::val(Node.ctx(), VectorWidth));
521 Node =
522 isl::manage(isl_schedule_node_band_tile(Node.release(), Sizes.release()));
523 Node = isolateFullPartialTiles(Node, VectorWidth);
524 Node = Node.child(0);
525 // Make sure the "trivially vectorizable loop" is not unrolled. Otherwise,
526 // we will have troubles to match it in the backend.
527 Node = Node.as<isl::schedule_node_band>().set_ast_build_options(
528 isl::union_set(Node.ctx(), "{ unroll[x]: 1 = 0 }"));
529
530 // Sink the inner loop into the smallest possible statements to make them
531 // represent a single vector instruction if possible.
533 if (Node.is_null())
534 return {};
535
536 // Add SIMD markers to those vector statements.
537 InsertSimdMarkers SimdMarkerInserter;
538 Node = SimdMarkerInserter.visit(Node);
539
540 if (!Node.is_null())
541 PrevectOpts++;
542 return Node.parent();
543}
544
545static bool isSimpleInnermostBand(const isl::schedule_node &Node) {
548
549 auto ChildType = isl_schedule_node_get_type(Node.child(0).get());
550
551 if (ChildType == isl_schedule_node_leaf)
552 return true;
553
554 if (ChildType != isl_schedule_node_sequence)
555 return false;
556
557 auto Sequence = Node.child(0);
558
559 for (int c = 0, nc = isl_schedule_node_n_children(Sequence.get()); c < nc;
560 ++c) {
561 auto Child = Sequence.child(c);
563 return false;
564 if (isl_schedule_node_get_type(Child.child(0).get()) !=
566 return false;
567 }
568 return true;
569}
570
571/// Check if this node is a band node, which has only one child.
572///
573/// @param Node The node to check.
574static bool isOneTimeParentBandNode(isl::schedule_node Node) {
576 return false;
577
578 if (isl_schedule_node_n_children(Node.get()) != 1)
579 return false;
580
581 return true;
582}
583
584bool ScheduleTreeOptimizer::isTileableBandNode(isl::schedule_node Node) {
585 if (!isOneTimeParentBandNode(Node))
586 return false;
587
589 return false;
590
592
593 if (unsignedFromIslSize(Space.dim(isl::dim::set)) <= 1u)
594 return false;
595
596 return isSimpleInnermostBand(Node);
597}
598
599bool ScheduleTreeOptimizer::isPMOptimizableBandNode(isl::schedule_node Node) {
600 if (!isOneTimeParentBandNode(Node))
601 return false;
602
603 return Node.child(0).isa<isl::schedule_node_leaf>();
604}
605
606/// Resolve the tile size of every dimension of the band @p Node.
607static SmallVector<int, 4> resolveTileSizes(isl::schedule_node Node,
608 ArrayRef<int> TileSizes,
609 int DefaultTileSize) {
610 SmallVector<int, 4> Sizes;
611 isl::space Space = isl::manage(isl_schedule_node_band_get_space(Node.get()));
612 for (unsigned i : rangeIslSize(0, Space.dim(isl::dim::set)))
613 Sizes.push_back(i < TileSizes.size() ? TileSizes[i] : DefaultTileSize);
614 return Sizes;
615}
616
617__isl_give isl::schedule_node
618ScheduleTreeOptimizer::applyTileBandOpt(isl::schedule_node Node) {
619 if (FirstLevelTiling) {
620 // Resolve the tile size of every dimension before tiling splits the band.
621 SmallVector<int, 4> Sizes;
623 Sizes = resolveTileSizes(Node, FirstLevelTileSizes,
625
626 Node = tileNode(Node, "1st level tiling", FirstLevelTileSizes,
628 FirstLevelTileOpts++;
629
631 Node = isolateCompleteTiles(Node, Sizes);
632 }
633
634 if (SecondLevelTiling) {
635 SmallVector<int, 4> Sizes;
637 Sizes = resolveTileSizes(Node, SecondLevelTileSizes,
639 Node = tileNode(Node, "2nd level tiling", SecondLevelTileSizes,
641 SecondLevelTileOpts++;
643 Node = isolateCompleteTiles(Node, Sizes);
644 }
645
646 if (RegisterTiling) {
647 SmallVector<int, 4> Sizes;
649 Sizes =
650 resolveTileSizes(Node, RegisterTileSizes, RegisterDefaultTileSize);
651 Node =
653 RegisterTileOpts++;
655 Node = isolateCompleteTiles(Node, Sizes);
656 }
657
658 return Node;
659}
660
661isl::schedule_node
662ScheduleTreeOptimizer::applyPrevectBandOpt(isl::schedule_node Node) {
664 if (Space.is_null())
665 return {};
666 int Dims = unsignedFromIslSize(Space.dim(isl::dim::set));
667
668 for (int i = Dims - 1; i >= 0; i--)
669 if (Node.as<isl::schedule_node_band>().member_get_coincident(i)) {
670 Node = prevectSchedBand(Node, i, PrevectorWidth);
671 break;
672 }
673
674 return Node;
675}
676
678ScheduleTreeOptimizer::optimizeBand(__isl_take isl_schedule_node *NodeArg,
679 void *User) {
680 const OptimizerAdditionalInfoTy *OAI =
681 static_cast<const OptimizerAdditionalInfoTy *>(User);
682 assert(OAI && "Expecting optimization options");
683
684 isl::schedule_node Node = isl::manage(NodeArg);
685
686 if (OAI->PatternOpts && isPMOptimizableBandNode(Node)) {
687 isl::schedule_node PatternOptimizedSchedule =
688 tryOptimizeMatMulPattern(Node, OAI->TTI, OAI->D);
689 if (!PatternOptimizedSchedule.is_null()) {
690 MatMulOpts++;
691 OAI->DepsChanged = true;
692 return PatternOptimizedSchedule.release();
693 }
694 }
695
696 if (!isTileableBandNode(Node))
697 return Node.release();
698
699 if (OAI->Postopts)
700 Node = applyTileBandOpt(Node);
701
702 if (OAI->Prevect) {
703 IslQuotaScope MaxScope = OAI->MaxOpGuard.enter();
704
705 // FIXME: Prevectorization requirements are different from those checked by
706 // isTileableBandNode.
707 Node = applyPrevectBandOpt(Node);
708
709 if (OAI->MaxOpGuard.hasQuotaExceeded() || Node.is_null())
710 return (isl::schedule_node()).release();
711 }
712
713 return Node.release();
714}
715
716isl::schedule
717ScheduleTreeOptimizer::optimizeSchedule(isl::schedule Schedule,
718 const OptimizerAdditionalInfoTy *OAI) {
719 auto Root = Schedule.get_root();
720 Root = optimizeScheduleNode(Root, OAI);
721 return Root.get_schedule();
722}
723
724isl::schedule_node ScheduleTreeOptimizer::optimizeScheduleNode(
725 isl::schedule_node Node, const OptimizerAdditionalInfoTy *OAI) {
727 Node.release(), optimizeBand,
728 const_cast<void *>(static_cast<const void *>(OAI))));
729 return Node;
730}
731
732bool ScheduleTreeOptimizer::isProfitableSchedule(Scop &S,
733 isl::schedule NewSchedule) {
734 // To understand if the schedule has been optimized we check if the schedule
735 // has changed at all.
736 // TODO: We can improve this by tracking if any necessarily beneficial
737 // transformations have been performed. This can e.g. be tiling, loop
738 // interchange, or ...) We can track this either at the place where the
739 // transformation has been performed or, in case of automatic ILP based
740 // optimizations, by comparing (yet to be defined) performance metrics
741 // before/after the scheduling optimizer
742 // (e.g., #stride-one accesses)
743 // FIXME: A schedule tree whose union_map-conversion is identical to the
744 // original schedule map may still allow for parallelization, i.e. can still
745 // be profitable.
746 auto NewScheduleMap = NewSchedule.get_map();
747 auto OldSchedule = S.getSchedule();
748 assert(!OldSchedule.is_null() &&
749 "Only IslScheduleOptimizer can insert extension nodes "
750 "that make Scop::getSchedule() return nullptr.");
751 bool changed = !OldSchedule.is_equal(NewScheduleMap);
752 return changed;
753}
754
755#ifndef NDEBUG
756static void printSchedule(llvm::raw_ostream &OS, const isl::schedule &Schedule,
757 StringRef Desc) {
758 isl::ctx Ctx = Schedule.ctx();
761 P = isl_printer_print_schedule(P, Schedule.get());
762 char *Str = isl_printer_get_str(P);
763 OS << Desc << ": \n" << Str << "\n";
764 free(Str);
766}
767#endif
768
769/// Return whether the dependence distances of @p Map, which relates instances
770/// of the same statement, are bounded.
771static bool hasBoundedDistances(const isl::map &Map) {
772 isl::set Deltas = Map.deltas();
773 return !Deltas.is_null() && Deltas.is_bounded().is_true();
774}
775
776/// Undo the simplification of the proximity dependences of a statement on
777/// itself where it made their distances unbounded.
778///
779/// The scheduler looks for schedule rows that bound the distance of every
780/// proximity dependence. If the simplification drops the constraints of the
781/// domain that bound the distance of a dependence, such as a value that is
782/// read by all later iterations of a loop, then every row that advances along
783/// that loop has an unbounded distance, and the scheduler falls back to
784/// carrying dependences one row at a time instead of forming a permutable
785/// band.
786///
787/// @param Simplified The simplified proximity dependences.
788/// @param Exact The proximity dependences before simplification.
789static isl::union_map keepBoundedDistances(const isl::union_map &Simplified,
790 const isl::union_map &Exact) {
791 isl::union_map Result = isl::union_map::empty(Simplified.ctx());
792 for (isl::map Map : Simplified.get_map_list()) {
793 isl::space Space = Map.get_space();
794 if (Space.domain().is_equal(Space.range()) && !hasBoundedDistances(Map)) {
795 // Only add the constraints that bound the distances before the
796 // simplification rather than restoring all constraints of the exact
797 // dependence: preferably the hull of the exact distances, which is a
798 // single convex set, otherwise the exact distances themselves.
799 isl::set ExactDeltas = Exact.extract_map(Space).deltas();
800 isl::map Bounded = Map.intersect(ExactDeltas.simple_hull().translation());
801 if (!hasBoundedDistances(Bounded))
802 Bounded = Map.intersect(ExactDeltas.translation());
803 if (hasBoundedDistances(Bounded))
804 Map = Bounded;
805 }
806 Result = Result.unite(isl::union_map(Map));
807 }
808 return Result;
809}
810
811/// Collect statistics for the schedule tree.
812///
813/// @param Schedule The schedule tree to analyze. If not a schedule tree it is
814/// ignored.
815/// @param Version The version of the schedule tree that is analyzed.
816/// 0 for the original schedule tree before any transformation.
817/// 1 for the schedule tree after isl's rescheduling.
818/// 2 for the schedule tree after optimizations are applied
819/// (tiling, pattern matching)
820static void walkScheduleTreeForStatistics(isl::schedule Schedule, int Version) {
821 auto Root = Schedule.get_root();
822 if (Root.is_null())
823 return;
824
826 Root.get(),
827 [](__isl_keep isl_schedule_node *nodeptr, void *user) -> isl_bool {
828 isl::schedule_node Node = isl::manage_copy(nodeptr);
829 int Version = *static_cast<int *>(user);
830
831 switch (isl_schedule_node_get_type(Node.get())) {
832 case isl_schedule_node_band: {
833 NumBands[Version]++;
834 if (isl_schedule_node_band_get_permutable(Node.get()) ==
835 isl_bool_true)
836 NumPermutable[Version]++;
837
838 int CountMembers = isl_schedule_node_band_n_member(Node.get());
839 NumBandMembers[Version] += CountMembers;
840 for (int i = 0; i < CountMembers; i += 1) {
841 if (Node.as<isl::schedule_node_band>().member_get_coincident(i))
842 NumCoincident[Version]++;
843 }
844 break;
845 }
846
847 case isl_schedule_node_filter:
848 NumFilters[Version]++;
849 break;
850
851 case isl_schedule_node_extension:
852 NumExtension[Version]++;
853 break;
854
855 default:
856 break;
857 }
858
859 return isl_bool_true;
860 },
861 &Version);
862}
863
864static void runIslScheduleOptimizerImpl(
865 Scop &S,
866 function_ref<const Dependences &(Dependences::AnalysisLevel)> GetDeps,
867 TargetTransformInfo *TTI, OptimizationRemarkEmitter *ORE,
868 isl::schedule &LastSchedule, bool &DepsChanged) {
869 // Skip empty SCoPs but still allow code generation as it will delete the
870 // loops present but not needed.
871 if (S.getSize() == 0) {
872 S.markAsOptimized();
873 return;
874 }
875
876 ScopsProcessed++;
877
878 // Schedule without optimizations.
879 isl::schedule Schedule = S.getScheduleTree();
880 walkScheduleTreeForStatistics(S.getScheduleTree(), 0);
881 POLLY_DEBUG(printSchedule(dbgs(), Schedule, "Original schedule tree"));
882
883 bool HasUserTransformation = false;
884 if (PragmaBasedOpts) {
885 isl::schedule ManuallyTransformed = applyManualTransformations(
886 &S, Schedule, GetDeps(Dependences::AL_Statement), ORE);
887 if (ManuallyTransformed.is_null()) {
888 POLLY_DEBUG(dbgs() << "Error during manual optimization\n");
889 return;
890 }
891
892 if (ManuallyTransformed.get() != Schedule.get()) {
893 // User transformations have precedence over other transformations.
894 HasUserTransformation = true;
895 Schedule = std::move(ManuallyTransformed);
897 printSchedule(dbgs(), Schedule, "After manual transformations"));
898 }
899 }
900
901 // Only continue if either manual transformations have been applied or we are
902 // allowed to apply heuristics.
903 // TODO: Detect disabled heuristics and no user-directed transformation
904 // metadata earlier in ScopDetection.
905 if (!HasUserTransformation && S.hasDisableHeuristicsHint()) {
906 POLLY_DEBUG(dbgs() << "Heuristic optimizations disabled by metadata\n");
907 return;
908 }
909
910 // Get dependency analysis.
911 const Dependences &D = GetDeps(Dependences::AL_Statement);
912 if (D.getSharedIslCtx() != S.getSharedIslCtx()) {
913 POLLY_DEBUG(dbgs() << "DependenceInfo for another SCoP/isl_ctx\n");
914 return;
915 }
916 if (!D.hasValidDependences()) {
917 POLLY_DEBUG(dbgs() << "Dependency information not available\n");
918 return;
919 }
920
921 isl_ctx *Ctx = S.getIslCtx().get();
923 /*AutoEnter=*/false);
924
925 // Apply ISL's algorithm only if not overridden by the user. Note that
926 // post-rescheduling optimizations (tiling, pattern-based, prevectorization)
927 // rely on the coincidence/permutable annotations on schedule tree bands that
928 // are added by the rescheduling analyzer. Therefore, disabling the
929 // rescheduler implicitly also disables these optimizations.
930 if (!EnableReschedule) {
931 POLLY_DEBUG(dbgs() << "Skipping rescheduling due to command line option\n");
932 } else if (HasUserTransformation) {
934 dbgs() << "Skipping rescheduling due to manual transformation\n");
935 } else {
936 // Build input data.
937 int ValidityKinds =
939 int ProximityKinds;
940
941 if (OptimizeDeps == "all")
942 ProximityKinds =
944 else if (OptimizeDeps == "raw")
945 ProximityKinds = Dependences::TYPE_RAW;
946 else {
947 errs() << "Do not know how to optimize for '" << OptimizeDeps << "'"
948 << " Falling back to optimizing all dependences.\n";
949 ProximityKinds =
951 }
952
953 isl::union_set Domain = S.getDomains();
954
955 if (Domain.is_null())
956 return;
957
958 isl::union_map Validity = D.getDependences(ValidityKinds);
959 isl::union_map Proximity = D.getDependences(ProximityKinds);
960
961 // Simplify the dependences by removing the constraints introduced by the
962 // domains. This can speed up the scheduling time significantly, as large
963 // constant coefficients will be removed from the dependences. The
964 // introduction of some additional dependences reduces the possible
965 // transformations, but in most cases, such transformation do not seem to be
966 // interesting anyway. In some cases this option may stop the scheduler to
967 // find any schedule.
968 if (SimplifyDeps == "yes") {
969 isl::union_map ExactProximity = Proximity;
970 Validity = Validity.gist_domain(Domain);
971 Validity = Validity.gist_range(Domain);
972 Proximity = Proximity.gist_domain(Domain);
973 Proximity = Proximity.gist_range(Domain);
974 Proximity = keepBoundedDistances(Proximity, ExactProximity);
975 } else if (SimplifyDeps != "no") {
976 errs()
977 << "warning: Option -polly-opt-simplify-deps should either be 'yes' "
978 "or 'no'. Falling back to default: 'yes'\n";
979 }
980
981 POLLY_DEBUG(dbgs() << "\n\nCompute schedule from: ");
982 POLLY_DEBUG(dbgs() << "Domain := " << Domain << ";\n");
983 POLLY_DEBUG(dbgs() << "Proximity := " << Proximity << ";\n");
984 POLLY_DEBUG(dbgs() << "Validity := " << Validity << ";\n");
985
986 int IslMaximizeBands;
987 if (MaximizeBandDepth == "yes") {
988 IslMaximizeBands = 1;
989 } else if (MaximizeBandDepth == "no") {
990 IslMaximizeBands = 0;
991 } else {
992 errs()
993 << "warning: Option -polly-opt-maximize-bands should either be 'yes'"
994 " or 'no'. Falling back to default: 'yes'\n";
995 IslMaximizeBands = 1;
996 }
997
998 int IslOuterCoincidence;
999 if (OuterCoincidence == "yes") {
1000 IslOuterCoincidence = 1;
1001 } else if (OuterCoincidence == "no") {
1002 IslOuterCoincidence = 0;
1003 } else {
1004 errs() << "warning: Option -polly-opt-outer-coincidence should either be "
1005 "'yes' or 'no'. Falling back to default: 'no'\n";
1006 IslOuterCoincidence = 0;
1007 }
1008
1009 isl_options_set_schedule_outer_coincidence(Ctx, IslOuterCoincidence);
1014
1015 auto OnErrorStatus = isl_options_get_on_error(Ctx);
1017
1019 SC = SC.set_proximity(Proximity);
1020 SC = SC.set_validity(Validity);
1021 SC = SC.set_coincidence(Validity);
1022
1023 {
1024 IslQuotaScope MaxOpScope = MaxOpGuard.enter();
1025 Schedule = SC.compute_schedule();
1026 }
1027
1028 isl_options_set_on_error(Ctx, OnErrorStatus);
1029
1030 if (!Schedule.is_null())
1031 ScopsRescheduled++;
1032 POLLY_DEBUG(printSchedule(dbgs(), Schedule, "After rescheduling"));
1033 }
1034
1035 walkScheduleTreeForStatistics(Schedule, 1);
1036
1037 if (GreedyFusion && !Schedule.is_null()) {
1038 isl::union_map Validity = D.getDependences(
1040 Schedule = applyGreedyFusion(Schedule, Validity);
1041 assert(!Schedule.is_null());
1042 }
1043
1044 // Apply post-rescheduling optimizations (if enabled) and/or prevectorization.
1045 const OptimizerAdditionalInfoTy OAI = {
1046 TTI,
1047 const_cast<Dependences *>(&D),
1048 /*PatternOpts=*/!HasUserTransformation && PMBasedOpts,
1049 /*Postopts=*/!HasUserTransformation && EnablePostopts,
1051 DepsChanged,
1052 MaxOpGuard};
1053 if (!Schedule.is_null() && (OAI.PatternOpts || OAI.Postopts || OAI.Prevect)) {
1054 Schedule = ScheduleTreeOptimizer::optimizeSchedule(Schedule, &OAI);
1055 Schedule = hoistExtensionNodes(Schedule);
1056 POLLY_DEBUG(printSchedule(dbgs(), Schedule, "After post-optimizations"));
1057 walkScheduleTreeForStatistics(Schedule, 2);
1058 }
1059
1060 // Check for why any computation could have failed
1061 if (MaxOpGuard.hasQuotaExceeded()) {
1062 POLLY_DEBUG(dbgs() << "Schedule optimizer calculation exceeds ISL quota\n");
1063 return;
1064 } else if (isl_ctx_last_error(Ctx) != isl_error_none) {
1065 POLLY_DEBUG({
1066 const char *File = isl_ctx_last_error_file(Ctx);
1067 int Line = isl_ctx_last_error_line(Ctx);
1068 const char *Msg = isl_ctx_last_error_msg(Ctx);
1069 dbgs() << "ISL reported an error during the computation of a new "
1070 "schedule at "
1071 << File << ":" << Line << ": " << Msg;
1072 });
1074 return;
1075 } else if (Schedule.is_null()) {
1076 POLLY_DEBUG(dbgs() << "Schedule optimizer did not compute a new schedule "
1077 "for unknown reasons\n");
1078 return;
1079 }
1080
1081 // Skip profitability check if user transformation(s) have been applied.
1082 if (!HasUserTransformation &&
1083 !ScheduleTreeOptimizer::isProfitableSchedule(S, Schedule))
1084 return;
1085
1086 auto ScopStats = S.getStatistics();
1087 ScopsOptimized++;
1088 NumAffineLoopsOptimized += ScopStats.NumAffineLoops;
1089 NumBoxedLoopsOptimized += ScopStats.NumBoxedLoops;
1090 LastSchedule = Schedule;
1091
1092 S.setScheduleTree(Schedule);
1093 S.markAsOptimized();
1094
1095 if (OptimizedScops)
1096 errs() << S;
1097}
1098
1099static void runScheduleOptimizerPrinter(raw_ostream &OS,
1100 isl::schedule LastSchedule) {
1101 isl_printer *p;
1102 char *ScheduleStr;
1103
1104 OS << "Calculated schedule:\n";
1105
1106 if (LastSchedule.is_null()) {
1107 OS << "n/a\n";
1108 return;
1109 }
1110
1111 p = isl_printer_to_str(LastSchedule.ctx().get());
1113 p = isl_printer_print_schedule(p, LastSchedule.get());
1114 ScheduleStr = isl_printer_get_str(p);
1116
1117 OS << ScheduleStr << "\n";
1118
1119 free(ScheduleStr);
1120}
1121
1122} // namespace
1123
1124void polly::runIslScheduleOptimizer(Scop &S, TargetTransformInfo *TTI,
1126 auto GetDeps = [&Deps](Dependences::AnalysisLevel) -> const Dependences & {
1128 };
1129 OptimizationRemarkEmitter ORE(&S.getFunction());
1130 isl::schedule LastSchedule;
1131 bool DepsChanged = false;
1132 runIslScheduleOptimizerImpl(S, GetDeps, TTI, &ORE, LastSchedule, DepsChanged);
1133 if (DepsChanged)
1134 Deps.abandonDependences();
1135
1136 if (PollyPrintOptIsl) {
1137 outs()
1138 << "Printing analysis 'Polly - Optimize schedule of SCoP' for region: '"
1139 << S.getName() << "' in function '" << S.getFunction().getName()
1140 << "':\n";
1141 runScheduleOptimizerPrinter(outs(), LastSchedule);
1142 }
1143}
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 > IsolateCompleteTiles2ndLevel("polly-isolate-complete-tiles-2nd-level", cl::desc("Separate the complete tiles of the second level of tiling from " "the partial ones"), cl::Hidden, cl::init(false), cl::cat(PollyCategory))
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< bool > IsolateCompleteTiles("polly-isolate-complete-tiles", cl::desc("Separate the complete tiles of a tiled band from the partial " "ones, so that the point loops of the complete tiles have " "constant bounds"), cl::Hidden, cl::init(false), 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 > IsolateCompleteRegisterTiles("polly-isolate-complete-register-tiles", cl::desc("Separate the complete register tiles from the partial ones, so " "that their unrolled point loops need no guards"), cl::Hidden, cl::init(false), 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::opt< int > IsolateCompleteTileDims("polly-isolate-complete-tile-dims", cl::desc("Number of innermost tile dimensions that have to be complete for " "a tile to be isolated (0: all of them). Requiring fewer of them " "generates less code, but also gives fewer point loops a constant " "bound"), cl::Hidden, cl::init(0), cl::cat(PollyCategory))
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.
llvm::iota_range< unsigned > rangeIslSize(unsigned Begin, isl::size End)
Check that End is valid and return an iterator from Begin to End.
Definition ISLTools.cpp:597
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::set getCompleteTilePrefixes(isl::set ScheduleRange, llvm::ArrayRef< int > TileSizes, unsigned NumCompleteDims)
Compute the prefixes of the complete tiles of a tiled band.
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