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