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