1 //===------ ZoneAlgo.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 // Derive information about array elements between statements ("Zones"). 11 // 12 // The algorithms here work on the scatter space - the image space of the 13 // schedule returned by Scop::getSchedule(). We call an element in that space a 14 // "timepoint". Timepoints are lexicographically ordered such that we can 15 // defined ranges in the scatter space. We use two flavors of such ranges: 16 // Timepoint sets and zones. A timepoint set is simply a subset of the scatter 17 // space and is directly stored as isl_set. 18 // 19 // Zones are used to describe the space between timepoints as open sets, i.e. 20 // they do not contain the extrema. Using isl rational sets to express these 21 // would be overkill. We also cannot store them as the integer timepoints they 22 // contain; the (nonempty) zone between 1 and 2 would be empty and 23 // indistinguishable from e.g. the zone between 3 and 4. Also, we cannot store 24 // the integer set including the extrema; the set ]1,2[ + ]3,4[ could be 25 // coalesced to ]1,3[, although we defined the range [2,3] to be not in the set. 26 // Instead, we store the "half-open" integer extrema, including the lower bound, 27 // but excluding the upper bound. Examples: 28 // 29 // * The set { [i] : 1 <= i <= 3 } represents the zone ]0,3[ (which contains the 30 // integer points 1 and 2, but not 0 or 3) 31 // 32 // * { [1] } represents the zone ]0,1[ 33 // 34 // * { [i] : i = 1 or i = 3 } represents the zone ]0,1[ + ]2,3[ 35 // 36 // Therefore, an integer i in the set represents the zone ]i-1,i[, i.e. strictly 37 // speaking the integer points never belong to the zone. However, depending an 38 // the interpretation, one might want to include them. Part of the 39 // interpretation may not be known when the zone is constructed. 40 // 41 // Reads are assumed to always take place before writes, hence we can think of 42 // reads taking place at the beginning of a timepoint and writes at the end. 43 // 44 // Let's assume that the zone represents the lifetime of a variable. That is, 45 // the zone begins with a write that defines the value during its lifetime and 46 // ends with the last read of that value. In the following we consider whether a 47 // read/write at the beginning/ending of the lifetime zone should be within the 48 // zone or outside of it. 49 // 50 // * A read at the timepoint that starts the live-range loads the previous 51 // value. Hence, exclude the timepoint starting the zone. 52 // 53 // * A write at the timepoint that starts the live-range is not defined whether 54 // it occurs before or after the write that starts the lifetime. We do not 55 // allow this situation to occur. Hence, we include the timepoint starting the 56 // zone to determine whether they are conflicting. 57 // 58 // * A read at the timepoint that ends the live-range reads the same variable. 59 // We include the timepoint at the end of the zone to include that read into 60 // the live-range. Doing otherwise would mean that the two reads access 61 // different values, which would mean that the value they read are both alive 62 // at the same time but occupy the same variable. 63 // 64 // * A write at the timepoint that ends the live-range starts a new live-range. 65 // It must not be included in the live-range of the previous definition. 66 // 67 // All combinations of reads and writes at the endpoints are possible, but most 68 // of the time only the write->read (for instance, a live-range from definition 69 // to last use) and read->write (for instance, an unused range from last use to 70 // overwrite) and combinations are interesting (half-open ranges). write->write 71 // zones might be useful as well in some context to represent 72 // output-dependencies. 73 // 74 // @see convertZoneToTimepoints 75 // 76 // 77 // The code makes use of maps and sets in many different spaces. To not loose 78 // track in which space a set or map is expected to be in, variables holding an 79 // isl reference are usually annotated in the comments. They roughly follow isl 80 // syntax for spaces, but only the tuples, not the dimensions. The tuples have a 81 // meaning as follows: 82 // 83 // * Space[] - An unspecified tuple. Used for function parameters such that the 84 // function caller can use it for anything they like. 85 // 86 // * Domain[] - A statement instance as returned by ScopStmt::getDomain() 87 // isl_id_get_name: Stmt_<NameOfBasicBlock> 88 // isl_id_get_user: Pointer to ScopStmt 89 // 90 // * Element[] - An array element as in the range part of 91 // MemoryAccess::getAccessRelation() 92 // isl_id_get_name: MemRef_<NameOfArrayVariable> 93 // isl_id_get_user: Pointer to ScopArrayInfo 94 // 95 // * Scatter[] - Scatter space or space of timepoints 96 // Has no tuple id 97 // 98 // * Zone[] - Range between timepoints as described above 99 // Has no tuple id 100 // 101 // * ValInst[] - An llvm::Value as defined at a specific timepoint. 102 // 103 // A ValInst[] itself can be structured as one of: 104 // 105 // * [] - An unknown value. 106 // Always zero dimensions 107 // Has no tuple id 108 // 109 // * Value[] - An llvm::Value that is read-only in the SCoP, i.e. its 110 // runtime content does not depend on the timepoint. 111 // Always zero dimensions 112 // isl_id_get_name: Val_<NameOfValue> 113 // isl_id_get_user: A pointer to an llvm::Value 114 // 115 // * SCEV[...] - A synthesizable llvm::SCEV Expression. 116 // In contrast to a Value[] is has at least one dimension per 117 // SCEVAddRecExpr in the SCEV. 118 // 119 // * [Domain[] -> Value[]] - An llvm::Value that may change during the 120 // Scop's execution. 121 // The tuple itself has no id, but it wraps a map space holding a 122 // statement instance which defines the llvm::Value as the map's domain 123 // and llvm::Value itself as range. 124 // 125 // @see makeValInst() 126 // 127 // An annotation "{ Domain[] -> Scatter[] }" therefore means: A map from a 128 // statement instance to a timepoint, aka a schedule. There is only one scatter 129 // space, but most of the time multiple statements are processed in one set. 130 // This is why most of the time isl_union_map has to be used. 131 // 132 // The basic algorithm works as follows: 133 // At first we verify that the SCoP is compatible with this technique. For 134 // instance, two writes cannot write to the same location at the same statement 135 // instance because we cannot determine within the polyhedral model which one 136 // comes first. Once this was verified, we compute zones at which an array 137 // element is unused. This computation can fail if it takes too long. Then the 138 // main algorithm is executed. Because every store potentially trails an unused 139 // zone, we start at stores. We search for a scalar (MemoryKind::Value or 140 // MemoryKind::PHI) that we can map to the array element overwritten by the 141 // store, preferably one that is used by the store or at least the ScopStmt. 142 // When it does not conflict with the lifetime of the values in the array 143 // element, the map is applied and the unused zone updated as it is now used. We 144 // continue to try to map scalars to the array element until there are no more 145 // candidates to map. The algorithm is greedy in the sense that the first scalar 146 // not conflicting will be mapped. Other scalars processed later that could have 147 // fit the same unused zone will be rejected. As such the result depends on the 148 // processing order. 149 // 150 //===----------------------------------------------------------------------===// 151 152 #include "polly/ZoneAlgo.h" 153 #include "polly/ScopInfo.h" 154 #include "polly/Support/GICHelper.h" 155 #include "polly/Support/ISLTools.h" 156 #include "polly/Support/VirtualInstruction.h" 157 #include "llvm/ADT/Statistic.h" 158 159 #define DEBUG_TYPE "polly-zone" 160 161 STATISTIC(NumIncompatibleArrays, "Number of not zone-analyzable arrays"); 162 STATISTIC(NumCompatibleArrays, "Number of zone-analyzable arrays"); 163 164 using namespace polly; 165 using namespace llvm; 166 167 static isl::union_map computeReachingDefinition(isl::union_map Schedule, 168 isl::union_map Writes, 169 bool InclDef, bool InclRedef) { 170 return computeReachingWrite(Schedule, Writes, false, InclDef, InclRedef); 171 } 172 173 /// Compute the reaching definition of a scalar. 174 /// 175 /// Compared to computeReachingDefinition, there is just one element which is 176 /// accessed and therefore only a set if instances that accesses that element is 177 /// required. 178 /// 179 /// @param Schedule { DomainWrite[] -> Scatter[] } 180 /// @param Writes { DomainWrite[] } 181 /// @param InclDef Include the timepoint of the definition to the result. 182 /// @param InclRedef Include the timepoint of the overwrite into the result. 183 /// 184 /// @return { Scatter[] -> DomainWrite[] } 185 static isl::union_map computeScalarReachingDefinition(isl::union_map Schedule, 186 isl::union_set Writes, 187 bool InclDef, 188 bool InclRedef) { 189 // { DomainWrite[] -> Element[] } 190 isl::union_map Defs = isl::union_map::from_domain(Writes); 191 192 // { [Element[] -> Scatter[]] -> DomainWrite[] } 193 auto ReachDefs = 194 computeReachingDefinition(Schedule, Defs, InclDef, InclRedef); 195 196 // { Scatter[] -> DomainWrite[] } 197 return ReachDefs.curry().range().unwrap(); 198 } 199 200 /// Compute the reaching definition of a scalar. 201 /// 202 /// This overload accepts only a single writing statement as an isl_map, 203 /// consequently the result also is only a single isl_map. 204 /// 205 /// @param Schedule { DomainWrite[] -> Scatter[] } 206 /// @param Writes { DomainWrite[] } 207 /// @param InclDef Include the timepoint of the definition to the result. 208 /// @param InclRedef Include the timepoint of the overwrite into the result. 209 /// 210 /// @return { Scatter[] -> DomainWrite[] } 211 static isl::map computeScalarReachingDefinition(isl::union_map Schedule, 212 isl::set Writes, bool InclDef, 213 bool InclRedef) { 214 isl::space DomainSpace = Writes.get_space(); 215 isl::space ScatterSpace = getScatterSpace(Schedule); 216 217 // { Scatter[] -> DomainWrite[] } 218 isl::union_map UMap = computeScalarReachingDefinition( 219 Schedule, isl::union_set(Writes), InclDef, InclRedef); 220 221 isl::space ResultSpace = ScatterSpace.map_from_domain_and_range(DomainSpace); 222 return singleton(UMap, ResultSpace); 223 } 224 225 isl::union_map polly::makeUnknownForDomain(isl::union_set Domain) { 226 return give(isl_union_map_from_domain(Domain.take())); 227 } 228 229 /// Create a domain-to-unknown value mapping. 230 /// 231 /// @see makeUnknownForDomain(isl::union_set) 232 /// 233 /// @param Domain { Domain[] } 234 /// 235 /// @return { Domain[] -> ValInst[] } 236 static isl::map makeUnknownForDomain(isl::set Domain) { 237 return give(isl_map_from_domain(Domain.take())); 238 } 239 240 /// Return whether @p Map maps to an unknown value. 241 /// 242 /// @param { [] -> ValInst[] } 243 static bool isMapToUnknown(const isl::map &Map) { 244 isl::space Space = Map.get_space().range(); 245 return Space.has_tuple_id(isl::dim::set).is_false() && 246 Space.is_wrapping().is_false() && Space.dim(isl::dim::set) == 0; 247 } 248 249 isl::union_map polly::filterKnownValInst(const isl::union_map &UMap) { 250 isl::union_map Result = isl::union_map::empty(UMap.get_space()); 251 isl::stat Success = UMap.foreach_map([=, &Result](isl::map Map) -> isl::stat { 252 if (!isMapToUnknown(Map)) 253 Result = Result.add_map(Map); 254 return isl::stat::ok; 255 }); 256 if (Success != isl::stat::ok) 257 return {}; 258 return Result; 259 } 260 261 ZoneAlgorithm::ZoneAlgorithm(const char *PassName, Scop *S, LoopInfo *LI) 262 : PassName(PassName), IslCtx(S->getSharedIslCtx()), S(S), LI(LI), 263 Schedule(S->getSchedule()) { 264 auto Domains = S->getDomains(); 265 266 Schedule = 267 give(isl_union_map_intersect_domain(Schedule.take(), Domains.take())); 268 ParamSpace = give(isl_union_map_get_space(Schedule.keep())); 269 ScatterSpace = getScatterSpace(Schedule); 270 } 271 272 /// Check if all stores in @p Stmt store the very same value. 273 /// 274 /// This covers a special situation occurring in Polybench's 275 /// covariance/correlation (which is typical for algorithms that cover symmetric 276 /// matrices): 277 /// 278 /// for (int i = 0; i < n; i += 1) 279 /// for (int j = 0; j <= i; j += 1) { 280 /// double x = ...; 281 /// C[i][j] = x; 282 /// C[j][i] = x; 283 /// } 284 /// 285 /// For i == j, the same value is written twice to the same element.Double 286 /// writes to the same element are not allowed in DeLICM because its algorithm 287 /// does not see which of the writes is effective.But if its the same value 288 /// anyway, it doesn't matter. 289 /// 290 /// LLVM passes, however, cannot simplify this because the write is necessary 291 /// for i != j (unless it would add a condition for one of the writes to occur 292 /// only if i != j). 293 /// 294 /// TODO: In the future we may want to extent this to make the checks 295 /// specific to different memory locations. 296 static bool onlySameValueWrites(ScopStmt *Stmt) { 297 Value *V = nullptr; 298 299 for (auto *MA : *Stmt) { 300 if (!MA->isLatestArrayKind() || !MA->isMustWrite() || 301 !MA->isOriginalArrayKind()) 302 continue; 303 304 if (!V) { 305 V = MA->getAccessValue(); 306 continue; 307 } 308 309 if (V != MA->getAccessValue()) 310 return false; 311 } 312 return true; 313 } 314 315 void ZoneAlgorithm::collectIncompatibleElts(ScopStmt *Stmt, 316 isl::union_set &IncompatibleElts, 317 isl::union_set &AllElts) { 318 auto Stores = makeEmptyUnionMap(); 319 auto Loads = makeEmptyUnionMap(); 320 321 // This assumes that the MemoryKind::Array MemoryAccesses are iterated in 322 // order. 323 for (auto *MA : *Stmt) { 324 if (!MA->isLatestArrayKind()) 325 continue; 326 327 isl::map AccRelMap = getAccessRelationFor(MA); 328 isl::union_map AccRel = AccRelMap; 329 330 // To avoid solving any ILP problems, always add entire arrays instead of 331 // just the elements that are accessed. 332 auto ArrayElts = isl::set::universe(AccRelMap.get_space().range()); 333 AllElts = AllElts.add_set(ArrayElts); 334 335 if (MA->isRead()) { 336 // Reject load after store to same location. 337 if (!isl_union_map_is_disjoint(Stores.keep(), AccRel.keep())) { 338 DEBUG(dbgs() << "Load after store of same element in same statement\n"); 339 OptimizationRemarkMissed R(PassName, "LoadAfterStore", 340 MA->getAccessInstruction()); 341 R << "load after store of same element in same statement"; 342 R << " (previous stores: " << Stores; 343 R << ", loading: " << AccRel << ")"; 344 S->getFunction().getContext().diagnose(R); 345 346 IncompatibleElts = IncompatibleElts.add_set(ArrayElts); 347 } 348 349 Loads = give(isl_union_map_union(Loads.take(), AccRel.take())); 350 351 continue; 352 } 353 354 // In region statements the order is less clear, eg. the load and store 355 // might be in a boxed loop. 356 if (Stmt->isRegionStmt() && 357 !isl_union_map_is_disjoint(Loads.keep(), AccRel.keep())) { 358 DEBUG(dbgs() << "WRITE in non-affine subregion not supported\n"); 359 OptimizationRemarkMissed R(PassName, "StoreInSubregion", 360 MA->getAccessInstruction()); 361 R << "store is in a non-affine subregion"; 362 S->getFunction().getContext().diagnose(R); 363 364 IncompatibleElts = IncompatibleElts.add_set(ArrayElts); 365 } 366 367 // Do not allow more than one store to the same location. 368 if (!isl_union_map_is_disjoint(Stores.keep(), AccRel.keep()) && 369 !onlySameValueWrites(Stmt)) { 370 DEBUG(dbgs() << "WRITE after WRITE to same element\n"); 371 OptimizationRemarkMissed R(PassName, "StoreAfterStore", 372 MA->getAccessInstruction()); 373 R << "store after store of same element in same statement"; 374 R << " (previous stores: " << Stores; 375 R << ", storing: " << AccRel << ")"; 376 S->getFunction().getContext().diagnose(R); 377 378 IncompatibleElts = IncompatibleElts.add_set(ArrayElts); 379 } 380 381 Stores = give(isl_union_map_union(Stores.take(), AccRel.take())); 382 } 383 } 384 385 void ZoneAlgorithm::addArrayReadAccess(MemoryAccess *MA) { 386 assert(MA->isLatestArrayKind()); 387 assert(MA->isRead()); 388 ScopStmt *Stmt = MA->getStatement(); 389 390 // { DomainRead[] -> Element[] } 391 auto AccRel = intersectRange(getAccessRelationFor(MA), CompatibleElts); 392 AllReads = give(isl_union_map_add_map(AllReads.take(), AccRel.copy())); 393 394 if (LoadInst *Load = dyn_cast_or_null<LoadInst>(MA->getAccessInstruction())) { 395 // { DomainRead[] -> ValInst[] } 396 isl::map LoadValInst = makeValInst( 397 Load, Stmt, LI->getLoopFor(Load->getParent()), Stmt->isBlockStmt()); 398 399 // { DomainRead[] -> [Element[] -> DomainRead[]] } 400 isl::map IncludeElement = 401 give(isl_map_curry(isl_map_domain_map(AccRel.take()))); 402 403 // { [Element[] -> DomainRead[]] -> ValInst[] } 404 isl::map EltLoadValInst = 405 give(isl_map_apply_domain(LoadValInst.take(), IncludeElement.take())); 406 407 AllReadValInst = give( 408 isl_union_map_add_map(AllReadValInst.take(), EltLoadValInst.take())); 409 } 410 } 411 412 isl::map ZoneAlgorithm::getWrittenValue(MemoryAccess *MA, isl::map AccRel) { 413 if (!MA->isMustWrite()) 414 return {}; 415 416 Value *AccVal = MA->getAccessValue(); 417 ScopStmt *Stmt = MA->getStatement(); 418 Instruction *AccInst = MA->getAccessInstruction(); 419 420 // Write a value to a single element. 421 auto L = MA->isOriginalArrayKind() ? LI->getLoopFor(AccInst->getParent()) 422 : Stmt->getSurroundingLoop(); 423 if (AccVal && 424 AccVal->getType() == MA->getLatestScopArrayInfo()->getElementType() && 425 AccRel.is_single_valued().is_true()) 426 return makeValInst(AccVal, Stmt, L); 427 428 // memset(_, '0', ) is equivalent to writing the null value to all touched 429 // elements. isMustWrite() ensures that all of an element's bytes are 430 // overwritten. 431 if (auto *Memset = dyn_cast<MemSetInst>(AccInst)) { 432 auto *WrittenConstant = dyn_cast<Constant>(Memset->getValue()); 433 Type *Ty = MA->getLatestScopArrayInfo()->getElementType(); 434 if (WrittenConstant && WrittenConstant->isZeroValue()) { 435 Constant *Zero = Constant::getNullValue(Ty); 436 return makeValInst(Zero, Stmt, L); 437 } 438 } 439 440 return {}; 441 } 442 443 void ZoneAlgorithm::addArrayWriteAccess(MemoryAccess *MA) { 444 assert(MA->isLatestArrayKind()); 445 assert(MA->isWrite()); 446 auto *Stmt = MA->getStatement(); 447 448 // { Domain[] -> Element[] } 449 isl::map AccRel = intersectRange(getAccessRelationFor(MA), CompatibleElts); 450 451 if (MA->isMustWrite()) 452 AllMustWrites = AllMustWrites.add_map(AccRel); 453 454 if (MA->isMayWrite()) 455 AllMayWrites = AllMayWrites.add_map(AccRel); 456 457 // { Domain[] -> ValInst[] } 458 isl::map WriteValInstance = getWrittenValue(MA, AccRel); 459 if (!WriteValInstance) 460 WriteValInstance = makeUnknownForDomain(Stmt); 461 462 // { Domain[] -> [Element[] -> Domain[]] } 463 isl::map IncludeElement = AccRel.domain_map().curry(); 464 465 // { [Element[] -> DomainWrite[]] -> ValInst[] } 466 isl::map EltWriteValInst = WriteValInstance.apply_domain(IncludeElement); 467 468 AllWriteValInst = AllWriteValInst.add_map(EltWriteValInst); 469 } 470 471 isl::union_set ZoneAlgorithm::makeEmptyUnionSet() const { 472 return give(isl_union_set_empty(ParamSpace.copy())); 473 } 474 475 isl::union_map ZoneAlgorithm::makeEmptyUnionMap() const { 476 return give(isl_union_map_empty(ParamSpace.copy())); 477 } 478 479 void ZoneAlgorithm::collectCompatibleElts() { 480 // First find all the incompatible elements, then take the complement. 481 // We compile the list of compatible (rather than incompatible) elements so 482 // users can intersect with the list, not requiring a subtract operation. It 483 // also allows us to define a 'universe' of all elements and makes it more 484 // explicit in which array elements can be used. 485 isl::union_set AllElts = makeEmptyUnionSet(); 486 isl::union_set IncompatibleElts = makeEmptyUnionSet(); 487 488 for (auto &Stmt : *S) 489 collectIncompatibleElts(&Stmt, IncompatibleElts, AllElts); 490 491 NumIncompatibleArrays += isl_union_set_n_set(IncompatibleElts.keep()); 492 CompatibleElts = AllElts.subtract(IncompatibleElts); 493 NumCompatibleArrays += isl_union_set_n_set(CompatibleElts.keep()); 494 } 495 496 isl::map ZoneAlgorithm::getScatterFor(ScopStmt *Stmt) const { 497 isl::space ResultSpace = give(isl_space_map_from_domain_and_range( 498 Stmt->getDomainSpace().release(), ScatterSpace.copy())); 499 return give(isl_union_map_extract_map(Schedule.keep(), ResultSpace.take())); 500 } 501 502 isl::map ZoneAlgorithm::getScatterFor(MemoryAccess *MA) const { 503 return getScatterFor(MA->getStatement()); 504 } 505 506 isl::union_map ZoneAlgorithm::getScatterFor(isl::union_set Domain) const { 507 return give(isl_union_map_intersect_domain(Schedule.copy(), Domain.take())); 508 } 509 510 isl::map ZoneAlgorithm::getScatterFor(isl::set Domain) const { 511 auto ResultSpace = give(isl_space_map_from_domain_and_range( 512 isl_set_get_space(Domain.keep()), ScatterSpace.copy())); 513 auto UDomain = give(isl_union_set_from_set(Domain.copy())); 514 auto UResult = getScatterFor(std::move(UDomain)); 515 auto Result = singleton(std::move(UResult), std::move(ResultSpace)); 516 assert(!Result || isl_set_is_equal(give(isl_map_domain(Result.copy())).keep(), 517 Domain.keep()) == isl_bool_true); 518 return Result; 519 } 520 521 isl::set ZoneAlgorithm::getDomainFor(ScopStmt *Stmt) const { 522 return Stmt->getDomain().remove_redundancies(); 523 } 524 525 isl::set ZoneAlgorithm::getDomainFor(MemoryAccess *MA) const { 526 return getDomainFor(MA->getStatement()); 527 } 528 529 isl::map ZoneAlgorithm::getAccessRelationFor(MemoryAccess *MA) const { 530 auto Domain = getDomainFor(MA); 531 auto AccRel = MA->getLatestAccessRelation(); 532 return give(isl_map_intersect_domain(AccRel.take(), Domain.take())); 533 } 534 535 isl::map ZoneAlgorithm::getScalarReachingDefinition(ScopStmt *Stmt) { 536 auto &Result = ScalarReachDefZone[Stmt]; 537 if (Result) 538 return Result; 539 540 auto Domain = getDomainFor(Stmt); 541 Result = computeScalarReachingDefinition(Schedule, Domain, false, true); 542 simplify(Result); 543 544 return Result; 545 } 546 547 isl::map ZoneAlgorithm::getScalarReachingDefinition(isl::set DomainDef) { 548 auto DomId = give(isl_set_get_tuple_id(DomainDef.keep())); 549 auto *Stmt = static_cast<ScopStmt *>(isl_id_get_user(DomId.keep())); 550 551 auto StmtResult = getScalarReachingDefinition(Stmt); 552 553 return give(isl_map_intersect_range(StmtResult.take(), DomainDef.take())); 554 } 555 556 isl::map ZoneAlgorithm::makeUnknownForDomain(ScopStmt *Stmt) const { 557 return ::makeUnknownForDomain(getDomainFor(Stmt)); 558 } 559 560 isl::id ZoneAlgorithm::makeValueId(Value *V) { 561 if (!V) 562 return nullptr; 563 564 auto &Id = ValueIds[V]; 565 if (Id.is_null()) { 566 auto Name = getIslCompatibleName("Val_", V, ValueIds.size() - 1, 567 std::string(), UseInstructionNames); 568 Id = give(isl_id_alloc(IslCtx.get(), Name.c_str(), V)); 569 } 570 return Id; 571 } 572 573 isl::space ZoneAlgorithm::makeValueSpace(Value *V) { 574 auto Result = give(isl_space_set_from_params(ParamSpace.copy())); 575 return give(isl_space_set_tuple_id(Result.take(), isl_dim_set, 576 makeValueId(V).take())); 577 } 578 579 isl::set ZoneAlgorithm::makeValueSet(Value *V) { 580 auto Space = makeValueSpace(V); 581 return give(isl_set_universe(Space.take())); 582 } 583 584 isl::map ZoneAlgorithm::makeValInst(Value *Val, ScopStmt *UserStmt, Loop *Scope, 585 bool IsCertain) { 586 // If the definition/write is conditional, the value at the location could 587 // be either the written value or the old value. Since we cannot know which 588 // one, consider the value to be unknown. 589 if (!IsCertain) 590 return makeUnknownForDomain(UserStmt); 591 592 auto DomainUse = getDomainFor(UserStmt); 593 auto VUse = VirtualUse::create(S, UserStmt, Scope, Val, true); 594 switch (VUse.getKind()) { 595 case VirtualUse::Constant: 596 case VirtualUse::Block: 597 case VirtualUse::Hoisted: 598 case VirtualUse::ReadOnly: { 599 // The definition does not depend on the statement which uses it. 600 auto ValSet = makeValueSet(Val); 601 return give(isl_map_from_domain_and_range(DomainUse.take(), ValSet.take())); 602 } 603 604 case VirtualUse::Synthesizable: { 605 auto *ScevExpr = VUse.getScevExpr(); 606 auto UseDomainSpace = give(isl_set_get_space(DomainUse.keep())); 607 608 // Construct the SCEV space. 609 // TODO: Add only the induction variables referenced in SCEVAddRecExpr 610 // expressions, not just all of them. 611 auto ScevId = give(isl_id_alloc(UseDomainSpace.get_ctx().get(), nullptr, 612 const_cast<SCEV *>(ScevExpr))); 613 auto ScevSpace = 614 give(isl_space_drop_dims(UseDomainSpace.copy(), isl_dim_set, 0, 0)); 615 ScevSpace = give( 616 isl_space_set_tuple_id(ScevSpace.take(), isl_dim_set, ScevId.copy())); 617 618 // { DomainUse[] -> ScevExpr[] } 619 auto ValInst = give(isl_map_identity(isl_space_map_from_domain_and_range( 620 UseDomainSpace.copy(), ScevSpace.copy()))); 621 return ValInst; 622 } 623 624 case VirtualUse::Intra: { 625 // Definition and use is in the same statement. We do not need to compute 626 // a reaching definition. 627 628 // { llvm::Value } 629 auto ValSet = makeValueSet(Val); 630 631 // { UserDomain[] -> llvm::Value } 632 auto ValInstSet = 633 give(isl_map_from_domain_and_range(DomainUse.take(), ValSet.take())); 634 635 // { UserDomain[] -> [UserDomain[] - >llvm::Value] } 636 auto Result = give(isl_map_reverse(isl_map_domain_map(ValInstSet.take()))); 637 simplify(Result); 638 return Result; 639 } 640 641 case VirtualUse::Inter: { 642 // The value is defined in a different statement. 643 644 auto *Inst = cast<Instruction>(Val); 645 auto *ValStmt = S->getStmtFor(Inst); 646 647 // If the llvm::Value is defined in a removed Stmt, we cannot derive its 648 // domain. We could use an arbitrary statement, but this could result in 649 // different ValInst[] for the same llvm::Value. 650 if (!ValStmt) 651 return ::makeUnknownForDomain(DomainUse); 652 653 // { DomainDef[] } 654 auto DomainDef = getDomainFor(ValStmt); 655 656 // { Scatter[] -> DomainDef[] } 657 auto ReachDef = getScalarReachingDefinition(DomainDef); 658 659 // { DomainUse[] -> Scatter[] } 660 auto UserSched = getScatterFor(DomainUse); 661 662 // { DomainUse[] -> DomainDef[] } 663 auto UsedInstance = 664 give(isl_map_apply_range(UserSched.take(), ReachDef.take())); 665 666 // { llvm::Value } 667 auto ValSet = makeValueSet(Val); 668 669 // { DomainUse[] -> llvm::Value[] } 670 auto ValInstSet = 671 give(isl_map_from_domain_and_range(DomainUse.take(), ValSet.take())); 672 673 // { DomainUse[] -> [DomainDef[] -> llvm::Value] } 674 auto Result = 675 give(isl_map_range_product(UsedInstance.take(), ValInstSet.take())); 676 677 simplify(Result); 678 return Result; 679 } 680 } 681 llvm_unreachable("Unhandled use type"); 682 } 683 684 bool ZoneAlgorithm::isCompatibleAccess(MemoryAccess *MA) { 685 if (!MA) 686 return false; 687 if (!MA->isLatestArrayKind()) 688 return false; 689 Instruction *AccInst = MA->getAccessInstruction(); 690 return isa<StoreInst>(AccInst) || isa<LoadInst>(AccInst); 691 } 692 693 void ZoneAlgorithm::computeCommon() { 694 AllReads = makeEmptyUnionMap(); 695 AllMayWrites = makeEmptyUnionMap(); 696 AllMustWrites = makeEmptyUnionMap(); 697 AllWriteValInst = makeEmptyUnionMap(); 698 AllReadValInst = makeEmptyUnionMap(); 699 700 for (auto &Stmt : *S) { 701 for (auto *MA : Stmt) { 702 if (!MA->isLatestArrayKind()) 703 continue; 704 705 if (MA->isRead()) 706 addArrayReadAccess(MA); 707 708 if (MA->isWrite()) 709 addArrayWriteAccess(MA); 710 } 711 } 712 713 // { DomainWrite[] -> Element[] } 714 AllWrites = 715 give(isl_union_map_union(AllMustWrites.copy(), AllMayWrites.copy())); 716 717 // { [Element[] -> Zone[]] -> DomainWrite[] } 718 WriteReachDefZone = 719 computeReachingDefinition(Schedule, AllWrites, false, true); 720 simplify(WriteReachDefZone); 721 } 722 723 void ZoneAlgorithm::printAccesses(llvm::raw_ostream &OS, int Indent) const { 724 OS.indent(Indent) << "After accesses {\n"; 725 for (auto &Stmt : *S) { 726 OS.indent(Indent + 4) << Stmt.getBaseName() << "\n"; 727 for (auto *MA : Stmt) 728 MA->print(OS); 729 } 730 OS.indent(Indent) << "}\n"; 731 } 732 733 isl::union_map ZoneAlgorithm::computeKnownFromMustWrites() const { 734 // { [Element[] -> Zone[]] -> [Element[] -> DomainWrite[]] } 735 isl::union_map EltReachdDef = distributeDomain(WriteReachDefZone.curry()); 736 737 // { [Element[] -> DomainWrite[]] -> ValInst[] } 738 isl::union_map AllKnownWriteValInst = filterKnownValInst(AllWriteValInst); 739 740 // { [Element[] -> Zone[]] -> ValInst[] } 741 return EltReachdDef.apply_range(AllKnownWriteValInst); 742 } 743 744 isl::union_map ZoneAlgorithm::computeKnownFromLoad() const { 745 // { Element[] } 746 isl::union_set AllAccessedElts = AllReads.range().unite(AllWrites.range()); 747 748 // { Element[] -> Scatter[] } 749 isl::union_map EltZoneUniverse = isl::union_map::from_domain_and_range( 750 AllAccessedElts, isl::set::universe(ScatterSpace)); 751 752 // This assumes there are no "holes" in 753 // isl_union_map_domain(WriteReachDefZone); alternatively, compute the zone 754 // before the first write or that are not written at all. 755 // { Element[] -> Scatter[] } 756 isl::union_set NonReachDef = 757 EltZoneUniverse.wrap().subtract(WriteReachDefZone.domain()); 758 759 // { [Element[] -> Zone[]] -> ReachDefId[] } 760 isl::union_map DefZone = 761 WriteReachDefZone.unite(isl::union_map::from_domain(NonReachDef)); 762 763 // { [Element[] -> Scatter[]] -> Element[] } 764 isl::union_map EltZoneElt = EltZoneUniverse.domain_map(); 765 766 // { [Element[] -> Zone[]] -> [Element[] -> ReachDefId[]] } 767 isl::union_map DefZoneEltDefId = EltZoneElt.range_product(DefZone); 768 769 // { Element[] -> [Zone[] -> ReachDefId[]] } 770 isl::union_map EltDefZone = DefZone.curry(); 771 772 // { [Element[] -> Zone[] -> [Element[] -> ReachDefId[]] } 773 isl::union_map EltZoneEltDefid = distributeDomain(EltDefZone); 774 775 // { [Element[] -> Scatter[]] -> DomainRead[] } 776 isl::union_map Reads = AllReads.range_product(Schedule).reverse(); 777 778 // { [Element[] -> Scatter[]] -> [Element[] -> DomainRead[]] } 779 isl::union_map ReadsElt = EltZoneElt.range_product(Reads); 780 781 // { [Element[] -> Scatter[]] -> ValInst[] } 782 isl::union_map ScatterKnown = ReadsElt.apply_range(AllReadValInst); 783 784 // { [Element[] -> ReachDefId[]] -> ValInst[] } 785 isl::union_map DefidKnown = 786 DefZoneEltDefId.apply_domain(ScatterKnown).reverse(); 787 788 // { [Element[] -> Zone[]] -> ValInst[] } 789 return DefZoneEltDefId.apply_range(DefidKnown); 790 } 791 792 isl::union_map ZoneAlgorithm::computeKnown(bool FromWrite, 793 bool FromRead) const { 794 isl::union_map Result = makeEmptyUnionMap(); 795 796 if (FromWrite) 797 Result = Result.unite(computeKnownFromMustWrites()); 798 799 if (FromRead) 800 Result = Result.unite(computeKnownFromLoad()); 801 802 simplify(Result); 803 return Result; 804 } 805