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