1 //===- DependenceInfo.cpp - Calculate dependency information for a Scop. --===// 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 // Calculate the data dependency relations for a Scop using ISL. 10 // 11 // The integer set library (ISL) from Sven, has a integrated dependency analysis 12 // to calculate data dependences. This pass takes advantage of this and 13 // calculate those dependences a Scop. 14 // 15 // The dependences in this pass are exact in terms that for a specific read 16 // statement instance only the last write statement instance is returned. In 17 // case of may writes a set of possible write instances is returned. This 18 // analysis will never produce redundant dependences. 19 // 20 //===----------------------------------------------------------------------===// 21 // 22 #include "polly/DependenceInfo.h" 23 #include "polly/LinkAllPasses.h" 24 #include "polly/Options.h" 25 #include "polly/ScopInfo.h" 26 #include "polly/Support/GICHelper.h" 27 #include "polly/Support/ISLTools.h" 28 #include "llvm/ADT/Sequence.h" 29 #include "llvm/Support/Debug.h" 30 #include "isl/aff.h" 31 #include "isl/ctx.h" 32 #include "isl/flow.h" 33 #include "isl/map.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::cat(PollyCategory)); 49 50 static cl::opt<bool> 51 LegalityCheckDisabled("disable-polly-legality", 52 cl::desc("Disable polly legality check"), cl::Hidden, 53 cl::cat(PollyCategory)); 54 55 static cl::opt<bool> 56 UseReductions("polly-dependences-use-reductions", 57 cl::desc("Exploit reductions in dependence analysis"), 58 cl::Hidden, cl::init(true), 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::cat(PollyCategory)); 70 71 static cl::opt<Dependences::AnalysisLevel> OptAnalysisLevel( 72 "polly-dependences-analysis-level", 73 cl::desc("The level of dependence analysis"), 74 cl::values(clEnumValN(Dependences::AL_Statement, "statement-wise", 75 "Statement-level analysis"), 76 clEnumValN(Dependences::AL_Reference, "reference-wise", 77 "Memory reference level analysis that distinguish" 78 " accessed references in the same statement"), 79 clEnumValN(Dependences::AL_Access, "access-wise", 80 "Memory reference level analysis that distinguish" 81 " access instructions in the same statement")), 82 cl::Hidden, cl::init(Dependences::AL_Statement), cl::cat(PollyCategory)); 83 84 //===----------------------------------------------------------------------===// 85 86 /// Tag the @p Relation domain with @p TagId 87 static __isl_give isl_map *tag(__isl_take isl_map *Relation, 88 __isl_take isl_id *TagId) { 89 isl_space *Space = isl_map_get_space(Relation); 90 Space = isl_space_drop_dims(Space, isl_dim_out, 0, 91 isl_map_dim(Relation, isl_dim_out)); 92 Space = isl_space_set_tuple_id(Space, isl_dim_out, TagId); 93 isl_multi_aff *Tag = isl_multi_aff_domain_map(Space); 94 Relation = isl_map_preimage_domain_multi_aff(Relation, Tag); 95 return Relation; 96 } 97 98 /// Tag the @p Relation domain with either MA->getArrayId() or 99 /// MA->getId() based on @p TagLevel 100 static __isl_give isl_map *tag(__isl_take isl_map *Relation, MemoryAccess *MA, 101 Dependences::AnalysisLevel TagLevel) { 102 if (TagLevel == Dependences::AL_Reference) 103 return tag(Relation, MA->getArrayId().release()); 104 105 if (TagLevel == Dependences::AL_Access) 106 return tag(Relation, MA->getId().release()); 107 108 // No need to tag at the statement level. 109 return Relation; 110 } 111 112 /// Collect information about the SCoP @p S. 113 static void collectInfo(Scop &S, isl_union_map *&Read, 114 isl_union_map *&MustWrite, isl_union_map *&MayWrite, 115 isl_union_map *&ReductionTagMap, 116 isl_union_set *&TaggedStmtDomain, 117 Dependences::AnalysisLevel Level) { 118 isl_space *Space = S.getParamSpace().release(); 119 Read = isl_union_map_empty(isl_space_copy(Space)); 120 MustWrite = isl_union_map_empty(isl_space_copy(Space)); 121 MayWrite = isl_union_map_empty(isl_space_copy(Space)); 122 ReductionTagMap = isl_union_map_empty(isl_space_copy(Space)); 123 isl_union_map *StmtSchedule = isl_union_map_empty(Space); 124 125 SmallPtrSet<const ScopArrayInfo *, 8> ReductionArrays; 126 if (UseReductions) 127 for (ScopStmt &Stmt : S) 128 for (MemoryAccess *MA : Stmt) 129 if (MA->isReductionLike()) 130 ReductionArrays.insert(MA->getScopArrayInfo()); 131 132 for (ScopStmt &Stmt : S) { 133 for (MemoryAccess *MA : Stmt) { 134 isl_set *domcp = Stmt.getDomain().release(); 135 isl_map *accdom = MA->getAccessRelation().release(); 136 137 accdom = isl_map_intersect_domain(accdom, domcp); 138 139 if (ReductionArrays.count(MA->getScopArrayInfo())) { 140 // Wrap the access domain and adjust the schedule accordingly. 141 // 142 // An access domain like 143 // Stmt[i0, i1] -> MemAcc_A[i0 + i1] 144 // will be transformed into 145 // [Stmt[i0, i1] -> MemAcc_A[i0 + i1]] -> MemAcc_A[i0 + i1] 146 // 147 // We collect all the access domains in the ReductionTagMap. 148 // This is used in Dependences::calculateDependences to create 149 // a tagged Schedule tree. 150 151 ReductionTagMap = 152 isl_union_map_add_map(ReductionTagMap, isl_map_copy(accdom)); 153 accdom = isl_map_range_map(accdom); 154 } else { 155 accdom = tag(accdom, MA, Level); 156 if (Level > Dependences::AL_Statement) { 157 isl_map *StmtScheduleMap = Stmt.getSchedule().release(); 158 assert(StmtScheduleMap && 159 "Schedules that contain extension nodes require special " 160 "handling."); 161 isl_map *Schedule = tag(StmtScheduleMap, MA, Level); 162 StmtSchedule = isl_union_map_add_map(StmtSchedule, Schedule); 163 } 164 } 165 166 if (MA->isRead()) 167 Read = isl_union_map_add_map(Read, accdom); 168 else if (MA->isMayWrite()) 169 MayWrite = isl_union_map_add_map(MayWrite, accdom); 170 else 171 MustWrite = isl_union_map_add_map(MustWrite, accdom); 172 } 173 174 if (!ReductionArrays.empty() && Level == Dependences::AL_Statement) 175 StmtSchedule = 176 isl_union_map_add_map(StmtSchedule, Stmt.getSchedule().release()); 177 } 178 179 StmtSchedule = isl_union_map_intersect_params( 180 StmtSchedule, S.getAssumedContext().release()); 181 TaggedStmtDomain = isl_union_map_domain(StmtSchedule); 182 183 ReductionTagMap = isl_union_map_coalesce(ReductionTagMap); 184 Read = isl_union_map_coalesce(Read); 185 MustWrite = isl_union_map_coalesce(MustWrite); 186 MayWrite = isl_union_map_coalesce(MayWrite); 187 } 188 189 /// Fix all dimension of @p Zero to 0 and add it to @p user 190 static void fixSetToZero(isl::set Zero, isl::union_set *User) { 191 for (auto i : rangeIslSize(0, Zero.tuple_dim())) 192 Zero = Zero.fix_si(isl::dim::set, i, 0); 193 *User = User->unite(Zero); 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 = 256 isl::manage(isl_union_set_empty(isl_union_set_get_space(Universe))); 257 258 for (isl::set Set : isl::manage_copy(Universe).get_set_list()) 259 fixSetToZero(Set, &Zero); 260 261 isl_union_map *NonPositive = 262 isl_union_set_lex_le_union_set(UDeltas, Zero.release()); 263 264 TC_RED = isl_union_map_subtract(TC_RED, NonPositive); 265 266 TC_RED = isl_union_map_union( 267 TC_RED, isl_union_map_reverse(isl_union_map_copy(TC_RED))); 268 TC_RED = isl_union_map_coalesce(TC_RED); 269 270 isl_union_map **Maps[] = {&RAW, &WAW, &WAR}; 271 isl_union_map **PrivMaps[] = {&PrivRAW, &PrivWAW, &PrivWAR}; 272 for (unsigned u = 0; u < 3; u++) { 273 isl_union_map **Map = Maps[u], **PrivMap = PrivMaps[u]; 274 275 *PrivMap = isl_union_map_apply_range(isl_union_map_copy(*Map), 276 isl_union_map_copy(TC_RED)); 277 *PrivMap = isl_union_map_union( 278 *PrivMap, isl_union_map_apply_range(isl_union_map_copy(TC_RED), 279 isl_union_map_copy(*Map))); 280 281 *Map = isl_union_map_union(*Map, *PrivMap); 282 } 283 284 isl_union_set_free(Universe); 285 } 286 287 static __isl_give isl_union_flow *buildFlow(__isl_keep isl_union_map *Snk, 288 __isl_keep isl_union_map *Src, 289 __isl_keep isl_union_map *MaySrc, 290 __isl_keep isl_union_map *Kill, 291 __isl_keep isl_schedule *Schedule) { 292 isl_union_access_info *AI; 293 294 AI = isl_union_access_info_from_sink(isl_union_map_copy(Snk)); 295 if (MaySrc) 296 AI = isl_union_access_info_set_may_source(AI, isl_union_map_copy(MaySrc)); 297 if (Src) 298 AI = isl_union_access_info_set_must_source(AI, isl_union_map_copy(Src)); 299 if (Kill) 300 AI = isl_union_access_info_set_kill(AI, isl_union_map_copy(Kill)); 301 AI = isl_union_access_info_set_schedule(AI, isl_schedule_copy(Schedule)); 302 auto Flow = isl_union_access_info_compute_flow(AI); 303 LLVM_DEBUG(if (!Flow) dbgs() 304 << "last error: " 305 << isl_ctx_last_error(isl_schedule_get_ctx(Schedule)) 306 << '\n';); 307 return Flow; 308 } 309 310 void Dependences::calculateDependences(Scop &S) { 311 isl_union_map *Read, *MustWrite, *MayWrite, *ReductionTagMap; 312 isl_schedule *Schedule; 313 isl_union_set *TaggedStmtDomain; 314 315 LLVM_DEBUG(dbgs() << "Scop: \n" << S << "\n"); 316 317 collectInfo(S, Read, MustWrite, MayWrite, ReductionTagMap, TaggedStmtDomain, 318 Level); 319 320 bool HasReductions = !isl_union_map_is_empty(ReductionTagMap); 321 322 LLVM_DEBUG(dbgs() << "Read: " << Read << '\n'; 323 dbgs() << "MustWrite: " << MustWrite << '\n'; 324 dbgs() << "MayWrite: " << MayWrite << '\n'; 325 dbgs() << "ReductionTagMap: " << ReductionTagMap << '\n'; 326 dbgs() << "TaggedStmtDomain: " << TaggedStmtDomain << '\n';); 327 328 Schedule = S.getScheduleTree().release(); 329 330 if (!HasReductions) { 331 isl_union_map_free(ReductionTagMap); 332 // Tag the schedule tree if we want fine-grain dependence info 333 if (Level > AL_Statement) { 334 auto TaggedMap = 335 isl_union_set_unwrap(isl_union_set_copy(TaggedStmtDomain)); 336 auto Tags = isl_union_map_domain_map_union_pw_multi_aff(TaggedMap); 337 Schedule = isl_schedule_pullback_union_pw_multi_aff(Schedule, Tags); 338 } 339 } else { 340 isl_union_map *IdentityMap; 341 isl_union_pw_multi_aff *ReductionTags, *IdentityTags, *Tags; 342 343 // Extract Reduction tags from the combined access domains in the given 344 // SCoP. The result is a map that maps each tagged element in the domain to 345 // the memory location it accesses. ReductionTags = {[Stmt[i] -> 346 // Array[f(i)]] -> Stmt[i] } 347 ReductionTags = 348 isl_union_map_domain_map_union_pw_multi_aff(ReductionTagMap); 349 350 // Compute an identity map from each statement in domain to itself. 351 // IdentityTags = { [Stmt[i] -> Stmt[i] } 352 IdentityMap = isl_union_set_identity(isl_union_set_copy(TaggedStmtDomain)); 353 IdentityTags = isl_union_pw_multi_aff_from_union_map(IdentityMap); 354 355 Tags = isl_union_pw_multi_aff_union_add(ReductionTags, IdentityTags); 356 357 // By pulling back Tags from Schedule, we have a schedule tree that can 358 // be used to compute normal dependences, as well as 'tagged' reduction 359 // dependences. 360 Schedule = isl_schedule_pullback_union_pw_multi_aff(Schedule, Tags); 361 } 362 363 LLVM_DEBUG(dbgs() << "Read: " << Read << "\n"; 364 dbgs() << "MustWrite: " << MustWrite << "\n"; 365 dbgs() << "MayWrite: " << MayWrite << "\n"; 366 dbgs() << "Schedule: " << Schedule << "\n"); 367 368 isl_union_map *StrictWAW = nullptr; 369 { 370 IslMaxOperationsGuard MaxOpGuard(IslCtx.get(), OptComputeOut); 371 372 RAW = WAW = WAR = RED = nullptr; 373 isl_union_map *Write = isl_union_map_union(isl_union_map_copy(MustWrite), 374 isl_union_map_copy(MayWrite)); 375 376 // We are interested in detecting reductions that do not have intermediate 377 // computations that are captured by other statements. 378 // 379 // Example: 380 // void f(int *A, int *B) { 381 // for(int i = 0; i <= 100; i++) { 382 // 383 // *-WAR (S0[i] -> S0[i + 1] 0 <= i <= 100)------------* 384 // | | 385 // *-WAW (S0[i] -> S0[i + 1] 0 <= i <= 100)------------* 386 // | | 387 // v | 388 // S0: *A += i; >------------------*-----------------------* 389 // | 390 // if (i >= 98) { WAR (S0[i] -> S1[i]) 98 <= i <= 100 391 // | 392 // S1: *B = *A; <--------------* 393 // } 394 // } 395 // } 396 // 397 // S0[0 <= i <= 100] has a reduction. However, the values in 398 // S0[98 <= i <= 100] is captured in S1[98 <= i <= 100]. 399 // Since we allow free reordering on our reduction dependences, we need to 400 // remove all instances of a reduction statement that have data dependences 401 // originating from them. 402 // In the case of the example, we need to remove S0[98 <= i <= 100] from 403 // our reduction dependences. 404 // 405 // When we build up the WAW dependences that are used to detect reductions, 406 // we consider only **Writes that have no intermediate Reads**. 407 // 408 // `isl_union_flow_get_must_dependence` gives us dependences of the form: 409 // (sink <- must_source). 410 // 411 // It *will not give* dependences of the form: 412 // 1. (sink <- ... <- may_source <- ... <- must_source) 413 // 2. (sink <- ... <- must_source <- ... <- must_source) 414 // 415 // For a detailed reference on ISL's flow analysis, see: 416 // "Presburger Formulas and Polyhedral Compilation" - Approximate Dataflow 417 // Analysis. 418 // 419 // Since we set "Write" as a must-source, "Read" as a may-source, and ask 420 // for must dependences, we get all Writes to Writes that **do not flow 421 // through a Read**. 422 // 423 // ScopInfo::checkForReductions makes sure that if something captures 424 // the reduction variable in the same basic block, then it is rejected 425 // before it is even handed here. This makes sure that there is exactly 426 // one read and one write to a reduction variable in a Statement. 427 // Example: 428 // void f(int *sum, int A[N], int B[N]) { 429 // for (int i = 0; i < N; i++) { 430 // *sum += A[i]; < the store and the load is not tagged as a 431 // B[i] = *sum; < reduction-like access due to the overlap. 432 // } 433 // } 434 435 isl_union_flow *Flow = buildFlow(Write, Write, Read, nullptr, Schedule); 436 StrictWAW = isl_union_flow_get_must_dependence(Flow); 437 isl_union_flow_free(Flow); 438 439 if (OptAnalysisType == VALUE_BASED_ANALYSIS) { 440 Flow = buildFlow(Read, MustWrite, MayWrite, nullptr, Schedule); 441 RAW = isl_union_flow_get_may_dependence(Flow); 442 isl_union_flow_free(Flow); 443 444 Flow = buildFlow(Write, MustWrite, MayWrite, nullptr, Schedule); 445 WAW = isl_union_flow_get_may_dependence(Flow); 446 isl_union_flow_free(Flow); 447 448 // ISL now supports "kills" in approximate dataflow analysis, we can 449 // specify the MustWrite as kills, Read as source and Write as sink. 450 Flow = buildFlow(Write, nullptr, Read, MustWrite, Schedule); 451 WAR = isl_union_flow_get_may_dependence(Flow); 452 isl_union_flow_free(Flow); 453 } else { 454 Flow = buildFlow(Read, nullptr, Write, nullptr, Schedule); 455 RAW = isl_union_flow_get_may_dependence(Flow); 456 isl_union_flow_free(Flow); 457 458 Flow = buildFlow(Write, nullptr, Read, nullptr, Schedule); 459 WAR = isl_union_flow_get_may_dependence(Flow); 460 isl_union_flow_free(Flow); 461 462 Flow = buildFlow(Write, nullptr, Write, nullptr, Schedule); 463 WAW = isl_union_flow_get_may_dependence(Flow); 464 isl_union_flow_free(Flow); 465 } 466 467 isl_union_map_free(Write); 468 isl_union_map_free(MustWrite); 469 isl_union_map_free(MayWrite); 470 isl_union_map_free(Read); 471 isl_schedule_free(Schedule); 472 473 RAW = isl_union_map_coalesce(RAW); 474 WAW = isl_union_map_coalesce(WAW); 475 WAR = isl_union_map_coalesce(WAR); 476 477 // End of max_operations scope. 478 } 479 480 if (isl_ctx_last_error(IslCtx.get()) == isl_error_quota) { 481 isl_union_map_free(RAW); 482 isl_union_map_free(WAW); 483 isl_union_map_free(WAR); 484 isl_union_map_free(StrictWAW); 485 RAW = WAW = WAR = StrictWAW = nullptr; 486 isl_ctx_reset_error(IslCtx.get()); 487 } 488 489 // Drop out early, as the remaining computations are only needed for 490 // reduction dependences or dependences that are finer than statement 491 // level dependences. 492 if (!HasReductions && Level == AL_Statement) { 493 RED = isl_union_map_empty(isl_union_map_get_space(RAW)); 494 TC_RED = isl_union_map_empty(isl_union_set_get_space(TaggedStmtDomain)); 495 isl_union_set_free(TaggedStmtDomain); 496 isl_union_map_free(StrictWAW); 497 return; 498 } 499 500 isl_union_map *STMT_RAW, *STMT_WAW, *STMT_WAR; 501 STMT_RAW = isl_union_map_intersect_domain( 502 isl_union_map_copy(RAW), isl_union_set_copy(TaggedStmtDomain)); 503 STMT_WAW = isl_union_map_intersect_domain( 504 isl_union_map_copy(WAW), isl_union_set_copy(TaggedStmtDomain)); 505 STMT_WAR = 506 isl_union_map_intersect_domain(isl_union_map_copy(WAR), TaggedStmtDomain); 507 LLVM_DEBUG({ 508 dbgs() << "Wrapped Dependences:\n"; 509 dump(); 510 dbgs() << "\n"; 511 }); 512 513 // To handle reduction dependences we proceed as follows: 514 // 1) Aggregate all possible reduction dependences, namely all self 515 // dependences on reduction like statements. 516 // 2) Intersect them with the actual RAW & WAW dependences to the get the 517 // actual reduction dependences. This will ensure the load/store memory 518 // addresses were __identical__ in the two iterations of the statement. 519 // 3) Relax the original RAW, WAW and WAR dependences by subtracting the 520 // actual reduction dependences. Binary reductions (sum += A[i]) cause 521 // the same, RAW, WAW and WAR dependences. 522 // 4) Add the privatization dependences which are widened versions of 523 // already present dependences. They model the effect of manual 524 // privatization at the outermost possible place (namely after the last 525 // write and before the first access to a reduction location). 526 527 // Step 1) 528 RED = isl_union_map_empty(isl_union_map_get_space(RAW)); 529 for (ScopStmt &Stmt : S) { 530 for (MemoryAccess *MA : Stmt) { 531 if (!MA->isReductionLike()) 532 continue; 533 isl_set *AccDomW = isl_map_wrap(MA->getAccessRelation().release()); 534 isl_map *Identity = 535 isl_map_from_domain_and_range(isl_set_copy(AccDomW), AccDomW); 536 RED = isl_union_map_add_map(RED, Identity); 537 } 538 } 539 540 // Step 2) 541 RED = isl_union_map_intersect(RED, isl_union_map_copy(RAW)); 542 RED = isl_union_map_intersect(RED, StrictWAW); 543 544 if (!isl_union_map_is_empty(RED)) { 545 546 // Step 3) 547 RAW = isl_union_map_subtract(RAW, isl_union_map_copy(RED)); 548 WAW = isl_union_map_subtract(WAW, isl_union_map_copy(RED)); 549 WAR = isl_union_map_subtract(WAR, isl_union_map_copy(RED)); 550 551 // Step 4) 552 addPrivatizationDependences(); 553 } else 554 TC_RED = isl_union_map_empty(isl_union_map_get_space(RED)); 555 556 LLVM_DEBUG({ 557 dbgs() << "Final Wrapped Dependences:\n"; 558 dump(); 559 dbgs() << "\n"; 560 }); 561 562 // RED_SIN is used to collect all reduction dependences again after we 563 // split them according to the causing memory accesses. The current assumption 564 // is that our method of splitting will not have any leftovers. In the end 565 // we validate this assumption until we have more confidence in this method. 566 isl_union_map *RED_SIN = isl_union_map_empty(isl_union_map_get_space(RAW)); 567 568 // For each reduction like memory access, check if there are reduction 569 // dependences with the access relation of the memory access as a domain 570 // (wrapped space!). If so these dependences are caused by this memory access. 571 // We then move this portion of reduction dependences back to the statement -> 572 // statement space and add a mapping from the memory access to these 573 // dependences. 574 for (ScopStmt &Stmt : S) { 575 for (MemoryAccess *MA : Stmt) { 576 if (!MA->isReductionLike()) 577 continue; 578 579 isl_set *AccDomW = isl_map_wrap(MA->getAccessRelation().release()); 580 isl_union_map *AccRedDepU = isl_union_map_intersect_domain( 581 isl_union_map_copy(TC_RED), isl_union_set_from_set(AccDomW)); 582 if (isl_union_map_is_empty(AccRedDepU)) { 583 isl_union_map_free(AccRedDepU); 584 continue; 585 } 586 587 isl_map *AccRedDep = isl_map_from_union_map(AccRedDepU); 588 RED_SIN = isl_union_map_add_map(RED_SIN, isl_map_copy(AccRedDep)); 589 AccRedDep = isl_map_zip(AccRedDep); 590 AccRedDep = isl_set_unwrap(isl_map_domain(AccRedDep)); 591 setReductionDependences(MA, AccRedDep); 592 } 593 } 594 595 assert(isl_union_map_is_equal(RED_SIN, TC_RED) && 596 "Intersecting the reduction dependence domain with the wrapped access " 597 "relation is not enough, we need to loosen the access relation also"); 598 isl_union_map_free(RED_SIN); 599 600 RAW = isl_union_map_zip(RAW); 601 WAW = isl_union_map_zip(WAW); 602 WAR = isl_union_map_zip(WAR); 603 RED = isl_union_map_zip(RED); 604 TC_RED = isl_union_map_zip(TC_RED); 605 606 LLVM_DEBUG({ 607 dbgs() << "Zipped Dependences:\n"; 608 dump(); 609 dbgs() << "\n"; 610 }); 611 612 RAW = isl_union_set_unwrap(isl_union_map_domain(RAW)); 613 WAW = isl_union_set_unwrap(isl_union_map_domain(WAW)); 614 WAR = isl_union_set_unwrap(isl_union_map_domain(WAR)); 615 RED = isl_union_set_unwrap(isl_union_map_domain(RED)); 616 TC_RED = isl_union_set_unwrap(isl_union_map_domain(TC_RED)); 617 618 LLVM_DEBUG({ 619 dbgs() << "Unwrapped Dependences:\n"; 620 dump(); 621 dbgs() << "\n"; 622 }); 623 624 RAW = isl_union_map_union(RAW, STMT_RAW); 625 WAW = isl_union_map_union(WAW, STMT_WAW); 626 WAR = isl_union_map_union(WAR, STMT_WAR); 627 628 RAW = isl_union_map_coalesce(RAW); 629 WAW = isl_union_map_coalesce(WAW); 630 WAR = isl_union_map_coalesce(WAR); 631 RED = isl_union_map_coalesce(RED); 632 TC_RED = isl_union_map_coalesce(TC_RED); 633 634 LLVM_DEBUG(dump()); 635 } 636 637 bool Dependences::isValidSchedule(Scop &S, isl::schedule NewSched) const { 638 // TODO: Also check permutable/coincident flags as well. 639 640 StatementToIslMapTy NewSchedules; 641 for (auto NewMap : NewSched.get_map().get_map_list()) { 642 auto Stmt = reinterpret_cast<ScopStmt *>( 643 NewMap.get_tuple_id(isl::dim::in).get_user()); 644 NewSchedules[Stmt] = NewMap; 645 } 646 647 return isValidSchedule(S, NewSchedules); 648 } 649 650 bool Dependences::isValidSchedule( 651 Scop &S, const StatementToIslMapTy &NewSchedule) const { 652 if (LegalityCheckDisabled) 653 return true; 654 655 isl::union_map Dependences = getDependences(TYPE_RAW | TYPE_WAW | TYPE_WAR); 656 isl::union_map Schedule = isl::union_map::empty(S.getIslCtx()); 657 658 isl::space ScheduleSpace; 659 660 for (ScopStmt &Stmt : S) { 661 isl::map StmtScat; 662 663 auto Lookup = NewSchedule.find(&Stmt); 664 if (Lookup == NewSchedule.end()) 665 StmtScat = Stmt.getSchedule(); 666 else 667 StmtScat = Lookup->second; 668 assert(!StmtScat.is_null() && 669 "Schedules that contain extension nodes require special handling."); 670 671 if (ScheduleSpace.is_null()) 672 ScheduleSpace = StmtScat.get_space().range(); 673 674 Schedule = Schedule.unite(StmtScat); 675 } 676 677 Dependences = Dependences.apply_domain(Schedule); 678 Dependences = Dependences.apply_range(Schedule); 679 680 isl::set Zero = isl::set::universe(ScheduleSpace); 681 for (auto i : rangeIslSize(0, Zero.tuple_dim())) 682 Zero = Zero.fix_si(isl::dim::set, i, 0); 683 684 isl::union_set UDeltas = Dependences.deltas(); 685 isl::set Deltas = singleton(UDeltas, ScheduleSpace); 686 687 isl::space Space = Deltas.get_space(); 688 isl::map NonPositive = isl::map::universe(Space.map_from_set()); 689 NonPositive = 690 NonPositive.lex_le_at(isl::multi_pw_aff::identity_on_domain(Space)); 691 NonPositive = NonPositive.intersect_domain(Deltas); 692 NonPositive = NonPositive.intersect_range(Zero); 693 694 return NonPositive.is_empty(); 695 } 696 697 // Check if the current scheduling dimension is parallel. 698 // 699 // We check for parallelism by verifying that the loop does not carry any 700 // dependences. 701 // 702 // Parallelism test: if the distance is zero in all outer dimensions, then it 703 // has to be zero in the current dimension as well. 704 // 705 // Implementation: first, translate dependences into time space, then force 706 // outer dimensions to be equal. If the distance is zero in the current 707 // dimension, then the loop is parallel. The distance is zero in the current 708 // dimension if it is a subset of a map with equal values for the current 709 // dimension. 710 bool Dependences::isParallel(__isl_keep isl_union_map *Schedule, 711 __isl_take isl_union_map *Deps, 712 __isl_give isl_pw_aff **MinDistancePtr) const { 713 isl_set *Deltas, *Distance; 714 isl_map *ScheduleDeps; 715 unsigned Dimension; 716 bool IsParallel; 717 718 Deps = isl_union_map_apply_range(Deps, isl_union_map_copy(Schedule)); 719 Deps = isl_union_map_apply_domain(Deps, isl_union_map_copy(Schedule)); 720 721 if (isl_union_map_is_empty(Deps)) { 722 isl_union_map_free(Deps); 723 return true; 724 } 725 726 ScheduleDeps = isl_map_from_union_map(Deps); 727 Dimension = isl_map_dim(ScheduleDeps, isl_dim_out) - 1; 728 729 for (unsigned i = 0; i < Dimension; i++) 730 ScheduleDeps = isl_map_equate(ScheduleDeps, isl_dim_out, i, isl_dim_in, i); 731 732 Deltas = isl_map_deltas(ScheduleDeps); 733 Distance = isl_set_universe(isl_set_get_space(Deltas)); 734 735 // [0, ..., 0, +] - All zeros and last dimension larger than zero 736 for (unsigned i = 0; i < Dimension; i++) 737 Distance = isl_set_fix_si(Distance, isl_dim_set, i, 0); 738 739 Distance = isl_set_lower_bound_si(Distance, isl_dim_set, Dimension, 1); 740 Distance = isl_set_intersect(Distance, Deltas); 741 742 IsParallel = isl_set_is_empty(Distance); 743 if (IsParallel || !MinDistancePtr) { 744 isl_set_free(Distance); 745 return IsParallel; 746 } 747 748 Distance = isl_set_project_out(Distance, isl_dim_set, 0, Dimension); 749 Distance = isl_set_coalesce(Distance); 750 751 // This last step will compute a expression for the minimal value in the 752 // distance polyhedron Distance with regards to the first (outer most) 753 // dimension. 754 *MinDistancePtr = isl_pw_aff_coalesce(isl_set_dim_min(Distance, 0)); 755 756 return false; 757 } 758 759 static void printDependencyMap(raw_ostream &OS, __isl_keep isl_union_map *DM) { 760 if (DM) 761 OS << DM << "\n"; 762 else 763 OS << "n/a\n"; 764 } 765 766 void Dependences::print(raw_ostream &OS) const { 767 OS << "\tRAW dependences:\n\t\t"; 768 printDependencyMap(OS, RAW); 769 OS << "\tWAR dependences:\n\t\t"; 770 printDependencyMap(OS, WAR); 771 OS << "\tWAW dependences:\n\t\t"; 772 printDependencyMap(OS, WAW); 773 OS << "\tReduction dependences:\n\t\t"; 774 printDependencyMap(OS, RED); 775 OS << "\tTransitive closure of reduction dependences:\n\t\t"; 776 printDependencyMap(OS, TC_RED); 777 } 778 779 void Dependences::dump() const { print(dbgs()); } 780 781 void Dependences::releaseMemory() { 782 isl_union_map_free(RAW); 783 isl_union_map_free(WAR); 784 isl_union_map_free(WAW); 785 isl_union_map_free(RED); 786 isl_union_map_free(TC_RED); 787 788 RED = RAW = WAR = WAW = TC_RED = nullptr; 789 790 for (auto &ReductionDeps : ReductionDependences) 791 isl_map_free(ReductionDeps.second); 792 ReductionDependences.clear(); 793 } 794 795 isl::union_map Dependences::getDependences(int Kinds) const { 796 assert(hasValidDependences() && "No valid dependences available"); 797 isl::space Space = isl::manage_copy(RAW).get_space(); 798 isl::union_map Deps = Deps.empty(Space.ctx()); 799 800 if (Kinds & TYPE_RAW) 801 Deps = Deps.unite(isl::manage_copy(RAW)); 802 803 if (Kinds & TYPE_WAR) 804 Deps = Deps.unite(isl::manage_copy(WAR)); 805 806 if (Kinds & TYPE_WAW) 807 Deps = Deps.unite(isl::manage_copy(WAW)); 808 809 if (Kinds & TYPE_RED) 810 Deps = Deps.unite(isl::manage_copy(RED)); 811 812 if (Kinds & TYPE_TC_RED) 813 Deps = Deps.unite(isl::manage_copy(TC_RED)); 814 815 Deps = Deps.coalesce(); 816 Deps = Deps.detect_equalities(); 817 return Deps; 818 } 819 820 bool Dependences::hasValidDependences() const { 821 return (RAW != nullptr) && (WAR != nullptr) && (WAW != nullptr); 822 } 823 824 __isl_give isl_map * 825 Dependences::getReductionDependences(MemoryAccess *MA) const { 826 return isl_map_copy(ReductionDependences.lookup(MA)); 827 } 828 829 void Dependences::setReductionDependences(MemoryAccess *MA, 830 __isl_take isl_map *D) { 831 assert(ReductionDependences.count(MA) == 0 && 832 "Reduction dependences set twice!"); 833 ReductionDependences[MA] = D; 834 } 835 836 const Dependences & 837 DependenceAnalysis::Result::getDependences(Dependences::AnalysisLevel Level) { 838 if (Dependences *d = D[Level].get()) 839 return *d; 840 841 return recomputeDependences(Level); 842 } 843 844 const Dependences &DependenceAnalysis::Result::recomputeDependences( 845 Dependences::AnalysisLevel Level) { 846 D[Level].reset(new Dependences(S.getSharedIslCtx(), Level)); 847 D[Level]->calculateDependences(S); 848 return *D[Level]; 849 } 850 851 DependenceAnalysis::Result 852 DependenceAnalysis::run(Scop &S, ScopAnalysisManager &SAM, 853 ScopStandardAnalysisResults &SAR) { 854 return {S, {}}; 855 } 856 857 AnalysisKey DependenceAnalysis::Key; 858 859 PreservedAnalyses 860 DependenceInfoPrinterPass::run(Scop &S, ScopAnalysisManager &SAM, 861 ScopStandardAnalysisResults &SAR, 862 SPMUpdater &U) { 863 auto &DI = SAM.getResult<DependenceAnalysis>(S, SAR); 864 865 if (auto d = DI.D[OptAnalysisLevel].get()) { 866 d->print(OS); 867 return PreservedAnalyses::all(); 868 } 869 870 // Otherwise create the dependences on-the-fly and print them 871 Dependences D(S.getSharedIslCtx(), OptAnalysisLevel); 872 D.calculateDependences(S); 873 D.print(OS); 874 875 return PreservedAnalyses::all(); 876 } 877 878 const Dependences & 879 DependenceInfo::getDependences(Dependences::AnalysisLevel Level) { 880 if (Dependences *d = D[Level].get()) 881 return *d; 882 883 return recomputeDependences(Level); 884 } 885 886 const Dependences & 887 DependenceInfo::recomputeDependences(Dependences::AnalysisLevel Level) { 888 D[Level].reset(new Dependences(S->getSharedIslCtx(), Level)); 889 D[Level]->calculateDependences(*S); 890 return *D[Level]; 891 } 892 893 bool DependenceInfo::runOnScop(Scop &ScopVar) { 894 S = &ScopVar; 895 return false; 896 } 897 898 /// Print the dependences for the given SCoP to @p OS. 899 900 void polly::DependenceInfo::printScop(raw_ostream &OS, Scop &S) const { 901 if (auto d = D[OptAnalysisLevel].get()) { 902 d->print(OS); 903 return; 904 } 905 906 // Otherwise create the dependences on-the-fly and print it 907 Dependences D(S.getSharedIslCtx(), OptAnalysisLevel); 908 D.calculateDependences(S); 909 D.print(OS); 910 } 911 912 void DependenceInfo::getAnalysisUsage(AnalysisUsage &AU) const { 913 AU.addRequiredTransitive<ScopInfoRegionPass>(); 914 AU.setPreservesAll(); 915 } 916 917 char DependenceInfo::ID = 0; 918 919 Pass *polly::createDependenceInfoPass() { return new DependenceInfo(); } 920 921 INITIALIZE_PASS_BEGIN(DependenceInfo, "polly-dependences", 922 "Polly - Calculate dependences", false, false); 923 INITIALIZE_PASS_DEPENDENCY(ScopInfoRegionPass); 924 INITIALIZE_PASS_END(DependenceInfo, "polly-dependences", 925 "Polly - Calculate dependences", false, false) 926 927 //===----------------------------------------------------------------------===// 928 929 namespace { 930 /// Print result from DependenceAnalysis. 931 class DependenceInfoPrinterLegacyPass final : public ScopPass { 932 public: 933 static char ID; 934 935 DependenceInfoPrinterLegacyPass() : DependenceInfoPrinterLegacyPass(outs()) {} 936 937 explicit DependenceInfoPrinterLegacyPass(llvm::raw_ostream &OS) 938 : ScopPass(ID), OS(OS) {} 939 940 bool runOnScop(Scop &S) override { 941 DependenceInfo &P = getAnalysis<DependenceInfo>(); 942 943 OS << "Printing analysis '" << P.getPassName() << "' for " 944 << "region: '" << S.getRegion().getNameStr() << "' in function '" 945 << S.getFunction().getName() << "':\n"; 946 P.printScop(OS, S); 947 948 return false; 949 } 950 951 void getAnalysisUsage(AnalysisUsage &AU) const override { 952 ScopPass::getAnalysisUsage(AU); 953 AU.addRequired<DependenceInfo>(); 954 AU.setPreservesAll(); 955 } 956 957 private: 958 llvm::raw_ostream &OS; 959 }; 960 961 char DependenceInfoPrinterLegacyPass::ID = 0; 962 } // namespace 963 964 Pass *polly::createDependenceInfoPrinterLegacyPass(raw_ostream &OS) { 965 return new DependenceInfoPrinterLegacyPass(OS); 966 } 967 968 INITIALIZE_PASS_BEGIN(DependenceInfoPrinterLegacyPass, 969 "polly-print-dependences", "Polly - Print dependences", 970 false, false); 971 INITIALIZE_PASS_DEPENDENCY(DependenceInfo); 972 INITIALIZE_PASS_END(DependenceInfoPrinterLegacyPass, "polly-print-dependences", 973 "Polly - Print dependences", false, false) 974 975 //===----------------------------------------------------------------------===// 976 977 const Dependences & 978 DependenceInfoWrapperPass::getDependences(Scop *S, 979 Dependences::AnalysisLevel Level) { 980 auto It = ScopToDepsMap.find(S); 981 if (It != ScopToDepsMap.end()) 982 if (It->second) { 983 if (It->second->getDependenceLevel() == Level) 984 return *It->second.get(); 985 } 986 return recomputeDependences(S, Level); 987 } 988 989 const Dependences &DependenceInfoWrapperPass::recomputeDependences( 990 Scop *S, Dependences::AnalysisLevel Level) { 991 std::unique_ptr<Dependences> D(new Dependences(S->getSharedIslCtx(), Level)); 992 D->calculateDependences(*S); 993 auto Inserted = ScopToDepsMap.insert(std::make_pair(S, std::move(D))); 994 return *Inserted.first->second; 995 } 996 997 bool DependenceInfoWrapperPass::runOnFunction(Function &F) { 998 auto &SI = *getAnalysis<ScopInfoWrapperPass>().getSI(); 999 for (auto &It : SI) { 1000 assert(It.second && "Invalid SCoP object!"); 1001 recomputeDependences(It.second.get(), Dependences::AL_Access); 1002 } 1003 return false; 1004 } 1005 1006 void DependenceInfoWrapperPass::print(raw_ostream &OS, const Module *M) const { 1007 for (auto &It : ScopToDepsMap) { 1008 assert((It.first && It.second) && "Invalid Scop or Dependence object!\n"); 1009 It.second->print(OS); 1010 } 1011 } 1012 1013 void DependenceInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { 1014 AU.addRequiredTransitive<ScopInfoWrapperPass>(); 1015 AU.setPreservesAll(); 1016 } 1017 1018 char DependenceInfoWrapperPass::ID = 0; 1019 1020 Pass *polly::createDependenceInfoWrapperPassPass() { 1021 return new DependenceInfoWrapperPass(); 1022 } 1023 1024 INITIALIZE_PASS_BEGIN( 1025 DependenceInfoWrapperPass, "polly-function-dependences", 1026 "Polly - Calculate dependences for all the SCoPs of a function", false, 1027 false) 1028 INITIALIZE_PASS_DEPENDENCY(ScopInfoWrapperPass); 1029 INITIALIZE_PASS_END( 1030 DependenceInfoWrapperPass, "polly-function-dependences", 1031 "Polly - Calculate dependences for all the SCoPs of a function", false, 1032 false) 1033 1034 //===----------------------------------------------------------------------===// 1035 1036 namespace { 1037 /// Print result from DependenceInfoWrapperPass. 1038 class DependenceInfoPrinterLegacyFunctionPass final : public FunctionPass { 1039 public: 1040 static char ID; 1041 1042 DependenceInfoPrinterLegacyFunctionPass() 1043 : DependenceInfoPrinterLegacyFunctionPass(outs()) {} 1044 1045 explicit DependenceInfoPrinterLegacyFunctionPass(llvm::raw_ostream &OS) 1046 : FunctionPass(ID), OS(OS) {} 1047 1048 bool runOnFunction(Function &F) override { 1049 DependenceInfoWrapperPass &P = getAnalysis<DependenceInfoWrapperPass>(); 1050 1051 OS << "Printing analysis '" << P.getPassName() << "' for function '" 1052 << F.getName() << "':\n"; 1053 P.print(OS); 1054 1055 return false; 1056 } 1057 1058 void getAnalysisUsage(AnalysisUsage &AU) const override { 1059 FunctionPass::getAnalysisUsage(AU); 1060 AU.addRequired<DependenceInfoWrapperPass>(); 1061 AU.setPreservesAll(); 1062 } 1063 1064 private: 1065 llvm::raw_ostream &OS; 1066 }; 1067 1068 char DependenceInfoPrinterLegacyFunctionPass::ID = 0; 1069 } // namespace 1070 1071 Pass *polly::createDependenceInfoPrinterLegacyFunctionPass(raw_ostream &OS) { 1072 return new DependenceInfoPrinterLegacyFunctionPass(OS); 1073 } 1074 1075 INITIALIZE_PASS_BEGIN( 1076 DependenceInfoPrinterLegacyFunctionPass, "polly-print-function-dependences", 1077 "Polly - Print dependences for all the SCoPs of a function", false, false); 1078 INITIALIZE_PASS_DEPENDENCY(DependenceInfoWrapperPass); 1079 INITIALIZE_PASS_END(DependenceInfoPrinterLegacyFunctionPass, 1080 "polly-print-function-dependences", 1081 "Polly - Print dependences for all the SCoPs of a function", 1082 false, false) 1083