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