1 //===- DependenceInfo.cpp - Calculate dependency information for a Scop. --===// 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 // Calculate the data dependency relations for a Scop using ISL. 11 // 12 // The integer set library (ISL) from Sven, has a integrated dependency analysis 13 // to calculate data dependences. This pass takes advantage of this and 14 // calculate those dependences a Scop. 15 // 16 // The dependences in this pass are exact in terms that for a specific read 17 // statement instance only the last write statement instance is returned. In 18 // case of may writes a set of possible write instances is returned. This 19 // analysis will never produce redundant dependences. 20 // 21 //===----------------------------------------------------------------------===// 22 // 23 #include "polly/DependenceInfo.h" 24 #include "polly/LinkAllPasses.h" 25 #include "polly/Options.h" 26 #include "polly/ScopInfo.h" 27 #include "polly/Support/GICHelper.h" 28 #include "llvm/Support/Debug.h" 29 #include <isl/aff.h> 30 #include <isl/ctx.h> 31 #include <isl/flow.h> 32 #include <isl/map.h> 33 #include <isl/options.h> 34 #include <isl/schedule.h> 35 #include <isl/set.h> 36 #include <isl/union_map.h> 37 #include <isl/union_set.h> 38 39 using namespace polly; 40 using namespace llvm; 41 42 #define DEBUG_TYPE "polly-dependence" 43 44 static cl::opt<int> OptComputeOut( 45 "polly-dependences-computeout", 46 cl::desc("Bound the dependence analysis by a maximal amount of " 47 "computational steps (0 means no bound)"), 48 cl::Hidden, cl::init(500000), cl::ZeroOrMore, cl::cat(PollyCategory)); 49 50 static cl::opt<bool> LegalityCheckDisabled( 51 "disable-polly-legality", cl::desc("Disable polly legality check"), 52 cl::Hidden, cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory)); 53 54 static cl::opt<bool> 55 UseReductions("polly-dependences-use-reductions", 56 cl::desc("Exploit reductions in dependence analysis"), 57 cl::Hidden, cl::init(true), cl::ZeroOrMore, 58 cl::cat(PollyCategory)); 59 60 enum AnalysisType { VALUE_BASED_ANALYSIS, MEMORY_BASED_ANALYSIS }; 61 62 static cl::opt<enum AnalysisType> OptAnalysisType( 63 "polly-dependences-analysis-type", 64 cl::desc("The kind of dependence analysis to use"), 65 cl::values(clEnumValN(VALUE_BASED_ANALYSIS, "value-based", 66 "Exact dependences without transitive dependences"), 67 clEnumValN(MEMORY_BASED_ANALYSIS, "memory-based", 68 "Overapproximation of dependences")), 69 cl::Hidden, cl::init(VALUE_BASED_ANALYSIS), cl::ZeroOrMore, 70 cl::cat(PollyCategory)); 71 72 static cl::opt<Dependences::AnalysisLevel> OptAnalysisLevel( 73 "polly-dependences-analysis-level", 74 cl::desc("The level of dependence analysis"), 75 cl::values(clEnumValN(Dependences::AL_Statement, "statement-wise", 76 "Statement-level analysis"), 77 clEnumValN(Dependences::AL_Reference, "reference-wise", 78 "Memory reference level analysis that distinguish" 79 " accessed references in the same statement"), 80 clEnumValN(Dependences::AL_Access, "access-wise", 81 "Memory reference level analysis that distinguish" 82 " access instructions in the same statement")), 83 cl::Hidden, cl::init(Dependences::AL_Statement), cl::ZeroOrMore, 84 cl::cat(PollyCategory)); 85 86 //===----------------------------------------------------------------------===// 87 88 /// Tag the @p Relation domain with @p TagId 89 static __isl_give isl_map *tag(__isl_take isl_map *Relation, 90 __isl_take isl_id *TagId) { 91 isl_space *Space = isl_map_get_space(Relation); 92 Space = isl_space_drop_dims(Space, isl_dim_out, 0, isl_map_n_out(Relation)); 93 Space = isl_space_set_tuple_id(Space, isl_dim_out, TagId); 94 isl_multi_aff *Tag = isl_multi_aff_domain_map(Space); 95 Relation = isl_map_preimage_domain_multi_aff(Relation, Tag); 96 return Relation; 97 } 98 99 /// Tag the @p Relation domain with either MA->getArrayId() or 100 /// MA->getId() based on @p TagLevel 101 static __isl_give isl_map *tag(__isl_take isl_map *Relation, MemoryAccess *MA, 102 Dependences::AnalysisLevel TagLevel) { 103 if (TagLevel == Dependences::AL_Reference) 104 return tag(Relation, MA->getArrayId()); 105 106 if (TagLevel == Dependences::AL_Access) 107 return tag(Relation, MA->getId()); 108 109 // No need to tag at the statement level. 110 return Relation; 111 } 112 113 /// Collect information about the SCoP @p S. 114 static void collectInfo(Scop &S, isl_union_map *&Read, isl_union_map *&Write, 115 isl_union_map *&MayWrite, 116 isl_union_map *&ReductionTagMap, 117 isl_union_set *&TaggedStmtDomain, 118 Dependences::AnalysisLevel Level) { 119 isl_space *Space = S.getParamSpace(); 120 Read = isl_union_map_empty(isl_space_copy(Space)); 121 Write = isl_union_map_empty(isl_space_copy(Space)); 122 MayWrite = isl_union_map_empty(isl_space_copy(Space)); 123 ReductionTagMap = isl_union_map_empty(isl_space_copy(Space)); 124 isl_union_map *StmtSchedule = isl_union_map_empty(Space); 125 126 SmallPtrSet<const ScopArrayInfo *, 8> ReductionArrays; 127 if (UseReductions) 128 for (ScopStmt &Stmt : S) 129 for (MemoryAccess *MA : Stmt) 130 if (MA->isReductionLike()) 131 ReductionArrays.insert(MA->getScopArrayInfo()); 132 133 for (ScopStmt &Stmt : S) { 134 for (MemoryAccess *MA : Stmt) { 135 isl_set *domcp = Stmt.getDomain(); 136 isl_map *accdom = MA->getAccessRelation(); 137 138 accdom = isl_map_intersect_domain(accdom, domcp); 139 140 if (ReductionArrays.count(MA->getScopArrayInfo())) { 141 // Wrap the access domain and adjust the schedule accordingly. 142 // 143 // An access domain like 144 // Stmt[i0, i1] -> MemAcc_A[i0 + i1] 145 // will be transformed into 146 // [Stmt[i0, i1] -> MemAcc_A[i0 + i1]] -> MemAcc_A[i0 + i1] 147 // 148 // We collect all the access domains in the ReductionTagMap. 149 // This is used in Dependences::calculateDependences to create 150 // a tagged Schedule tree. 151 152 ReductionTagMap = 153 isl_union_map_add_map(ReductionTagMap, isl_map_copy(accdom)); 154 accdom = isl_map_range_map(accdom); 155 } else { 156 accdom = tag(accdom, MA, Level); 157 if (Level > Dependences::AL_Statement) { 158 auto *StmtScheduleMap = Stmt.getSchedule(); 159 assert(StmtScheduleMap && 160 "Schedules that contain extension nodes require special " 161 "handling."); 162 isl_map *Schedule = tag(StmtScheduleMap, MA, Level); 163 StmtSchedule = isl_union_map_add_map(StmtSchedule, Schedule); 164 } 165 } 166 167 if (MA->isRead()) 168 Read = isl_union_map_add_map(Read, accdom); 169 else 170 Write = isl_union_map_add_map(Write, accdom); 171 } 172 173 if (!ReductionArrays.empty() && Level == Dependences::AL_Statement) 174 StmtSchedule = isl_union_map_add_map(StmtSchedule, Stmt.getSchedule()); 175 } 176 177 StmtSchedule = 178 isl_union_map_intersect_params(StmtSchedule, S.getAssumedContext()); 179 TaggedStmtDomain = isl_union_map_domain(StmtSchedule); 180 181 ReductionTagMap = isl_union_map_coalesce(ReductionTagMap); 182 Read = isl_union_map_coalesce(Read); 183 Write = isl_union_map_coalesce(Write); 184 MayWrite = isl_union_map_coalesce(MayWrite); 185 } 186 187 /// Fix all dimension of @p Zero to 0 and add it to @p user 188 static isl_stat fixSetToZero(__isl_take isl_set *Zero, void *user) { 189 isl_union_set **User = (isl_union_set **)user; 190 for (unsigned i = 0; i < isl_set_dim(Zero, isl_dim_set); i++) 191 Zero = isl_set_fix_si(Zero, isl_dim_set, i, 0); 192 *User = isl_union_set_add_set(*User, Zero); 193 return isl_stat_ok; 194 } 195 196 /// Compute the privatization dependences for a given dependency @p Map 197 /// 198 /// Privatization dependences are widened original dependences which originate 199 /// or end in a reduction access. To compute them we apply the transitive close 200 /// of the reduction dependences (which maps each iteration of a reduction 201 /// statement to all following ones) on the RAW/WAR/WAW dependences. The 202 /// dependences which start or end at a reduction statement will be extended to 203 /// depend on all following reduction statement iterations as well. 204 /// Note: "Following" here means according to the reduction dependences. 205 /// 206 /// For the input: 207 /// 208 /// S0: *sum = 0; 209 /// for (int i = 0; i < 1024; i++) 210 /// S1: *sum += i; 211 /// S2: *sum = *sum * 3; 212 /// 213 /// we have the following dependences before we add privatization dependences: 214 /// 215 /// RAW: 216 /// { S0[] -> S1[0]; S1[1023] -> S2[] } 217 /// WAR: 218 /// { } 219 /// WAW: 220 /// { S0[] -> S1[0]; S1[1024] -> S2[] } 221 /// RED: 222 /// { S1[i0] -> S1[1 + i0] : i0 >= 0 and i0 <= 1022 } 223 /// 224 /// and afterwards: 225 /// 226 /// RAW: 227 /// { S0[] -> S1[i0] : i0 >= 0 and i0 <= 1023; 228 /// S1[i0] -> S2[] : i0 >= 0 and i0 <= 1023} 229 /// WAR: 230 /// { } 231 /// WAW: 232 /// { S0[] -> S1[i0] : i0 >= 0 and i0 <= 1023; 233 /// S1[i0] -> S2[] : i0 >= 0 and i0 <= 1023} 234 /// RED: 235 /// { S1[i0] -> S1[1 + i0] : i0 >= 0 and i0 <= 1022 } 236 /// 237 /// Note: This function also computes the (reverse) transitive closure of the 238 /// reduction dependences. 239 void Dependences::addPrivatizationDependences() { 240 isl_union_map *PrivRAW, *PrivWAW, *PrivWAR; 241 242 // The transitive closure might be over approximated, thus could lead to 243 // dependency cycles in the privatization dependences. To make sure this 244 // will not happen we remove all negative dependences after we computed 245 // the transitive closure. 246 TC_RED = isl_union_map_transitive_closure(isl_union_map_copy(RED), nullptr); 247 248 // FIXME: Apply the current schedule instead of assuming the identity schedule 249 // here. The current approach is only valid as long as we compute the 250 // dependences only with the initial (identity schedule). Any other 251 // schedule could change "the direction of the backward dependences" we 252 // want to eliminate here. 253 isl_union_set *UDeltas = isl_union_map_deltas(isl_union_map_copy(TC_RED)); 254 isl_union_set *Universe = isl_union_set_universe(isl_union_set_copy(UDeltas)); 255 isl_union_set *Zero = isl_union_set_empty(isl_union_set_get_space(Universe)); 256 isl_union_set_foreach_set(Universe, fixSetToZero, &Zero); 257 isl_union_map *NonPositive = isl_union_set_lex_le_union_set(UDeltas, Zero); 258 259 TC_RED = isl_union_map_subtract(TC_RED, NonPositive); 260 261 TC_RED = isl_union_map_union( 262 TC_RED, isl_union_map_reverse(isl_union_map_copy(TC_RED))); 263 TC_RED = isl_union_map_coalesce(TC_RED); 264 265 isl_union_map **Maps[] = {&RAW, &WAW, &WAR}; 266 isl_union_map **PrivMaps[] = {&PrivRAW, &PrivWAW, &PrivWAR}; 267 for (unsigned u = 0; u < 3; u++) { 268 isl_union_map **Map = Maps[u], **PrivMap = PrivMaps[u]; 269 270 *PrivMap = isl_union_map_apply_range(isl_union_map_copy(*Map), 271 isl_union_map_copy(TC_RED)); 272 *PrivMap = isl_union_map_union( 273 *PrivMap, isl_union_map_apply_range(isl_union_map_copy(TC_RED), 274 isl_union_map_copy(*Map))); 275 276 *Map = isl_union_map_union(*Map, *PrivMap); 277 } 278 279 isl_union_set_free(Universe); 280 } 281 282 static __isl_give isl_union_flow *buildFlow(__isl_keep isl_union_map *Snk, 283 __isl_keep isl_union_map *Src, 284 __isl_keep isl_union_map *MaySrc, 285 __isl_keep isl_schedule *Schedule) { 286 isl_union_access_info *AI; 287 288 AI = isl_union_access_info_from_sink(isl_union_map_copy(Snk)); 289 AI = isl_union_access_info_set_may_source(AI, isl_union_map_copy(MaySrc)); 290 if (Src) 291 AI = isl_union_access_info_set_must_source(AI, isl_union_map_copy(Src)); 292 AI = isl_union_access_info_set_schedule(AI, isl_schedule_copy(Schedule)); 293 auto Flow = isl_union_access_info_compute_flow(AI); 294 DEBUG(if (!Flow) dbgs() << "last error: " 295 << isl_ctx_last_error(isl_schedule_get_ctx(Schedule)) 296 << '\n';); 297 return Flow; 298 } 299 300 void Dependences::calculateDependences(Scop &S) { 301 isl_union_map *Read, *Write, *MayWrite, *ReductionTagMap; 302 isl_schedule *Schedule; 303 isl_union_set *TaggedStmtDomain; 304 305 DEBUG(dbgs() << "Scop: \n" << S << "\n"); 306 307 collectInfo(S, Read, Write, MayWrite, ReductionTagMap, TaggedStmtDomain, 308 Level); 309 310 bool HasReductions = !isl_union_map_is_empty(ReductionTagMap); 311 312 DEBUG(dbgs() << "Read: " << Read << '\n'; 313 dbgs() << "Write: " << Write << '\n'; 314 dbgs() << "MayWrite: " << MayWrite << '\n'; 315 dbgs() << "ReductionTagMap: " << ReductionTagMap << '\n'; 316 dbgs() << "TaggedStmtDomain: " << TaggedStmtDomain << '\n';); 317 318 Schedule = S.getScheduleTree(); 319 320 if (!HasReductions) { 321 isl_union_map_free(ReductionTagMap); 322 // Tag the schedule tree if we want fine-grain dependence info 323 if (Level > AL_Statement) { 324 auto TaggedMap = 325 isl_union_set_unwrap(isl_union_set_copy(TaggedStmtDomain)); 326 auto Tags = isl_union_map_domain_map_union_pw_multi_aff(TaggedMap); 327 Schedule = isl_schedule_pullback_union_pw_multi_aff(Schedule, Tags); 328 } 329 } else { 330 isl_union_map *IdentityMap; 331 isl_union_pw_multi_aff *ReductionTags, *IdentityTags, *Tags; 332 333 // Extract Reduction tags from the combined access domains in the given 334 // SCoP. The result is a map that maps each tagged element in the domain to 335 // the memory location it accesses. ReductionTags = {[Stmt[i] -> 336 // Array[f(i)]] -> Stmt[i] } 337 ReductionTags = 338 isl_union_map_domain_map_union_pw_multi_aff(ReductionTagMap); 339 340 // Compute an identity map from each statement in domain to itself. 341 // IdentityTags = { [Stmt[i] -> Stmt[i] } 342 IdentityMap = isl_union_set_identity(isl_union_set_copy(TaggedStmtDomain)); 343 IdentityTags = isl_union_pw_multi_aff_from_union_map(IdentityMap); 344 345 Tags = isl_union_pw_multi_aff_union_add(ReductionTags, IdentityTags); 346 347 // By pulling back Tags from Schedule, we have a schedule tree that can 348 // be used to compute normal dependences, as well as 'tagged' reduction 349 // dependences. 350 Schedule = isl_schedule_pullback_union_pw_multi_aff(Schedule, Tags); 351 } 352 353 DEBUG(dbgs() << "Read: " << Read << "\n"; 354 dbgs() << "Write: " << Write << "\n"; 355 dbgs() << "MayWrite: " << MayWrite << "\n"; 356 dbgs() << "Schedule: " << Schedule << "\n"); 357 358 { 359 IslMaxOperationsGuard MaxOpGuard(IslCtx.get(), OptComputeOut); 360 361 RAW = WAW = WAR = RED = nullptr; 362 363 if (OptAnalysisType == VALUE_BASED_ANALYSIS) { 364 isl_union_flow *Flow; 365 366 Flow = buildFlow(Read, Write, MayWrite, Schedule); 367 368 RAW = isl_union_flow_get_must_dependence(Flow); 369 isl_union_flow_free(Flow); 370 371 Flow = buildFlow(Write, Write, Read, Schedule); 372 373 WAW = isl_union_flow_get_must_dependence(Flow); 374 WAR = isl_union_flow_get_may_dependence(Flow); 375 376 // This subtraction is needed to obtain the same results as were given by 377 // isl_union_map_compute_flow. For large sets this may add some 378 // compile-time cost. As there does not seem to be a need to distinguish 379 // between WAW and WAR, refactoring Polly to only track general non-flow 380 // dependences may improve performance. 381 WAR = isl_union_map_subtract(WAR, isl_union_map_copy(WAW)); 382 383 isl_union_flow_free(Flow); 384 isl_schedule_free(Schedule); 385 } else { 386 isl_union_flow *Flow; 387 388 Write = isl_union_map_union(Write, isl_union_map_copy(MayWrite)); 389 390 Flow = buildFlow(Read, nullptr, Write, Schedule); 391 392 RAW = isl_union_flow_get_may_dependence(Flow); 393 isl_union_flow_free(Flow); 394 395 Flow = buildFlow(Write, nullptr, Read, Schedule); 396 397 WAR = isl_union_flow_get_may_dependence(Flow); 398 isl_union_flow_free(Flow); 399 400 Flow = buildFlow(Write, nullptr, Write, Schedule); 401 402 WAW = isl_union_flow_get_may_dependence(Flow); 403 isl_union_flow_free(Flow); 404 isl_schedule_free(Schedule); 405 } 406 407 isl_union_map_free(MayWrite); 408 isl_union_map_free(Write); 409 isl_union_map_free(Read); 410 411 RAW = isl_union_map_coalesce(RAW); 412 WAW = isl_union_map_coalesce(WAW); 413 WAR = isl_union_map_coalesce(WAR); 414 415 // End of max_operations scope. 416 } 417 418 if (isl_ctx_last_error(IslCtx.get()) == isl_error_quota) { 419 isl_union_map_free(RAW); 420 isl_union_map_free(WAW); 421 isl_union_map_free(WAR); 422 RAW = WAW = WAR = nullptr; 423 isl_ctx_reset_error(IslCtx.get()); 424 } 425 426 // Drop out early, as the remaining computations are only needed for 427 // reduction dependences or dependences that are finer than statement 428 // level dependences. 429 if (!HasReductions && Level == AL_Statement) { 430 TC_RED = isl_union_map_empty(isl_union_set_get_space(TaggedStmtDomain)); 431 isl_union_set_free(TaggedStmtDomain); 432 return; 433 } 434 435 isl_union_map *STMT_RAW, *STMT_WAW, *STMT_WAR; 436 STMT_RAW = isl_union_map_intersect_domain( 437 isl_union_map_copy(RAW), isl_union_set_copy(TaggedStmtDomain)); 438 STMT_WAW = isl_union_map_intersect_domain( 439 isl_union_map_copy(WAW), isl_union_set_copy(TaggedStmtDomain)); 440 STMT_WAR = 441 isl_union_map_intersect_domain(isl_union_map_copy(WAR), TaggedStmtDomain); 442 DEBUG({ 443 dbgs() << "Wrapped Dependences:\n"; 444 dump(); 445 dbgs() << "\n"; 446 }); 447 448 // To handle reduction dependences we proceed as follows: 449 // 1) Aggregate all possible reduction dependences, namely all self 450 // dependences on reduction like statements. 451 // 2) Intersect them with the actual RAW & WAW dependences to the get the 452 // actual reduction dependences. This will ensure the load/store memory 453 // addresses were __identical__ in the two iterations of the statement. 454 // 3) Relax the original RAW and WAW dependences by subtracting the actual 455 // reduction dependences. Binary reductions (sum += A[i]) cause both, and 456 // the same, RAW and WAW dependences. 457 // 4) Add the privatization dependences which are widened versions of 458 // already present dependences. They model the effect of manual 459 // privatization at the outermost possible place (namely after the last 460 // write and before the first access to a reduction location). 461 462 // Step 1) 463 RED = isl_union_map_empty(isl_union_map_get_space(RAW)); 464 for (ScopStmt &Stmt : S) { 465 for (MemoryAccess *MA : Stmt) { 466 if (!MA->isReductionLike()) 467 continue; 468 isl_set *AccDomW = isl_map_wrap(MA->getAccessRelation()); 469 isl_map *Identity = 470 isl_map_from_domain_and_range(isl_set_copy(AccDomW), AccDomW); 471 RED = isl_union_map_add_map(RED, Identity); 472 } 473 } 474 475 // Step 2) 476 RED = isl_union_map_intersect(RED, isl_union_map_copy(RAW)); 477 RED = isl_union_map_intersect(RED, isl_union_map_copy(WAW)); 478 479 if (!isl_union_map_is_empty(RED)) { 480 481 // Step 3) 482 RAW = isl_union_map_subtract(RAW, isl_union_map_copy(RED)); 483 WAW = isl_union_map_subtract(WAW, isl_union_map_copy(RED)); 484 485 // Step 4) 486 addPrivatizationDependences(); 487 } 488 489 DEBUG({ 490 dbgs() << "Final Wrapped Dependences:\n"; 491 dump(); 492 dbgs() << "\n"; 493 }); 494 495 // RED_SIN is used to collect all reduction dependences again after we 496 // split them according to the causing memory accesses. The current assumption 497 // is that our method of splitting will not have any leftovers. In the end 498 // we validate this assumption until we have more confidence in this method. 499 isl_union_map *RED_SIN = isl_union_map_empty(isl_union_map_get_space(RAW)); 500 501 // For each reduction like memory access, check if there are reduction 502 // dependences with the access relation of the memory access as a domain 503 // (wrapped space!). If so these dependences are caused by this memory access. 504 // We then move this portion of reduction dependences back to the statement -> 505 // statement space and add a mapping from the memory access to these 506 // dependences. 507 for (ScopStmt &Stmt : S) { 508 for (MemoryAccess *MA : Stmt) { 509 if (!MA->isReductionLike()) 510 continue; 511 512 isl_set *AccDomW = isl_map_wrap(MA->getAccessRelation()); 513 isl_union_map *AccRedDepU = isl_union_map_intersect_domain( 514 isl_union_map_copy(TC_RED), isl_union_set_from_set(AccDomW)); 515 if (isl_union_map_is_empty(AccRedDepU)) { 516 isl_union_map_free(AccRedDepU); 517 continue; 518 } 519 520 isl_map *AccRedDep = isl_map_from_union_map(AccRedDepU); 521 RED_SIN = isl_union_map_add_map(RED_SIN, isl_map_copy(AccRedDep)); 522 AccRedDep = isl_map_zip(AccRedDep); 523 AccRedDep = isl_set_unwrap(isl_map_domain(AccRedDep)); 524 setReductionDependences(MA, AccRedDep); 525 } 526 } 527 528 assert(isl_union_map_is_equal(RED_SIN, TC_RED) && 529 "Intersecting the reduction dependence domain with the wrapped access " 530 "relation is not enough, we need to loosen the access relation also"); 531 isl_union_map_free(RED_SIN); 532 533 RAW = isl_union_map_zip(RAW); 534 WAW = isl_union_map_zip(WAW); 535 WAR = isl_union_map_zip(WAR); 536 RED = isl_union_map_zip(RED); 537 TC_RED = isl_union_map_zip(TC_RED); 538 539 DEBUG({ 540 dbgs() << "Zipped Dependences:\n"; 541 dump(); 542 dbgs() << "\n"; 543 }); 544 545 RAW = isl_union_set_unwrap(isl_union_map_domain(RAW)); 546 WAW = isl_union_set_unwrap(isl_union_map_domain(WAW)); 547 WAR = isl_union_set_unwrap(isl_union_map_domain(WAR)); 548 RED = isl_union_set_unwrap(isl_union_map_domain(RED)); 549 TC_RED = isl_union_set_unwrap(isl_union_map_domain(TC_RED)); 550 551 DEBUG({ 552 dbgs() << "Unwrapped Dependences:\n"; 553 dump(); 554 dbgs() << "\n"; 555 }); 556 557 RAW = isl_union_map_union(RAW, STMT_RAW); 558 WAW = isl_union_map_union(WAW, STMT_WAW); 559 WAR = isl_union_map_union(WAR, STMT_WAR); 560 561 RAW = isl_union_map_coalesce(RAW); 562 WAW = isl_union_map_coalesce(WAW); 563 WAR = isl_union_map_coalesce(WAR); 564 RED = isl_union_map_coalesce(RED); 565 TC_RED = isl_union_map_coalesce(TC_RED); 566 567 DEBUG(dump()); 568 } 569 570 bool Dependences::isValidSchedule(Scop &S, 571 StatementToIslMapTy *NewSchedule) const { 572 if (LegalityCheckDisabled) 573 return true; 574 575 isl_union_map *Dependences = getDependences(TYPE_RAW | TYPE_WAW | TYPE_WAR); 576 isl_space *Space = S.getParamSpace(); 577 isl_union_map *Schedule = isl_union_map_empty(Space); 578 579 isl_space *ScheduleSpace = nullptr; 580 581 for (ScopStmt &Stmt : S) { 582 isl_map *StmtScat; 583 584 if (NewSchedule->find(&Stmt) == NewSchedule->end()) 585 StmtScat = Stmt.getSchedule(); 586 else 587 StmtScat = isl_map_copy((*NewSchedule)[&Stmt]); 588 assert(StmtScat && 589 "Schedules that contain extension nodes require special handling."); 590 591 if (!ScheduleSpace) 592 ScheduleSpace = isl_space_range(isl_map_get_space(StmtScat)); 593 594 Schedule = isl_union_map_add_map(Schedule, StmtScat); 595 } 596 597 Dependences = 598 isl_union_map_apply_domain(Dependences, isl_union_map_copy(Schedule)); 599 Dependences = isl_union_map_apply_range(Dependences, Schedule); 600 601 isl_set *Zero = isl_set_universe(isl_space_copy(ScheduleSpace)); 602 for (unsigned i = 0; i < isl_set_dim(Zero, isl_dim_set); i++) 603 Zero = isl_set_fix_si(Zero, isl_dim_set, i, 0); 604 605 isl_union_set *UDeltas = isl_union_map_deltas(Dependences); 606 isl_set *Deltas = isl_union_set_extract_set(UDeltas, ScheduleSpace); 607 isl_union_set_free(UDeltas); 608 609 isl_map *NonPositive = isl_set_lex_le_set(Deltas, Zero); 610 bool IsValid = isl_map_is_empty(NonPositive); 611 isl_map_free(NonPositive); 612 613 return IsValid; 614 } 615 616 // Check if the current scheduling dimension is parallel. 617 // 618 // We check for parallelism by verifying that the loop does not carry any 619 // dependences. 620 // 621 // Parallelism test: if the distance is zero in all outer dimensions, then it 622 // has to be zero in the current dimension as well. 623 // 624 // Implementation: first, translate dependences into time space, then force 625 // outer dimensions to be equal. If the distance is zero in the current 626 // dimension, then the loop is parallel. The distance is zero in the current 627 // dimension if it is a subset of a map with equal values for the current 628 // dimension. 629 bool Dependences::isParallel(isl_union_map *Schedule, isl_union_map *Deps, 630 isl_pw_aff **MinDistancePtr) const { 631 isl_set *Deltas, *Distance; 632 isl_map *ScheduleDeps; 633 unsigned Dimension; 634 bool IsParallel; 635 636 Deps = isl_union_map_apply_range(Deps, isl_union_map_copy(Schedule)); 637 Deps = isl_union_map_apply_domain(Deps, isl_union_map_copy(Schedule)); 638 639 if (isl_union_map_is_empty(Deps)) { 640 isl_union_map_free(Deps); 641 return true; 642 } 643 644 ScheduleDeps = isl_map_from_union_map(Deps); 645 Dimension = isl_map_dim(ScheduleDeps, isl_dim_out) - 1; 646 647 for (unsigned i = 0; i < Dimension; i++) 648 ScheduleDeps = isl_map_equate(ScheduleDeps, isl_dim_out, i, isl_dim_in, i); 649 650 Deltas = isl_map_deltas(ScheduleDeps); 651 Distance = isl_set_universe(isl_set_get_space(Deltas)); 652 653 // [0, ..., 0, +] - All zeros and last dimension larger than zero 654 for (unsigned i = 0; i < Dimension; i++) 655 Distance = isl_set_fix_si(Distance, isl_dim_set, i, 0); 656 657 Distance = isl_set_lower_bound_si(Distance, isl_dim_set, Dimension, 1); 658 Distance = isl_set_intersect(Distance, Deltas); 659 660 IsParallel = isl_set_is_empty(Distance); 661 if (IsParallel || !MinDistancePtr) { 662 isl_set_free(Distance); 663 return IsParallel; 664 } 665 666 Distance = isl_set_project_out(Distance, isl_dim_set, 0, Dimension); 667 Distance = isl_set_coalesce(Distance); 668 669 // This last step will compute a expression for the minimal value in the 670 // distance polyhedron Distance with regards to the first (outer most) 671 // dimension. 672 *MinDistancePtr = isl_pw_aff_coalesce(isl_set_dim_min(Distance, 0)); 673 674 return false; 675 } 676 677 static void printDependencyMap(raw_ostream &OS, __isl_keep isl_union_map *DM) { 678 if (DM) 679 OS << DM << "\n"; 680 else 681 OS << "n/a\n"; 682 } 683 684 void Dependences::print(raw_ostream &OS) const { 685 OS << "\tRAW dependences:\n\t\t"; 686 printDependencyMap(OS, RAW); 687 OS << "\tWAR dependences:\n\t\t"; 688 printDependencyMap(OS, WAR); 689 OS << "\tWAW dependences:\n\t\t"; 690 printDependencyMap(OS, WAW); 691 OS << "\tReduction dependences:\n\t\t"; 692 printDependencyMap(OS, RED); 693 OS << "\tTransitive closure of reduction dependences:\n\t\t"; 694 printDependencyMap(OS, TC_RED); 695 } 696 697 void Dependences::dump() const { print(dbgs()); } 698 699 void Dependences::releaseMemory() { 700 isl_union_map_free(RAW); 701 isl_union_map_free(WAR); 702 isl_union_map_free(WAW); 703 isl_union_map_free(RED); 704 isl_union_map_free(TC_RED); 705 706 RED = RAW = WAR = WAW = TC_RED = nullptr; 707 708 for (auto &ReductionDeps : ReductionDependences) 709 isl_map_free(ReductionDeps.second); 710 ReductionDependences.clear(); 711 } 712 713 __isl_give isl_union_map *Dependences::getDependences(int Kinds) const { 714 assert(hasValidDependences() && "No valid dependences available"); 715 isl_space *Space = isl_union_map_get_space(RAW); 716 isl_union_map *Deps = isl_union_map_empty(Space); 717 718 if (Kinds & TYPE_RAW) 719 Deps = isl_union_map_union(Deps, isl_union_map_copy(RAW)); 720 721 if (Kinds & TYPE_WAR) 722 Deps = isl_union_map_union(Deps, isl_union_map_copy(WAR)); 723 724 if (Kinds & TYPE_WAW) 725 Deps = isl_union_map_union(Deps, isl_union_map_copy(WAW)); 726 727 if (Kinds & TYPE_RED) 728 Deps = isl_union_map_union(Deps, isl_union_map_copy(RED)); 729 730 if (Kinds & TYPE_TC_RED) 731 Deps = isl_union_map_union(Deps, isl_union_map_copy(TC_RED)); 732 733 Deps = isl_union_map_coalesce(Deps); 734 Deps = isl_union_map_detect_equalities(Deps); 735 return Deps; 736 } 737 738 bool Dependences::hasValidDependences() const { 739 return (RAW != nullptr) && (WAR != nullptr) && (WAW != nullptr); 740 } 741 742 __isl_give isl_map * 743 Dependences::getReductionDependences(MemoryAccess *MA) const { 744 return isl_map_copy(ReductionDependences.lookup(MA)); 745 } 746 747 void Dependences::setReductionDependences(MemoryAccess *MA, isl_map *D) { 748 assert(ReductionDependences.count(MA) == 0 && 749 "Reduction dependences set twice!"); 750 ReductionDependences[MA] = D; 751 } 752 753 const Dependences & 754 DependenceInfo::getDependences(Dependences::AnalysisLevel Level) { 755 if (Dependences *d = D[Level].get()) 756 return *d; 757 758 return recomputeDependences(Level); 759 } 760 761 const Dependences & 762 DependenceInfo::recomputeDependences(Dependences::AnalysisLevel Level) { 763 D[Level].reset(new Dependences(S->getSharedIslCtx(), Level)); 764 D[Level]->calculateDependences(*S); 765 return *D[Level]; 766 } 767 768 bool DependenceInfo::runOnScop(Scop &ScopVar) { 769 S = &ScopVar; 770 return false; 771 } 772 773 /// Print the dependences for the given SCoP to @p OS. 774 775 void polly::DependenceInfo::printScop(raw_ostream &OS, Scop &S) const { 776 if (auto d = D[OptAnalysisLevel].get()) { 777 d->print(OS); 778 return; 779 } 780 781 // Otherwise create the dependences on-the-fly and print it 782 Dependences D(S.getSharedIslCtx(), OptAnalysisLevel); 783 D.calculateDependences(S); 784 D.print(OS); 785 } 786 787 void DependenceInfo::getAnalysisUsage(AnalysisUsage &AU) const { 788 AU.addRequiredTransitive<ScopInfoRegionPass>(); 789 AU.setPreservesAll(); 790 } 791 792 char DependenceInfo::ID = 0; 793 794 Pass *polly::createDependenceInfoPass() { return new DependenceInfo(); } 795 796 INITIALIZE_PASS_BEGIN(DependenceInfo, "polly-dependences", 797 "Polly - Calculate dependences", false, false); 798 INITIALIZE_PASS_DEPENDENCY(ScopInfoRegionPass); 799 INITIALIZE_PASS_END(DependenceInfo, "polly-dependences", 800 "Polly - Calculate dependences", false, false) 801 802 //===----------------------------------------------------------------------===// 803 const Dependences & 804 DependenceInfoWrapperPass::getDependences(Scop *S, 805 Dependences::AnalysisLevel Level) { 806 auto It = ScopToDepsMap.find(S); 807 if (It != ScopToDepsMap.end()) 808 if (It->second) { 809 if (It->second->getDependenceLevel() == Level) 810 return *It->second.get(); 811 } 812 return recomputeDependences(S, Level); 813 } 814 815 const Dependences &DependenceInfoWrapperPass::recomputeDependences( 816 Scop *S, Dependences::AnalysisLevel Level) { 817 std::unique_ptr<Dependences> D(new Dependences(S->getSharedIslCtx(), Level)); 818 D->calculateDependences(*S); 819 auto Inserted = ScopToDepsMap.insert(std::make_pair(S, std::move(D))); 820 return *Inserted.first->second; 821 } 822 823 bool DependenceInfoWrapperPass::runOnFunction(Function &F) { 824 auto &SI = getAnalysis<ScopInfoWrapperPass>(); 825 for (auto &It : SI) { 826 assert(It.second && "Invalid SCoP object!"); 827 recomputeDependences(It.second.get(), Dependences::AL_Access); 828 } 829 return false; 830 } 831 832 void DependenceInfoWrapperPass::print(raw_ostream &OS, const Module *M) const { 833 for (auto &It : ScopToDepsMap) { 834 assert((It.first && It.second) && "Invalid Scop or Dependence object!\n"); 835 It.second->print(OS); 836 } 837 } 838 839 void DependenceInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { 840 AU.addRequiredTransitive<ScopInfoWrapperPass>(); 841 AU.setPreservesAll(); 842 } 843 844 char DependenceInfoWrapperPass::ID = 0; 845 846 Pass *polly::createDependenceInfoWrapperPassPass() { 847 return new DependenceInfoWrapperPass(); 848 } 849 850 INITIALIZE_PASS_BEGIN( 851 DependenceInfoWrapperPass, "polly-function-dependences", 852 "Polly - Calculate dependences for all the SCoPs of a function", false, 853 false) 854 INITIALIZE_PASS_DEPENDENCY(ScopInfoWrapperPass); 855 INITIALIZE_PASS_END( 856 DependenceInfoWrapperPass, "polly-function-dependences", 857 "Polly - Calculate dependences for all the SCoPs of a function", false, 858 false) 859