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