1 //===- Schedule.cpp - Calculate an optimized schedule ---------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This pass the isl to calculate a schedule that is optimized for parallelism
11 // and tileablility. The algorithm used in isl is an optimized version of the
12 // algorithm described in following paper:
13 //
14 // U. Bondhugula, A. Hartono, J. Ramanujam, and P. Sadayappan.
15 // A Practical Automatic Polyhedral Parallelizer and Locality Optimizer.
16 // In Proceedings of the 2008 ACM SIGPLAN Conference On Programming Language
17 // Design and Implementation, PLDI ’08, pages 101–113. ACM, 2008.
18 //===----------------------------------------------------------------------===//
19 
20 #include "polly/ScheduleOptimizer.h"
21 #include "isl/aff.h"
22 #include "isl/band.h"
23 #include "isl/constraint.h"
24 #include "isl/map.h"
25 #include "isl/options.h"
26 #include "isl/schedule.h"
27 #include "isl/space.h"
28 #include "polly/CodeGen/CodeGeneration.h"
29 #include "polly/Dependences.h"
30 #include "polly/LinkAllPasses.h"
31 #include "polly/Options.h"
32 #include "polly/ScopInfo.h"
33 #include "polly/Support/GICHelper.h"
34 #include "llvm/Support/Debug.h"
35 
36 using namespace llvm;
37 using namespace polly;
38 
39 #define DEBUG_TYPE "polly-opt-isl"
40 
41 namespace polly {
42 bool DisablePollyTiling;
43 }
44 static cl::opt<bool, true>
45     DisableTiling("polly-no-tiling",
46                   cl::desc("Disable tiling in the scheduler"),
47                   cl::location(polly::DisablePollyTiling), cl::init(false),
48                   cl::ZeroOrMore, cl::cat(PollyCategory));
49 
50 static cl::opt<std::string>
51     OptimizeDeps("polly-opt-optimize-only",
52                  cl::desc("Only a certain kind of dependences (all/raw)"),
53                  cl::Hidden, cl::init("all"), cl::ZeroOrMore,
54                  cl::cat(PollyCategory));
55 
56 static cl::opt<std::string>
57     SimplifyDeps("polly-opt-simplify-deps",
58                  cl::desc("Dependences should be simplified (yes/no)"),
59                  cl::Hidden, cl::init("yes"), cl::ZeroOrMore,
60                  cl::cat(PollyCategory));
61 
62 static cl::opt<int> MaxConstantTerm(
63     "polly-opt-max-constant-term",
64     cl::desc("The maximal constant term allowed (-1 is unlimited)"), cl::Hidden,
65     cl::init(20), cl::ZeroOrMore, cl::cat(PollyCategory));
66 
67 static cl::opt<int> MaxCoefficient(
68     "polly-opt-max-coefficient",
69     cl::desc("The maximal coefficient allowed (-1 is unlimited)"), cl::Hidden,
70     cl::init(20), cl::ZeroOrMore, cl::cat(PollyCategory));
71 
72 static cl::opt<std::string> FusionStrategy(
73     "polly-opt-fusion", cl::desc("The fusion strategy to choose (min/max)"),
74     cl::Hidden, cl::init("min"), cl::ZeroOrMore, cl::cat(PollyCategory));
75 
76 static cl::opt<std::string>
77     MaximizeBandDepth("polly-opt-maximize-bands",
78                       cl::desc("Maximize the band depth (yes/no)"), cl::Hidden,
79                       cl::init("yes"), cl::ZeroOrMore, cl::cat(PollyCategory));
80 
81 static cl::opt<int> DefaultTileSize(
82     "polly-default-tile-size",
83     cl::desc("The default tile size (if not enough were provided by"
84              " --polly-tile-sizes)"),
85     cl::Hidden, cl::init(32), cl::ZeroOrMore, cl::cat(PollyCategory));
86 
87 static cl::list<int> TileSizes("polly-tile-sizes",
88                                cl::desc("A tile size"
89                                         " for each loop dimension, filled with"
90                                         " --polly-default-tile-size"),
91                                cl::Hidden, cl::ZeroOrMore, cl::CommaSeparated,
92                                cl::cat(PollyCategory));
93 namespace {
94 
95 class IslScheduleOptimizer : public ScopPass {
96 public:
97   static char ID;
98   explicit IslScheduleOptimizer() : ScopPass(ID) { LastSchedule = nullptr; }
99 
100   ~IslScheduleOptimizer() { isl_schedule_free(LastSchedule); }
101 
102   virtual bool runOnScop(Scop &S);
103   void printScop(llvm::raw_ostream &OS) const;
104   void getAnalysisUsage(AnalysisUsage &AU) const;
105 
106 private:
107   isl_schedule *LastSchedule;
108 
109   static void extendScattering(Scop &S, unsigned NewDimensions);
110 
111   /// @brief Create a map that describes a n-dimensonal tiling.
112   ///
113   /// getTileMap creates a map from a n-dimensional scattering space into an
114   /// 2*n-dimensional scattering space. The map describes a rectangular
115   /// tiling.
116   ///
117   /// Example:
118   ///   scheduleDimensions = 2, parameterDimensions = 1, TileSizes = <32, 64>
119   ///
120   ///   tileMap := [p0] -> {[s0, s1] -> [t0, t1, s0, s1]:
121   ///                        t0 % 32 = 0 and t0 <= s0 < t0 + 32 and
122   ///                        t1 % 64 = 0 and t1 <= s1 < t1 + 64}
123   ///
124   ///  Before tiling:
125   ///
126   ///  for (i = 0; i < N; i++)
127   ///    for (j = 0; j < M; j++)
128   ///	S(i,j)
129   ///
130   ///  After tiling:
131   ///
132   ///  for (t_i = 0; t_i < N; i+=32)
133   ///    for (t_j = 0; t_j < M; j+=64)
134   ///	for (i = t_i; i < min(t_i + 32, N); i++)  | Unknown that N % 32 = 0
135   ///	  for (j = t_j; j < t_j + 64; j++)        |   Known that M % 64 = 0
136   ///	    S(i,j)
137   ///
138   static isl_basic_map *getTileMap(isl_ctx *ctx, int scheduleDimensions,
139                                    isl_space *SpaceModel);
140 
141   /// @brief Get the schedule for this band.
142   ///
143   /// Polly applies transformations like tiling on top of the isl calculated
144   /// value.  This can influence the number of scheduling dimension. The
145   /// number of schedule dimensions is returned in the parameter 'Dimension'.
146   static isl_union_map *getScheduleForBand(isl_band *Band, int *Dimensions);
147 
148   /// @brief Create a map that pre-vectorizes one scheduling dimension.
149   ///
150   /// getPrevectorMap creates a map that maps each input dimension to the same
151   /// output dimension, except for the dimension DimToVectorize.
152   /// DimToVectorize is strip mined by 'VectorWidth' and the newly created
153   /// point loop of DimToVectorize is moved to the innermost level.
154   ///
155   /// Example (DimToVectorize=0, ScheduleDimensions=2, VectorWidth=4):
156   ///
157   /// | Before transformation
158   /// |
159   /// | A[i,j] -> [i,j]
160   /// |
161   /// | for (i = 0; i < 128; i++)
162   /// |    for (j = 0; j < 128; j++)
163   /// |      A(i,j);
164   ///
165   ///   Prevector map:
166   ///   [i,j] -> [it,j,ip] : it % 4 = 0 and it <= ip <= it + 3 and i = ip
167   ///
168   /// | After transformation:
169   /// |
170   /// | A[i,j] -> [it,j,ip] : it % 4 = 0 and it <= ip <= it + 3 and i = ip
171   /// |
172   /// | for (it = 0; it < 128; it+=4)
173   /// |    for (j = 0; j < 128; j++)
174   /// |      for (ip = max(0,it); ip < min(128, it + 3); ip++)
175   /// |        A(ip,j);
176   ///
177   /// The goal of this transformation is to create a trivially vectorizable
178   /// loop.  This means a parallel loop at the innermost level that has a
179   /// constant number of iterations corresponding to the target vector width.
180   ///
181   /// This transformation creates a loop at the innermost level. The loop has
182   /// a constant number of iterations, if the number of loop iterations at
183   /// DimToVectorize can be divided by VectorWidth. The default VectorWidth is
184   /// currently constant and not yet target specific. This function does not
185   /// reason about parallelism.
186   static isl_map *getPrevectorMap(isl_ctx *ctx, int DimToVectorize,
187                                   int ScheduleDimensions, int VectorWidth = 4);
188 
189   /// @brief Get the scheduling map for a list of bands.
190   ///
191   /// Walk recursively the forest of bands to combine the schedules of the
192   /// individual bands to the overall schedule. In case tiling is requested,
193   /// the individual bands are tiled.
194   static isl_union_map *getScheduleForBandList(isl_band_list *BandList);
195 
196   static isl_union_map *getScheduleMap(isl_schedule *Schedule);
197 
198   using llvm::Pass::doFinalization;
199 
200   virtual bool doFinalization() {
201     isl_schedule_free(LastSchedule);
202     LastSchedule = nullptr;
203     return true;
204   }
205 };
206 }
207 
208 char IslScheduleOptimizer::ID = 0;
209 
210 void IslScheduleOptimizer::extendScattering(Scop &S, unsigned NewDimensions) {
211   for (ScopStmt *Stmt : S) {
212     unsigned OldDimensions = Stmt->getNumScattering();
213     isl_space *Space;
214     isl_map *Map, *New;
215 
216     Space = isl_space_alloc(Stmt->getIslCtx(), 0, OldDimensions, NewDimensions);
217     Map = isl_map_universe(Space);
218 
219     for (unsigned i = 0; i < OldDimensions; i++)
220       Map = isl_map_equate(Map, isl_dim_in, i, isl_dim_out, i);
221 
222     for (unsigned i = OldDimensions; i < NewDimensions; i++)
223       Map = isl_map_fix_si(Map, isl_dim_out, i, 0);
224 
225     Map = isl_map_align_params(Map, S.getParamSpace());
226     New = isl_map_apply_range(Stmt->getScattering(), Map);
227     Stmt->setScattering(New);
228   }
229 }
230 
231 isl_basic_map *IslScheduleOptimizer::getTileMap(isl_ctx *ctx,
232                                                 int scheduleDimensions,
233                                                 isl_space *SpaceModel) {
234   // We construct
235   //
236   // tileMap := [p0] -> {[s0, s1] -> [t0, t1, p0, p1, a0, a1]:
237   //	                  s0 = a0 * 32 and s0 = p0 and t0 <= p0 < t0 + 64 and
238   //	                  s1 = a1 * 64 and s1 = p1 and t1 <= p1 < t1 + 64}
239   //
240   // and project out the auxilary dimensions a0 and a1.
241   isl_space *Space =
242       isl_space_alloc(ctx, 0, scheduleDimensions, scheduleDimensions * 3);
243   isl_basic_map *tileMap = isl_basic_map_universe(isl_space_copy(Space));
244 
245   isl_local_space *LocalSpace = isl_local_space_from_space(Space);
246 
247   for (int x = 0; x < scheduleDimensions; x++) {
248     int sX = x;
249     int tX = x;
250     int pX = scheduleDimensions + x;
251     int aX = 2 * scheduleDimensions + x;
252     int tileSize = (int)TileSizes.size() > x ? TileSizes[x] : DefaultTileSize;
253     assert(tileSize > 0 && "Invalid tile size");
254 
255     isl_constraint *c;
256 
257     // sX = aX * tileSize;
258     c = isl_equality_alloc(isl_local_space_copy(LocalSpace));
259     isl_constraint_set_coefficient_si(c, isl_dim_out, sX, 1);
260     isl_constraint_set_coefficient_si(c, isl_dim_out, aX, -tileSize);
261     tileMap = isl_basic_map_add_constraint(tileMap, c);
262 
263     // pX = sX;
264     c = isl_equality_alloc(isl_local_space_copy(LocalSpace));
265     isl_constraint_set_coefficient_si(c, isl_dim_out, pX, 1);
266     isl_constraint_set_coefficient_si(c, isl_dim_in, sX, -1);
267     tileMap = isl_basic_map_add_constraint(tileMap, c);
268 
269     // tX <= pX
270     c = isl_inequality_alloc(isl_local_space_copy(LocalSpace));
271     isl_constraint_set_coefficient_si(c, isl_dim_out, pX, 1);
272     isl_constraint_set_coefficient_si(c, isl_dim_out, tX, -1);
273     tileMap = isl_basic_map_add_constraint(tileMap, c);
274 
275     // pX <= tX + (tileSize - 1)
276     c = isl_inequality_alloc(isl_local_space_copy(LocalSpace));
277     isl_constraint_set_coefficient_si(c, isl_dim_out, tX, 1);
278     isl_constraint_set_coefficient_si(c, isl_dim_out, pX, -1);
279     isl_constraint_set_constant_si(c, tileSize - 1);
280     tileMap = isl_basic_map_add_constraint(tileMap, c);
281   }
282 
283   // Project out auxilary dimensions.
284   //
285   // The auxilary dimensions are transformed into existentially quantified ones.
286   // This reduces the number of visible scattering dimensions and allows Cloog
287   // to produces better code.
288   tileMap = isl_basic_map_project_out(
289       tileMap, isl_dim_out, 2 * scheduleDimensions, scheduleDimensions);
290   isl_local_space_free(LocalSpace);
291   return tileMap;
292 }
293 
294 isl_union_map *IslScheduleOptimizer::getScheduleForBand(isl_band *Band,
295                                                         int *Dimensions) {
296   isl_union_map *PartialSchedule;
297   isl_ctx *ctx;
298   isl_space *Space;
299   isl_basic_map *TileMap;
300   isl_union_map *TileUMap;
301 
302   PartialSchedule = isl_band_get_partial_schedule(Band);
303   *Dimensions = isl_band_n_member(Band);
304 
305   if (DisableTiling)
306     return PartialSchedule;
307 
308   // It does not make any sense to tile a band with just one dimension.
309   if (*Dimensions == 1)
310     return PartialSchedule;
311 
312   ctx = isl_union_map_get_ctx(PartialSchedule);
313   Space = isl_union_map_get_space(PartialSchedule);
314 
315   TileMap = getTileMap(ctx, *Dimensions, Space);
316   TileUMap = isl_union_map_from_map(isl_map_from_basic_map(TileMap));
317   TileUMap = isl_union_map_align_params(TileUMap, Space);
318   *Dimensions = 2 * *Dimensions;
319 
320   return isl_union_map_apply_range(PartialSchedule, TileUMap);
321 }
322 
323 isl_map *IslScheduleOptimizer::getPrevectorMap(isl_ctx *ctx, int DimToVectorize,
324                                                int ScheduleDimensions,
325                                                int VectorWidth) {
326   isl_space *Space;
327   isl_local_space *LocalSpace, *LocalSpaceRange;
328   isl_set *Modulo;
329   isl_map *TilingMap;
330   isl_constraint *c;
331   isl_aff *Aff;
332   int PointDimension; /* ip */
333   int TileDimension;  /* it */
334   isl_val *VectorWidthMP;
335 
336   assert(0 <= DimToVectorize && DimToVectorize < ScheduleDimensions);
337 
338   Space = isl_space_alloc(ctx, 0, ScheduleDimensions, ScheduleDimensions + 1);
339   TilingMap = isl_map_universe(isl_space_copy(Space));
340   LocalSpace = isl_local_space_from_space(Space);
341   PointDimension = ScheduleDimensions;
342   TileDimension = DimToVectorize;
343 
344   // Create an identity map for everything except DimToVectorize and map
345   // DimToVectorize to the point loop at the innermost dimension.
346   for (int i = 0; i < ScheduleDimensions; i++) {
347     c = isl_equality_alloc(isl_local_space_copy(LocalSpace));
348     c = isl_constraint_set_coefficient_si(c, isl_dim_in, i, -1);
349 
350     if (i == DimToVectorize)
351       c = isl_constraint_set_coefficient_si(c, isl_dim_out, PointDimension, 1);
352     else
353       c = isl_constraint_set_coefficient_si(c, isl_dim_out, i, 1);
354 
355     TilingMap = isl_map_add_constraint(TilingMap, c);
356   }
357 
358   // it % 'VectorWidth' = 0
359   LocalSpaceRange = isl_local_space_range(isl_local_space_copy(LocalSpace));
360   Aff = isl_aff_zero_on_domain(LocalSpaceRange);
361   Aff = isl_aff_set_constant_si(Aff, VectorWidth);
362   Aff = isl_aff_set_coefficient_si(Aff, isl_dim_in, TileDimension, 1);
363   VectorWidthMP = isl_val_int_from_si(ctx, VectorWidth);
364   Aff = isl_aff_mod_val(Aff, VectorWidthMP);
365   Modulo = isl_pw_aff_zero_set(isl_pw_aff_from_aff(Aff));
366   TilingMap = isl_map_intersect_range(TilingMap, Modulo);
367 
368   // it <= ip
369   c = isl_inequality_alloc(isl_local_space_copy(LocalSpace));
370   isl_constraint_set_coefficient_si(c, isl_dim_out, TileDimension, -1);
371   isl_constraint_set_coefficient_si(c, isl_dim_out, PointDimension, 1);
372   TilingMap = isl_map_add_constraint(TilingMap, c);
373 
374   // ip <= it + ('VectorWidth' - 1)
375   c = isl_inequality_alloc(LocalSpace);
376   isl_constraint_set_coefficient_si(c, isl_dim_out, TileDimension, 1);
377   isl_constraint_set_coefficient_si(c, isl_dim_out, PointDimension, -1);
378   isl_constraint_set_constant_si(c, VectorWidth - 1);
379   TilingMap = isl_map_add_constraint(TilingMap, c);
380 
381   return TilingMap;
382 }
383 
384 isl_union_map *
385 IslScheduleOptimizer::getScheduleForBandList(isl_band_list *BandList) {
386   int NumBands;
387   isl_union_map *Schedule;
388   isl_ctx *ctx;
389 
390   ctx = isl_band_list_get_ctx(BandList);
391   NumBands = isl_band_list_n_band(BandList);
392   Schedule = isl_union_map_empty(isl_space_params_alloc(ctx, 0));
393 
394   for (int i = 0; i < NumBands; i++) {
395     isl_band *Band;
396     isl_union_map *PartialSchedule;
397     int ScheduleDimensions;
398     isl_space *Space;
399 
400     Band = isl_band_list_get_band(BandList, i);
401     PartialSchedule = getScheduleForBand(Band, &ScheduleDimensions);
402     Space = isl_union_map_get_space(PartialSchedule);
403 
404     if (isl_band_has_children(Band)) {
405       isl_band_list *Children;
406       isl_union_map *SuffixSchedule;
407 
408       Children = isl_band_get_children(Band);
409       SuffixSchedule = getScheduleForBandList(Children);
410       PartialSchedule =
411           isl_union_map_flat_range_product(PartialSchedule, SuffixSchedule);
412       isl_band_list_free(Children);
413     } else if (PollyVectorizerChoice != VECTORIZER_NONE) {
414       // In case we are at the innermost band, we try to prepare for
415       // vectorization. This means, we look for the innermost parallel loop
416       // and strip mine this loop to the innermost level using a strip-mine
417       // factor corresponding to the number of vector iterations.
418       int NumDims = isl_band_n_member(Band);
419       for (int j = NumDims - 1; j >= 0; j--) {
420         if (isl_band_member_is_coincident(Band, j)) {
421           isl_map *TileMap;
422           isl_union_map *TileUMap;
423 
424           TileMap = getPrevectorMap(ctx, ScheduleDimensions - NumDims + j,
425                                     ScheduleDimensions);
426           TileUMap = isl_union_map_from_map(TileMap);
427           TileUMap =
428               isl_union_map_align_params(TileUMap, isl_space_copy(Space));
429           PartialSchedule =
430               isl_union_map_apply_range(PartialSchedule, TileUMap);
431           break;
432         }
433       }
434     }
435 
436     Schedule = isl_union_map_union(Schedule, PartialSchedule);
437 
438     isl_band_free(Band);
439     isl_space_free(Space);
440   }
441 
442   return Schedule;
443 }
444 
445 isl_union_map *IslScheduleOptimizer::getScheduleMap(isl_schedule *Schedule) {
446   isl_band_list *BandList = isl_schedule_get_band_forest(Schedule);
447   isl_union_map *ScheduleMap = getScheduleForBandList(BandList);
448   isl_band_list_free(BandList);
449   return ScheduleMap;
450 }
451 
452 bool IslScheduleOptimizer::runOnScop(Scop &S) {
453   Dependences *D = &getAnalysis<Dependences>();
454 
455   if (!D->hasValidDependences())
456     return false;
457 
458   isl_schedule_free(LastSchedule);
459   LastSchedule = nullptr;
460 
461   // Build input data.
462   int ValidityKinds =
463       Dependences::TYPE_RAW | Dependences::TYPE_WAR | Dependences::TYPE_WAW;
464   int ProximityKinds;
465 
466   if (OptimizeDeps == "all")
467     ProximityKinds =
468         Dependences::TYPE_RAW | Dependences::TYPE_WAR | Dependences::TYPE_WAW;
469   else if (OptimizeDeps == "raw")
470     ProximityKinds = Dependences::TYPE_RAW;
471   else {
472     errs() << "Do not know how to optimize for '" << OptimizeDeps << "'"
473            << " Falling back to optimizing all dependences.\n";
474     ProximityKinds =
475         Dependences::TYPE_RAW | Dependences::TYPE_WAR | Dependences::TYPE_WAW;
476   }
477 
478   isl_union_set *Domain = S.getDomains();
479 
480   if (!Domain)
481     return false;
482 
483   isl_union_map *Validity = D->getDependences(ValidityKinds);
484   isl_union_map *Proximity = D->getDependences(ProximityKinds);
485 
486   // Simplify the dependences by removing the constraints introduced by the
487   // domains. This can speed up the scheduling time significantly, as large
488   // constant coefficients will be removed from the dependences. The
489   // introduction of some additional dependences reduces the possible
490   // transformations, but in most cases, such transformation do not seem to be
491   // interesting anyway. In some cases this option may stop the scheduler to
492   // find any schedule.
493   if (SimplifyDeps == "yes") {
494     Validity = isl_union_map_gist_domain(Validity, isl_union_set_copy(Domain));
495     Validity = isl_union_map_gist_range(Validity, isl_union_set_copy(Domain));
496     Proximity =
497         isl_union_map_gist_domain(Proximity, isl_union_set_copy(Domain));
498     Proximity = isl_union_map_gist_range(Proximity, isl_union_set_copy(Domain));
499   } else if (SimplifyDeps != "no") {
500     errs() << "warning: Option -polly-opt-simplify-deps should either be 'yes' "
501               "or 'no'. Falling back to default: 'yes'\n";
502   }
503 
504   DEBUG(dbgs() << "\n\nCompute schedule from: ");
505   DEBUG(dbgs() << "Domain := " << stringFromIslObj(Domain) << ";\n");
506   DEBUG(dbgs() << "Proximity := " << stringFromIslObj(Proximity) << ";\n");
507   DEBUG(dbgs() << "Validity := " << stringFromIslObj(Validity) << ";\n");
508 
509   int IslFusionStrategy;
510 
511   if (FusionStrategy == "max") {
512     IslFusionStrategy = ISL_SCHEDULE_FUSE_MAX;
513   } else if (FusionStrategy == "min") {
514     IslFusionStrategy = ISL_SCHEDULE_FUSE_MIN;
515   } else {
516     errs() << "warning: Unknown fusion strategy. Falling back to maximal "
517               "fusion.\n";
518     IslFusionStrategy = ISL_SCHEDULE_FUSE_MAX;
519   }
520 
521   int IslMaximizeBands;
522 
523   if (MaximizeBandDepth == "yes") {
524     IslMaximizeBands = 1;
525   } else if (MaximizeBandDepth == "no") {
526     IslMaximizeBands = 0;
527   } else {
528     errs() << "warning: Option -polly-opt-maximize-bands should either be 'yes'"
529               " or 'no'. Falling back to default: 'yes'\n";
530     IslMaximizeBands = 1;
531   }
532 
533   isl_options_set_schedule_fuse(S.getIslCtx(), IslFusionStrategy);
534   isl_options_set_schedule_maximize_band_depth(S.getIslCtx(), IslMaximizeBands);
535   isl_options_set_schedule_max_constant_term(S.getIslCtx(), MaxConstantTerm);
536   isl_options_set_schedule_max_coefficient(S.getIslCtx(), MaxCoefficient);
537 
538   isl_options_set_on_error(S.getIslCtx(), ISL_ON_ERROR_CONTINUE);
539 
540   isl_schedule_constraints *ScheduleConstraints;
541   ScheduleConstraints = isl_schedule_constraints_on_domain(Domain);
542   ScheduleConstraints =
543       isl_schedule_constraints_set_proximity(ScheduleConstraints, Proximity);
544   ScheduleConstraints = isl_schedule_constraints_set_validity(
545       ScheduleConstraints, isl_union_map_copy(Validity));
546   ScheduleConstraints =
547       isl_schedule_constraints_set_coincidence(ScheduleConstraints, Validity);
548   isl_schedule *Schedule;
549   Schedule = isl_schedule_constraints_compute_schedule(ScheduleConstraints);
550   isl_options_set_on_error(S.getIslCtx(), ISL_ON_ERROR_ABORT);
551 
552   // In cases the scheduler is not able to optimize the code, we just do not
553   // touch the schedule.
554   if (!Schedule)
555     return false;
556 
557   DEBUG(dbgs() << "Schedule := " << stringFromIslObj(Schedule) << ";\n");
558 
559   isl_union_map *ScheduleMap = getScheduleMap(Schedule);
560 
561   for (ScopStmt *Stmt : S) {
562     isl_map *StmtSchedule;
563     isl_set *Domain = Stmt->getDomain();
564     isl_union_map *StmtBand;
565     StmtBand = isl_union_map_intersect_domain(isl_union_map_copy(ScheduleMap),
566                                               isl_union_set_from_set(Domain));
567     if (isl_union_map_is_empty(StmtBand)) {
568       StmtSchedule = isl_map_from_domain(isl_set_empty(Stmt->getDomainSpace()));
569       isl_union_map_free(StmtBand);
570     } else {
571       assert(isl_union_map_n_map(StmtBand) == 1);
572       StmtSchedule = isl_map_from_union_map(StmtBand);
573     }
574 
575     Stmt->setScattering(StmtSchedule);
576   }
577 
578   isl_union_map_free(ScheduleMap);
579   LastSchedule = Schedule;
580 
581   unsigned MaxScatDims = 0;
582 
583   for (ScopStmt *Stmt : S)
584     MaxScatDims = std::max(Stmt->getNumScattering(), MaxScatDims);
585 
586   extendScattering(S, MaxScatDims);
587   return false;
588 }
589 
590 void IslScheduleOptimizer::printScop(raw_ostream &OS) const {
591   isl_printer *p;
592   char *ScheduleStr;
593 
594   OS << "Calculated schedule:\n";
595 
596   if (!LastSchedule) {
597     OS << "n/a\n";
598     return;
599   }
600 
601   p = isl_printer_to_str(isl_schedule_get_ctx(LastSchedule));
602   p = isl_printer_print_schedule(p, LastSchedule);
603   ScheduleStr = isl_printer_get_str(p);
604   isl_printer_free(p);
605 
606   OS << ScheduleStr << "\n";
607 }
608 
609 void IslScheduleOptimizer::getAnalysisUsage(AnalysisUsage &AU) const {
610   ScopPass::getAnalysisUsage(AU);
611   AU.addRequired<Dependences>();
612 }
613 
614 Pass *polly::createIslScheduleOptimizerPass() {
615   return new IslScheduleOptimizer();
616 }
617 
618 INITIALIZE_PASS_BEGIN(IslScheduleOptimizer, "polly-opt-isl",
619                       "Polly - Optimize schedule of SCoP", false, false);
620 INITIALIZE_PASS_DEPENDENCY(Dependences);
621 INITIALIZE_PASS_DEPENDENCY(ScopInfo);
622 INITIALIZE_PASS_END(IslScheduleOptimizer, "polly-opt-isl",
623                     "Polly - Optimize schedule of SCoP", false, false)
624