1 //===------ DeLICM.cpp -----------------------------------------*- C++ -*-===// 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 // Undo the effect of Loop Invariant Code Motion (LICM) and 11 // GVN Partial Redundancy Elimination (PRE) on SCoP-level. 12 // 13 // Namely, remove register/scalar dependencies by mapping them back to array 14 // elements. 15 // 16 // The algorithms here work on the scatter space - the image space of the 17 // schedule returned by Scop::getSchedule(). We call an element in that space a 18 // "timepoint". Timepoints are lexicographically ordered such that we can 19 // defined ranges in the scatter space. We use two flavors of such ranges: 20 // Timepoint sets and zones. A timepoint set is simply a subset of the scatter 21 // space and is directly stored as isl_set. 22 // 23 // Zones are used to describe the space between timepoints as open sets, i.e. 24 // they do not contain the extrema. Using isl rational sets to express these 25 // would be overkill. We also cannot store them as the integer timepoints they 26 // contain; the (nonempty) zone between 1 and 2 would be empty and 27 // indistinguishable from e.g. the zone between 3 and 4. Also, we cannot store 28 // the integer set including the extrema; the set ]1,2[ + ]3,4[ could be 29 // coalesced to ]1,3[, although we defined the range [2,3] to be not in the set. 30 // Instead, we store the "half-open" integer extrema, including the lower bound, 31 // but excluding the upper bound. Examples: 32 // 33 // * The set { [i] : 1 <= i <= 3 } represents the zone ]0,3[ (which contains the 34 // integer points 1 and 2, but not 0 or 3) 35 // 36 // * { [1] } represents the zone ]0,1[ 37 // 38 // * { [i] : i = 1 or i = 3 } represents the zone ]0,1[ + ]2,3[ 39 // 40 // Therefore, an integer i in the set represents the zone ]i-1,i[, i.e. strictly 41 // speaking the integer points never belong to the zone. However, depending an 42 // the interpretation, one might want to include them. Part of the 43 // interpretation may not be known when the zone is constructed. 44 // 45 // Reads are assumed to always take place before writes, hence we can think of 46 // reads taking place at the beginning of a timepoint and writes at the end. 47 // 48 // Let's assume that the zone represents the lifetime of a variable. That is, 49 // the zone begins with a write that defines the value during its lifetime and 50 // ends with the last read of that value. In the following we consider whether a 51 // read/write at the beginning/ending of the lifetime zone should be within the 52 // zone or outside of it. 53 // 54 // * A read at the timepoint that starts the live-range loads the previous 55 // value. Hence, exclude the timepoint starting the zone. 56 // 57 // * A write at the timepoint that starts the live-range is not defined whether 58 // it occurs before or after the write that starts the lifetime. We do not 59 // allow this situation to occur. Hence, we include the timepoint starting the 60 // zone to determine whether they are conflicting. 61 // 62 // * A read at the timepoint that ends the live-range reads the same variable. 63 // We include the timepoint at the end of the zone to include that read into 64 // the live-range. Doing otherwise would mean that the two reads access 65 // different values, which would mean that the value they read are both alive 66 // at the same time but occupy the same variable. 67 // 68 // * A write at the timepoint that ends the live-range starts a new live-range. 69 // It must not be included in the live-range of the previous definition. 70 // 71 // All combinations of reads and writes at the endpoints are possible, but most 72 // of the time only the write->read (for instance, a live-range from definition 73 // to last use) and read->write (for instance, an unused range from last use to 74 // overwrite) and combinations are interesting (half-open ranges). write->write 75 // zones might be useful as well in some context to represent 76 // output-dependencies. 77 // 78 // @see convertZoneToTimepoints 79 // 80 // 81 // The code makes use of maps and sets in many different spaces. To not loose 82 // track in which space a set or map is expected to be in, variables holding an 83 // isl reference are usually annotated in the comments. They roughly follow isl 84 // syntax for spaces, but only the tuples, not the dimensions. The tuples have a 85 // meaning as follows: 86 // 87 // * Space[] - An unspecified tuple. Used for function parameters such that the 88 // function caller can use it for anything they like. 89 // 90 // * Domain[] - A statement instance as returned by ScopStmt::getDomain() 91 // isl_id_get_name: Stmt_<NameOfBasicBlock> 92 // isl_id_get_user: Pointer to ScopStmt 93 // 94 // * Element[] - An array element as in the range part of 95 // MemoryAccess::getAccessRelation() 96 // isl_id_get_name: MemRef_<NameOfArrayVariable> 97 // isl_id_get_user: Pointer to ScopArrayInfo 98 // 99 // * Scatter[] - Scatter space or space of timepoints 100 // Has no tuple id 101 // 102 // * Zone[] - Range between timepoints as described above 103 // Has no tuple id 104 // 105 // An annotation "{ Domain[] -> Scatter[] }" therefore means: A map from a 106 // statement instance to a timepoint, aka a schedule. There is only one scatter 107 // space, but most of the time multiple statements are processed in one set. 108 // This is why most of the time isl_union_map has to be used. 109 // 110 // The basic algorithm works as follows: 111 // At first we verify that the SCoP is compatible with this technique. For 112 // instance, two writes cannot write to the same location at the same statement 113 // instance because we cannot determine within the polyhedral model which one 114 // comes first. Once this was verified, we compute zones at which an array 115 // element is unused. This computation can fail if it takes too long. Then the 116 // main algorithm is executed. Because every store potentially trails an unused 117 // zone, we start at stores. We search for a scalar (MemoryKind::Value or 118 // MemoryKind::PHI) that we can map to the array element overwritten by the 119 // store, preferably one that is used by the store or at least the ScopStmt. 120 // When it does not conflict with the lifetime of the values in the array 121 // element, the map is applied and the unused zone updated as it is now used. We 122 // continue to try to map scalars to the array element until there are no more 123 // candidates to map. The algorithm is greedy in the sense that the first scalar 124 // not conflicting will be mapped. Other scalars processed later that could have 125 // fit the same unused zone will be rejected. As such the result depends on the 126 // processing order. 127 // 128 //===----------------------------------------------------------------------===// 129 130 #include "polly/DeLICM.h" 131 #include "polly/Options.h" 132 #include "polly/ScopInfo.h" 133 #include "polly/ScopPass.h" 134 #include "polly/Support/ISLTools.h" 135 #include "llvm/ADT/Statistic.h" 136 #define DEBUG_TYPE "polly-delicm" 137 138 using namespace polly; 139 using namespace llvm; 140 141 namespace { 142 143 cl::opt<int> 144 DelicmMaxOps("polly-delicm-max-ops", 145 cl::desc("Maximum number of isl operations to invest for " 146 "lifetime analysis; 0=no limit"), 147 cl::init(1000000), cl::cat(PollyCategory)); 148 149 STATISTIC(DeLICMAnalyzed, "Number of successfully analyzed SCoPs"); 150 STATISTIC(DeLICMOutOfQuota, 151 "Analyses aborted because max_operations was reached"); 152 STATISTIC(DeLICMIncompatible, "Number of SCoPs incompatible for analysis"); 153 STATISTIC(MappedValueScalars, "Number of mapped Value scalars"); 154 STATISTIC(MappedPHIScalars, "Number of mapped PHI scalars"); 155 STATISTIC(TargetsMapped, "Number of stores used for at least one mapping"); 156 STATISTIC(DeLICMScopsModified, "Number of SCoPs optimized"); 157 158 /// Class for keeping track of scalar def-use chains in the polyhedral 159 /// representation. 160 /// 161 /// MemoryKind::Value: 162 /// There is one definition per llvm::Value or zero (read-only values defined 163 /// before the SCoP) and an arbitrary number of reads. 164 /// 165 /// MemoryKind::PHI, MemoryKind::ExitPHI: 166 /// There is at least one write (the incoming blocks/stmts) and one 167 /// (MemoryKind::PHI) or zero (MemoryKind::ExitPHI) reads per llvm::PHINode. 168 class ScalarDefUseChains { 169 private: 170 /// The definitions (i.e. write MemoryAccess) of a MemoryKind::Value scalar. 171 DenseMap<const ScopArrayInfo *, MemoryAccess *> ValueDefAccs; 172 173 /// List of all uses (i.e. read MemoryAccesses) for a MemoryKind::Value 174 /// scalar. 175 DenseMap<const ScopArrayInfo *, SmallVector<MemoryAccess *, 4>> ValueUseAccs; 176 177 /// The receiving part (i.e. read MemoryAccess) of a MemoryKind::PHI scalar. 178 DenseMap<const ScopArrayInfo *, MemoryAccess *> PHIReadAccs; 179 180 /// List of all incoming values (write MemoryAccess) of a MemoryKind::PHI or 181 /// MemoryKind::ExitPHI scalar. 182 DenseMap<const ScopArrayInfo *, SmallVector<MemoryAccess *, 4>> 183 PHIIncomingAccs; 184 185 public: 186 /// Find the MemoryAccesses that access the ScopArrayInfo-represented memory. 187 /// 188 /// @param S The SCoP to analyze. 189 void compute(Scop *S) { 190 // Purge any previous result. 191 reset(); 192 193 for (auto &Stmt : *S) { 194 for (auto *MA : Stmt) { 195 if (MA->isOriginalValueKind() && MA->isWrite()) { 196 auto *SAI = MA->getScopArrayInfo(); 197 assert(!ValueDefAccs.count(SAI) && 198 "There can be at most one " 199 "definition per MemoryKind::Value scalar"); 200 ValueDefAccs[SAI] = MA; 201 } 202 203 if (MA->isOriginalValueKind() && MA->isRead()) 204 ValueUseAccs[MA->getScopArrayInfo()].push_back(MA); 205 206 if (MA->isOriginalAnyPHIKind() && MA->isRead()) { 207 auto *SAI = MA->getScopArrayInfo(); 208 assert(!PHIReadAccs.count(SAI) && 209 "There must be exactly one read " 210 "per PHI (that's where the PHINode is)"); 211 PHIReadAccs[SAI] = MA; 212 } 213 214 if (MA->isOriginalAnyPHIKind() && MA->isWrite()) 215 PHIIncomingAccs[MA->getScopArrayInfo()].push_back(MA); 216 } 217 } 218 } 219 220 /// Free all memory used by the analysis. 221 void reset() { 222 ValueDefAccs.clear(); 223 ValueUseAccs.clear(); 224 PHIReadAccs.clear(); 225 PHIIncomingAccs.clear(); 226 } 227 228 MemoryAccess *getValueDef(const ScopArrayInfo *SAI) const { 229 return ValueDefAccs.lookup(SAI); 230 } 231 232 ArrayRef<MemoryAccess *> getValueUses(const ScopArrayInfo *SAI) const { 233 auto It = ValueUseAccs.find(SAI); 234 if (It == ValueUseAccs.end()) 235 return {}; 236 return It->second; 237 } 238 239 MemoryAccess *getPHIRead(const ScopArrayInfo *SAI) const { 240 return PHIReadAccs.lookup(SAI); 241 } 242 243 ArrayRef<MemoryAccess *> getPHIIncomings(const ScopArrayInfo *SAI) const { 244 auto It = PHIIncomingAccs.find(SAI); 245 if (It == PHIIncomingAccs.end()) 246 return {}; 247 return It->second; 248 } 249 }; 250 251 IslPtr<isl_union_map> computeReachingDefinition(IslPtr<isl_union_map> Schedule, 252 IslPtr<isl_union_map> Writes, 253 bool InclDef, bool InclRedef) { 254 return computeReachingWrite(Schedule, Writes, false, InclDef, InclRedef); 255 } 256 257 IslPtr<isl_union_map> computeReachingOverwrite(IslPtr<isl_union_map> Schedule, 258 IslPtr<isl_union_map> Writes, 259 bool InclPrevWrite, 260 bool InclOverwrite) { 261 return computeReachingWrite(Schedule, Writes, true, InclPrevWrite, 262 InclOverwrite); 263 } 264 265 /// Compute the next overwrite for a scalar. 266 /// 267 /// @param Schedule { DomainWrite[] -> Scatter[] } 268 /// Schedule of (at least) all writes. Instances not in @p 269 /// Writes are ignored. 270 /// @param Writes { DomainWrite[] } 271 /// The element instances that write to the scalar. 272 /// @param InclPrevWrite Whether to extend the timepoints to include 273 /// the timepoint where the previous write happens. 274 /// @param InclOverwrite Whether the reaching overwrite includes the timepoint 275 /// of the overwrite itself. 276 /// 277 /// @return { Scatter[] -> DomainDef[] } 278 IslPtr<isl_union_map> 279 computeScalarReachingOverwrite(IslPtr<isl_union_map> Schedule, 280 IslPtr<isl_union_set> Writes, bool InclPrevWrite, 281 bool InclOverwrite) { 282 283 // { DomainWrite[] } 284 auto WritesMap = give(isl_union_map_from_domain(Writes.take())); 285 286 // { [Element[] -> Scatter[]] -> DomainWrite[] } 287 auto Result = computeReachingOverwrite( 288 std::move(Schedule), std::move(WritesMap), InclPrevWrite, InclOverwrite); 289 290 return give(isl_union_map_domain_factor_range(Result.take())); 291 } 292 293 /// Overload of computeScalarReachingOverwrite, with only one writing statement. 294 /// Consequently, the result consists of only one map space. 295 /// 296 /// @param Schedule { DomainWrite[] -> Scatter[] } 297 /// @param Writes { DomainWrite[] } 298 /// @param InclPrevWrite Include the previous write to result. 299 /// @param InclOverwrite Include the overwrite to the result. 300 /// 301 /// @return { Scatter[] -> DomainWrite[] } 302 IslPtr<isl_map> computeScalarReachingOverwrite(IslPtr<isl_union_map> Schedule, 303 IslPtr<isl_set> Writes, 304 bool InclPrevWrite, 305 bool InclOverwrite) { 306 auto ScatterSpace = getScatterSpace(Schedule); 307 auto DomSpace = give(isl_set_get_space(Writes.keep())); 308 309 auto ReachOverwrite = computeScalarReachingOverwrite( 310 Schedule, give(isl_union_set_from_set(Writes.take())), InclPrevWrite, 311 InclOverwrite); 312 313 auto ResultSpace = give(isl_space_map_from_domain_and_range( 314 ScatterSpace.take(), DomSpace.take())); 315 return singleton(std::move(ReachOverwrite), ResultSpace); 316 } 317 318 /// Compute the reaching definition of a scalar. 319 /// 320 /// Compared to computeReachingDefinition, there is just one element which is 321 /// accessed and therefore only a set if instances that accesses that element is 322 /// required. 323 /// 324 /// @param Schedule { DomainWrite[] -> Scatter[] } 325 /// @param Writes { DomainWrite[] } 326 /// @param InclDef Include the timepoint of the definition to the result. 327 /// @param InclRedef Include the timepoint of the overwrite into the result. 328 /// 329 /// @return { Scatter[] -> DomainWrite[] } 330 IslPtr<isl_union_map> 331 computeScalarReachingDefinition(IslPtr<isl_union_map> Schedule, 332 IslPtr<isl_union_set> Writes, bool InclDef, 333 bool InclRedef) { 334 335 // { DomainWrite[] -> Element[] } 336 auto Defs = give(isl_union_map_from_domain(Writes.take())); 337 338 // { [Element[] -> Scatter[]] -> DomainWrite[] } 339 auto ReachDefs = 340 computeReachingDefinition(Schedule, Defs, InclDef, InclRedef); 341 342 // { Scatter[] -> DomainWrite[] } 343 return give(isl_union_set_unwrap( 344 isl_union_map_range(isl_union_map_curry(ReachDefs.take())))); 345 } 346 347 /// Compute the reaching definition of a scalar. 348 /// 349 /// This overload accepts only a single writing statement as an isl_map, 350 /// consequently the result also is only a single isl_map. 351 /// 352 /// @param Schedule { DomainWrite[] -> Scatter[] } 353 /// @param Writes { DomainWrite[] } 354 /// @param InclDef Include the timepoint of the definition to the result. 355 /// @param InclRedef Include the timepoint of the overwrite into the result. 356 /// 357 /// @return { Scatter[] -> DomainWrite[] } 358 IslPtr<isl_map> computeScalarReachingDefinition( // { Domain[] -> Zone[] } 359 IslPtr<isl_union_map> Schedule, IslPtr<isl_set> Writes, bool InclDef, 360 bool InclRedef) { 361 auto DomainSpace = give(isl_set_get_space(Writes.keep())); 362 auto ScatterSpace = getScatterSpace(Schedule); 363 364 // { Scatter[] -> DomainWrite[] } 365 auto UMap = computeScalarReachingDefinition( 366 Schedule, give(isl_union_set_from_set(Writes.take())), InclDef, 367 InclRedef); 368 369 auto ResultSpace = give(isl_space_map_from_domain_and_range( 370 ScatterSpace.take(), DomainSpace.take())); 371 return singleton(UMap, ResultSpace); 372 } 373 374 /// If InputVal is not defined in the stmt itself, return the MemoryAccess that 375 /// reads the scalar. Return nullptr otherwise (if the value is defined in the 376 /// scop, or is synthesizable). 377 MemoryAccess *getInputAccessOf(Value *InputVal, ScopStmt *Stmt) { 378 for (auto *MA : *Stmt) { 379 if (!MA->isRead()) 380 continue; 381 if (!MA->isLatestScalarKind()) 382 continue; 383 384 assert(MA->getAccessValue() == MA->getBaseAddr()); 385 if (MA->getAccessValue() == InputVal) 386 return MA; 387 } 388 return nullptr; 389 } 390 391 /// Represent the knowledge of the contents of any array elements in any zone or 392 /// the knowledge we would add when mapping a scalar to an array element. 393 /// 394 /// Every array element at every zone unit has one of two states: 395 /// 396 /// - Unused: Not occupied by any value so a transformation can change it to 397 /// other values. 398 /// 399 /// - Occupied: The element contains a value that is still needed. 400 /// 401 /// The union of Unused and Unknown zones forms the universe, the set of all 402 /// elements at every timepoint. The universe can easily be derived from the 403 /// array elements that are accessed someway. Arrays that are never accessed 404 /// also never play a role in any computation and can hence be ignored. With a 405 /// given universe, only one of the sets needs to stored implicitly. Computing 406 /// the complement is also an expensive operation, hence this class has been 407 /// designed that only one of sets is needed while the other is assumed to be 408 /// implicit. It can still be given, but is mostly ignored. 409 /// 410 /// There are two use cases for the Knowledge class: 411 /// 412 /// 1) To represent the knowledge of the current state of ScopInfo. The unused 413 /// state means that an element is currently unused: there is no read of it 414 /// before the next overwrite. Also called 'Existing'. 415 /// 416 /// 2) To represent the requirements for mapping a scalar to array elements. The 417 /// unused state means that there is no change/requirement. Also called 418 /// 'Proposed'. 419 /// 420 /// In addition to these states at unit zones, Knowledge needs to know when 421 /// values are written. This is because written values may have no lifetime (one 422 /// reason is that the value is never read). Such writes would therefore never 423 /// conflict, but overwrite values that might still be required. Another source 424 /// of problems are multiple writes to the same element at the same timepoint, 425 /// because their order is undefined. 426 class Knowledge { 427 private: 428 /// { [Element[] -> Zone[]] } 429 /// Set of array elements and when they are alive. 430 /// Can contain a nullptr; in this case the set is implicitly defined as the 431 /// complement of #Unused. 432 /// 433 /// The set of alive array elements is represented as zone, as the set of live 434 /// values can differ depending on how the elements are interpreted. 435 /// Assuming a value X is written at timestep [0] and read at timestep [1] 436 /// without being used at any later point, then the value is alive in the 437 /// interval ]0,1[. This interval cannot be represented by an integer set, as 438 /// it does not contain any integer point. Zones allow us to represent this 439 /// interval and can be converted to sets of timepoints when needed (e.g., in 440 /// isConflicting when comparing to the write sets). 441 /// @see convertZoneToTimepoints and this file's comment for more details. 442 IslPtr<isl_union_set> Occupied; 443 444 /// { [Element[] -> Zone[]] } 445 /// Set of array elements when they are not alive, i.e. their memory can be 446 /// used for other purposed. Can contain a nullptr; in this case the set is 447 /// implicitly defined as the complement of #Occupied. 448 IslPtr<isl_union_set> Unused; 449 450 /// { [Element[] -> Scatter[]] } 451 /// The write actions currently in the scop or that would be added when 452 /// mapping a scalar. 453 IslPtr<isl_union_set> Written; 454 455 /// Check whether this Knowledge object is well-formed. 456 void checkConsistency() const { 457 #ifndef NDEBUG 458 // Default-initialized object 459 if (!Occupied && !Unused && !Written) 460 return; 461 462 assert(Occupied || Unused); 463 assert(Written); 464 465 // If not all fields are defined, we cannot derived the universe. 466 if (!Occupied || !Unused) 467 return; 468 469 assert(isl_union_set_is_disjoint(Occupied.keep(), Unused.keep()) == 470 isl_bool_true); 471 auto Universe = give(isl_union_set_union(Occupied.copy(), Unused.copy())); 472 assert(isl_union_set_is_subset(Written.keep(), Universe.keep()) == 473 isl_bool_true); 474 #endif 475 } 476 477 public: 478 /// Initialize a nullptr-Knowledge. This is only provided for convenience; do 479 /// not use such an object. 480 Knowledge() {} 481 482 /// Create a new object with the given members. 483 Knowledge(IslPtr<isl_union_set> Occupied, IslPtr<isl_union_set> Unused, 484 IslPtr<isl_union_set> Written) 485 : Occupied(std::move(Occupied)), Unused(std::move(Unused)), 486 Written(std::move(Written)) { 487 checkConsistency(); 488 } 489 490 /// Alternative constructor taking isl_sets instead isl_union_sets. 491 Knowledge(IslPtr<isl_set> Occupied, IslPtr<isl_set> Unused, 492 IslPtr<isl_set> Written) 493 : Knowledge(give(isl_union_set_from_set(Occupied.take())), 494 give(isl_union_set_from_set(Unused.take())), 495 give(isl_union_set_from_set(Written.take()))) {} 496 497 /// Return whether this object was not default-constructed. 498 bool isUsable() const { return (Occupied || Unused) && Written; } 499 500 /// Print the content of this object to @p OS. 501 void print(llvm::raw_ostream &OS, unsigned Indent = 0) const { 502 if (isUsable()) { 503 if (Occupied) 504 OS.indent(Indent) << "Occupied: " << Occupied << "\n"; 505 else 506 OS.indent(Indent) << "Occupied: <Everything else not in Unused>\n"; 507 if (Unused) 508 OS.indent(Indent) << "Unused: " << Unused << "\n"; 509 else 510 OS.indent(Indent) << "Unused: <Everything else not in Occupied>\n"; 511 OS.indent(Indent) << "Written : " << Written << '\n'; 512 } else { 513 OS.indent(Indent) << "Invalid knowledge\n"; 514 } 515 } 516 517 /// Combine two knowledges, this and @p That. 518 void learnFrom(Knowledge That) { 519 assert(!isConflicting(*this, That)); 520 assert(Unused && That.Occupied); 521 assert( 522 !That.Unused && 523 "This function is only prepared to learn occupied elements from That"); 524 assert(!Occupied && "This function does not implement " 525 "`this->Occupied = " 526 "give(isl_union_set_union(this->Occupied.take(), " 527 "That.Occupied.copy()));`"); 528 529 Unused = give(isl_union_set_subtract(Unused.take(), That.Occupied.copy())); 530 Written = give(isl_union_set_union(Written.take(), That.Written.take())); 531 532 checkConsistency(); 533 } 534 535 /// Determine whether two Knowledges conflict with each other. 536 /// 537 /// In theory @p Existing and @p Proposed are symmetric, but the 538 /// implementation is constrained by the implicit interpretation. That is, @p 539 /// Existing must have #Unused defined (use case 1) and @p Proposed must have 540 /// #Occupied defined (use case 1). 541 /// 542 /// A conflict is defined as non-preserved semantics when they are merged. For 543 /// instance, when for the same array and zone they assume different 544 /// llvm::Values. 545 /// 546 /// @param Existing One of the knowledges with #Unused defined. 547 /// @param Proposed One of the knowledges with #Occupied defined. 548 /// @param OS Dump the conflict reason to this output stream; use 549 /// nullptr to not output anything. 550 /// @param Indent Indention for the conflict reason. 551 /// 552 /// @return True, iff the two knowledges are conflicting. 553 static bool isConflicting(const Knowledge &Existing, 554 const Knowledge &Proposed, 555 llvm::raw_ostream *OS = nullptr, 556 unsigned Indent = 0) { 557 assert(Existing.Unused); 558 assert(Proposed.Occupied); 559 560 #ifndef NDEBUG 561 if (Existing.Occupied && Proposed.Unused) { 562 auto ExistingUniverse = give(isl_union_set_union(Existing.Occupied.copy(), 563 Existing.Unused.copy())); 564 auto ProposedUniverse = give(isl_union_set_union(Proposed.Occupied.copy(), 565 Proposed.Unused.copy())); 566 assert(isl_union_set_is_equal(ExistingUniverse.keep(), 567 ProposedUniverse.keep()) == isl_bool_true && 568 "Both inputs' Knowledges must be over the same universe"); 569 } 570 #endif 571 572 // Are the new lifetimes required for Proposed unused in Existing? 573 if (isl_union_set_is_subset(Proposed.Occupied.keep(), 574 Existing.Unused.keep()) != isl_bool_true) { 575 if (OS) { 576 auto ConflictingLifetimes = give(isl_union_set_subtract( 577 Proposed.Occupied.copy(), Existing.Unused.copy())); 578 OS->indent(Indent) << "Proposed lifetimes are not unused in existing\n"; 579 OS->indent(Indent) << "Conflicting lifetimes: " << ConflictingLifetimes 580 << "\n"; 581 } 582 return true; 583 } 584 585 // Do the writes in Existing only overwrite unused values in Proposed? 586 // We convert here the set of lifetimes to actual timepoints. A lifetime is 587 // in conflict with a set of write timepoints, if either a live timepoint is 588 // clearly within the lifetime or if a write happens at the beginning of the 589 // lifetime (where it would conflict with the value that actually writes the 590 // value alive). There is no conflict at the end of a lifetime, as the alive 591 // value will always be read, before it is overwritten again. The last 592 // property holds in Polly for all scalar values and we expect all users of 593 // Knowledge to check this property also for accesses to MemoryKind::Array. 594 auto ProposedFixedDefs = 595 convertZoneToTimepoints(Proposed.Occupied, true, false); 596 if (isl_union_set_is_disjoint(Existing.Written.keep(), 597 ProposedFixedDefs.keep()) != isl_bool_true) { 598 if (OS) { 599 auto ConflictingWrites = give(isl_union_set_intersect( 600 Existing.Written.copy(), ProposedFixedDefs.copy())); 601 OS->indent(Indent) << "Proposed writes into range used by existing\n"; 602 OS->indent(Indent) << "Conflicting writes: " << ConflictingWrites 603 << "\n"; 604 } 605 return true; 606 } 607 608 // Do the new writes in Proposed only overwrite unused values in Existing? 609 auto ExistingAvailableDefs = 610 convertZoneToTimepoints(Existing.Unused, true, false); 611 if (isl_union_set_is_subset(Proposed.Written.keep(), 612 ExistingAvailableDefs.keep()) != 613 isl_bool_true) { 614 if (OS) { 615 auto ConflictingWrites = give(isl_union_set_subtract( 616 Proposed.Written.copy(), ExistingAvailableDefs.copy())); 617 OS->indent(Indent) 618 << "Proposed a lifetime where there is an Existing write into it\n"; 619 OS->indent(Indent) << "Conflicting writes: " << ConflictingWrites 620 << "\n"; 621 } 622 return true; 623 } 624 625 // Does Proposed write at the same time as Existing already does (order of 626 // writes is undefined)? 627 if (isl_union_set_is_disjoint(Existing.Written.keep(), 628 Proposed.Written.keep()) != isl_bool_true) { 629 if (OS) { 630 auto ConflictingWrites = give(isl_union_set_intersect( 631 Existing.Written.copy(), Proposed.Written.copy())); 632 OS->indent(Indent) << "Proposed writes at the same time as an already " 633 "Existing write\n"; 634 OS->indent(Indent) << "Conflicting writes: " << ConflictingWrites 635 << "\n"; 636 } 637 return true; 638 } 639 640 return false; 641 } 642 }; 643 644 std::string printIntruction(Instruction *Instr, bool IsForDebug = false) { 645 std::string Result; 646 raw_string_ostream OS(Result); 647 Instr->print(OS, IsForDebug); 648 OS.flush(); 649 size_t i = 0; 650 while (i < Result.size() && Result[i] == ' ') 651 i += 1; 652 return Result.substr(i); 653 } 654 655 /// Base class for algorithms based on zones, like DeLICM. 656 class ZoneAlgorithm { 657 protected: 658 /// Hold a reference to the isl_ctx to avoid it being freed before we released 659 /// all of the isl objects. 660 /// 661 /// This must be declared before any other member that holds an isl object. 662 /// This guarantees that the shared_ptr and its isl_ctx is destructed last, 663 /// after all other members free'd the isl objects they were holding. 664 std::shared_ptr<isl_ctx> IslCtx; 665 666 /// Cached reaching definitions for each ScopStmt. 667 /// 668 /// Use getScalarReachingDefinition() to get its contents. 669 DenseMap<ScopStmt *, IslPtr<isl_map>> ScalarReachDefZone; 670 671 /// The analyzed Scop. 672 Scop *S; 673 674 /// Parameter space that does not need realignment. 675 IslPtr<isl_space> ParamSpace; 676 677 /// Space the schedule maps to. 678 IslPtr<isl_space> ScatterSpace; 679 680 /// Cached version of the schedule and domains. 681 IslPtr<isl_union_map> Schedule; 682 683 /// Set of all referenced elements. 684 /// { Element[] -> Element[] } 685 IslPtr<isl_union_set> AllElements; 686 687 /// Combined access relations of all MemoryKind::Array READ accesses. 688 /// { DomainRead[] -> Element[] } 689 IslPtr<isl_union_map> AllReads; 690 691 /// Combined access relations of all MemoryKind::Array, MAY_WRITE accesses. 692 /// { DomainMayWrite[] -> Element[] } 693 IslPtr<isl_union_map> AllMayWrites; 694 695 /// Combined access relations of all MemoryKind::Array, MUST_WRITE accesses. 696 /// { DomainMustWrite[] -> Element[] } 697 IslPtr<isl_union_map> AllMustWrites; 698 699 /// Prepare the object before computing the zones of @p S. 700 ZoneAlgorithm(Scop *S) 701 : IslCtx(S->getSharedIslCtx()), S(S), Schedule(give(S->getSchedule())) { 702 703 auto Domains = give(S->getDomains()); 704 705 Schedule = 706 give(isl_union_map_intersect_domain(Schedule.take(), Domains.take())); 707 ParamSpace = give(isl_union_map_get_space(Schedule.keep())); 708 ScatterSpace = getScatterSpace(Schedule); 709 } 710 711 private: 712 /// Check whether @p Stmt can be accurately analyzed by zones. 713 /// 714 /// What violates our assumptions: 715 /// - A load after a write of the same location; we assume that all reads 716 /// occur before the writes. 717 /// - Two writes to the same location; we cannot model the order in which 718 /// these occur. 719 /// 720 /// Scalar reads implicitly always occur before other accesses therefore never 721 /// violate the first condition. There is also at most one write to a scalar, 722 /// satisfying the second condition. 723 bool isCompatibleStmt(ScopStmt *Stmt) { 724 auto Stores = makeEmptyUnionMap(); 725 auto Loads = makeEmptyUnionMap(); 726 727 // This assumes that the MemoryKind::Array MemoryAccesses are iterated in 728 // order. 729 for (auto *MA : *Stmt) { 730 if (!MA->isLatestArrayKind()) 731 continue; 732 733 auto AccRel = 734 give(isl_union_map_from_map(getAccessRelationFor(MA).take())); 735 736 if (MA->isRead()) { 737 // Reject load after store to same location. 738 if (!isl_union_map_is_disjoint(Stores.keep(), AccRel.keep())) { 739 OptimizationRemarkMissed R(DEBUG_TYPE, "LoadAfterStore", 740 MA->getAccessInstruction()); 741 R << "load after store of same element in same statement"; 742 R << " (previous stores: " << Stores; 743 R << ", loading: " << AccRel << ")"; 744 S->getFunction().getContext().diagnose(R); 745 return false; 746 } 747 748 Loads = give(isl_union_map_union(Loads.take(), AccRel.take())); 749 750 continue; 751 } 752 753 if (!isa<StoreInst>(MA->getAccessInstruction())) { 754 DEBUG(dbgs() << "WRITE that is not a StoreInst not supported\n"); 755 OptimizationRemarkMissed R(DEBUG_TYPE, "UnusualStore", 756 MA->getAccessInstruction()); 757 R << "encountered write that is not a StoreInst: " 758 << printIntruction(MA->getAccessInstruction()); 759 S->getFunction().getContext().diagnose(R); 760 return false; 761 } 762 763 // In region statements the order is less clear, eg. the load and store 764 // might be in a boxed loop. 765 if (Stmt->isRegionStmt() && 766 !isl_union_map_is_disjoint(Loads.keep(), AccRel.keep())) { 767 OptimizationRemarkMissed R(DEBUG_TYPE, "StoreInSubregion", 768 MA->getAccessInstruction()); 769 R << "store is in a non-affine subregion"; 770 S->getFunction().getContext().diagnose(R); 771 return false; 772 } 773 774 // Do not allow more than one store to the same location. 775 if (!isl_union_map_is_disjoint(Stores.keep(), AccRel.keep())) { 776 OptimizationRemarkMissed R(DEBUG_TYPE, "StoreAfterStore", 777 MA->getAccessInstruction()); 778 R << "store after store of same element in same statement"; 779 R << " (previous stores: " << Stores; 780 R << ", storing: " << AccRel << ")"; 781 S->getFunction().getContext().diagnose(R); 782 return false; 783 } 784 785 Stores = give(isl_union_map_union(Stores.take(), AccRel.take())); 786 } 787 788 return true; 789 } 790 791 void addArrayReadAccess(MemoryAccess *MA) { 792 assert(MA->isLatestArrayKind()); 793 assert(MA->isRead()); 794 795 // { DomainRead[] -> Element[] } 796 auto AccRel = getAccessRelationFor(MA); 797 AllReads = give(isl_union_map_add_map(AllReads.take(), AccRel.copy())); 798 } 799 800 void addArrayWriteAccess(MemoryAccess *MA) { 801 assert(MA->isLatestArrayKind()); 802 assert(MA->isWrite()); 803 804 // { Domain[] -> Element[] } 805 auto AccRel = getAccessRelationFor(MA); 806 807 if (MA->isMustWrite()) 808 AllMustWrites = 809 give(isl_union_map_add_map(AllMustWrites.take(), AccRel.copy())); 810 811 if (MA->isMayWrite()) 812 AllMayWrites = 813 give(isl_union_map_add_map(AllMayWrites.take(), AccRel.copy())); 814 } 815 816 protected: 817 IslPtr<isl_union_set> makeEmptyUnionSet() { 818 return give(isl_union_set_empty(ParamSpace.copy())); 819 } 820 821 IslPtr<isl_union_map> makeEmptyUnionMap() { 822 return give(isl_union_map_empty(ParamSpace.copy())); 823 } 824 825 /// Check whether @p S can be accurately analyzed by zones. 826 bool isCompatibleScop() { 827 for (auto &Stmt : *S) { 828 if (!isCompatibleStmt(&Stmt)) 829 return false; 830 } 831 return true; 832 } 833 834 /// Get the schedule for @p Stmt. 835 /// 836 /// The domain of the result is as narrow as possible. 837 IslPtr<isl_map> getScatterFor(ScopStmt *Stmt) const { 838 auto ResultSpace = give(isl_space_map_from_domain_and_range( 839 Stmt->getDomainSpace(), ScatterSpace.copy())); 840 return give(isl_union_map_extract_map(Schedule.keep(), ResultSpace.take())); 841 } 842 843 /// Get the schedule of @p MA's parent statement. 844 IslPtr<isl_map> getScatterFor(MemoryAccess *MA) const { 845 return getScatterFor(MA->getStatement()); 846 } 847 848 /// Get the schedule for the statement instances of @p Domain. 849 IslPtr<isl_union_map> getScatterFor(IslPtr<isl_union_set> Domain) const { 850 return give(isl_union_map_intersect_domain(Schedule.copy(), Domain.take())); 851 } 852 853 /// Get the schedule for the statement instances of @p Domain. 854 IslPtr<isl_map> getScatterFor(IslPtr<isl_set> Domain) const { 855 auto ResultSpace = give(isl_space_map_from_domain_and_range( 856 isl_set_get_space(Domain.keep()), ScatterSpace.copy())); 857 auto UDomain = give(isl_union_set_from_set(Domain.copy())); 858 auto UResult = getScatterFor(std::move(UDomain)); 859 auto Result = singleton(std::move(UResult), std::move(ResultSpace)); 860 assert(isl_set_is_equal(give(isl_map_domain(Result.copy())).keep(), 861 Domain.keep()) == isl_bool_true); 862 return Result; 863 } 864 865 /// Get the domain of @p Stmt. 866 IslPtr<isl_set> getDomainFor(ScopStmt *Stmt) const { 867 return give(Stmt->getDomain()); 868 } 869 870 /// Get the domain @p MA's parent statement. 871 IslPtr<isl_set> getDomainFor(MemoryAccess *MA) const { 872 return getDomainFor(MA->getStatement()); 873 } 874 875 /// Get the access relation of @p MA. 876 /// 877 /// The domain of the result is as narrow as possible. 878 IslPtr<isl_map> getAccessRelationFor(MemoryAccess *MA) const { 879 auto Domain = getDomainFor(MA); 880 auto AccRel = give(MA->getLatestAccessRelation()); 881 return give(isl_map_intersect_domain(AccRel.take(), Domain.take())); 882 } 883 884 /// Get the reaching definition of a scalar defined in @p Stmt. 885 /// 886 /// Note that this does not depend on the llvm::Instruction, only on the 887 /// statement it is defined in. Therefore the same computation can be reused. 888 /// 889 /// @param Stmt The statement in which a scalar is defined. 890 /// 891 /// @return { Scatter[] -> DomainDef[] } 892 IslPtr<isl_map> getScalarReachingDefinition(ScopStmt *Stmt) { 893 auto &Result = ScalarReachDefZone[Stmt]; 894 if (Result) 895 return Result; 896 897 auto Domain = getDomainFor(Stmt); 898 Result = computeScalarReachingDefinition(Schedule, Domain, false, true); 899 simplify(Result); 900 901 assert(Result); 902 return Result; 903 } 904 905 /// Compute the different zones. 906 void computeCommon() { 907 AllReads = makeEmptyUnionMap(); 908 AllMayWrites = makeEmptyUnionMap(); 909 AllMustWrites = makeEmptyUnionMap(); 910 911 for (auto &Stmt : *S) { 912 for (auto *MA : Stmt) { 913 if (!MA->isLatestArrayKind()) 914 continue; 915 916 if (MA->isRead()) 917 addArrayReadAccess(MA); 918 919 if (MA->isWrite()) 920 addArrayWriteAccess(MA); 921 } 922 } 923 924 // { DomainWrite[] -> Element[] } 925 auto AllWrites = 926 give(isl_union_map_union(AllMustWrites.copy(), AllMayWrites.copy())); 927 928 // { Element[] } 929 AllElements = makeEmptyUnionSet(); 930 foreachElt(AllWrites, [this](IslPtr<isl_map> Write) { 931 auto Space = give(isl_map_get_space(Write.keep())); 932 auto EltSpace = give(isl_space_range(Space.take())); 933 auto EltUniv = give(isl_set_universe(EltSpace.take())); 934 AllElements = 935 give(isl_union_set_add_set(AllElements.take(), EltUniv.take())); 936 }); 937 } 938 939 /// Print the current state of all MemoryAccesses to @p. 940 void printAccesses(llvm::raw_ostream &OS, int Indent = 0) const { 941 OS.indent(Indent) << "After accesses {\n"; 942 for (auto &Stmt : *S) { 943 OS.indent(Indent + 4) << Stmt.getBaseName() << "\n"; 944 for (auto *MA : Stmt) 945 MA->print(OS); 946 } 947 OS.indent(Indent) << "}\n"; 948 } 949 950 public: 951 /// Return the SCoP this object is analyzing. 952 Scop *getScop() const { return S; } 953 }; 954 955 /// Implementation of the DeLICM/DePRE transformation. 956 class DeLICMImpl : public ZoneAlgorithm { 957 private: 958 /// Knowledge before any transformation took place. 959 Knowledge OriginalZone; 960 961 /// Current knowledge of the SCoP including all already applied 962 /// transformations. 963 Knowledge Zone; 964 965 /// For getting the MemoryAccesses that write or read a given scalar. 966 ScalarDefUseChains DefUse; 967 968 /// Number of StoreInsts something can be mapped to. 969 int NumberOfCompatibleTargets = 0; 970 971 /// The number of StoreInsts to which at least one value or PHI has been 972 /// mapped to. 973 int NumberOfTargetsMapped = 0; 974 975 /// The number of llvm::Value mapped to some array element. 976 int NumberOfMappedValueScalars = 0; 977 978 /// The number of PHIs mapped to some array element. 979 int NumberOfMappedPHIScalars = 0; 980 981 /// Determine whether two knowledges are conflicting with each other. 982 /// 983 /// @see Knowledge::isConflicting 984 bool isConflicting(const Knowledge &Proposed) { 985 raw_ostream *OS = nullptr; 986 DEBUG(OS = &llvm::dbgs()); 987 return Knowledge::isConflicting(Zone, Proposed, OS, 4); 988 } 989 990 /// Determine whether @p SAI is a scalar that can be mapped to an array 991 /// element. 992 bool isMappable(const ScopArrayInfo *SAI) { 993 assert(SAI); 994 995 if (SAI->isValueKind()) { 996 auto *MA = DefUse.getValueDef(SAI); 997 if (!MA) { 998 DEBUG(dbgs() 999 << " Reject because value is read-only within the scop\n"); 1000 return false; 1001 } 1002 1003 // Mapping if value is used after scop is not supported. The code 1004 // generator would need to reload the scalar after the scop, but it 1005 // does not have the information to where it is mapped to. Only the 1006 // MemoryAccesses have that information, not the ScopArrayInfo. 1007 auto Inst = MA->getAccessInstruction(); 1008 for (auto User : Inst->users()) { 1009 if (!isa<Instruction>(User)) 1010 return false; 1011 auto UserInst = cast<Instruction>(User); 1012 1013 if (!S->contains(UserInst)) { 1014 DEBUG(dbgs() << " Reject because value is escaping\n"); 1015 return false; 1016 } 1017 } 1018 1019 return true; 1020 } 1021 1022 if (SAI->isPHIKind()) { 1023 auto *MA = DefUse.getPHIRead(SAI); 1024 assert(MA); 1025 1026 // Mapping of an incoming block from before the SCoP is not supported by 1027 // the code generator. 1028 auto PHI = cast<PHINode>(MA->getAccessInstruction()); 1029 for (auto Incoming : PHI->blocks()) { 1030 if (!S->contains(Incoming)) { 1031 DEBUG(dbgs() << " Reject because at least one incoming block is " 1032 "not in the scop region\n"); 1033 return false; 1034 } 1035 } 1036 1037 return true; 1038 } 1039 1040 DEBUG(dbgs() << " Reject ExitPHI or other non-value\n"); 1041 return false; 1042 } 1043 1044 /// Compute the uses of a MemoryKind::Value and its lifetime (from its 1045 /// definition to the last use). 1046 /// 1047 /// @param SAI The ScopArrayInfo representing the value's storage. 1048 /// 1049 /// @return { DomainDef[] -> DomainUse[] }, { DomainDef[] -> Zone[] } 1050 /// First element is the set of uses for each definition. 1051 /// The second is the lifetime of each definition. 1052 std::tuple<IslPtr<isl_union_map>, IslPtr<isl_map>> 1053 computeValueUses(const ScopArrayInfo *SAI) { 1054 assert(SAI->isValueKind()); 1055 1056 // { DomainRead[] } 1057 auto Reads = makeEmptyUnionSet(); 1058 1059 // Find all uses. 1060 for (auto *MA : DefUse.getValueUses(SAI)) 1061 Reads = 1062 give(isl_union_set_add_set(Reads.take(), getDomainFor(MA).take())); 1063 1064 // { DomainRead[] -> Scatter[] } 1065 auto ReadSchedule = getScatterFor(Reads); 1066 1067 auto *DefMA = DefUse.getValueDef(SAI); 1068 assert(DefMA); 1069 1070 // { DomainDef[] } 1071 auto Writes = getDomainFor(DefMA); 1072 1073 // { DomainDef[] -> Scatter[] } 1074 auto WriteScatter = getScatterFor(Writes); 1075 1076 // { Scatter[] -> DomainDef[] } 1077 auto ReachDef = getScalarReachingDefinition(DefMA->getStatement()); 1078 1079 // { [DomainDef[] -> Scatter[]] -> DomainUse[] } 1080 auto Uses = give( 1081 isl_union_map_apply_range(isl_union_map_from_map(isl_map_range_map( 1082 isl_map_reverse(ReachDef.take()))), 1083 isl_union_map_reverse(ReadSchedule.take()))); 1084 1085 // { DomainDef[] -> Scatter[] } 1086 auto UseScatter = 1087 singleton(give(isl_union_set_unwrap(isl_union_map_domain(Uses.copy()))), 1088 give(isl_space_map_from_domain_and_range( 1089 isl_set_get_space(Writes.keep()), ScatterSpace.copy()))); 1090 1091 // { DomainDef[] -> Zone[] } 1092 auto Lifetime = betweenScatter(WriteScatter, UseScatter, false, true); 1093 1094 // { DomainDef[] -> DomainRead[] } 1095 auto DefUses = give(isl_union_map_domain_factor_domain(Uses.take())); 1096 1097 return std::make_pair(DefUses, Lifetime); 1098 } 1099 1100 /// For each 'execution' of a PHINode, get the incoming block that was 1101 /// executed before. 1102 /// 1103 /// For each PHI instance we can directly determine which was the incoming 1104 /// block, and hence derive which value the PHI has. 1105 /// 1106 /// @param SAI The ScopArrayInfo representing the PHI's storage. 1107 /// 1108 /// @return { DomainPHIRead[] -> DomainPHIWrite[] } 1109 IslPtr<isl_union_map> computePerPHI(const ScopArrayInfo *SAI) { 1110 assert(SAI->isPHIKind()); 1111 1112 // { DomainPHIWrite[] -> Scatter[] } 1113 auto PHIWriteScatter = makeEmptyUnionMap(); 1114 1115 // Collect all incoming block timepoint. 1116 for (auto *MA : DefUse.getPHIIncomings(SAI)) { 1117 auto Scatter = getScatterFor(MA); 1118 PHIWriteScatter = 1119 give(isl_union_map_add_map(PHIWriteScatter.take(), Scatter.take())); 1120 } 1121 1122 // { DomainPHIRead[] -> Scatter[] } 1123 auto PHIReadScatter = getScatterFor(DefUse.getPHIRead(SAI)); 1124 1125 // { DomainPHIRead[] -> Scatter[] } 1126 auto BeforeRead = beforeScatter(PHIReadScatter, true); 1127 1128 // { Scatter[] } 1129 auto WriteTimes = singleton( 1130 give(isl_union_map_range(PHIWriteScatter.copy())), ScatterSpace); 1131 1132 // { DomainPHIRead[] -> Scatter[] } 1133 auto PHIWriteTimes = 1134 give(isl_map_intersect_range(BeforeRead.take(), WriteTimes.take())); 1135 auto LastPerPHIWrites = give(isl_map_lexmax(PHIWriteTimes.take())); 1136 1137 // { DomainPHIRead[] -> DomainPHIWrite[] } 1138 auto Result = give(isl_union_map_apply_range( 1139 isl_union_map_from_map(LastPerPHIWrites.take()), 1140 isl_union_map_reverse(PHIWriteScatter.take()))); 1141 assert(isl_union_map_is_single_valued(Result.keep()) == isl_bool_true); 1142 assert(isl_union_map_is_injective(Result.keep()) == isl_bool_true); 1143 return Result; 1144 } 1145 1146 /// Try to map a MemoryKind::Value to a given array element. 1147 /// 1148 /// @param SAI Representation of the scalar's memory to map. 1149 /// @param TargetElt { Scatter[] -> Element[] } 1150 /// Suggestion where to map a scalar to when at a timepoint. 1151 /// 1152 /// @return true if the scalar was successfully mapped. 1153 bool tryMapValue(const ScopArrayInfo *SAI, IslPtr<isl_map> TargetElt) { 1154 assert(SAI->isValueKind()); 1155 1156 auto *DefMA = DefUse.getValueDef(SAI); 1157 assert(DefMA->isValueKind()); 1158 assert(DefMA->isMustWrite()); 1159 1160 // Stop if the scalar has already been mapped. 1161 if (!DefMA->getLatestScopArrayInfo()->isValueKind()) 1162 return false; 1163 1164 // { DomainDef[] -> Scatter[] } 1165 auto DefSched = getScatterFor(DefMA); 1166 1167 // Where each write is mapped to, according to the suggestion. 1168 // { DomainDef[] -> Element[] } 1169 auto DefTarget = give(isl_map_apply_domain( 1170 TargetElt.copy(), isl_map_reverse(DefSched.copy()))); 1171 simplify(DefTarget); 1172 DEBUG(dbgs() << " Def Mapping: " << DefTarget << '\n'); 1173 1174 auto OrigDomain = getDomainFor(DefMA); 1175 auto MappedDomain = give(isl_map_domain(DefTarget.copy())); 1176 if (!isl_set_is_subset(OrigDomain.keep(), MappedDomain.keep())) { 1177 DEBUG(dbgs() 1178 << " Reject because mapping does not encompass all instances\n"); 1179 return false; 1180 } 1181 1182 // { DomainDef[] -> Zone[] } 1183 IslPtr<isl_map> Lifetime; 1184 1185 // { DomainDef[] -> DomainUse[] } 1186 IslPtr<isl_union_map> DefUses; 1187 1188 std::tie(DefUses, Lifetime) = computeValueUses(SAI); 1189 DEBUG(dbgs() << " Lifetime: " << Lifetime << '\n'); 1190 1191 /// { [Element[] -> Zone[]] } 1192 auto EltZone = give( 1193 isl_map_wrap(isl_map_apply_domain(Lifetime.copy(), DefTarget.copy()))); 1194 simplify(EltZone); 1195 1196 // { [Element[] -> Scatter[]] } 1197 auto DefEltSched = give(isl_map_wrap(isl_map_reverse( 1198 isl_map_apply_domain(DefTarget.copy(), DefSched.copy())))); 1199 simplify(DefEltSched); 1200 1201 Knowledge Proposed(EltZone, nullptr, DefEltSched); 1202 if (isConflicting(Proposed)) 1203 return false; 1204 1205 // { DomainUse[] -> Element[] } 1206 auto UseTarget = give( 1207 isl_union_map_apply_range(isl_union_map_reverse(DefUses.take()), 1208 isl_union_map_from_map(DefTarget.copy()))); 1209 1210 mapValue(SAI, std::move(DefTarget), std::move(UseTarget), 1211 std::move(Lifetime), std::move(Proposed)); 1212 return true; 1213 } 1214 1215 /// After a scalar has been mapped, update the global knowledge. 1216 void applyLifetime(Knowledge Proposed) { 1217 Zone.learnFrom(std::move(Proposed)); 1218 } 1219 1220 /// Map a MemoryKind::Value scalar to an array element. 1221 /// 1222 /// Callers must have ensured that the mapping is valid and not conflicting. 1223 /// 1224 /// @param SAI The ScopArrayInfo representing the scalar's memory to 1225 /// map. 1226 /// @param DefTarget { DomainDef[] -> Element[] } 1227 /// The array element to map the scalar to. 1228 /// @param UseTarget { DomainUse[] -> Element[] } 1229 /// The array elements the uses are mapped to. 1230 /// @param Lifetime { DomainDef[] -> Zone[] } 1231 /// The lifetime of each llvm::Value definition for 1232 /// reporting. 1233 /// @param Proposed Mapping constraints for reporting. 1234 void mapValue(const ScopArrayInfo *SAI, IslPtr<isl_map> DefTarget, 1235 IslPtr<isl_union_map> UseTarget, IslPtr<isl_map> Lifetime, 1236 Knowledge Proposed) { 1237 // Redirect the read accesses. 1238 for (auto *MA : DefUse.getValueUses(SAI)) { 1239 // { DomainUse[] } 1240 auto Domain = getDomainFor(MA); 1241 1242 // { DomainUse[] -> Element[] } 1243 auto NewAccRel = give(isl_union_map_intersect_domain( 1244 UseTarget.copy(), isl_union_set_from_set(Domain.take()))); 1245 simplify(NewAccRel); 1246 1247 assert(isl_union_map_n_map(NewAccRel.keep()) == 1); 1248 MA->setNewAccessRelation(isl_map_from_union_map(NewAccRel.take())); 1249 } 1250 1251 auto *WA = DefUse.getValueDef(SAI); 1252 WA->setNewAccessRelation(DefTarget.copy()); 1253 applyLifetime(Proposed); 1254 1255 MappedValueScalars++; 1256 NumberOfMappedValueScalars += 1; 1257 } 1258 1259 /// Try to map a MemoryKind::PHI scalar to a given array element. 1260 /// 1261 /// @param SAI Representation of the scalar's memory to map. 1262 /// @param TargetElt { Scatter[] -> Element[] } 1263 /// Suggestion where to map the scalar to when at a 1264 /// timepoint. 1265 /// 1266 /// @return true if the PHI scalar has been mapped. 1267 bool tryMapPHI(const ScopArrayInfo *SAI, IslPtr<isl_map> TargetElt) { 1268 auto *PHIRead = DefUse.getPHIRead(SAI); 1269 assert(PHIRead->isPHIKind()); 1270 assert(PHIRead->isRead()); 1271 1272 // Skip if already been mapped. 1273 if (!PHIRead->getLatestScopArrayInfo()->isPHIKind()) 1274 return false; 1275 1276 // { DomainRead[] -> Scatter[] } 1277 auto PHISched = getScatterFor(PHIRead); 1278 1279 // { DomainRead[] -> Element[] } 1280 auto PHITarget = 1281 give(isl_map_apply_range(PHISched.copy(), TargetElt.copy())); 1282 simplify(PHITarget); 1283 DEBUG(dbgs() << " Mapping: " << PHITarget << '\n'); 1284 1285 auto OrigDomain = getDomainFor(PHIRead); 1286 auto MappedDomain = give(isl_map_domain(PHITarget.copy())); 1287 if (!isl_set_is_subset(OrigDomain.keep(), MappedDomain.keep())) { 1288 DEBUG(dbgs() 1289 << " Reject because mapping does not encompass all instances\n"); 1290 return false; 1291 } 1292 1293 // { DomainRead[] -> DomainWrite[] } 1294 auto PerPHIWrites = computePerPHI(SAI); 1295 1296 // { DomainWrite[] -> Element[] } 1297 auto WritesTarget = give(isl_union_map_reverse(isl_union_map_apply_domain( 1298 PerPHIWrites.copy(), isl_union_map_from_map(PHITarget.copy())))); 1299 simplify(WritesTarget); 1300 1301 // { DomainWrite[] } 1302 auto ExpandedWritesDom = give(isl_union_map_domain(WritesTarget.copy())); 1303 auto UniverseWritesDom = give(isl_union_set_empty(ParamSpace.copy())); 1304 1305 for (auto *MA : DefUse.getPHIIncomings(SAI)) 1306 UniverseWritesDom = give(isl_union_set_add_set(UniverseWritesDom.take(), 1307 getDomainFor(MA).take())); 1308 1309 if (!isl_union_set_is_subset(UniverseWritesDom.keep(), 1310 ExpandedWritesDom.keep())) { 1311 DEBUG(dbgs() << " Reject because did not find PHI write mapping for " 1312 "all instances\n"); 1313 DEBUG(dbgs() << " Deduced Mapping: " << WritesTarget << '\n'); 1314 DEBUG(dbgs() << " Missing instances: " 1315 << give(isl_union_set_subtract(UniverseWritesDom.copy(), 1316 ExpandedWritesDom.copy())) 1317 << '\n'); 1318 return false; 1319 } 1320 1321 // { DomainRead[] -> Scatter[] } 1322 auto PerPHIWriteScatter = give(isl_map_from_union_map( 1323 isl_union_map_apply_range(PerPHIWrites.copy(), Schedule.copy()))); 1324 1325 // { DomainRead[] -> Zone[] } 1326 auto Lifetime = betweenScatter(PerPHIWriteScatter, PHISched, false, true); 1327 simplify(Lifetime); 1328 DEBUG(dbgs() << " Lifetime: " << Lifetime << "\n"); 1329 1330 // { DomainWrite[] -> Zone[] } 1331 auto WriteLifetime = give(isl_union_map_apply_domain( 1332 isl_union_map_from_map(Lifetime.copy()), PerPHIWrites.copy())); 1333 1334 // { DomainWrite[] -> [Element[] -> Scatter[]] } 1335 auto WrittenTranslator = 1336 give(isl_union_map_range_product(WritesTarget.copy(), Schedule.copy())); 1337 1338 // { [Element[] -> Scatter[]] } 1339 auto Written = give(isl_union_map_range(WrittenTranslator.copy())); 1340 simplify(Written); 1341 1342 // { DomainWrite[] -> [Element[] -> Zone[]] } 1343 auto LifetimeTranslator = give( 1344 isl_union_map_range_product(WritesTarget.copy(), WriteLifetime.take())); 1345 1346 // { [Element[] -> Zone[] } 1347 auto Occupied = give(isl_union_map_range(LifetimeTranslator.copy())); 1348 simplify(Occupied); 1349 1350 Knowledge Proposed(Occupied, nullptr, Written); 1351 if (isConflicting(Proposed)) 1352 return false; 1353 1354 mapPHI(SAI, std::move(PHITarget), std::move(WritesTarget), 1355 std::move(Lifetime), std::move(Proposed)); 1356 return true; 1357 } 1358 1359 /// Map a MemoryKind::PHI scalar to an array element. 1360 /// 1361 /// Callers must have ensured that the mapping is valid and not conflicting 1362 /// with the common knowledge. 1363 /// 1364 /// @param SAI The ScopArrayInfo representing the scalar's memory to 1365 /// map. 1366 /// @param ReadTarget { DomainRead[] -> Element[] } 1367 /// The array element to map the scalar to. 1368 /// @param WriteTarget { DomainWrite[] -> Element[] } 1369 /// New access target for each PHI incoming write. 1370 /// @param Lifetime { DomainRead[] -> Zone[] } 1371 /// The lifetime of each PHI for reporting. 1372 /// @param Proposed Mapping constraints for reporting. 1373 void mapPHI(const ScopArrayInfo *SAI, IslPtr<isl_map> ReadTarget, 1374 IslPtr<isl_union_map> WriteTarget, IslPtr<isl_map> Lifetime, 1375 Knowledge Proposed) { 1376 // Redirect the PHI incoming writes. 1377 for (auto *MA : DefUse.getPHIIncomings(SAI)) { 1378 // { DomainWrite[] } 1379 auto Domain = getDomainFor(MA); 1380 1381 // { DomainWrite[] -> Element[] } 1382 auto NewAccRel = give(isl_union_map_intersect_domain( 1383 WriteTarget.copy(), isl_union_set_from_set(Domain.take()))); 1384 simplify(NewAccRel); 1385 1386 assert(isl_union_map_n_map(NewAccRel.keep()) == 1); 1387 MA->setNewAccessRelation(isl_map_from_union_map(NewAccRel.take())); 1388 } 1389 1390 // Redirect the PHI read. 1391 auto *PHIRead = DefUse.getPHIRead(SAI); 1392 PHIRead->setNewAccessRelation(ReadTarget.copy()); 1393 applyLifetime(Proposed); 1394 1395 MappedPHIScalars++; 1396 NumberOfMappedPHIScalars++; 1397 } 1398 1399 /// Search and map scalars to memory overwritten by @p TargetStoreMA. 1400 /// 1401 /// Start trying to map scalars that are used in the same statement as the 1402 /// store. For every successful mapping, try to also map scalars of the 1403 /// statements where those are written. Repeat, until no more mapping 1404 /// opportunity is found. 1405 /// 1406 /// There is currently no preference in which order scalars are tried. 1407 /// Ideally, we would direct it towards a load instruction of the same array 1408 /// element. 1409 bool collapseScalarsToStore(MemoryAccess *TargetStoreMA) { 1410 assert(TargetStoreMA->isLatestArrayKind()); 1411 assert(TargetStoreMA->isMustWrite()); 1412 1413 auto TargetStmt = TargetStoreMA->getStatement(); 1414 1415 // { DomTarget[] } 1416 auto TargetDom = getDomainFor(TargetStmt); 1417 1418 // { DomTarget[] -> Element[] } 1419 auto TargetAccRel = getAccessRelationFor(TargetStoreMA); 1420 1421 // { Zone[] -> DomTarget[] } 1422 // For each point in time, find the next target store instance. 1423 auto Target = 1424 computeScalarReachingOverwrite(Schedule, TargetDom, false, true); 1425 1426 // { Zone[] -> Element[] } 1427 // Use the target store's write location as a suggestion to map scalars to. 1428 auto EltTarget = 1429 give(isl_map_apply_range(Target.take(), TargetAccRel.take())); 1430 simplify(EltTarget); 1431 DEBUG(dbgs() << " Target mapping is " << EltTarget << '\n'); 1432 1433 // Stack of elements not yet processed. 1434 SmallVector<MemoryAccess *, 16> Worklist; 1435 1436 // Set of scalars already tested. 1437 SmallPtrSet<const ScopArrayInfo *, 16> Closed; 1438 1439 // Lambda to add all scalar reads to the work list. 1440 auto ProcessAllIncoming = [&](ScopStmt *Stmt) { 1441 for (auto *MA : *Stmt) { 1442 if (!MA->isLatestScalarKind()) 1443 continue; 1444 if (!MA->isRead()) 1445 continue; 1446 1447 Worklist.push_back(MA); 1448 } 1449 }; 1450 1451 // Add initial scalar. Either the value written by the store, or all inputs 1452 // of its statement. 1453 auto WrittenVal = TargetStoreMA->getAccessValue(); 1454 if (auto InputAcc = getInputAccessOf(WrittenVal, TargetStmt)) 1455 Worklist.push_back(InputAcc); 1456 else 1457 ProcessAllIncoming(TargetStmt); 1458 1459 auto AnyMapped = false; 1460 auto &DL = 1461 S->getRegion().getEntry()->getParent()->getParent()->getDataLayout(); 1462 auto StoreSize = 1463 DL.getTypeAllocSize(TargetStoreMA->getAccessValue()->getType()); 1464 1465 while (!Worklist.empty()) { 1466 auto *MA = Worklist.pop_back_val(); 1467 1468 auto *SAI = MA->getScopArrayInfo(); 1469 if (Closed.count(SAI)) 1470 continue; 1471 Closed.insert(SAI); 1472 DEBUG(dbgs() << "\n Trying to map " << MA << " (SAI: " << SAI 1473 << ")\n"); 1474 1475 // Skip non-mappable scalars. 1476 if (!isMappable(SAI)) 1477 continue; 1478 1479 auto MASize = DL.getTypeAllocSize(MA->getAccessValue()->getType()); 1480 if (MASize > StoreSize) { 1481 DEBUG(dbgs() << " Reject because storage size is insufficient\n"); 1482 continue; 1483 } 1484 1485 // Try to map MemoryKind::Value scalars. 1486 if (SAI->isValueKind()) { 1487 if (!tryMapValue(SAI, EltTarget)) 1488 continue; 1489 1490 auto *DefAcc = DefUse.getValueDef(SAI); 1491 ProcessAllIncoming(DefAcc->getStatement()); 1492 1493 AnyMapped = true; 1494 continue; 1495 } 1496 1497 // Try to map MemoryKind::PHI scalars. 1498 if (SAI->isPHIKind()) { 1499 if (!tryMapPHI(SAI, EltTarget)) 1500 continue; 1501 // Add inputs of all incoming statements to the worklist. 1502 for (auto *PHIWrite : DefUse.getPHIIncomings(SAI)) 1503 ProcessAllIncoming(PHIWrite->getStatement()); 1504 1505 AnyMapped = true; 1506 continue; 1507 } 1508 } 1509 1510 if (AnyMapped) { 1511 TargetsMapped++; 1512 NumberOfTargetsMapped++; 1513 } 1514 return AnyMapped; 1515 } 1516 1517 /// Compute when an array element is unused. 1518 /// 1519 /// @return { [Element[] -> Zone[]] } 1520 IslPtr<isl_union_set> computeLifetime() const { 1521 // { Element[] -> Zone[] } 1522 auto ArrayUnused = computeArrayUnused(Schedule, AllMustWrites, AllReads, 1523 false, false, true); 1524 1525 auto Result = give(isl_union_map_wrap(ArrayUnused.copy())); 1526 1527 simplify(Result); 1528 return Result; 1529 } 1530 1531 /// Determine when an array element is written to. 1532 /// 1533 /// @return { [Element[] -> Scatter[]] } 1534 IslPtr<isl_union_set> computeWritten() const { 1535 // { WriteDomain[] -> Element[] } 1536 auto AllWrites = 1537 give(isl_union_map_union(AllMustWrites.copy(), AllMayWrites.copy())); 1538 1539 // { Scatter[] -> Element[] } 1540 auto WriteTimepoints = 1541 give(isl_union_map_apply_domain(AllWrites.copy(), Schedule.copy())); 1542 1543 auto Result = 1544 give(isl_union_map_wrap(isl_union_map_reverse(WriteTimepoints.copy()))); 1545 1546 simplify(Result); 1547 return Result; 1548 } 1549 1550 /// Determine whether an access touches at most one element. 1551 /// 1552 /// The accessed element could be a scalar or accessing an array with constant 1553 /// subscript, such that all instances access only that element. 1554 /// 1555 /// @param MA The access to test. 1556 /// 1557 /// @return True, if zero or one elements are accessed; False if at least two 1558 /// different elements are accessed. 1559 bool isScalarAccess(MemoryAccess *MA) { 1560 auto Map = getAccessRelationFor(MA); 1561 auto Set = give(isl_map_range(Map.take())); 1562 return isl_set_is_singleton(Set.keep()) == isl_bool_true; 1563 } 1564 1565 /// Print mapping statistics to @p OS. 1566 void printStatistics(llvm::raw_ostream &OS, int Indent = 0) const { 1567 OS.indent(Indent) << "Statistics {\n"; 1568 OS.indent(Indent + 4) << "Compatible overwrites: " 1569 << NumberOfCompatibleTargets << "\n"; 1570 OS.indent(Indent + 4) << "Overwrites mapped to: " << NumberOfTargetsMapped 1571 << '\n'; 1572 OS.indent(Indent + 4) << "Value scalars mapped: " 1573 << NumberOfMappedValueScalars << '\n'; 1574 OS.indent(Indent + 4) << "PHI scalars mapped: " 1575 << NumberOfMappedPHIScalars << '\n'; 1576 OS.indent(Indent) << "}\n"; 1577 } 1578 1579 /// Return whether at least one transformation been applied. 1580 bool isModified() const { return NumberOfTargetsMapped > 0; } 1581 1582 public: 1583 DeLICMImpl(Scop *S) : ZoneAlgorithm(S) {} 1584 1585 /// Calculate the lifetime (definition to last use) of every array element. 1586 /// 1587 /// @return True if the computed lifetimes (#Zone) is usable. 1588 bool computeZone() { 1589 // Check that nothing strange occurs. 1590 if (!isCompatibleScop()) { 1591 DeLICMIncompatible++; 1592 return false; 1593 } 1594 1595 DefUse.compute(S); 1596 IslPtr<isl_union_set> EltUnused, EltWritten; 1597 1598 { 1599 IslMaxOperationsGuard MaxOpGuard(IslCtx.get(), DelicmMaxOps); 1600 1601 computeCommon(); 1602 1603 EltUnused = computeLifetime(); 1604 EltWritten = computeWritten(); 1605 } 1606 DeLICMAnalyzed++; 1607 1608 if (!EltUnused || !EltWritten) { 1609 assert(isl_ctx_last_error(IslCtx.get()) == isl_error_quota && 1610 "The only reason that these things have not been computed should " 1611 "be if the max-operations limit hit"); 1612 DeLICMOutOfQuota++; 1613 DEBUG(dbgs() << "DeLICM analysis exceeded max_operations\n"); 1614 DebugLoc Begin, End; 1615 getDebugLocations(getBBPairForRegion(&S->getRegion()), Begin, End); 1616 OptimizationRemarkAnalysis R(DEBUG_TYPE, "OutOfQuota", Begin, 1617 S->getEntry()); 1618 R << "maximal number of operations exceeded during zone analysis"; 1619 S->getFunction().getContext().diagnose(R); 1620 return false; 1621 } 1622 1623 Zone = OriginalZone = Knowledge(nullptr, EltUnused, EltWritten); 1624 DEBUG(dbgs() << "Computed Zone:\n"; OriginalZone.print(dbgs(), 4)); 1625 1626 assert(Zone.isUsable() && OriginalZone.isUsable()); 1627 return true; 1628 } 1629 1630 /// Try to map as many scalars to unused array elements as possible. 1631 /// 1632 /// Multiple scalars might be mappable to intersecting unused array element 1633 /// zones, but we can only chose one. This is a greedy algorithm, therefore 1634 /// the first processed element claims it. 1635 void greedyCollapse() { 1636 bool Modified = false; 1637 1638 for (auto &Stmt : *S) { 1639 for (auto *MA : Stmt) { 1640 if (!MA->isLatestArrayKind()) 1641 continue; 1642 if (!MA->isWrite()) 1643 continue; 1644 1645 if (MA->isMayWrite()) { 1646 DEBUG(dbgs() << "Access " << MA 1647 << " pruned because it is a MAY_WRITE\n"); 1648 OptimizationRemarkMissed R(DEBUG_TYPE, "TargetMayWrite", 1649 MA->getAccessInstruction()); 1650 R << "Skipped possible mapping target because it is not an " 1651 "unconditional overwrite"; 1652 S->getFunction().getContext().diagnose(R); 1653 continue; 1654 } 1655 1656 if (Stmt.getNumIterators() == 0) { 1657 DEBUG(dbgs() << "Access " << MA 1658 << " pruned because it is not in a loop\n"); 1659 OptimizationRemarkMissed R(DEBUG_TYPE, "WriteNotInLoop", 1660 MA->getAccessInstruction()); 1661 R << "skipped possible mapping target because it is not in a loop"; 1662 S->getFunction().getContext().diagnose(R); 1663 continue; 1664 } 1665 1666 if (isScalarAccess(MA)) { 1667 DEBUG(dbgs() << "Access " << MA 1668 << " pruned because it writes only a single element\n"); 1669 OptimizationRemarkMissed R(DEBUG_TYPE, "ScalarWrite", 1670 MA->getAccessInstruction()); 1671 R << "skipped possible mapping target because the memory location " 1672 "written to does not depend on its outer loop"; 1673 S->getFunction().getContext().diagnose(R); 1674 continue; 1675 } 1676 1677 NumberOfCompatibleTargets++; 1678 DEBUG(dbgs() << "Analyzing target access " << MA << "\n"); 1679 if (collapseScalarsToStore(MA)) 1680 Modified = true; 1681 } 1682 } 1683 1684 if (Modified) 1685 DeLICMScopsModified++; 1686 } 1687 1688 /// Dump the internal information about a performed DeLICM to @p OS. 1689 void print(llvm::raw_ostream &OS, int Indent = 0) { 1690 if (!Zone.isUsable()) { 1691 OS.indent(Indent) << "Zone not computed\n"; 1692 return; 1693 } 1694 1695 printStatistics(OS, Indent); 1696 if (!isModified()) { 1697 OS.indent(Indent) << "No modification has been made\n"; 1698 return; 1699 } 1700 printAccesses(OS, Indent); 1701 } 1702 }; 1703 1704 class DeLICM : public ScopPass { 1705 private: 1706 DeLICM(const DeLICM &) = delete; 1707 const DeLICM &operator=(const DeLICM &) = delete; 1708 1709 /// The pass implementation, also holding per-scop data. 1710 std::unique_ptr<DeLICMImpl> Impl; 1711 1712 void collapseToUnused(Scop &S) { 1713 Impl = make_unique<DeLICMImpl>(&S); 1714 1715 if (!Impl->computeZone()) { 1716 DEBUG(dbgs() << "Abort because cannot reliably compute lifetimes\n"); 1717 return; 1718 } 1719 1720 DEBUG(dbgs() << "Collapsing scalars to unused array elements...\n"); 1721 Impl->greedyCollapse(); 1722 1723 DEBUG(dbgs() << "\nFinal Scop:\n"); 1724 DEBUG(S.print(dbgs())); 1725 } 1726 1727 public: 1728 static char ID; 1729 explicit DeLICM() : ScopPass(ID) {} 1730 1731 virtual void getAnalysisUsage(AnalysisUsage &AU) const override { 1732 AU.addRequiredTransitive<ScopInfoRegionPass>(); 1733 AU.setPreservesAll(); 1734 } 1735 1736 virtual bool runOnScop(Scop &S) override { 1737 // Free resources for previous scop's computation, if not yet done. 1738 releaseMemory(); 1739 1740 collapseToUnused(S); 1741 1742 return false; 1743 } 1744 1745 virtual void printScop(raw_ostream &OS, Scop &S) const override { 1746 if (!Impl) 1747 return; 1748 assert(Impl->getScop() == &S); 1749 1750 OS << "DeLICM result:\n"; 1751 Impl->print(OS); 1752 } 1753 1754 virtual void releaseMemory() override { Impl.reset(); } 1755 }; 1756 1757 char DeLICM::ID; 1758 } // anonymous namespace 1759 1760 Pass *polly::createDeLICMPass() { return new DeLICM(); } 1761 1762 INITIALIZE_PASS_BEGIN(DeLICM, "polly-delicm", "Polly - DeLICM/DePRE", false, 1763 false) 1764 INITIALIZE_PASS_DEPENDENCY(ScopInfoWrapperPass) 1765 INITIALIZE_PASS_END(DeLICM, "polly-delicm", "Polly - DeLICM/DePRE", false, 1766 false) 1767 1768 bool polly::isConflicting(IslPtr<isl_union_set> ExistingOccupied, 1769 IslPtr<isl_union_set> ExistingUnused, 1770 IslPtr<isl_union_set> ExistingWrites, 1771 IslPtr<isl_union_set> ProposedOccupied, 1772 IslPtr<isl_union_set> ProposedUnused, 1773 IslPtr<isl_union_set> ProposedWrites, 1774 llvm::raw_ostream *OS, unsigned Indent) { 1775 Knowledge Existing(std::move(ExistingOccupied), std::move(ExistingUnused), 1776 std::move(ExistingWrites)); 1777 Knowledge Proposed(std::move(ProposedOccupied), std::move(ProposedUnused), 1778 std::move(ProposedWrites)); 1779 1780 return Knowledge::isConflicting(Existing, Proposed, OS, Indent); 1781 } 1782