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 /// @brief 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 /// @brief 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 /// @brief 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 (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 /// @brief 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 /// @brief 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), 0); 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 DEBUG(dbgs() << "Read: " << Read << '\n'; 339 dbgs() << "Write: " << Write << '\n'; 340 dbgs() << "MayWrite: " << MayWrite << '\n'; 341 dbgs() << "AccessSchedule: " << AccessSchedule << '\n'; 342 dbgs() << "StmtSchedule: " << StmtSchedule << '\n';); 343 344 if (isl_union_map_is_empty(AccessSchedule)) { 345 isl_union_map_free(AccessSchedule); 346 Schedule = S.getScheduleTree(); 347 // Tag the schedule tree if we want fine-grain dependence info 348 if (Level > AL_Statement) { 349 auto TaggedDom = isl_union_map_domain((isl_union_map_copy(StmtSchedule))); 350 auto TaggedMap = isl_union_set_unwrap(TaggedDom); 351 auto Tags = isl_union_map_domain_map_union_pw_multi_aff(TaggedMap); 352 Schedule = isl_schedule_pullback_union_pw_multi_aff(Schedule, Tags); 353 } 354 } else { 355 auto *ScheduleMap = 356 isl_union_map_union(AccessSchedule, isl_union_map_copy(StmtSchedule)); 357 Schedule = isl_schedule_from_domain( 358 isl_union_map_domain(isl_union_map_copy(ScheduleMap))); 359 if (!isl_union_map_is_empty(ScheduleMap)) { 360 ScheduleMap = addZeroPaddingToSchedule(ScheduleMap); 361 Schedule = isl_schedule_insert_partial_schedule( 362 Schedule, isl_multi_union_pw_aff_from_union_map(ScheduleMap)); 363 } else { 364 isl_union_map_free(ScheduleMap); 365 } 366 } 367 368 long MaxOpsOld = isl_ctx_get_max_operations(IslCtx.get()); 369 if (OptComputeOut) 370 isl_ctx_set_max_operations(IslCtx.get(), OptComputeOut); 371 isl_options_set_on_error(IslCtx.get(), ISL_ON_ERROR_CONTINUE); 372 373 DEBUG(dbgs() << "Read: " << Read << "\n"; 374 dbgs() << "Write: " << Write << "\n"; 375 dbgs() << "MayWrite: " << MayWrite << "\n"; 376 dbgs() << "Schedule: " << Schedule << "\n"); 377 378 RAW = WAW = WAR = RED = nullptr; 379 380 if (OptAnalysisType == VALUE_BASED_ANALYSIS) { 381 isl_union_flow *Flow; 382 383 Flow = buildFlow(Read, Write, MayWrite, Schedule); 384 385 RAW = isl_union_flow_get_must_dependence(Flow); 386 isl_union_flow_free(Flow); 387 388 Flow = buildFlow(Write, Write, Read, Schedule); 389 390 WAW = isl_union_flow_get_must_dependence(Flow); 391 WAR = isl_union_flow_get_may_dependence(Flow); 392 393 // This subtraction is needed to obtain the same results as were given by 394 // isl_union_map_compute_flow. For large sets this may add some compile-time 395 // cost. As there does not seem to be a need to distinguish between WAW and 396 // WAR, refactoring Polly to only track general non-flow dependences may 397 // improve performance. 398 WAR = isl_union_map_subtract(WAR, isl_union_map_copy(WAW)); 399 400 isl_union_flow_free(Flow); 401 isl_schedule_free(Schedule); 402 } else { 403 isl_union_flow *Flow; 404 405 Write = isl_union_map_union(Write, isl_union_map_copy(MayWrite)); 406 407 Flow = buildFlow(Read, nullptr, Write, Schedule); 408 409 RAW = isl_union_flow_get_may_dependence(Flow); 410 isl_union_flow_free(Flow); 411 412 Flow = buildFlow(Write, nullptr, Read, Schedule); 413 414 WAR = isl_union_flow_get_may_dependence(Flow); 415 isl_union_flow_free(Flow); 416 417 Flow = buildFlow(Write, nullptr, Write, Schedule); 418 419 WAW = isl_union_flow_get_may_dependence(Flow); 420 isl_union_flow_free(Flow); 421 isl_schedule_free(Schedule); 422 } 423 424 isl_union_map_free(MayWrite); 425 isl_union_map_free(Write); 426 isl_union_map_free(Read); 427 428 RAW = isl_union_map_coalesce(RAW); 429 WAW = isl_union_map_coalesce(WAW); 430 WAR = isl_union_map_coalesce(WAR); 431 432 if (isl_ctx_last_error(IslCtx.get()) == isl_error_quota) { 433 isl_union_map_free(RAW); 434 isl_union_map_free(WAW); 435 isl_union_map_free(WAR); 436 RAW = WAW = WAR = nullptr; 437 isl_ctx_reset_error(IslCtx.get()); 438 } 439 isl_options_set_on_error(IslCtx.get(), ISL_ON_ERROR_ABORT); 440 isl_ctx_reset_operations(IslCtx.get()); 441 isl_ctx_set_max_operations(IslCtx.get(), MaxOpsOld); 442 443 isl_union_map *STMT_RAW, *STMT_WAW, *STMT_WAR; 444 STMT_RAW = isl_union_map_intersect_domain( 445 isl_union_map_copy(RAW), 446 isl_union_map_domain(isl_union_map_copy(StmtSchedule))); 447 STMT_WAW = isl_union_map_intersect_domain( 448 isl_union_map_copy(WAW), 449 isl_union_map_domain(isl_union_map_copy(StmtSchedule))); 450 STMT_WAR = isl_union_map_intersect_domain(isl_union_map_copy(WAR), 451 isl_union_map_domain(StmtSchedule)); 452 DEBUG({ 453 dbgs() << "Wrapped Dependences:\n"; 454 dump(); 455 dbgs() << "\n"; 456 }); 457 458 // To handle reduction dependences we proceed as follows: 459 // 1) Aggregate all possible reduction dependences, namely all self 460 // dependences on reduction like statements. 461 // 2) Intersect them with the actual RAW & WAW dependences to the get the 462 // actual reduction dependences. This will ensure the load/store memory 463 // addresses were __identical__ in the two iterations of the statement. 464 // 3) Relax the original RAW and WAW dependences by subtracting the actual 465 // reduction dependences. Binary reductions (sum += A[i]) cause both, and 466 // the same, RAW and WAW dependences. 467 // 4) Add the privatization dependences which are widened versions of 468 // already present dependences. They model the effect of manual 469 // privatization at the outermost possible place (namely after the last 470 // write and before the first access to a reduction location). 471 472 // Step 1) 473 RED = isl_union_map_empty(isl_union_map_get_space(RAW)); 474 for (ScopStmt &Stmt : S) { 475 for (MemoryAccess *MA : Stmt) { 476 if (!MA->isReductionLike()) 477 continue; 478 isl_set *AccDomW = isl_map_wrap(MA->getAccessRelation()); 479 isl_map *Identity = 480 isl_map_from_domain_and_range(isl_set_copy(AccDomW), AccDomW); 481 RED = isl_union_map_add_map(RED, Identity); 482 } 483 } 484 485 // Step 2) 486 RED = isl_union_map_intersect(RED, isl_union_map_copy(RAW)); 487 RED = isl_union_map_intersect(RED, isl_union_map_copy(WAW)); 488 489 if (!isl_union_map_is_empty(RED)) { 490 491 // Step 3) 492 RAW = isl_union_map_subtract(RAW, isl_union_map_copy(RED)); 493 WAW = isl_union_map_subtract(WAW, isl_union_map_copy(RED)); 494 495 // Step 4) 496 addPrivatizationDependences(); 497 } 498 499 DEBUG({ 500 dbgs() << "Final Wrapped Dependences:\n"; 501 dump(); 502 dbgs() << "\n"; 503 }); 504 505 // RED_SIN is used to collect all reduction dependences again after we 506 // split them according to the causing memory accesses. The current assumption 507 // is that our method of splitting will not have any leftovers. In the end 508 // we validate this assumption until we have more confidence in this method. 509 isl_union_map *RED_SIN = isl_union_map_empty(isl_union_map_get_space(RAW)); 510 511 // For each reduction like memory access, check if there are reduction 512 // dependences with the access relation of the memory access as a domain 513 // (wrapped space!). If so these dependences are caused by this memory access. 514 // We then move this portion of reduction dependences back to the statement -> 515 // statement space and add a mapping from the memory access to these 516 // dependences. 517 for (ScopStmt &Stmt : S) { 518 for (MemoryAccess *MA : Stmt) { 519 if (!MA->isReductionLike()) 520 continue; 521 522 isl_set *AccDomW = isl_map_wrap(MA->getAccessRelation()); 523 isl_union_map *AccRedDepU = isl_union_map_intersect_domain( 524 isl_union_map_copy(TC_RED), isl_union_set_from_set(AccDomW)); 525 if (isl_union_map_is_empty(AccRedDepU) && !isl_union_map_free(AccRedDepU)) 526 continue; 527 528 isl_map *AccRedDep = isl_map_from_union_map(AccRedDepU); 529 RED_SIN = isl_union_map_add_map(RED_SIN, isl_map_copy(AccRedDep)); 530 AccRedDep = isl_map_zip(AccRedDep); 531 AccRedDep = isl_set_unwrap(isl_map_domain(AccRedDep)); 532 setReductionDependences(MA, AccRedDep); 533 } 534 } 535 536 assert(isl_union_map_is_equal(RED_SIN, TC_RED) && 537 "Intersecting the reduction dependence domain with the wrapped access " 538 "relation is not enough, we need to loosen the access relation also"); 539 isl_union_map_free(RED_SIN); 540 541 RAW = isl_union_map_zip(RAW); 542 WAW = isl_union_map_zip(WAW); 543 WAR = isl_union_map_zip(WAR); 544 RED = isl_union_map_zip(RED); 545 TC_RED = isl_union_map_zip(TC_RED); 546 547 DEBUG({ 548 dbgs() << "Zipped Dependences:\n"; 549 dump(); 550 dbgs() << "\n"; 551 }); 552 553 RAW = isl_union_set_unwrap(isl_union_map_domain(RAW)); 554 WAW = isl_union_set_unwrap(isl_union_map_domain(WAW)); 555 WAR = isl_union_set_unwrap(isl_union_map_domain(WAR)); 556 RED = isl_union_set_unwrap(isl_union_map_domain(RED)); 557 TC_RED = isl_union_set_unwrap(isl_union_map_domain(TC_RED)); 558 559 DEBUG({ 560 dbgs() << "Unwrapped Dependences:\n"; 561 dump(); 562 dbgs() << "\n"; 563 }); 564 565 RAW = isl_union_map_union(RAW, STMT_RAW); 566 WAW = isl_union_map_union(WAW, STMT_WAW); 567 WAR = isl_union_map_union(WAR, STMT_WAR); 568 569 RAW = isl_union_map_coalesce(RAW); 570 WAW = isl_union_map_coalesce(WAW); 571 WAR = isl_union_map_coalesce(WAR); 572 RED = isl_union_map_coalesce(RED); 573 TC_RED = isl_union_map_coalesce(TC_RED); 574 575 DEBUG(dump()); 576 } 577 578 bool Dependences::isValidSchedule(Scop &S, 579 StatementToIslMapTy *NewSchedule) const { 580 if (LegalityCheckDisabled) 581 return true; 582 583 isl_union_map *Dependences = getDependences(TYPE_RAW | TYPE_WAW | TYPE_WAR); 584 isl_space *Space = S.getParamSpace(); 585 isl_union_map *Schedule = isl_union_map_empty(Space); 586 587 isl_space *ScheduleSpace = nullptr; 588 589 for (ScopStmt &Stmt : S) { 590 isl_map *StmtScat; 591 592 if (NewSchedule->find(&Stmt) == NewSchedule->end()) 593 StmtScat = Stmt.getSchedule(); 594 else 595 StmtScat = isl_map_copy((*NewSchedule)[&Stmt]); 596 597 if (!ScheduleSpace) 598 ScheduleSpace = isl_space_range(isl_map_get_space(StmtScat)); 599 600 Schedule = isl_union_map_add_map(Schedule, StmtScat); 601 } 602 603 Dependences = 604 isl_union_map_apply_domain(Dependences, isl_union_map_copy(Schedule)); 605 Dependences = isl_union_map_apply_range(Dependences, Schedule); 606 607 isl_set *Zero = isl_set_universe(isl_space_copy(ScheduleSpace)); 608 for (unsigned i = 0; i < isl_set_dim(Zero, isl_dim_set); i++) 609 Zero = isl_set_fix_si(Zero, isl_dim_set, i, 0); 610 611 isl_union_set *UDeltas = isl_union_map_deltas(Dependences); 612 isl_set *Deltas = isl_union_set_extract_set(UDeltas, ScheduleSpace); 613 isl_union_set_free(UDeltas); 614 615 isl_map *NonPositive = isl_set_lex_le_set(Deltas, Zero); 616 bool IsValid = isl_map_is_empty(NonPositive); 617 isl_map_free(NonPositive); 618 619 return IsValid; 620 } 621 622 // Check if the current scheduling dimension is parallel. 623 // 624 // We check for parallelism by verifying that the loop does not carry any 625 // dependences. 626 // 627 // Parallelism test: if the distance is zero in all outer dimensions, then it 628 // has to be zero in the current dimension as well. 629 // 630 // Implementation: first, translate dependences into time space, then force 631 // outer dimensions to be equal. If the distance is zero in the current 632 // dimension, then the loop is parallel. The distance is zero in the current 633 // dimension if it is a subset of a map with equal values for the current 634 // dimension. 635 bool Dependences::isParallel(isl_union_map *Schedule, isl_union_map *Deps, 636 isl_pw_aff **MinDistancePtr) const { 637 isl_set *Deltas, *Distance; 638 isl_map *ScheduleDeps; 639 unsigned Dimension; 640 bool IsParallel; 641 642 Deps = isl_union_map_apply_range(Deps, isl_union_map_copy(Schedule)); 643 Deps = isl_union_map_apply_domain(Deps, isl_union_map_copy(Schedule)); 644 645 if (isl_union_map_is_empty(Deps)) { 646 isl_union_map_free(Deps); 647 return true; 648 } 649 650 ScheduleDeps = isl_map_from_union_map(Deps); 651 Dimension = isl_map_dim(ScheduleDeps, isl_dim_out) - 1; 652 653 for (unsigned i = 0; i < Dimension; i++) 654 ScheduleDeps = isl_map_equate(ScheduleDeps, isl_dim_out, i, isl_dim_in, i); 655 656 Deltas = isl_map_deltas(ScheduleDeps); 657 Distance = isl_set_universe(isl_set_get_space(Deltas)); 658 659 // [0, ..., 0, +] - All zeros and last dimension larger than zero 660 for (unsigned i = 0; i < Dimension; i++) 661 Distance = isl_set_fix_si(Distance, isl_dim_set, i, 0); 662 663 Distance = isl_set_lower_bound_si(Distance, isl_dim_set, Dimension, 1); 664 Distance = isl_set_intersect(Distance, Deltas); 665 666 IsParallel = isl_set_is_empty(Distance); 667 if (IsParallel || !MinDistancePtr) { 668 isl_set_free(Distance); 669 return IsParallel; 670 } 671 672 Distance = isl_set_project_out(Distance, isl_dim_set, 0, Dimension); 673 Distance = isl_set_coalesce(Distance); 674 675 // This last step will compute a expression for the minimal value in the 676 // distance polyhedron Distance with regards to the first (outer most) 677 // dimension. 678 *MinDistancePtr = isl_pw_aff_coalesce(isl_set_dim_min(Distance, 0)); 679 680 return false; 681 } 682 683 static void printDependencyMap(raw_ostream &OS, __isl_keep isl_union_map *DM) { 684 if (DM) 685 OS << DM << "\n"; 686 else 687 OS << "n/a\n"; 688 } 689 690 void Dependences::print(raw_ostream &OS) const { 691 OS << "\tRAW dependences:\n\t\t"; 692 printDependencyMap(OS, RAW); 693 OS << "\tWAR dependences:\n\t\t"; 694 printDependencyMap(OS, WAR); 695 OS << "\tWAW dependences:\n\t\t"; 696 printDependencyMap(OS, WAW); 697 OS << "\tReduction dependences:\n\t\t"; 698 printDependencyMap(OS, RED); 699 OS << "\tTransitive closure of reduction dependences:\n\t\t"; 700 printDependencyMap(OS, TC_RED); 701 } 702 703 void Dependences::dump() const { print(dbgs()); } 704 705 void Dependences::releaseMemory() { 706 isl_union_map_free(RAW); 707 isl_union_map_free(WAR); 708 isl_union_map_free(WAW); 709 isl_union_map_free(RED); 710 isl_union_map_free(TC_RED); 711 712 RED = RAW = WAR = WAW = TC_RED = nullptr; 713 714 for (auto &ReductionDeps : ReductionDependences) 715 isl_map_free(ReductionDeps.second); 716 ReductionDependences.clear(); 717 } 718 719 isl_union_map *Dependences::getDependences(int Kinds) const { 720 assert(hasValidDependences() && "No valid dependences available"); 721 isl_space *Space = isl_union_map_get_space(RAW); 722 isl_union_map *Deps = isl_union_map_empty(Space); 723 724 if (Kinds & TYPE_RAW) 725 Deps = isl_union_map_union(Deps, isl_union_map_copy(RAW)); 726 727 if (Kinds & TYPE_WAR) 728 Deps = isl_union_map_union(Deps, isl_union_map_copy(WAR)); 729 730 if (Kinds & TYPE_WAW) 731 Deps = isl_union_map_union(Deps, isl_union_map_copy(WAW)); 732 733 if (Kinds & TYPE_RED) 734 Deps = isl_union_map_union(Deps, isl_union_map_copy(RED)); 735 736 if (Kinds & TYPE_TC_RED) 737 Deps = isl_union_map_union(Deps, isl_union_map_copy(TC_RED)); 738 739 Deps = isl_union_map_coalesce(Deps); 740 Deps = isl_union_map_detect_equalities(Deps); 741 return Deps; 742 } 743 744 bool Dependences::hasValidDependences() const { 745 return (RAW != nullptr) && (WAR != nullptr) && (WAW != nullptr); 746 } 747 748 isl_map *Dependences::getReductionDependences(MemoryAccess *MA) const { 749 return isl_map_copy(ReductionDependences.lookup(MA)); 750 } 751 752 void Dependences::setReductionDependences(MemoryAccess *MA, isl_map *D) { 753 assert(ReductionDependences.count(MA) == 0 && 754 "Reduction dependences set twice!"); 755 ReductionDependences[MA] = D; 756 } 757 758 const Dependences & 759 DependenceInfo::getDependences(Dependences::AnalyisLevel Level) { 760 if (Dependences *d = D[Level].get()) 761 return *d; 762 763 return recomputeDependences(Level); 764 } 765 766 const Dependences & 767 DependenceInfo::recomputeDependences(Dependences::AnalyisLevel Level) { 768 D[Level].reset(new Dependences(S->getSharedIslCtx(), Level)); 769 D[Level]->calculateDependences(*S); 770 return *D[Level]; 771 } 772 773 bool DependenceInfo::runOnScop(Scop &ScopVar) { 774 S = &ScopVar; 775 return false; 776 } 777 778 /// @brief Print the dependences for the given SCoP to @p OS. 779 780 void polly::DependenceInfo::printScop(raw_ostream &OS, Scop &S) const { 781 if (auto d = D[OptAnalysisLevel].get()) { 782 d->print(OS); 783 return; 784 } 785 786 // Otherwise create the dependences on-the-fly and print it 787 Dependences D(S.getSharedIslCtx(), OptAnalysisLevel); 788 D.calculateDependences(S); 789 D.print(OS); 790 } 791 792 void DependenceInfo::getAnalysisUsage(AnalysisUsage &AU) const { 793 AU.addRequiredTransitive<ScopInfo>(); 794 AU.setPreservesAll(); 795 } 796 797 char DependenceInfo::ID = 0; 798 799 Pass *polly::createDependenceInfoPass() { return new DependenceInfo(); } 800 801 INITIALIZE_PASS_BEGIN(DependenceInfo, "polly-dependences", 802 "Polly - Calculate dependences", false, false); 803 INITIALIZE_PASS_DEPENDENCY(ScopInfo); 804 INITIALIZE_PASS_END(DependenceInfo, "polly-dependences", 805 "Polly - Calculate dependences", false, false) 806