1 //===- ScopInfo.cpp -------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Create a polyhedral description for a static control flow region. 10 // 11 // The pass creates a polyhedral description of the Scops detected by the Scop 12 // detection derived from their LLVM-IR code. 13 // 14 // This representation is shared among several tools in the polyhedral 15 // community, which are e.g. Cloog, Pluto, Loopo, Graphite. 16 // 17 //===----------------------------------------------------------------------===// 18 19 #include "polly/ScopInfo.h" 20 #include "polly/LinkAllPasses.h" 21 #include "polly/Options.h" 22 #include "polly/ScopBuilder.h" 23 #include "polly/ScopDetection.h" 24 #include "polly/Support/GICHelper.h" 25 #include "polly/Support/ISLOStream.h" 26 #include "polly/Support/ISLTools.h" 27 #include "polly/Support/SCEVAffinator.h" 28 #include "polly/Support/SCEVValidator.h" 29 #include "polly/Support/ScopHelper.h" 30 #include "llvm/ADT/APInt.h" 31 #include "llvm/ADT/ArrayRef.h" 32 #include "llvm/ADT/PostOrderIterator.h" 33 #include "llvm/ADT/Sequence.h" 34 #include "llvm/ADT/SmallPtrSet.h" 35 #include "llvm/ADT/SmallSet.h" 36 #include "llvm/ADT/Statistic.h" 37 #include "llvm/ADT/StringExtras.h" 38 #include "llvm/Analysis/AliasAnalysis.h" 39 #include "llvm/Analysis/AssumptionCache.h" 40 #include "llvm/Analysis/Loads.h" 41 #include "llvm/Analysis/LoopInfo.h" 42 #include "llvm/Analysis/OptimizationRemarkEmitter.h" 43 #include "llvm/Analysis/RegionInfo.h" 44 #include "llvm/Analysis/RegionIterator.h" 45 #include "llvm/Analysis/ScalarEvolution.h" 46 #include "llvm/Analysis/ScalarEvolutionExpressions.h" 47 #include "llvm/IR/BasicBlock.h" 48 #include "llvm/IR/ConstantRange.h" 49 #include "llvm/IR/DataLayout.h" 50 #include "llvm/IR/DebugLoc.h" 51 #include "llvm/IR/Dominators.h" 52 #include "llvm/IR/Function.h" 53 #include "llvm/IR/InstrTypes.h" 54 #include "llvm/IR/Instruction.h" 55 #include "llvm/IR/Instructions.h" 56 #include "llvm/IR/Module.h" 57 #include "llvm/IR/PassManager.h" 58 #include "llvm/IR/Type.h" 59 #include "llvm/IR/Value.h" 60 #include "llvm/InitializePasses.h" 61 #include "llvm/Support/Compiler.h" 62 #include "llvm/Support/Debug.h" 63 #include "llvm/Support/ErrorHandling.h" 64 #include "llvm/Support/raw_ostream.h" 65 #include "isl/aff.h" 66 #include "isl/local_space.h" 67 #include "isl/map.h" 68 #include "isl/options.h" 69 #include "isl/set.h" 70 #include <cassert> 71 #include <numeric> 72 73 using namespace llvm; 74 using namespace polly; 75 76 #include "polly/Support/PollyDebug.h" 77 #define DEBUG_TYPE "polly-scops" 78 79 STATISTIC(AssumptionsAliasing, "Number of aliasing assumptions taken."); 80 STATISTIC(AssumptionsInbounds, "Number of inbounds assumptions taken."); 81 STATISTIC(AssumptionsWrapping, "Number of wrapping assumptions taken."); 82 STATISTIC(AssumptionsUnsigned, "Number of unsigned assumptions taken."); 83 STATISTIC(AssumptionsComplexity, "Number of too complex SCoPs."); 84 STATISTIC(AssumptionsUnprofitable, "Number of unprofitable SCoPs."); 85 STATISTIC(AssumptionsErrorBlock, "Number of error block assumptions taken."); 86 STATISTIC(AssumptionsInfiniteLoop, "Number of bounded loop assumptions taken."); 87 STATISTIC(AssumptionsInvariantLoad, 88 "Number of invariant loads assumptions taken."); 89 STATISTIC(AssumptionsDelinearization, 90 "Number of delinearization assumptions taken."); 91 92 STATISTIC(NumScops, "Number of feasible SCoPs after ScopInfo"); 93 STATISTIC(NumLoopsInScop, "Number of loops in scops"); 94 STATISTIC(NumBoxedLoops, "Number of boxed loops in SCoPs after ScopInfo"); 95 STATISTIC(NumAffineLoops, "Number of affine loops in SCoPs after ScopInfo"); 96 97 STATISTIC(NumScopsDepthZero, "Number of scops with maximal loop depth 0"); 98 STATISTIC(NumScopsDepthOne, "Number of scops with maximal loop depth 1"); 99 STATISTIC(NumScopsDepthTwo, "Number of scops with maximal loop depth 2"); 100 STATISTIC(NumScopsDepthThree, "Number of scops with maximal loop depth 3"); 101 STATISTIC(NumScopsDepthFour, "Number of scops with maximal loop depth 4"); 102 STATISTIC(NumScopsDepthFive, "Number of scops with maximal loop depth 5"); 103 STATISTIC(NumScopsDepthLarger, 104 "Number of scops with maximal loop depth 6 and larger"); 105 STATISTIC(MaxNumLoopsInScop, "Maximal number of loops in scops"); 106 107 STATISTIC(NumValueWrites, "Number of scalar value writes after ScopInfo"); 108 STATISTIC( 109 NumValueWritesInLoops, 110 "Number of scalar value writes nested in affine loops after ScopInfo"); 111 STATISTIC(NumPHIWrites, "Number of scalar phi writes after ScopInfo"); 112 STATISTIC(NumPHIWritesInLoops, 113 "Number of scalar phi writes nested in affine loops after ScopInfo"); 114 STATISTIC(NumSingletonWrites, "Number of singleton writes after ScopInfo"); 115 STATISTIC(NumSingletonWritesInLoops, 116 "Number of singleton writes nested in affine loops after ScopInfo"); 117 118 unsigned const polly::MaxDisjunctsInDomain = 20; 119 120 // The number of disjunct in the context after which we stop to add more 121 // disjuncts. This parameter is there to avoid exponential growth in the 122 // number of disjunct when adding non-convex sets to the context. 123 static int const MaxDisjunctsInContext = 4; 124 125 // Be a bit more generous for the defined behavior context which is used less 126 // often. 127 static int const MaxDisjunktsInDefinedBehaviourContext = 8; 128 129 static cl::opt<bool> PollyRemarksMinimal( 130 "polly-remarks-minimal", 131 cl::desc("Do not emit remarks about assumptions that are known"), 132 cl::Hidden, cl::cat(PollyCategory)); 133 134 static cl::opt<bool> 135 IslOnErrorAbort("polly-on-isl-error-abort", 136 cl::desc("Abort if an isl error is encountered"), 137 cl::init(true), cl::cat(PollyCategory)); 138 139 static cl::opt<bool> PollyPreciseInbounds( 140 "polly-precise-inbounds", 141 cl::desc("Take more precise inbounds assumptions (do not scale well)"), 142 cl::Hidden, cl::init(false), cl::cat(PollyCategory)); 143 144 static cl::opt<bool> PollyIgnoreParamBounds( 145 "polly-ignore-parameter-bounds", 146 cl::desc( 147 "Do not add parameter bounds and do no gist simplify sets accordingly"), 148 cl::Hidden, cl::init(false), cl::cat(PollyCategory)); 149 150 static cl::opt<bool> PollyPreciseFoldAccesses( 151 "polly-precise-fold-accesses", 152 cl::desc("Fold memory accesses to model more possible delinearizations " 153 "(does not scale well)"), 154 cl::Hidden, cl::init(false), cl::cat(PollyCategory)); 155 156 bool polly::UseInstructionNames; 157 158 static cl::opt<bool, true> XUseInstructionNames( 159 "polly-use-llvm-names", 160 cl::desc("Use LLVM-IR names when deriving statement names"), 161 cl::location(UseInstructionNames), cl::Hidden, cl::cat(PollyCategory)); 162 163 static cl::opt<bool> PollyPrintInstructions( 164 "polly-print-instructions", cl::desc("Output instructions per ScopStmt"), 165 cl::Hidden, cl::Optional, cl::init(false), cl::cat(PollyCategory)); 166 167 static cl::list<std::string> IslArgs("polly-isl-arg", 168 cl::value_desc("argument"), 169 cl::desc("Option passed to ISL"), 170 cl::cat(PollyCategory)); 171 172 //===----------------------------------------------------------------------===// 173 174 static isl::set addRangeBoundsToSet(isl::set S, const ConstantRange &Range, 175 int dim, isl::dim type) { 176 isl::val V; 177 isl::ctx Ctx = S.ctx(); 178 179 // The upper and lower bound for a parameter value is derived either from 180 // the data type of the parameter or from the - possibly more restrictive - 181 // range metadata. 182 V = valFromAPInt(Ctx.get(), Range.getSignedMin(), true); 183 S = S.lower_bound_val(type, dim, V); 184 V = valFromAPInt(Ctx.get(), Range.getSignedMax(), true); 185 S = S.upper_bound_val(type, dim, V); 186 187 if (Range.isFullSet()) 188 return S; 189 190 if (S.n_basic_set().release() > MaxDisjunctsInContext) 191 return S; 192 193 // In case of signed wrapping, we can refine the set of valid values by 194 // excluding the part not covered by the wrapping range. 195 if (Range.isSignWrappedSet()) { 196 V = valFromAPInt(Ctx.get(), Range.getLower(), true); 197 isl::set SLB = S.lower_bound_val(type, dim, V); 198 199 V = valFromAPInt(Ctx.get(), Range.getUpper(), true); 200 V = V.sub(1); 201 isl::set SUB = S.upper_bound_val(type, dim, V); 202 S = SLB.unite(SUB); 203 } 204 205 return S; 206 } 207 208 static const ScopArrayInfo *identifyBasePtrOriginSAI(Scop *S, Value *BasePtr) { 209 LoadInst *BasePtrLI = dyn_cast<LoadInst>(BasePtr); 210 if (!BasePtrLI) 211 return nullptr; 212 213 if (!S->contains(BasePtrLI)) 214 return nullptr; 215 216 ScalarEvolution &SE = *S->getSE(); 217 218 const SCEV *OriginBaseSCEV = 219 SE.getPointerBase(SE.getSCEV(BasePtrLI->getPointerOperand())); 220 if (!OriginBaseSCEV) 221 return nullptr; 222 223 auto *OriginBaseSCEVUnknown = dyn_cast<SCEVUnknown>(OriginBaseSCEV); 224 if (!OriginBaseSCEVUnknown) 225 return nullptr; 226 227 return S->getScopArrayInfo(OriginBaseSCEVUnknown->getValue(), 228 MemoryKind::Array); 229 } 230 231 ScopArrayInfo::ScopArrayInfo(Value *BasePtr, Type *ElementType, isl::ctx Ctx, 232 ArrayRef<const SCEV *> Sizes, MemoryKind Kind, 233 const DataLayout &DL, Scop *S, 234 const char *BaseName) 235 : BasePtr(BasePtr), ElementType(ElementType), Kind(Kind), DL(DL), S(*S) { 236 std::string BasePtrName = 237 BaseName ? BaseName 238 : getIslCompatibleName("MemRef", BasePtr, S->getNextArrayIdx(), 239 Kind == MemoryKind::PHI ? "__phi" : "", 240 UseInstructionNames); 241 Id = isl::id::alloc(Ctx, BasePtrName, this); 242 243 updateSizes(Sizes); 244 245 if (!BasePtr || Kind != MemoryKind::Array) { 246 BasePtrOriginSAI = nullptr; 247 return; 248 } 249 250 BasePtrOriginSAI = identifyBasePtrOriginSAI(S, BasePtr); 251 if (BasePtrOriginSAI) 252 const_cast<ScopArrayInfo *>(BasePtrOriginSAI)->addDerivedSAI(this); 253 } 254 255 ScopArrayInfo::~ScopArrayInfo() = default; 256 257 isl::space ScopArrayInfo::getSpace() const { 258 auto Space = isl::space(Id.ctx(), 0, getNumberOfDimensions()); 259 Space = Space.set_tuple_id(isl::dim::set, Id); 260 return Space; 261 } 262 263 bool ScopArrayInfo::isReadOnly() { 264 isl::union_set WriteSet = S.getWrites().range(); 265 isl::space Space = getSpace(); 266 WriteSet = WriteSet.extract_set(Space); 267 268 return bool(WriteSet.is_empty()); 269 } 270 271 bool ScopArrayInfo::isCompatibleWith(const ScopArrayInfo *Array) const { 272 if (Array->getElementType() != getElementType()) 273 return false; 274 275 if (Array->getNumberOfDimensions() != getNumberOfDimensions()) 276 return false; 277 278 for (unsigned i = 0; i < getNumberOfDimensions(); i++) 279 if (Array->getDimensionSize(i) != getDimensionSize(i)) 280 return false; 281 282 return true; 283 } 284 285 void ScopArrayInfo::updateElementType(Type *NewElementType) { 286 if (NewElementType == ElementType) 287 return; 288 289 auto OldElementSize = DL.getTypeAllocSizeInBits(ElementType); 290 auto NewElementSize = DL.getTypeAllocSizeInBits(NewElementType); 291 292 if (NewElementSize == OldElementSize || NewElementSize == 0) 293 return; 294 295 if (NewElementSize % OldElementSize == 0 && NewElementSize < OldElementSize) { 296 ElementType = NewElementType; 297 } else { 298 auto GCD = std::gcd((uint64_t)NewElementSize, (uint64_t)OldElementSize); 299 ElementType = IntegerType::get(ElementType->getContext(), GCD); 300 } 301 } 302 303 bool ScopArrayInfo::updateSizes(ArrayRef<const SCEV *> NewSizes, 304 bool CheckConsistency) { 305 int SharedDims = std::min(NewSizes.size(), DimensionSizes.size()); 306 int ExtraDimsNew = NewSizes.size() - SharedDims; 307 int ExtraDimsOld = DimensionSizes.size() - SharedDims; 308 309 if (CheckConsistency) { 310 for (int i = 0; i < SharedDims; i++) { 311 auto *NewSize = NewSizes[i + ExtraDimsNew]; 312 auto *KnownSize = DimensionSizes[i + ExtraDimsOld]; 313 if (NewSize && KnownSize && NewSize != KnownSize) 314 return false; 315 } 316 317 if (DimensionSizes.size() >= NewSizes.size()) 318 return true; 319 } 320 321 DimensionSizes.clear(); 322 DimensionSizes.insert(DimensionSizes.begin(), NewSizes.begin(), 323 NewSizes.end()); 324 DimensionSizesPw.clear(); 325 for (const SCEV *Expr : DimensionSizes) { 326 if (!Expr) { 327 DimensionSizesPw.push_back(isl::pw_aff()); 328 continue; 329 } 330 isl::pw_aff Size = S.getPwAffOnly(Expr); 331 DimensionSizesPw.push_back(Size); 332 } 333 return true; 334 } 335 336 std::string ScopArrayInfo::getName() const { return Id.get_name(); } 337 338 int ScopArrayInfo::getElemSizeInBytes() const { 339 return DL.getTypeAllocSize(ElementType); 340 } 341 342 isl::id ScopArrayInfo::getBasePtrId() const { return Id; } 343 344 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 345 LLVM_DUMP_METHOD void ScopArrayInfo::dump() const { print(errs()); } 346 #endif 347 348 void ScopArrayInfo::print(raw_ostream &OS, bool SizeAsPwAff) const { 349 OS.indent(8) << *getElementType() << " " << getName(); 350 unsigned u = 0; 351 352 if (getNumberOfDimensions() > 0 && !getDimensionSize(0)) { 353 OS << "[*]"; 354 u++; 355 } 356 for (; u < getNumberOfDimensions(); u++) { 357 OS << "["; 358 359 if (SizeAsPwAff) { 360 isl::pw_aff Size = getDimensionSizePw(u); 361 OS << " " << Size << " "; 362 } else { 363 OS << *getDimensionSize(u); 364 } 365 366 OS << "]"; 367 } 368 369 OS << ";"; 370 371 if (BasePtrOriginSAI) 372 OS << " [BasePtrOrigin: " << BasePtrOriginSAI->getName() << "]"; 373 374 OS << " // Element size " << getElemSizeInBytes() << "\n"; 375 } 376 377 const ScopArrayInfo * 378 ScopArrayInfo::getFromAccessFunction(isl::pw_multi_aff PMA) { 379 isl::id Id = PMA.get_tuple_id(isl::dim::out); 380 assert(!Id.is_null() && "Output dimension didn't have an ID"); 381 return getFromId(Id); 382 } 383 384 const ScopArrayInfo *ScopArrayInfo::getFromId(isl::id Id) { 385 void *User = Id.get_user(); 386 const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User); 387 return SAI; 388 } 389 390 void MemoryAccess::wrapConstantDimensions() { 391 auto *SAI = getScopArrayInfo(); 392 isl::space ArraySpace = SAI->getSpace(); 393 isl::ctx Ctx = ArraySpace.ctx(); 394 unsigned DimsArray = SAI->getNumberOfDimensions(); 395 396 isl::multi_aff DivModAff = isl::multi_aff::identity( 397 ArraySpace.map_from_domain_and_range(ArraySpace)); 398 isl::local_space LArraySpace = isl::local_space(ArraySpace); 399 400 // Begin with last dimension, to iteratively carry into higher dimensions. 401 for (int i = DimsArray - 1; i > 0; i--) { 402 auto *DimSize = SAI->getDimensionSize(i); 403 auto *DimSizeCst = dyn_cast<SCEVConstant>(DimSize); 404 405 // This transformation is not applicable to dimensions with dynamic size. 406 if (!DimSizeCst) 407 continue; 408 409 // This transformation is not applicable to dimensions of size zero. 410 if (DimSize->isZero()) 411 continue; 412 413 isl::val DimSizeVal = 414 valFromAPInt(Ctx.get(), DimSizeCst->getAPInt(), false); 415 isl::aff Var = isl::aff::var_on_domain(LArraySpace, isl::dim::set, i); 416 isl::aff PrevVar = 417 isl::aff::var_on_domain(LArraySpace, isl::dim::set, i - 1); 418 419 // Compute: index % size 420 // Modulo must apply in the divide of the previous iteration, if any. 421 isl::aff Modulo = Var.mod(DimSizeVal); 422 Modulo = Modulo.pullback(DivModAff); 423 424 // Compute: floor(index / size) 425 isl::aff Divide = Var.div(isl::aff(LArraySpace, DimSizeVal)); 426 Divide = Divide.floor(); 427 Divide = Divide.add(PrevVar); 428 Divide = Divide.pullback(DivModAff); 429 430 // Apply Modulo and Divide. 431 DivModAff = DivModAff.set_aff(i, Modulo); 432 DivModAff = DivModAff.set_aff(i - 1, Divide); 433 } 434 435 // Apply all modulo/divides on the accesses. 436 isl::map Relation = AccessRelation; 437 Relation = Relation.apply_range(isl::map::from_multi_aff(DivModAff)); 438 Relation = Relation.detect_equalities(); 439 AccessRelation = Relation; 440 } 441 442 void MemoryAccess::updateDimensionality() { 443 auto *SAI = getScopArrayInfo(); 444 isl::space ArraySpace = SAI->getSpace(); 445 isl::space AccessSpace = AccessRelation.get_space().range(); 446 isl::ctx Ctx = ArraySpace.ctx(); 447 448 unsigned DimsArray = unsignedFromIslSize(ArraySpace.dim(isl::dim::set)); 449 unsigned DimsAccess = unsignedFromIslSize(AccessSpace.dim(isl::dim::set)); 450 assert(DimsArray >= DimsAccess); 451 unsigned DimsMissing = DimsArray - DimsAccess; 452 453 auto *BB = getStatement()->getEntryBlock(); 454 auto &DL = BB->getModule()->getDataLayout(); 455 unsigned ArrayElemSize = SAI->getElemSizeInBytes(); 456 unsigned ElemBytes = DL.getTypeAllocSize(getElementType()); 457 458 isl::map Map = isl::map::from_domain_and_range( 459 isl::set::universe(AccessSpace), isl::set::universe(ArraySpace)); 460 461 for (auto i : seq<unsigned>(0, DimsMissing)) 462 Map = Map.fix_si(isl::dim::out, i, 0); 463 464 for (auto i : seq<unsigned>(DimsMissing, DimsArray)) 465 Map = Map.equate(isl::dim::in, i - DimsMissing, isl::dim::out, i); 466 467 AccessRelation = AccessRelation.apply_range(Map); 468 469 // For the non delinearized arrays, divide the access function of the last 470 // subscript by the size of the elements in the array. 471 // 472 // A stride one array access in C expressed as A[i] is expressed in 473 // LLVM-IR as something like A[i * elementsize]. This hides the fact that 474 // two subsequent values of 'i' index two values that are stored next to 475 // each other in memory. By this division we make this characteristic 476 // obvious again. If the base pointer was accessed with offsets not divisible 477 // by the accesses element size, we will have chosen a smaller ArrayElemSize 478 // that divides the offsets of all accesses to this base pointer. 479 if (DimsAccess == 1) { 480 isl::val V = isl::val(Ctx, ArrayElemSize); 481 AccessRelation = AccessRelation.floordiv_val(V); 482 } 483 484 // We currently do this only if we added at least one dimension, which means 485 // some dimension's indices have not been specified, an indicator that some 486 // index values have been added together. 487 // TODO: Investigate general usefulness; Effect on unit tests is to make index 488 // expressions more complicated. 489 if (DimsMissing) 490 wrapConstantDimensions(); 491 492 if (!isAffine()) 493 computeBoundsOnAccessRelation(ArrayElemSize); 494 495 // Introduce multi-element accesses in case the type loaded by this memory 496 // access is larger than the canonical element type of the array. 497 // 498 // An access ((float *)A)[i] to an array char *A is modeled as 499 // {[i] -> A[o] : 4 i <= o <= 4 i + 3 500 if (ElemBytes > ArrayElemSize) { 501 assert(ElemBytes % ArrayElemSize == 0 && 502 "Loaded element size should be multiple of canonical element size"); 503 assert(DimsArray >= 1); 504 isl::map Map = isl::map::from_domain_and_range( 505 isl::set::universe(ArraySpace), isl::set::universe(ArraySpace)); 506 for (auto i : seq<unsigned>(0, DimsArray - 1)) 507 Map = Map.equate(isl::dim::in, i, isl::dim::out, i); 508 509 isl::constraint C; 510 isl::local_space LS; 511 512 LS = isl::local_space(Map.get_space()); 513 int Num = ElemBytes / getScopArrayInfo()->getElemSizeInBytes(); 514 515 C = isl::constraint::alloc_inequality(LS); 516 C = C.set_constant_val(isl::val(Ctx, Num - 1)); 517 C = C.set_coefficient_si(isl::dim::in, DimsArray - 1, 1); 518 C = C.set_coefficient_si(isl::dim::out, DimsArray - 1, -1); 519 Map = Map.add_constraint(C); 520 521 C = isl::constraint::alloc_inequality(LS); 522 C = C.set_coefficient_si(isl::dim::in, DimsArray - 1, -1); 523 C = C.set_coefficient_si(isl::dim::out, DimsArray - 1, 1); 524 C = C.set_constant_val(isl::val(Ctx, 0)); 525 Map = Map.add_constraint(C); 526 AccessRelation = AccessRelation.apply_range(Map); 527 } 528 } 529 530 const std::string 531 MemoryAccess::getReductionOperatorStr(MemoryAccess::ReductionType RT) { 532 switch (RT) { 533 case MemoryAccess::RT_NONE: 534 llvm_unreachable("Requested a reduction operator string for a memory " 535 "access which isn't a reduction"); 536 case MemoryAccess::RT_BOTTOM: 537 llvm_unreachable("Requested a reduction operator string for a internal " 538 "reduction type!"); 539 case MemoryAccess::RT_ADD: 540 return "+"; 541 case MemoryAccess::RT_MUL: 542 return "*"; 543 case MemoryAccess::RT_BOR: 544 return "|"; 545 case MemoryAccess::RT_BXOR: 546 return "^"; 547 case MemoryAccess::RT_BAND: 548 return "&"; 549 } 550 llvm_unreachable("Unknown reduction type"); 551 } 552 553 const ScopArrayInfo *MemoryAccess::getOriginalScopArrayInfo() const { 554 isl::id ArrayId = getArrayId(); 555 void *User = ArrayId.get_user(); 556 const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User); 557 return SAI; 558 } 559 560 const ScopArrayInfo *MemoryAccess::getLatestScopArrayInfo() const { 561 isl::id ArrayId = getLatestArrayId(); 562 void *User = ArrayId.get_user(); 563 const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User); 564 return SAI; 565 } 566 567 isl::id MemoryAccess::getOriginalArrayId() const { 568 return AccessRelation.get_tuple_id(isl::dim::out); 569 } 570 571 isl::id MemoryAccess::getLatestArrayId() const { 572 if (!hasNewAccessRelation()) 573 return getOriginalArrayId(); 574 return NewAccessRelation.get_tuple_id(isl::dim::out); 575 } 576 577 isl::map MemoryAccess::getAddressFunction() const { 578 return getAccessRelation().lexmin(); 579 } 580 581 isl::pw_multi_aff 582 MemoryAccess::applyScheduleToAccessRelation(isl::union_map USchedule) const { 583 isl::map Schedule, ScheduledAccRel; 584 isl::union_set UDomain; 585 586 UDomain = getStatement()->getDomain(); 587 USchedule = USchedule.intersect_domain(UDomain); 588 Schedule = isl::map::from_union_map(USchedule); 589 ScheduledAccRel = getAddressFunction().apply_domain(Schedule); 590 return isl::pw_multi_aff::from_map(ScheduledAccRel); 591 } 592 593 isl::map MemoryAccess::getOriginalAccessRelation() const { 594 return AccessRelation; 595 } 596 597 std::string MemoryAccess::getOriginalAccessRelationStr() const { 598 return stringFromIslObj(AccessRelation); 599 } 600 601 isl::space MemoryAccess::getOriginalAccessRelationSpace() const { 602 return AccessRelation.get_space(); 603 } 604 605 isl::map MemoryAccess::getNewAccessRelation() const { 606 return NewAccessRelation; 607 } 608 609 std::string MemoryAccess::getNewAccessRelationStr() const { 610 return stringFromIslObj(NewAccessRelation); 611 } 612 613 std::string MemoryAccess::getAccessRelationStr() const { 614 return stringFromIslObj(getAccessRelation()); 615 } 616 617 isl::basic_map MemoryAccess::createBasicAccessMap(ScopStmt *Statement) { 618 isl::space Space = isl::space(Statement->getIslCtx(), 0, 1); 619 Space = Space.align_params(Statement->getDomainSpace()); 620 621 return isl::basic_map::from_domain_and_range( 622 isl::basic_set::universe(Statement->getDomainSpace()), 623 isl::basic_set::universe(Space)); 624 } 625 626 // Formalize no out-of-bound access assumption 627 // 628 // When delinearizing array accesses we optimistically assume that the 629 // delinearized accesses do not access out of bound locations (the subscript 630 // expression of each array evaluates for each statement instance that is 631 // executed to a value that is larger than zero and strictly smaller than the 632 // size of the corresponding dimension). The only exception is the outermost 633 // dimension for which we do not need to assume any upper bound. At this point 634 // we formalize this assumption to ensure that at code generation time the 635 // relevant run-time checks can be generated. 636 // 637 // To find the set of constraints necessary to avoid out of bound accesses, we 638 // first build the set of data locations that are not within array bounds. We 639 // then apply the reverse access relation to obtain the set of iterations that 640 // may contain invalid accesses and reduce this set of iterations to the ones 641 // that are actually executed by intersecting them with the domain of the 642 // statement. If we now project out all loop dimensions, we obtain a set of 643 // parameters that may cause statement instances to be executed that may 644 // possibly yield out of bound memory accesses. The complement of these 645 // constraints is the set of constraints that needs to be assumed to ensure such 646 // statement instances are never executed. 647 isl::set MemoryAccess::assumeNoOutOfBound() { 648 auto *SAI = getScopArrayInfo(); 649 isl::space Space = getOriginalAccessRelationSpace().range(); 650 isl::set Outside = isl::set::empty(Space); 651 for (int i = 1, Size = Space.dim(isl::dim::set).release(); i < Size; ++i) { 652 isl::local_space LS(Space); 653 isl::pw_aff Var = isl::pw_aff::var_on_domain(LS, isl::dim::set, i); 654 isl::pw_aff Zero = isl::pw_aff(LS); 655 656 isl::set DimOutside = Var.lt_set(Zero); 657 isl::pw_aff SizeE = SAI->getDimensionSizePw(i); 658 SizeE = SizeE.add_dims(isl::dim::in, Space.dim(isl::dim::set).release()); 659 SizeE = SizeE.set_tuple_id(isl::dim::in, Space.get_tuple_id(isl::dim::set)); 660 DimOutside = DimOutside.unite(SizeE.le_set(Var)); 661 662 Outside = Outside.unite(DimOutside); 663 } 664 665 Outside = Outside.apply(getAccessRelation().reverse()); 666 Outside = Outside.intersect(Statement->getDomain()); 667 Outside = Outside.params(); 668 669 // Remove divs to avoid the construction of overly complicated assumptions. 670 // Doing so increases the set of parameter combinations that are assumed to 671 // not appear. This is always save, but may make the resulting run-time check 672 // bail out more often than strictly necessary. 673 Outside = Outside.remove_divs(); 674 Outside = Outside.complement(); 675 676 if (!PollyPreciseInbounds) 677 Outside = Outside.gist_params(Statement->getDomain().params()); 678 return Outside; 679 } 680 681 void MemoryAccess::buildMemIntrinsicAccessRelation() { 682 assert(isMemoryIntrinsic()); 683 assert(Subscripts.size() == 2 && Sizes.size() == 1); 684 685 isl::pw_aff SubscriptPWA = getPwAff(Subscripts[0]); 686 isl::map SubscriptMap = isl::map::from_pw_aff(SubscriptPWA); 687 688 isl::map LengthMap; 689 if (Subscripts[1] == nullptr) { 690 LengthMap = isl::map::universe(SubscriptMap.get_space()); 691 } else { 692 isl::pw_aff LengthPWA = getPwAff(Subscripts[1]); 693 LengthMap = isl::map::from_pw_aff(LengthPWA); 694 isl::space RangeSpace = LengthMap.get_space().range(); 695 LengthMap = LengthMap.apply_range(isl::map::lex_gt(RangeSpace)); 696 } 697 LengthMap = LengthMap.lower_bound_si(isl::dim::out, 0, 0); 698 LengthMap = LengthMap.align_params(SubscriptMap.get_space()); 699 SubscriptMap = SubscriptMap.align_params(LengthMap.get_space()); 700 LengthMap = LengthMap.sum(SubscriptMap); 701 AccessRelation = 702 LengthMap.set_tuple_id(isl::dim::in, getStatement()->getDomainId()); 703 } 704 705 void MemoryAccess::computeBoundsOnAccessRelation(unsigned ElementSize) { 706 ScalarEvolution *SE = Statement->getParent()->getSE(); 707 708 auto MAI = MemAccInst(getAccessInstruction()); 709 if (isa<MemIntrinsic>(MAI)) 710 return; 711 712 Value *Ptr = MAI.getPointerOperand(); 713 if (!Ptr || !SE->isSCEVable(Ptr->getType())) 714 return; 715 716 const SCEV *PtrSCEV = SE->getSCEV(Ptr); 717 if (isa<SCEVCouldNotCompute>(PtrSCEV)) 718 return; 719 720 const SCEV *BasePtrSCEV = SE->getPointerBase(PtrSCEV); 721 if (BasePtrSCEV && !isa<SCEVCouldNotCompute>(BasePtrSCEV)) 722 PtrSCEV = SE->getMinusSCEV(PtrSCEV, BasePtrSCEV); 723 724 const ConstantRange &Range = SE->getSignedRange(PtrSCEV); 725 if (Range.isFullSet()) 726 return; 727 728 if (Range.isUpperWrapped() || Range.isSignWrappedSet()) 729 return; 730 731 bool isWrapping = Range.isSignWrappedSet(); 732 733 unsigned BW = Range.getBitWidth(); 734 const auto One = APInt(BW, 1); 735 const auto LB = isWrapping ? Range.getLower() : Range.getSignedMin(); 736 const auto UB = isWrapping ? (Range.getUpper() - One) : Range.getSignedMax(); 737 738 auto Min = LB.sdiv(APInt(BW, ElementSize)); 739 auto Max = UB.sdiv(APInt(BW, ElementSize)) + One; 740 741 assert(Min.sle(Max) && "Minimum expected to be less or equal than max"); 742 743 isl::map Relation = AccessRelation; 744 isl::set AccessRange = Relation.range(); 745 AccessRange = addRangeBoundsToSet(AccessRange, ConstantRange(Min, Max), 0, 746 isl::dim::set); 747 AccessRelation = Relation.intersect_range(AccessRange); 748 } 749 750 void MemoryAccess::foldAccessRelation() { 751 if (Sizes.size() < 2 || isa<SCEVConstant>(Sizes[1])) 752 return; 753 754 int Size = Subscripts.size(); 755 756 isl::map NewAccessRelation = AccessRelation; 757 758 for (int i = Size - 2; i >= 0; --i) { 759 isl::space Space; 760 isl::map MapOne, MapTwo; 761 isl::pw_aff DimSize = getPwAff(Sizes[i + 1]); 762 763 isl::space SpaceSize = DimSize.get_space(); 764 isl::id ParamId = SpaceSize.get_dim_id(isl::dim::param, 0); 765 766 Space = AccessRelation.get_space(); 767 Space = Space.range().map_from_set(); 768 Space = Space.align_params(SpaceSize); 769 770 int ParamLocation = Space.find_dim_by_id(isl::dim::param, ParamId); 771 772 MapOne = isl::map::universe(Space); 773 for (int j = 0; j < Size; ++j) 774 MapOne = MapOne.equate(isl::dim::in, j, isl::dim::out, j); 775 MapOne = MapOne.lower_bound_si(isl::dim::in, i + 1, 0); 776 777 MapTwo = isl::map::universe(Space); 778 for (int j = 0; j < Size; ++j) 779 if (j < i || j > i + 1) 780 MapTwo = MapTwo.equate(isl::dim::in, j, isl::dim::out, j); 781 782 isl::local_space LS(Space); 783 isl::constraint C; 784 C = isl::constraint::alloc_equality(LS); 785 C = C.set_constant_si(-1); 786 C = C.set_coefficient_si(isl::dim::in, i, 1); 787 C = C.set_coefficient_si(isl::dim::out, i, -1); 788 MapTwo = MapTwo.add_constraint(C); 789 C = isl::constraint::alloc_equality(LS); 790 C = C.set_coefficient_si(isl::dim::in, i + 1, 1); 791 C = C.set_coefficient_si(isl::dim::out, i + 1, -1); 792 C = C.set_coefficient_si(isl::dim::param, ParamLocation, 1); 793 MapTwo = MapTwo.add_constraint(C); 794 MapTwo = MapTwo.upper_bound_si(isl::dim::in, i + 1, -1); 795 796 MapOne = MapOne.unite(MapTwo); 797 NewAccessRelation = NewAccessRelation.apply_range(MapOne); 798 } 799 800 isl::id BaseAddrId = getScopArrayInfo()->getBasePtrId(); 801 isl::space Space = Statement->getDomainSpace(); 802 NewAccessRelation = NewAccessRelation.set_tuple_id( 803 isl::dim::in, Space.get_tuple_id(isl::dim::set)); 804 NewAccessRelation = NewAccessRelation.set_tuple_id(isl::dim::out, BaseAddrId); 805 NewAccessRelation = NewAccessRelation.gist_domain(Statement->getDomain()); 806 807 // Access dimension folding might in certain cases increase the number of 808 // disjuncts in the memory access, which can possibly complicate the generated 809 // run-time checks and can lead to costly compilation. 810 if (!PollyPreciseFoldAccesses && NewAccessRelation.n_basic_map().release() > 811 AccessRelation.n_basic_map().release()) { 812 } else { 813 AccessRelation = NewAccessRelation; 814 } 815 } 816 817 void MemoryAccess::buildAccessRelation(const ScopArrayInfo *SAI) { 818 assert(AccessRelation.is_null() && "AccessRelation already built"); 819 820 // Initialize the invalid domain which describes all iterations for which the 821 // access relation is not modeled correctly. 822 isl::set StmtInvalidDomain = getStatement()->getInvalidDomain(); 823 InvalidDomain = isl::set::empty(StmtInvalidDomain.get_space()); 824 825 isl::ctx Ctx = Id.ctx(); 826 isl::id BaseAddrId = SAI->getBasePtrId(); 827 828 if (getAccessInstruction() && isa<MemIntrinsic>(getAccessInstruction())) { 829 buildMemIntrinsicAccessRelation(); 830 AccessRelation = AccessRelation.set_tuple_id(isl::dim::out, BaseAddrId); 831 return; 832 } 833 834 if (!isAffine()) { 835 // We overapproximate non-affine accesses with a possible access to the 836 // whole array. For read accesses it does not make a difference, if an 837 // access must or may happen. However, for write accesses it is important to 838 // differentiate between writes that must happen and writes that may happen. 839 if (AccessRelation.is_null()) 840 AccessRelation = createBasicAccessMap(Statement); 841 842 AccessRelation = AccessRelation.set_tuple_id(isl::dim::out, BaseAddrId); 843 return; 844 } 845 846 isl::space Space = isl::space(Ctx, 0, Statement->getNumIterators(), 0); 847 AccessRelation = isl::map::universe(Space); 848 849 for (int i = 0, Size = Subscripts.size(); i < Size; ++i) { 850 isl::pw_aff Affine = getPwAff(Subscripts[i]); 851 isl::map SubscriptMap = isl::map::from_pw_aff(Affine); 852 AccessRelation = AccessRelation.flat_range_product(SubscriptMap); 853 } 854 855 Space = Statement->getDomainSpace(); 856 AccessRelation = AccessRelation.set_tuple_id( 857 isl::dim::in, Space.get_tuple_id(isl::dim::set)); 858 AccessRelation = AccessRelation.set_tuple_id(isl::dim::out, BaseAddrId); 859 860 AccessRelation = AccessRelation.gist_domain(Statement->getDomain()); 861 } 862 863 MemoryAccess::MemoryAccess(ScopStmt *Stmt, Instruction *AccessInst, 864 AccessType AccType, Value *BaseAddress, 865 Type *ElementType, bool Affine, 866 ArrayRef<const SCEV *> Subscripts, 867 ArrayRef<const SCEV *> Sizes, Value *AccessValue, 868 MemoryKind Kind) 869 : Kind(Kind), AccType(AccType), Statement(Stmt), InvalidDomain(), 870 BaseAddr(BaseAddress), ElementType(ElementType), 871 Sizes(Sizes.begin(), Sizes.end()), AccessInstruction(AccessInst), 872 AccessValue(AccessValue), IsAffine(Affine), 873 Subscripts(Subscripts.begin(), Subscripts.end()), AccessRelation(), 874 NewAccessRelation() { 875 static const std::string TypeStrings[] = {"", "_Read", "_Write", "_MayWrite"}; 876 const std::string Access = TypeStrings[AccType] + utostr(Stmt->size()); 877 878 std::string IdName = Stmt->getBaseName() + Access; 879 Id = isl::id::alloc(Stmt->getParent()->getIslCtx(), IdName, this); 880 } 881 882 MemoryAccess::MemoryAccess(ScopStmt *Stmt, AccessType AccType, isl::map AccRel) 883 : Kind(MemoryKind::Array), AccType(AccType), Statement(Stmt), 884 InvalidDomain(), AccessRelation(), NewAccessRelation(AccRel) { 885 isl::id ArrayInfoId = NewAccessRelation.get_tuple_id(isl::dim::out); 886 auto *SAI = ScopArrayInfo::getFromId(ArrayInfoId); 887 Sizes.push_back(nullptr); 888 for (unsigned i = 1; i < SAI->getNumberOfDimensions(); i++) 889 Sizes.push_back(SAI->getDimensionSize(i)); 890 ElementType = SAI->getElementType(); 891 BaseAddr = SAI->getBasePtr(); 892 static const std::string TypeStrings[] = {"", "_Read", "_Write", "_MayWrite"}; 893 const std::string Access = TypeStrings[AccType] + utostr(Stmt->size()); 894 895 std::string IdName = Stmt->getBaseName() + Access; 896 Id = isl::id::alloc(Stmt->getParent()->getIslCtx(), IdName, this); 897 } 898 899 MemoryAccess::~MemoryAccess() = default; 900 901 void MemoryAccess::realignParams() { 902 isl::set Ctx = Statement->getParent()->getContext(); 903 InvalidDomain = InvalidDomain.gist_params(Ctx); 904 AccessRelation = AccessRelation.gist_params(Ctx); 905 906 // Predictable parameter order is required for JSON imports. Ensure alignment 907 // by explicitly calling align_params. 908 isl::space CtxSpace = Ctx.get_space(); 909 InvalidDomain = InvalidDomain.align_params(CtxSpace); 910 AccessRelation = AccessRelation.align_params(CtxSpace); 911 } 912 913 const std::string MemoryAccess::getReductionOperatorStr() const { 914 return MemoryAccess::getReductionOperatorStr(getReductionType()); 915 } 916 917 isl::id MemoryAccess::getId() const { return Id; } 918 919 raw_ostream &polly::operator<<(raw_ostream &OS, 920 MemoryAccess::ReductionType RT) { 921 switch (RT) { 922 case MemoryAccess::RT_NONE: 923 case MemoryAccess::RT_BOTTOM: 924 OS << "NONE"; 925 break; 926 default: 927 OS << MemoryAccess::getReductionOperatorStr(RT); 928 break; 929 } 930 return OS; 931 } 932 933 void MemoryAccess::print(raw_ostream &OS) const { 934 switch (AccType) { 935 case READ: 936 OS.indent(12) << "ReadAccess :=\t"; 937 break; 938 case MUST_WRITE: 939 OS.indent(12) << "MustWriteAccess :=\t"; 940 break; 941 case MAY_WRITE: 942 OS.indent(12) << "MayWriteAccess :=\t"; 943 break; 944 } 945 946 OS << "[Reduction Type: " << getReductionType() << "] "; 947 948 OS << "[Scalar: " << isScalarKind() << "]\n"; 949 OS.indent(16) << getOriginalAccessRelationStr() << ";\n"; 950 if (hasNewAccessRelation()) 951 OS.indent(11) << "new: " << getNewAccessRelationStr() << ";\n"; 952 } 953 954 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 955 LLVM_DUMP_METHOD void MemoryAccess::dump() const { print(errs()); } 956 #endif 957 958 isl::pw_aff MemoryAccess::getPwAff(const SCEV *E) { 959 auto *Stmt = getStatement(); 960 PWACtx PWAC = Stmt->getParent()->getPwAff(E, Stmt->getEntryBlock()); 961 isl::set StmtDom = getStatement()->getDomain(); 962 StmtDom = StmtDom.reset_tuple_id(); 963 isl::set NewInvalidDom = StmtDom.intersect(PWAC.second); 964 InvalidDomain = InvalidDomain.unite(NewInvalidDom); 965 return PWAC.first; 966 } 967 968 // Create a map in the size of the provided set domain, that maps from the 969 // one element of the provided set domain to another element of the provided 970 // set domain. 971 // The mapping is limited to all points that are equal in all but the last 972 // dimension and for which the last dimension of the input is strict smaller 973 // than the last dimension of the output. 974 // 975 // getEqualAndLarger(set[i0, i1, ..., iX]): 976 // 977 // set[i0, i1, ..., iX] -> set[o0, o1, ..., oX] 978 // : i0 = o0, i1 = o1, ..., i(X-1) = o(X-1), iX < oX 979 // 980 static isl::map getEqualAndLarger(isl::space SetDomain) { 981 isl::space Space = SetDomain.map_from_set(); 982 isl::map Map = isl::map::universe(Space); 983 unsigned lastDimension = Map.domain_tuple_dim().release() - 1; 984 985 // Set all but the last dimension to be equal for the input and output 986 // 987 // input[i0, i1, ..., iX] -> output[o0, o1, ..., oX] 988 // : i0 = o0, i1 = o1, ..., i(X-1) = o(X-1) 989 for (unsigned i = 0; i < lastDimension; ++i) 990 Map = Map.equate(isl::dim::in, i, isl::dim::out, i); 991 992 // Set the last dimension of the input to be strict smaller than the 993 // last dimension of the output. 994 // 995 // input[?,?,?,...,iX] -> output[?,?,?,...,oX] : iX < oX 996 Map = Map.order_lt(isl::dim::in, lastDimension, isl::dim::out, lastDimension); 997 return Map; 998 } 999 1000 isl::set MemoryAccess::getStride(isl::map Schedule) const { 1001 isl::map AccessRelation = getAccessRelation(); 1002 isl::space Space = Schedule.get_space().range(); 1003 isl::map NextScatt = getEqualAndLarger(Space); 1004 1005 Schedule = Schedule.reverse(); 1006 NextScatt = NextScatt.lexmin(); 1007 1008 NextScatt = NextScatt.apply_range(Schedule); 1009 NextScatt = NextScatt.apply_range(AccessRelation); 1010 NextScatt = NextScatt.apply_domain(Schedule); 1011 NextScatt = NextScatt.apply_domain(AccessRelation); 1012 1013 isl::set Deltas = NextScatt.deltas(); 1014 return Deltas; 1015 } 1016 1017 bool MemoryAccess::isStrideX(isl::map Schedule, int StrideWidth) const { 1018 isl::set Stride, StrideX; 1019 bool IsStrideX; 1020 1021 Stride = getStride(Schedule); 1022 StrideX = isl::set::universe(Stride.get_space()); 1023 int Size = unsignedFromIslSize(StrideX.tuple_dim()); 1024 for (auto i : seq<int>(0, Size - 1)) 1025 StrideX = StrideX.fix_si(isl::dim::set, i, 0); 1026 StrideX = StrideX.fix_si(isl::dim::set, Size - 1, StrideWidth); 1027 IsStrideX = Stride.is_subset(StrideX); 1028 1029 return IsStrideX; 1030 } 1031 1032 bool MemoryAccess::isStrideZero(isl::map Schedule) const { 1033 return isStrideX(Schedule, 0); 1034 } 1035 1036 bool MemoryAccess::isStrideOne(isl::map Schedule) const { 1037 return isStrideX(Schedule, 1); 1038 } 1039 1040 void MemoryAccess::setAccessRelation(isl::map NewAccess) { 1041 AccessRelation = NewAccess; 1042 } 1043 1044 void MemoryAccess::setNewAccessRelation(isl::map NewAccess) { 1045 assert(!NewAccess.is_null()); 1046 1047 #ifndef NDEBUG 1048 // Check domain space compatibility. 1049 isl::space NewSpace = NewAccess.get_space(); 1050 isl::space NewDomainSpace = NewSpace.domain(); 1051 isl::space OriginalDomainSpace = getStatement()->getDomainSpace(); 1052 assert(OriginalDomainSpace.has_equal_tuples(NewDomainSpace)); 1053 1054 // Reads must be executed unconditionally. Writes might be executed in a 1055 // subdomain only. 1056 if (isRead()) { 1057 // Check whether there is an access for every statement instance. 1058 isl::set StmtDomain = getStatement()->getDomain(); 1059 isl::set DefinedContext = 1060 getStatement()->getParent()->getBestKnownDefinedBehaviorContext(); 1061 StmtDomain = StmtDomain.intersect_params(DefinedContext); 1062 isl::set NewDomain = NewAccess.domain(); 1063 assert(!StmtDomain.is_subset(NewDomain).is_false() && 1064 "Partial READ accesses not supported"); 1065 } 1066 1067 isl::space NewAccessSpace = NewAccess.get_space(); 1068 assert(NewAccessSpace.has_tuple_id(isl::dim::set) && 1069 "Must specify the array that is accessed"); 1070 isl::id NewArrayId = NewAccessSpace.get_tuple_id(isl::dim::set); 1071 auto *SAI = static_cast<ScopArrayInfo *>(NewArrayId.get_user()); 1072 assert(SAI && "Must set a ScopArrayInfo"); 1073 1074 if (SAI->isArrayKind() && SAI->getBasePtrOriginSAI()) { 1075 InvariantEquivClassTy *EqClass = 1076 getStatement()->getParent()->lookupInvariantEquivClass( 1077 SAI->getBasePtr()); 1078 assert(EqClass && 1079 "Access functions to indirect arrays must have an invariant and " 1080 "hoisted base pointer"); 1081 } 1082 1083 // Check whether access dimensions correspond to number of dimensions of the 1084 // accesses array. 1085 unsigned Dims = SAI->getNumberOfDimensions(); 1086 unsigned SpaceSize = unsignedFromIslSize(NewAccessSpace.dim(isl::dim::set)); 1087 assert(SpaceSize == Dims && "Access dims must match array dims"); 1088 #endif 1089 1090 NewAccess = NewAccess.gist_params(getStatement()->getParent()->getContext()); 1091 NewAccess = NewAccess.gist_domain(getStatement()->getDomain()); 1092 NewAccessRelation = NewAccess; 1093 } 1094 1095 bool MemoryAccess::isLatestPartialAccess() const { 1096 isl::set StmtDom = getStatement()->getDomain(); 1097 isl::set AccDom = getLatestAccessRelation().domain(); 1098 1099 return !StmtDom.is_subset(AccDom); 1100 } 1101 1102 //===----------------------------------------------------------------------===// 1103 1104 isl::map ScopStmt::getSchedule() const { 1105 isl::set Domain = getDomain(); 1106 if (Domain.is_empty()) 1107 return isl::map::from_aff(isl::aff(isl::local_space(getDomainSpace()))); 1108 auto Schedule = getParent()->getSchedule(); 1109 if (Schedule.is_null()) 1110 return {}; 1111 Schedule = Schedule.intersect_domain(isl::union_set(Domain)); 1112 if (Schedule.is_empty()) 1113 return isl::map::from_aff(isl::aff(isl::local_space(getDomainSpace()))); 1114 isl::map M = M.from_union_map(Schedule); 1115 M = M.coalesce(); 1116 M = M.gist_domain(Domain); 1117 M = M.coalesce(); 1118 return M; 1119 } 1120 1121 void ScopStmt::restrictDomain(isl::set NewDomain) { 1122 assert(NewDomain.is_subset(Domain) && 1123 "New domain is not a subset of old domain!"); 1124 Domain = NewDomain; 1125 } 1126 1127 void ScopStmt::addAccess(MemoryAccess *Access, bool Prepend) { 1128 Instruction *AccessInst = Access->getAccessInstruction(); 1129 1130 if (Access->isArrayKind()) { 1131 MemoryAccessList &MAL = InstructionToAccess[AccessInst]; 1132 MAL.emplace_front(Access); 1133 } else if (Access->isValueKind() && Access->isWrite()) { 1134 Instruction *AccessVal = cast<Instruction>(Access->getAccessValue()); 1135 assert(!ValueWrites.lookup(AccessVal)); 1136 1137 ValueWrites[AccessVal] = Access; 1138 } else if (Access->isValueKind() && Access->isRead()) { 1139 Value *AccessVal = Access->getAccessValue(); 1140 assert(!ValueReads.lookup(AccessVal)); 1141 1142 ValueReads[AccessVal] = Access; 1143 } else if (Access->isAnyPHIKind() && Access->isWrite()) { 1144 PHINode *PHI = cast<PHINode>(Access->getAccessValue()); 1145 assert(!PHIWrites.lookup(PHI)); 1146 1147 PHIWrites[PHI] = Access; 1148 } else if (Access->isAnyPHIKind() && Access->isRead()) { 1149 PHINode *PHI = cast<PHINode>(Access->getAccessValue()); 1150 assert(!PHIReads.lookup(PHI)); 1151 1152 PHIReads[PHI] = Access; 1153 } 1154 1155 if (Prepend) { 1156 MemAccs.insert(MemAccs.begin(), Access); 1157 return; 1158 } 1159 MemAccs.push_back(Access); 1160 } 1161 1162 void ScopStmt::realignParams() { 1163 for (MemoryAccess *MA : *this) 1164 MA->realignParams(); 1165 1166 simplify(InvalidDomain); 1167 simplify(Domain); 1168 1169 isl::set Ctx = Parent.getContext(); 1170 InvalidDomain = InvalidDomain.gist_params(Ctx); 1171 Domain = Domain.gist_params(Ctx); 1172 1173 // Predictable parameter order is required for JSON imports. Ensure alignment 1174 // by explicitly calling align_params. 1175 isl::space CtxSpace = Ctx.get_space(); 1176 InvalidDomain = InvalidDomain.align_params(CtxSpace); 1177 Domain = Domain.align_params(CtxSpace); 1178 } 1179 1180 ScopStmt::ScopStmt(Scop &parent, Region &R, StringRef Name, 1181 Loop *SurroundingLoop, 1182 std::vector<Instruction *> EntryBlockInstructions) 1183 : Parent(parent), InvalidDomain(), Domain(), R(&R), Build(), BaseName(Name), 1184 SurroundingLoop(SurroundingLoop), Instructions(EntryBlockInstructions) {} 1185 1186 ScopStmt::ScopStmt(Scop &parent, BasicBlock &bb, StringRef Name, 1187 Loop *SurroundingLoop, 1188 std::vector<Instruction *> Instructions) 1189 : Parent(parent), InvalidDomain(), Domain(), BB(&bb), Build(), 1190 BaseName(Name), SurroundingLoop(SurroundingLoop), 1191 Instructions(Instructions) {} 1192 1193 ScopStmt::ScopStmt(Scop &parent, isl::map SourceRel, isl::map TargetRel, 1194 isl::set NewDomain) 1195 : Parent(parent), InvalidDomain(), Domain(NewDomain), Build() { 1196 BaseName = getIslCompatibleName("CopyStmt_", "", 1197 std::to_string(parent.getCopyStmtsNum())); 1198 isl::id Id = isl::id::alloc(getIslCtx(), getBaseName(), this); 1199 Domain = Domain.set_tuple_id(Id); 1200 TargetRel = TargetRel.set_tuple_id(isl::dim::in, Id); 1201 auto *Access = 1202 new MemoryAccess(this, MemoryAccess::AccessType::MUST_WRITE, TargetRel); 1203 parent.addAccessFunction(Access); 1204 addAccess(Access); 1205 SourceRel = SourceRel.set_tuple_id(isl::dim::in, Id); 1206 Access = new MemoryAccess(this, MemoryAccess::AccessType::READ, SourceRel); 1207 parent.addAccessFunction(Access); 1208 addAccess(Access); 1209 } 1210 1211 ScopStmt::~ScopStmt() = default; 1212 1213 std::string ScopStmt::getDomainStr() const { return stringFromIslObj(Domain); } 1214 1215 std::string ScopStmt::getScheduleStr() const { 1216 return stringFromIslObj(getSchedule()); 1217 } 1218 1219 void ScopStmt::setInvalidDomain(isl::set ID) { InvalidDomain = ID; } 1220 1221 BasicBlock *ScopStmt::getEntryBlock() const { 1222 if (isBlockStmt()) 1223 return getBasicBlock(); 1224 return getRegion()->getEntry(); 1225 } 1226 1227 unsigned ScopStmt::getNumIterators() const { return NestLoops.size(); } 1228 1229 const char *ScopStmt::getBaseName() const { return BaseName.c_str(); } 1230 1231 Loop *ScopStmt::getLoopForDimension(unsigned Dimension) const { 1232 return NestLoops[Dimension]; 1233 } 1234 1235 isl::ctx ScopStmt::getIslCtx() const { return Parent.getIslCtx(); } 1236 1237 isl::set ScopStmt::getDomain() const { return Domain; } 1238 1239 isl::space ScopStmt::getDomainSpace() const { return Domain.get_space(); } 1240 1241 isl::id ScopStmt::getDomainId() const { return Domain.get_tuple_id(); } 1242 1243 void ScopStmt::printInstructions(raw_ostream &OS) const { 1244 OS << "Instructions {\n"; 1245 1246 for (Instruction *Inst : Instructions) 1247 OS.indent(16) << *Inst << "\n"; 1248 1249 OS.indent(12) << "}\n"; 1250 } 1251 1252 void ScopStmt::print(raw_ostream &OS, bool PrintInstructions) const { 1253 OS << "\t" << getBaseName() << "\n"; 1254 OS.indent(12) << "Domain :=\n"; 1255 1256 if (!Domain.is_null()) { 1257 OS.indent(16) << getDomainStr() << ";\n"; 1258 } else 1259 OS.indent(16) << "n/a\n"; 1260 1261 OS.indent(12) << "Schedule :=\n"; 1262 1263 if (!Domain.is_null()) { 1264 OS.indent(16) << getScheduleStr() << ";\n"; 1265 } else 1266 OS.indent(16) << "n/a\n"; 1267 1268 for (MemoryAccess *Access : MemAccs) 1269 Access->print(OS); 1270 1271 if (PrintInstructions) 1272 printInstructions(OS.indent(12)); 1273 } 1274 1275 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 1276 LLVM_DUMP_METHOD void ScopStmt::dump() const { print(dbgs(), true); } 1277 #endif 1278 1279 void ScopStmt::removeAccessData(MemoryAccess *MA) { 1280 if (MA->isRead() && MA->isOriginalValueKind()) { 1281 bool Found = ValueReads.erase(MA->getAccessValue()); 1282 (void)Found; 1283 assert(Found && "Expected access data not found"); 1284 } 1285 if (MA->isWrite() && MA->isOriginalValueKind()) { 1286 bool Found = ValueWrites.erase(cast<Instruction>(MA->getAccessValue())); 1287 (void)Found; 1288 assert(Found && "Expected access data not found"); 1289 } 1290 if (MA->isWrite() && MA->isOriginalAnyPHIKind()) { 1291 bool Found = PHIWrites.erase(cast<PHINode>(MA->getAccessInstruction())); 1292 (void)Found; 1293 assert(Found && "Expected access data not found"); 1294 } 1295 if (MA->isRead() && MA->isOriginalAnyPHIKind()) { 1296 bool Found = PHIReads.erase(cast<PHINode>(MA->getAccessInstruction())); 1297 (void)Found; 1298 assert(Found && "Expected access data not found"); 1299 } 1300 } 1301 1302 void ScopStmt::removeMemoryAccess(MemoryAccess *MA) { 1303 // Remove the memory accesses from this statement together with all scalar 1304 // accesses that were caused by it. MemoryKind::Value READs have no access 1305 // instruction, hence would not be removed by this function. However, it is 1306 // only used for invariant LoadInst accesses, its arguments are always affine, 1307 // hence synthesizable, and therefore there are no MemoryKind::Value READ 1308 // accesses to be removed. 1309 auto Predicate = [&](MemoryAccess *Acc) { 1310 return Acc->getAccessInstruction() == MA->getAccessInstruction(); 1311 }; 1312 for (auto *MA : MemAccs) { 1313 if (Predicate(MA)) { 1314 removeAccessData(MA); 1315 Parent.removeAccessData(MA); 1316 } 1317 } 1318 llvm::erase_if(MemAccs, Predicate); 1319 InstructionToAccess.erase(MA->getAccessInstruction()); 1320 } 1321 1322 void ScopStmt::removeSingleMemoryAccess(MemoryAccess *MA, bool AfterHoisting) { 1323 if (AfterHoisting) { 1324 auto MAIt = std::find(MemAccs.begin(), MemAccs.end(), MA); 1325 assert(MAIt != MemAccs.end()); 1326 MemAccs.erase(MAIt); 1327 1328 removeAccessData(MA); 1329 Parent.removeAccessData(MA); 1330 } 1331 1332 auto It = InstructionToAccess.find(MA->getAccessInstruction()); 1333 if (It != InstructionToAccess.end()) { 1334 It->second.remove(MA); 1335 if (It->second.empty()) 1336 InstructionToAccess.erase(MA->getAccessInstruction()); 1337 } 1338 } 1339 1340 MemoryAccess *ScopStmt::ensureValueRead(Value *V) { 1341 MemoryAccess *Access = lookupInputAccessOf(V); 1342 if (Access) 1343 return Access; 1344 1345 ScopArrayInfo *SAI = 1346 Parent.getOrCreateScopArrayInfo(V, V->getType(), {}, MemoryKind::Value); 1347 Access = new MemoryAccess(this, nullptr, MemoryAccess::READ, V, V->getType(), 1348 true, {}, {}, V, MemoryKind::Value); 1349 Parent.addAccessFunction(Access); 1350 Access->buildAccessRelation(SAI); 1351 addAccess(Access); 1352 Parent.addAccessData(Access); 1353 return Access; 1354 } 1355 1356 raw_ostream &polly::operator<<(raw_ostream &OS, const ScopStmt &S) { 1357 S.print(OS, PollyPrintInstructions); 1358 return OS; 1359 } 1360 1361 //===----------------------------------------------------------------------===// 1362 /// Scop class implement 1363 1364 void Scop::setContext(isl::set NewContext) { 1365 Context = NewContext.align_params(Context.get_space()); 1366 } 1367 1368 namespace { 1369 1370 /// Remap parameter values but keep AddRecs valid wrt. invariant loads. 1371 class SCEVSensitiveParameterRewriter final 1372 : public SCEVRewriteVisitor<SCEVSensitiveParameterRewriter> { 1373 const ValueToValueMap &VMap; 1374 1375 public: 1376 SCEVSensitiveParameterRewriter(const ValueToValueMap &VMap, 1377 ScalarEvolution &SE) 1378 : SCEVRewriteVisitor(SE), VMap(VMap) {} 1379 1380 static const SCEV *rewrite(const SCEV *E, ScalarEvolution &SE, 1381 const ValueToValueMap &VMap) { 1382 SCEVSensitiveParameterRewriter SSPR(VMap, SE); 1383 return SSPR.visit(E); 1384 } 1385 1386 const SCEV *visitAddRecExpr(const SCEVAddRecExpr *E) { 1387 const SCEV *Start = visit(E->getStart()); 1388 const SCEV *AddRec = SE.getAddRecExpr(SE.getConstant(E->getType(), 0), 1389 visit(E->getStepRecurrence(SE)), 1390 E->getLoop(), SCEV::FlagAnyWrap); 1391 return SE.getAddExpr(Start, AddRec); 1392 } 1393 1394 const SCEV *visitUnknown(const SCEVUnknown *E) { 1395 if (auto *NewValue = VMap.lookup(E->getValue())) 1396 return SE.getUnknown(NewValue); 1397 return E; 1398 } 1399 }; 1400 1401 /// Check whether we should remap a SCEV expression. 1402 class SCEVFindInsideScop : public SCEVTraversal<SCEVFindInsideScop> { 1403 const ValueToValueMap &VMap; 1404 bool FoundInside = false; 1405 const Scop *S; 1406 1407 public: 1408 SCEVFindInsideScop(const ValueToValueMap &VMap, ScalarEvolution &SE, 1409 const Scop *S) 1410 : SCEVTraversal(*this), VMap(VMap), S(S) {} 1411 1412 static bool hasVariant(const SCEV *E, ScalarEvolution &SE, 1413 const ValueToValueMap &VMap, const Scop *S) { 1414 SCEVFindInsideScop SFIS(VMap, SE, S); 1415 SFIS.visitAll(E); 1416 return SFIS.FoundInside; 1417 } 1418 1419 bool follow(const SCEV *E) { 1420 if (auto *AddRec = dyn_cast<SCEVAddRecExpr>(E)) { 1421 FoundInside |= S->getRegion().contains(AddRec->getLoop()); 1422 } else if (auto *Unknown = dyn_cast<SCEVUnknown>(E)) { 1423 if (Instruction *I = dyn_cast<Instruction>(Unknown->getValue())) 1424 FoundInside |= S->getRegion().contains(I) && !VMap.count(I); 1425 } 1426 return !FoundInside; 1427 } 1428 1429 bool isDone() { return FoundInside; } 1430 }; 1431 } // end anonymous namespace 1432 1433 const SCEV *Scop::getRepresentingInvariantLoadSCEV(const SCEV *E) const { 1434 // Check whether it makes sense to rewrite the SCEV. (ScalarEvolution 1435 // doesn't like addition between an AddRec and an expression that 1436 // doesn't have a dominance relationship with it.) 1437 if (SCEVFindInsideScop::hasVariant(E, *SE, InvEquivClassVMap, this)) 1438 return E; 1439 1440 // Rewrite SCEV. 1441 return SCEVSensitiveParameterRewriter::rewrite(E, *SE, InvEquivClassVMap); 1442 } 1443 1444 void Scop::createParameterId(const SCEV *Parameter) { 1445 assert(Parameters.count(Parameter)); 1446 assert(!ParameterIds.count(Parameter)); 1447 1448 std::string ParameterName = "p_" + std::to_string(getNumParams() - 1); 1449 1450 if (const SCEVUnknown *ValueParameter = dyn_cast<SCEVUnknown>(Parameter)) { 1451 Value *Val = ValueParameter->getValue(); 1452 1453 if (UseInstructionNames) { 1454 // If this parameter references a specific Value and this value has a name 1455 // we use this name as it is likely to be unique and more useful than just 1456 // a number. 1457 if (Val->hasName()) 1458 ParameterName = Val->getName().str(); 1459 else if (LoadInst *LI = dyn_cast<LoadInst>(Val)) { 1460 auto *LoadOrigin = LI->getPointerOperand()->stripInBoundsOffsets(); 1461 if (LoadOrigin->hasName()) { 1462 ParameterName += "_loaded_from_"; 1463 ParameterName += 1464 LI->getPointerOperand()->stripInBoundsOffsets()->getName(); 1465 } 1466 } 1467 } 1468 1469 ParameterName = getIslCompatibleName("", ParameterName, ""); 1470 } 1471 1472 isl::id Id = isl::id::alloc(getIslCtx(), ParameterName, 1473 const_cast<void *>((const void *)Parameter)); 1474 ParameterIds[Parameter] = Id; 1475 } 1476 1477 void Scop::addParams(const ParameterSetTy &NewParameters) { 1478 for (const SCEV *Parameter : NewParameters) { 1479 // Normalize the SCEV to get the representing element for an invariant load. 1480 Parameter = extractConstantFactor(Parameter, *SE).second; 1481 Parameter = getRepresentingInvariantLoadSCEV(Parameter); 1482 1483 if (Parameters.insert(Parameter)) 1484 createParameterId(Parameter); 1485 } 1486 } 1487 1488 isl::id Scop::getIdForParam(const SCEV *Parameter) const { 1489 // Normalize the SCEV to get the representing element for an invariant load. 1490 Parameter = getRepresentingInvariantLoadSCEV(Parameter); 1491 return ParameterIds.lookup(Parameter); 1492 } 1493 1494 bool Scop::isDominatedBy(const DominatorTree &DT, BasicBlock *BB) const { 1495 return DT.dominates(BB, getEntry()); 1496 } 1497 1498 void Scop::buildContext() { 1499 isl::space Space = isl::space::params_alloc(getIslCtx(), 0); 1500 Context = isl::set::universe(Space); 1501 InvalidContext = isl::set::empty(Space); 1502 AssumedContext = isl::set::universe(Space); 1503 DefinedBehaviorContext = isl::set::universe(Space); 1504 } 1505 1506 void Scop::addParameterBounds() { 1507 unsigned PDim = 0; 1508 for (auto *Parameter : Parameters) { 1509 ConstantRange SRange = SE->getSignedRange(Parameter); 1510 Context = addRangeBoundsToSet(Context, SRange, PDim++, isl::dim::param); 1511 } 1512 intersectDefinedBehavior(Context, AS_ASSUMPTION); 1513 } 1514 1515 void Scop::realignParams() { 1516 if (PollyIgnoreParamBounds) 1517 return; 1518 1519 // Add all parameters into a common model. 1520 isl::space Space = getFullParamSpace(); 1521 1522 // Align the parameters of all data structures to the model. 1523 Context = Context.align_params(Space); 1524 AssumedContext = AssumedContext.align_params(Space); 1525 InvalidContext = InvalidContext.align_params(Space); 1526 1527 // As all parameters are known add bounds to them. 1528 addParameterBounds(); 1529 1530 for (ScopStmt &Stmt : *this) 1531 Stmt.realignParams(); 1532 // Simplify the schedule according to the context too. 1533 Schedule = Schedule.gist_domain_params(getContext()); 1534 1535 // Predictable parameter order is required for JSON imports. Ensure alignment 1536 // by explicitly calling align_params. 1537 Schedule = Schedule.align_params(Space); 1538 } 1539 1540 static isl::set simplifyAssumptionContext(isl::set AssumptionContext, 1541 const Scop &S) { 1542 // If we have modeled all blocks in the SCoP that have side effects we can 1543 // simplify the context with the constraints that are needed for anything to 1544 // be executed at all. However, if we have error blocks in the SCoP we already 1545 // assumed some parameter combinations cannot occur and removed them from the 1546 // domains, thus we cannot use the remaining domain to simplify the 1547 // assumptions. 1548 if (!S.hasErrorBlock()) { 1549 auto DomainParameters = S.getDomains().params(); 1550 AssumptionContext = AssumptionContext.gist_params(DomainParameters); 1551 } 1552 1553 AssumptionContext = AssumptionContext.gist_params(S.getContext()); 1554 return AssumptionContext; 1555 } 1556 1557 void Scop::simplifyContexts() { 1558 // The parameter constraints of the iteration domains give us a set of 1559 // constraints that need to hold for all cases where at least a single 1560 // statement iteration is executed in the whole scop. We now simplify the 1561 // assumed context under the assumption that such constraints hold and at 1562 // least a single statement iteration is executed. For cases where no 1563 // statement instances are executed, the assumptions we have taken about 1564 // the executed code do not matter and can be changed. 1565 // 1566 // WARNING: This only holds if the assumptions we have taken do not reduce 1567 // the set of statement instances that are executed. Otherwise we 1568 // may run into a case where the iteration domains suggest that 1569 // for a certain set of parameter constraints no code is executed, 1570 // but in the original program some computation would have been 1571 // performed. In such a case, modifying the run-time conditions and 1572 // possibly influencing the run-time check may cause certain scops 1573 // to not be executed. 1574 // 1575 // Example: 1576 // 1577 // When delinearizing the following code: 1578 // 1579 // for (long i = 0; i < 100; i++) 1580 // for (long j = 0; j < m; j++) 1581 // A[i+p][j] = 1.0; 1582 // 1583 // we assume that the condition m <= 0 or (m >= 1 and p >= 0) holds as 1584 // otherwise we would access out of bound data. Now, knowing that code is 1585 // only executed for the case m >= 0, it is sufficient to assume p >= 0. 1586 AssumedContext = simplifyAssumptionContext(AssumedContext, *this); 1587 InvalidContext = InvalidContext.align_params(getParamSpace()); 1588 simplify(DefinedBehaviorContext); 1589 DefinedBehaviorContext = DefinedBehaviorContext.align_params(getParamSpace()); 1590 } 1591 1592 isl::set Scop::getDomainConditions(const ScopStmt *Stmt) const { 1593 return getDomainConditions(Stmt->getEntryBlock()); 1594 } 1595 1596 isl::set Scop::getDomainConditions(BasicBlock *BB) const { 1597 auto DIt = DomainMap.find(BB); 1598 if (DIt != DomainMap.end()) 1599 return DIt->getSecond(); 1600 1601 auto &RI = *R.getRegionInfo(); 1602 auto *BBR = RI.getRegionFor(BB); 1603 while (BBR->getEntry() == BB) 1604 BBR = BBR->getParent(); 1605 return getDomainConditions(BBR->getEntry()); 1606 } 1607 1608 Scop::Scop(Region &R, ScalarEvolution &ScalarEvolution, LoopInfo &LI, 1609 DominatorTree &DT, ScopDetection::DetectionContext &DC, 1610 OptimizationRemarkEmitter &ORE, int ID) 1611 : IslCtx(isl_ctx_alloc(), isl_ctx_free), SE(&ScalarEvolution), DT(&DT), 1612 R(R), name(std::nullopt), HasSingleExitEdge(R.getExitingBlock()), DC(DC), 1613 ORE(ORE), Affinator(this, LI), ID(ID) { 1614 1615 // Options defaults that are different from ISL's. 1616 isl_options_set_schedule_serialize_sccs(IslCtx.get(), true); 1617 1618 SmallVector<char *, 8> IslArgv; 1619 IslArgv.reserve(1 + IslArgs.size()); 1620 1621 // Substitute for program name. 1622 IslArgv.push_back(const_cast<char *>("-polly-isl-arg")); 1623 1624 for (std::string &Arg : IslArgs) 1625 IslArgv.push_back(const_cast<char *>(Arg.c_str())); 1626 1627 // Abort if unknown argument is passed. 1628 // Note that "-V" (print isl version) will always call exit(0), so we cannot 1629 // avoid ISL aborting the program at this point. 1630 unsigned IslParseFlags = ISL_ARG_ALL; 1631 1632 isl_ctx_parse_options(IslCtx.get(), IslArgv.size(), IslArgv.data(), 1633 IslParseFlags); 1634 1635 if (IslOnErrorAbort) 1636 isl_options_set_on_error(getIslCtx().get(), ISL_ON_ERROR_ABORT); 1637 buildContext(); 1638 } 1639 1640 Scop::~Scop() = default; 1641 1642 void Scop::removeFromStmtMap(ScopStmt &Stmt) { 1643 for (Instruction *Inst : Stmt.getInstructions()) 1644 InstStmtMap.erase(Inst); 1645 1646 if (Stmt.isRegionStmt()) { 1647 for (BasicBlock *BB : Stmt.getRegion()->blocks()) { 1648 StmtMap.erase(BB); 1649 // Skip entry basic block, as its instructions are already deleted as 1650 // part of the statement's instruction list. 1651 if (BB == Stmt.getEntryBlock()) 1652 continue; 1653 for (Instruction &Inst : *BB) 1654 InstStmtMap.erase(&Inst); 1655 } 1656 } else { 1657 auto StmtMapIt = StmtMap.find(Stmt.getBasicBlock()); 1658 if (StmtMapIt != StmtMap.end()) 1659 llvm::erase(StmtMapIt->second, &Stmt); 1660 for (Instruction *Inst : Stmt.getInstructions()) 1661 InstStmtMap.erase(Inst); 1662 } 1663 } 1664 1665 void Scop::removeStmts(function_ref<bool(ScopStmt &)> ShouldDelete, 1666 bool AfterHoisting) { 1667 for (auto StmtIt = Stmts.begin(), StmtEnd = Stmts.end(); StmtIt != StmtEnd;) { 1668 if (!ShouldDelete(*StmtIt)) { 1669 StmtIt++; 1670 continue; 1671 } 1672 1673 // Start with removing all of the statement's accesses including erasing it 1674 // from all maps that are pointing to them. 1675 // Make a temporary copy because removing MAs invalidates the iterator. 1676 SmallVector<MemoryAccess *, 16> MAList(StmtIt->begin(), StmtIt->end()); 1677 for (MemoryAccess *MA : MAList) 1678 StmtIt->removeSingleMemoryAccess(MA, AfterHoisting); 1679 1680 removeFromStmtMap(*StmtIt); 1681 StmtIt = Stmts.erase(StmtIt); 1682 } 1683 } 1684 1685 void Scop::removeStmtNotInDomainMap() { 1686 removeStmts([this](ScopStmt &Stmt) -> bool { 1687 isl::set Domain = DomainMap.lookup(Stmt.getEntryBlock()); 1688 if (Domain.is_null()) 1689 return true; 1690 return Domain.is_empty(); 1691 }); 1692 } 1693 1694 void Scop::simplifySCoP(bool AfterHoisting) { 1695 removeStmts( 1696 [AfterHoisting](ScopStmt &Stmt) -> bool { 1697 // Never delete statements that contain calls to debug functions. 1698 if (hasDebugCall(&Stmt)) 1699 return false; 1700 1701 bool RemoveStmt = Stmt.isEmpty(); 1702 1703 // Remove read only statements only after invariant load hoisting. 1704 if (!RemoveStmt && AfterHoisting) { 1705 bool OnlyRead = true; 1706 for (MemoryAccess *MA : Stmt) { 1707 if (MA->isRead()) 1708 continue; 1709 1710 OnlyRead = false; 1711 break; 1712 } 1713 1714 RemoveStmt = OnlyRead; 1715 } 1716 return RemoveStmt; 1717 }, 1718 AfterHoisting); 1719 } 1720 1721 InvariantEquivClassTy *Scop::lookupInvariantEquivClass(Value *Val) { 1722 LoadInst *LInst = dyn_cast<LoadInst>(Val); 1723 if (!LInst) 1724 return nullptr; 1725 1726 if (Value *Rep = InvEquivClassVMap.lookup(LInst)) 1727 LInst = cast<LoadInst>(Rep); 1728 1729 Type *Ty = LInst->getType(); 1730 const SCEV *PointerSCEV = SE->getSCEV(LInst->getPointerOperand()); 1731 for (auto &IAClass : InvariantEquivClasses) { 1732 if (PointerSCEV != IAClass.IdentifyingPointer || Ty != IAClass.AccessType) 1733 continue; 1734 1735 auto &MAs = IAClass.InvariantAccesses; 1736 for (auto *MA : MAs) 1737 if (MA->getAccessInstruction() == Val) 1738 return &IAClass; 1739 } 1740 1741 return nullptr; 1742 } 1743 1744 ScopArrayInfo *Scop::getOrCreateScopArrayInfo(Value *BasePtr, Type *ElementType, 1745 ArrayRef<const SCEV *> Sizes, 1746 MemoryKind Kind, 1747 const char *BaseName) { 1748 assert((BasePtr || BaseName) && 1749 "BasePtr and BaseName can not be nullptr at the same time."); 1750 assert(!(BasePtr && BaseName) && "BaseName is redundant."); 1751 auto &SAI = BasePtr ? ScopArrayInfoMap[std::make_pair(BasePtr, Kind)] 1752 : ScopArrayNameMap[BaseName]; 1753 if (!SAI) { 1754 auto &DL = getFunction().getParent()->getDataLayout(); 1755 SAI.reset(new ScopArrayInfo(BasePtr, ElementType, getIslCtx(), Sizes, Kind, 1756 DL, this, BaseName)); 1757 ScopArrayInfoSet.insert(SAI.get()); 1758 } else { 1759 SAI->updateElementType(ElementType); 1760 // In case of mismatching array sizes, we bail out by setting the run-time 1761 // context to false. 1762 if (!SAI->updateSizes(Sizes)) 1763 invalidate(DELINEARIZATION, DebugLoc()); 1764 } 1765 return SAI.get(); 1766 } 1767 1768 ScopArrayInfo *Scop::createScopArrayInfo(Type *ElementType, 1769 const std::string &BaseName, 1770 const std::vector<unsigned> &Sizes) { 1771 auto *DimSizeType = Type::getInt64Ty(getSE()->getContext()); 1772 std::vector<const SCEV *> SCEVSizes; 1773 1774 for (auto size : Sizes) 1775 if (size) 1776 SCEVSizes.push_back(getSE()->getConstant(DimSizeType, size, false)); 1777 else 1778 SCEVSizes.push_back(nullptr); 1779 1780 auto *SAI = getOrCreateScopArrayInfo(nullptr, ElementType, SCEVSizes, 1781 MemoryKind::Array, BaseName.c_str()); 1782 return SAI; 1783 } 1784 1785 ScopArrayInfo *Scop::getScopArrayInfoOrNull(Value *BasePtr, MemoryKind Kind) { 1786 auto *SAI = ScopArrayInfoMap[std::make_pair(BasePtr, Kind)].get(); 1787 return SAI; 1788 } 1789 1790 ScopArrayInfo *Scop::getScopArrayInfo(Value *BasePtr, MemoryKind Kind) { 1791 auto *SAI = getScopArrayInfoOrNull(BasePtr, Kind); 1792 assert(SAI && "No ScopArrayInfo available for this base pointer"); 1793 return SAI; 1794 } 1795 1796 std::string Scop::getContextStr() const { 1797 return stringFromIslObj(getContext()); 1798 } 1799 1800 std::string Scop::getAssumedContextStr() const { 1801 assert(!AssumedContext.is_null() && "Assumed context not yet built"); 1802 return stringFromIslObj(AssumedContext); 1803 } 1804 1805 std::string Scop::getInvalidContextStr() const { 1806 return stringFromIslObj(InvalidContext); 1807 } 1808 1809 std::string Scop::getNameStr() const { 1810 std::string ExitName, EntryName; 1811 std::tie(EntryName, ExitName) = getEntryExitStr(); 1812 return EntryName + "---" + ExitName; 1813 } 1814 1815 std::pair<std::string, std::string> Scop::getEntryExitStr() const { 1816 std::string ExitName, EntryName; 1817 raw_string_ostream ExitStr(ExitName); 1818 raw_string_ostream EntryStr(EntryName); 1819 1820 R.getEntry()->printAsOperand(EntryStr, false); 1821 1822 if (R.getExit()) { 1823 R.getExit()->printAsOperand(ExitStr, false); 1824 } else 1825 ExitName = "FunctionExit"; 1826 1827 return std::make_pair(EntryName, ExitName); 1828 } 1829 1830 isl::set Scop::getContext() const { return Context; } 1831 1832 isl::space Scop::getParamSpace() const { return getContext().get_space(); } 1833 1834 isl::space Scop::getFullParamSpace() const { 1835 1836 isl::space Space = isl::space::params_alloc(getIslCtx(), ParameterIds.size()); 1837 1838 unsigned PDim = 0; 1839 for (const SCEV *Parameter : Parameters) { 1840 isl::id Id = getIdForParam(Parameter); 1841 Space = Space.set_dim_id(isl::dim::param, PDim++, Id); 1842 } 1843 1844 return Space; 1845 } 1846 1847 isl::set Scop::getAssumedContext() const { 1848 assert(!AssumedContext.is_null() && "Assumed context not yet built"); 1849 return AssumedContext; 1850 } 1851 1852 bool Scop::isProfitable(bool ScalarsAreUnprofitable) const { 1853 if (PollyProcessUnprofitable) 1854 return true; 1855 1856 if (isEmpty()) 1857 return false; 1858 1859 unsigned OptimizableStmtsOrLoops = 0; 1860 for (auto &Stmt : *this) { 1861 if (Stmt.getNumIterators() == 0) 1862 continue; 1863 1864 bool ContainsArrayAccs = false; 1865 bool ContainsScalarAccs = false; 1866 for (auto *MA : Stmt) { 1867 if (MA->isRead()) 1868 continue; 1869 ContainsArrayAccs |= MA->isLatestArrayKind(); 1870 ContainsScalarAccs |= MA->isLatestScalarKind(); 1871 } 1872 1873 if (!ScalarsAreUnprofitable || (ContainsArrayAccs && !ContainsScalarAccs)) 1874 OptimizableStmtsOrLoops += Stmt.getNumIterators(); 1875 } 1876 1877 return OptimizableStmtsOrLoops > 1; 1878 } 1879 1880 bool Scop::hasFeasibleRuntimeContext() const { 1881 if (Stmts.empty()) 1882 return false; 1883 1884 isl::set PositiveContext = getAssumedContext(); 1885 isl::set NegativeContext = getInvalidContext(); 1886 PositiveContext = PositiveContext.intersect_params(Context); 1887 PositiveContext = PositiveContext.intersect_params(getDomains().params()); 1888 return PositiveContext.is_empty().is_false() && 1889 PositiveContext.is_subset(NegativeContext).is_false(); 1890 } 1891 1892 MemoryAccess *Scop::lookupBasePtrAccess(MemoryAccess *MA) { 1893 Value *PointerBase = MA->getOriginalBaseAddr(); 1894 1895 auto *PointerBaseInst = dyn_cast<Instruction>(PointerBase); 1896 if (!PointerBaseInst) 1897 return nullptr; 1898 1899 auto *BasePtrStmt = getStmtFor(PointerBaseInst); 1900 if (!BasePtrStmt) 1901 return nullptr; 1902 1903 return BasePtrStmt->getArrayAccessOrNULLFor(PointerBaseInst); 1904 } 1905 1906 static std::string toString(AssumptionKind Kind) { 1907 switch (Kind) { 1908 case ALIASING: 1909 return "No-aliasing"; 1910 case INBOUNDS: 1911 return "Inbounds"; 1912 case WRAPPING: 1913 return "No-overflows"; 1914 case UNSIGNED: 1915 return "Signed-unsigned"; 1916 case COMPLEXITY: 1917 return "Low complexity"; 1918 case PROFITABLE: 1919 return "Profitable"; 1920 case ERRORBLOCK: 1921 return "No-error"; 1922 case INFINITELOOP: 1923 return "Finite loop"; 1924 case INVARIANTLOAD: 1925 return "Invariant load"; 1926 case DELINEARIZATION: 1927 return "Delinearization"; 1928 } 1929 llvm_unreachable("Unknown AssumptionKind!"); 1930 } 1931 1932 bool Scop::isEffectiveAssumption(isl::set Set, AssumptionSign Sign) { 1933 if (Sign == AS_ASSUMPTION) { 1934 if (Context.is_subset(Set)) 1935 return false; 1936 1937 if (AssumedContext.is_subset(Set)) 1938 return false; 1939 } else { 1940 if (Set.is_disjoint(Context)) 1941 return false; 1942 1943 if (Set.is_subset(InvalidContext)) 1944 return false; 1945 } 1946 return true; 1947 } 1948 1949 bool Scop::trackAssumption(AssumptionKind Kind, isl::set Set, DebugLoc Loc, 1950 AssumptionSign Sign, BasicBlock *BB) { 1951 if (PollyRemarksMinimal && !isEffectiveAssumption(Set, Sign)) 1952 return false; 1953 1954 // Do never emit trivial assumptions as they only clutter the output. 1955 if (!PollyRemarksMinimal) { 1956 isl::set Univ; 1957 if (Sign == AS_ASSUMPTION) 1958 Univ = isl::set::universe(Set.get_space()); 1959 1960 bool IsTrivial = (Sign == AS_RESTRICTION && Set.is_empty()) || 1961 (Sign == AS_ASSUMPTION && Univ.is_equal(Set)); 1962 1963 if (IsTrivial) 1964 return false; 1965 } 1966 1967 switch (Kind) { 1968 case ALIASING: 1969 AssumptionsAliasing++; 1970 break; 1971 case INBOUNDS: 1972 AssumptionsInbounds++; 1973 break; 1974 case WRAPPING: 1975 AssumptionsWrapping++; 1976 break; 1977 case UNSIGNED: 1978 AssumptionsUnsigned++; 1979 break; 1980 case COMPLEXITY: 1981 AssumptionsComplexity++; 1982 break; 1983 case PROFITABLE: 1984 AssumptionsUnprofitable++; 1985 break; 1986 case ERRORBLOCK: 1987 AssumptionsErrorBlock++; 1988 break; 1989 case INFINITELOOP: 1990 AssumptionsInfiniteLoop++; 1991 break; 1992 case INVARIANTLOAD: 1993 AssumptionsInvariantLoad++; 1994 break; 1995 case DELINEARIZATION: 1996 AssumptionsDelinearization++; 1997 break; 1998 } 1999 2000 auto Suffix = Sign == AS_ASSUMPTION ? " assumption:\t" : " restriction:\t"; 2001 std::string Msg = toString(Kind) + Suffix + stringFromIslObj(Set); 2002 if (BB) 2003 ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "AssumpRestrict", Loc, BB) 2004 << Msg); 2005 else 2006 ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "AssumpRestrict", Loc, 2007 R.getEntry()) 2008 << Msg); 2009 return true; 2010 } 2011 2012 void Scop::addAssumption(AssumptionKind Kind, isl::set Set, DebugLoc Loc, 2013 AssumptionSign Sign, BasicBlock *BB, 2014 bool RequiresRTC) { 2015 // Simplify the assumptions/restrictions first. 2016 Set = Set.gist_params(getContext()); 2017 intersectDefinedBehavior(Set, Sign); 2018 2019 if (!RequiresRTC) 2020 return; 2021 2022 if (!trackAssumption(Kind, Set, Loc, Sign, BB)) 2023 return; 2024 2025 if (Sign == AS_ASSUMPTION) 2026 AssumedContext = AssumedContext.intersect(Set).coalesce(); 2027 else 2028 InvalidContext = InvalidContext.unite(Set).coalesce(); 2029 } 2030 2031 void Scop::intersectDefinedBehavior(isl::set Set, AssumptionSign Sign) { 2032 if (DefinedBehaviorContext.is_null()) 2033 return; 2034 2035 if (Sign == AS_ASSUMPTION) 2036 DefinedBehaviorContext = DefinedBehaviorContext.intersect(Set); 2037 else 2038 DefinedBehaviorContext = DefinedBehaviorContext.subtract(Set); 2039 2040 // Limit the complexity of the context. If complexity is exceeded, simplify 2041 // the set and check again. 2042 if (DefinedBehaviorContext.n_basic_set().release() > 2043 MaxDisjunktsInDefinedBehaviourContext) { 2044 simplify(DefinedBehaviorContext); 2045 if (DefinedBehaviorContext.n_basic_set().release() > 2046 MaxDisjunktsInDefinedBehaviourContext) 2047 DefinedBehaviorContext = {}; 2048 } 2049 } 2050 2051 void Scop::invalidate(AssumptionKind Kind, DebugLoc Loc, BasicBlock *BB) { 2052 POLLY_DEBUG(dbgs() << "Invalidate SCoP because of reason " << Kind << "\n"); 2053 addAssumption(Kind, isl::set::empty(getParamSpace()), Loc, AS_ASSUMPTION, BB); 2054 } 2055 2056 isl::set Scop::getInvalidContext() const { return InvalidContext; } 2057 2058 void Scop::printContext(raw_ostream &OS) const { 2059 OS << "Context:\n"; 2060 OS.indent(4) << Context << "\n"; 2061 2062 OS.indent(4) << "Assumed Context:\n"; 2063 OS.indent(4) << AssumedContext << "\n"; 2064 2065 OS.indent(4) << "Invalid Context:\n"; 2066 OS.indent(4) << InvalidContext << "\n"; 2067 2068 OS.indent(4) << "Defined Behavior Context:\n"; 2069 if (!DefinedBehaviorContext.is_null()) 2070 OS.indent(4) << DefinedBehaviorContext << "\n"; 2071 else 2072 OS.indent(4) << "<unavailable>\n"; 2073 2074 unsigned Dim = 0; 2075 for (const SCEV *Parameter : Parameters) 2076 OS.indent(4) << "p" << Dim++ << ": " << *Parameter << "\n"; 2077 } 2078 2079 void Scop::printAliasAssumptions(raw_ostream &OS) const { 2080 int noOfGroups = 0; 2081 for (const MinMaxVectorPairTy &Pair : MinMaxAliasGroups) { 2082 if (Pair.second.size() == 0) 2083 noOfGroups += 1; 2084 else 2085 noOfGroups += Pair.second.size(); 2086 } 2087 2088 OS.indent(4) << "Alias Groups (" << noOfGroups << "):\n"; 2089 if (MinMaxAliasGroups.empty()) { 2090 OS.indent(8) << "n/a\n"; 2091 return; 2092 } 2093 2094 for (const MinMaxVectorPairTy &Pair : MinMaxAliasGroups) { 2095 2096 // If the group has no read only accesses print the write accesses. 2097 if (Pair.second.empty()) { 2098 OS.indent(8) << "[["; 2099 for (const MinMaxAccessTy &MMANonReadOnly : Pair.first) { 2100 OS << " <" << MMANonReadOnly.first << ", " << MMANonReadOnly.second 2101 << ">"; 2102 } 2103 OS << " ]]\n"; 2104 } 2105 2106 for (const MinMaxAccessTy &MMAReadOnly : Pair.second) { 2107 OS.indent(8) << "[["; 2108 OS << " <" << MMAReadOnly.first << ", " << MMAReadOnly.second << ">"; 2109 for (const MinMaxAccessTy &MMANonReadOnly : Pair.first) { 2110 OS << " <" << MMANonReadOnly.first << ", " << MMANonReadOnly.second 2111 << ">"; 2112 } 2113 OS << " ]]\n"; 2114 } 2115 } 2116 } 2117 2118 void Scop::printStatements(raw_ostream &OS, bool PrintInstructions) const { 2119 OS << "Statements {\n"; 2120 2121 for (const ScopStmt &Stmt : *this) { 2122 OS.indent(4); 2123 Stmt.print(OS, PrintInstructions); 2124 } 2125 2126 OS.indent(4) << "}\n"; 2127 } 2128 2129 void Scop::printArrayInfo(raw_ostream &OS) const { 2130 OS << "Arrays {\n"; 2131 2132 for (auto &Array : arrays()) 2133 Array->print(OS); 2134 2135 OS.indent(4) << "}\n"; 2136 2137 OS.indent(4) << "Arrays (Bounds as pw_affs) {\n"; 2138 2139 for (auto &Array : arrays()) 2140 Array->print(OS, /* SizeAsPwAff */ true); 2141 2142 OS.indent(4) << "}\n"; 2143 } 2144 2145 void Scop::print(raw_ostream &OS, bool PrintInstructions) const { 2146 OS.indent(4) << "Function: " << getFunction().getName() << "\n"; 2147 OS.indent(4) << "Region: " << getNameStr() << "\n"; 2148 OS.indent(4) << "Max Loop Depth: " << getMaxLoopDepth() << "\n"; 2149 OS.indent(4) << "Invariant Accesses: {\n"; 2150 for (const auto &IAClass : InvariantEquivClasses) { 2151 const auto &MAs = IAClass.InvariantAccesses; 2152 if (MAs.empty()) { 2153 OS.indent(12) << "Class Pointer: " << *IAClass.IdentifyingPointer << "\n"; 2154 } else { 2155 MAs.front()->print(OS); 2156 OS.indent(12) << "Execution Context: " << IAClass.ExecutionContext 2157 << "\n"; 2158 } 2159 } 2160 OS.indent(4) << "}\n"; 2161 printContext(OS.indent(4)); 2162 printArrayInfo(OS.indent(4)); 2163 printAliasAssumptions(OS); 2164 printStatements(OS.indent(4), PrintInstructions); 2165 } 2166 2167 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 2168 LLVM_DUMP_METHOD void Scop::dump() const { print(dbgs(), true); } 2169 #endif 2170 2171 isl::ctx Scop::getIslCtx() const { return IslCtx.get(); } 2172 2173 __isl_give PWACtx Scop::getPwAff(const SCEV *E, BasicBlock *BB, 2174 bool NonNegative, 2175 RecordedAssumptionsTy *RecordedAssumptions) { 2176 // First try to use the SCEVAffinator to generate a piecewise defined 2177 // affine function from @p E in the context of @p BB. If that tasks becomes to 2178 // complex the affinator might return a nullptr. In such a case we invalidate 2179 // the SCoP and return a dummy value. This way we do not need to add error 2180 // handling code to all users of this function. 2181 auto PWAC = Affinator.getPwAff(E, BB, RecordedAssumptions); 2182 if (!PWAC.first.is_null()) { 2183 // TODO: We could use a heuristic and either use: 2184 // SCEVAffinator::takeNonNegativeAssumption 2185 // or 2186 // SCEVAffinator::interpretAsUnsigned 2187 // to deal with unsigned or "NonNegative" SCEVs. 2188 if (NonNegative) 2189 Affinator.takeNonNegativeAssumption(PWAC, RecordedAssumptions); 2190 return PWAC; 2191 } 2192 2193 auto DL = BB ? BB->getTerminator()->getDebugLoc() : DebugLoc(); 2194 invalidate(COMPLEXITY, DL, BB); 2195 return Affinator.getPwAff(SE->getZero(E->getType()), BB, RecordedAssumptions); 2196 } 2197 2198 isl::union_set Scop::getDomains() const { 2199 isl_space *EmptySpace = isl_space_params_alloc(getIslCtx().get(), 0); 2200 isl_union_set *Domain = isl_union_set_empty(EmptySpace); 2201 2202 for (const ScopStmt &Stmt : *this) 2203 Domain = isl_union_set_add_set(Domain, Stmt.getDomain().release()); 2204 2205 return isl::manage(Domain); 2206 } 2207 2208 isl::pw_aff Scop::getPwAffOnly(const SCEV *E, BasicBlock *BB, 2209 RecordedAssumptionsTy *RecordedAssumptions) { 2210 PWACtx PWAC = getPwAff(E, BB, RecordedAssumptions); 2211 return PWAC.first; 2212 } 2213 2214 isl::union_map 2215 Scop::getAccessesOfType(std::function<bool(MemoryAccess &)> Predicate) { 2216 isl::union_map Accesses = isl::union_map::empty(getIslCtx()); 2217 2218 for (ScopStmt &Stmt : *this) { 2219 for (MemoryAccess *MA : Stmt) { 2220 if (!Predicate(*MA)) 2221 continue; 2222 2223 isl::set Domain = Stmt.getDomain(); 2224 isl::map AccessDomain = MA->getAccessRelation(); 2225 AccessDomain = AccessDomain.intersect_domain(Domain); 2226 Accesses = Accesses.unite(AccessDomain); 2227 } 2228 } 2229 2230 return Accesses.coalesce(); 2231 } 2232 2233 isl::union_map Scop::getMustWrites() { 2234 return getAccessesOfType([](MemoryAccess &MA) { return MA.isMustWrite(); }); 2235 } 2236 2237 isl::union_map Scop::getMayWrites() { 2238 return getAccessesOfType([](MemoryAccess &MA) { return MA.isMayWrite(); }); 2239 } 2240 2241 isl::union_map Scop::getWrites() { 2242 return getAccessesOfType([](MemoryAccess &MA) { return MA.isWrite(); }); 2243 } 2244 2245 isl::union_map Scop::getReads() { 2246 return getAccessesOfType([](MemoryAccess &MA) { return MA.isRead(); }); 2247 } 2248 2249 isl::union_map Scop::getAccesses() { 2250 return getAccessesOfType([](MemoryAccess &MA) { return true; }); 2251 } 2252 2253 isl::union_map Scop::getAccesses(ScopArrayInfo *Array) { 2254 return getAccessesOfType( 2255 [Array](MemoryAccess &MA) { return MA.getScopArrayInfo() == Array; }); 2256 } 2257 2258 isl::union_map Scop::getSchedule() const { 2259 auto Tree = getScheduleTree(); 2260 return Tree.get_map(); 2261 } 2262 2263 isl::schedule Scop::getScheduleTree() const { 2264 return Schedule.intersect_domain(getDomains()); 2265 } 2266 2267 void Scop::setSchedule(isl::union_map NewSchedule) { 2268 auto S = isl::schedule::from_domain(getDomains()); 2269 Schedule = S.insert_partial_schedule( 2270 isl::multi_union_pw_aff::from_union_map(NewSchedule)); 2271 ScheduleModified = true; 2272 } 2273 2274 void Scop::setScheduleTree(isl::schedule NewSchedule) { 2275 Schedule = NewSchedule; 2276 ScheduleModified = true; 2277 } 2278 2279 bool Scop::restrictDomains(isl::union_set Domain) { 2280 bool Changed = false; 2281 for (ScopStmt &Stmt : *this) { 2282 isl::union_set StmtDomain = isl::union_set(Stmt.getDomain()); 2283 isl::union_set NewStmtDomain = StmtDomain.intersect(Domain); 2284 2285 if (StmtDomain.is_subset(NewStmtDomain)) 2286 continue; 2287 2288 Changed = true; 2289 2290 NewStmtDomain = NewStmtDomain.coalesce(); 2291 2292 if (NewStmtDomain.is_empty()) 2293 Stmt.restrictDomain(isl::set::empty(Stmt.getDomainSpace())); 2294 else 2295 Stmt.restrictDomain(isl::set(NewStmtDomain)); 2296 } 2297 return Changed; 2298 } 2299 2300 ScalarEvolution *Scop::getSE() const { return SE; } 2301 2302 void Scop::addScopStmt(BasicBlock *BB, StringRef Name, Loop *SurroundingLoop, 2303 std::vector<Instruction *> Instructions) { 2304 assert(BB && "Unexpected nullptr!"); 2305 Stmts.emplace_back(*this, *BB, Name, SurroundingLoop, Instructions); 2306 auto *Stmt = &Stmts.back(); 2307 StmtMap[BB].push_back(Stmt); 2308 for (Instruction *Inst : Instructions) { 2309 assert(!InstStmtMap.count(Inst) && 2310 "Unexpected statement corresponding to the instruction."); 2311 InstStmtMap[Inst] = Stmt; 2312 } 2313 } 2314 2315 void Scop::addScopStmt(Region *R, StringRef Name, Loop *SurroundingLoop, 2316 std::vector<Instruction *> Instructions) { 2317 assert(R && "Unexpected nullptr!"); 2318 Stmts.emplace_back(*this, *R, Name, SurroundingLoop, Instructions); 2319 auto *Stmt = &Stmts.back(); 2320 2321 for (Instruction *Inst : Instructions) { 2322 assert(!InstStmtMap.count(Inst) && 2323 "Unexpected statement corresponding to the instruction."); 2324 InstStmtMap[Inst] = Stmt; 2325 } 2326 2327 for (BasicBlock *BB : R->blocks()) { 2328 StmtMap[BB].push_back(Stmt); 2329 if (BB == R->getEntry()) 2330 continue; 2331 for (Instruction &Inst : *BB) { 2332 assert(!InstStmtMap.count(&Inst) && 2333 "Unexpected statement corresponding to the instruction."); 2334 InstStmtMap[&Inst] = Stmt; 2335 } 2336 } 2337 } 2338 2339 ScopStmt *Scop::addScopStmt(isl::map SourceRel, isl::map TargetRel, 2340 isl::set Domain) { 2341 #ifndef NDEBUG 2342 isl::set SourceDomain = SourceRel.domain(); 2343 isl::set TargetDomain = TargetRel.domain(); 2344 assert(Domain.is_subset(TargetDomain) && 2345 "Target access not defined for complete statement domain"); 2346 assert(Domain.is_subset(SourceDomain) && 2347 "Source access not defined for complete statement domain"); 2348 #endif 2349 Stmts.emplace_back(*this, SourceRel, TargetRel, Domain); 2350 CopyStmtsNum++; 2351 return &(Stmts.back()); 2352 } 2353 2354 ArrayRef<ScopStmt *> Scop::getStmtListFor(BasicBlock *BB) const { 2355 auto StmtMapIt = StmtMap.find(BB); 2356 if (StmtMapIt == StmtMap.end()) 2357 return {}; 2358 return StmtMapIt->second; 2359 } 2360 2361 ScopStmt *Scop::getIncomingStmtFor(const Use &U) const { 2362 auto *PHI = cast<PHINode>(U.getUser()); 2363 BasicBlock *IncomingBB = PHI->getIncomingBlock(U); 2364 2365 // If the value is a non-synthesizable from the incoming block, use the 2366 // statement that contains it as user statement. 2367 if (auto *IncomingInst = dyn_cast<Instruction>(U.get())) { 2368 if (IncomingInst->getParent() == IncomingBB) { 2369 if (ScopStmt *IncomingStmt = getStmtFor(IncomingInst)) 2370 return IncomingStmt; 2371 } 2372 } 2373 2374 // Otherwise, use the epilogue/last statement. 2375 return getLastStmtFor(IncomingBB); 2376 } 2377 2378 ScopStmt *Scop::getLastStmtFor(BasicBlock *BB) const { 2379 ArrayRef<ScopStmt *> StmtList = getStmtListFor(BB); 2380 if (!StmtList.empty()) 2381 return StmtList.back(); 2382 return nullptr; 2383 } 2384 2385 ArrayRef<ScopStmt *> Scop::getStmtListFor(RegionNode *RN) const { 2386 if (RN->isSubRegion()) 2387 return getStmtListFor(RN->getNodeAs<Region>()); 2388 return getStmtListFor(RN->getNodeAs<BasicBlock>()); 2389 } 2390 2391 ArrayRef<ScopStmt *> Scop::getStmtListFor(Region *R) const { 2392 return getStmtListFor(R->getEntry()); 2393 } 2394 2395 int Scop::getRelativeLoopDepth(const Loop *L) const { 2396 if (!L || !R.contains(L)) 2397 return -1; 2398 // outermostLoopInRegion always returns nullptr for top level regions 2399 if (R.isTopLevelRegion()) { 2400 // LoopInfo's depths start at 1, we start at 0 2401 return L->getLoopDepth() - 1; 2402 } else { 2403 Loop *OuterLoop = R.outermostLoopInRegion(const_cast<Loop *>(L)); 2404 assert(OuterLoop); 2405 return L->getLoopDepth() - OuterLoop->getLoopDepth(); 2406 } 2407 } 2408 2409 ScopArrayInfo *Scop::getArrayInfoByName(const std::string BaseName) { 2410 for (auto &SAI : arrays()) { 2411 if (SAI->getName() == BaseName) 2412 return SAI; 2413 } 2414 return nullptr; 2415 } 2416 2417 void Scop::addAccessData(MemoryAccess *Access) { 2418 const ScopArrayInfo *SAI = Access->getOriginalScopArrayInfo(); 2419 assert(SAI && "can only use after access relations have been constructed"); 2420 2421 if (Access->isOriginalValueKind() && Access->isRead()) 2422 ValueUseAccs[SAI].push_back(Access); 2423 else if (Access->isOriginalAnyPHIKind() && Access->isWrite()) 2424 PHIIncomingAccs[SAI].push_back(Access); 2425 } 2426 2427 void Scop::removeAccessData(MemoryAccess *Access) { 2428 if (Access->isOriginalValueKind() && Access->isWrite()) { 2429 ValueDefAccs.erase(Access->getAccessValue()); 2430 } else if (Access->isOriginalValueKind() && Access->isRead()) { 2431 auto &Uses = ValueUseAccs[Access->getScopArrayInfo()]; 2432 llvm::erase(Uses, Access); 2433 } else if (Access->isOriginalPHIKind() && Access->isRead()) { 2434 PHINode *PHI = cast<PHINode>(Access->getAccessInstruction()); 2435 PHIReadAccs.erase(PHI); 2436 } else if (Access->isOriginalAnyPHIKind() && Access->isWrite()) { 2437 auto &Incomings = PHIIncomingAccs[Access->getScopArrayInfo()]; 2438 llvm::erase(Incomings, Access); 2439 } 2440 } 2441 2442 MemoryAccess *Scop::getValueDef(const ScopArrayInfo *SAI) const { 2443 assert(SAI->isValueKind()); 2444 2445 Instruction *Val = dyn_cast<Instruction>(SAI->getBasePtr()); 2446 if (!Val) 2447 return nullptr; 2448 2449 return ValueDefAccs.lookup(Val); 2450 } 2451 2452 ArrayRef<MemoryAccess *> Scop::getValueUses(const ScopArrayInfo *SAI) const { 2453 assert(SAI->isValueKind()); 2454 auto It = ValueUseAccs.find(SAI); 2455 if (It == ValueUseAccs.end()) 2456 return {}; 2457 return It->second; 2458 } 2459 2460 MemoryAccess *Scop::getPHIRead(const ScopArrayInfo *SAI) const { 2461 assert(SAI->isPHIKind() || SAI->isExitPHIKind()); 2462 2463 if (SAI->isExitPHIKind()) 2464 return nullptr; 2465 2466 PHINode *PHI = cast<PHINode>(SAI->getBasePtr()); 2467 return PHIReadAccs.lookup(PHI); 2468 } 2469 2470 ArrayRef<MemoryAccess *> Scop::getPHIIncomings(const ScopArrayInfo *SAI) const { 2471 assert(SAI->isPHIKind() || SAI->isExitPHIKind()); 2472 auto It = PHIIncomingAccs.find(SAI); 2473 if (It == PHIIncomingAccs.end()) 2474 return {}; 2475 return It->second; 2476 } 2477 2478 bool Scop::isEscaping(Instruction *Inst) { 2479 assert(contains(Inst) && "The concept of escaping makes only sense for " 2480 "values defined inside the SCoP"); 2481 2482 for (Use &Use : Inst->uses()) { 2483 BasicBlock *UserBB = getUseBlock(Use); 2484 if (!contains(UserBB)) 2485 return true; 2486 2487 // When the SCoP region exit needs to be simplified, PHIs in the region exit 2488 // move to a new basic block such that its incoming blocks are not in the 2489 // SCoP anymore. 2490 if (hasSingleExitEdge() && isa<PHINode>(Use.getUser()) && 2491 isExit(cast<PHINode>(Use.getUser())->getParent())) 2492 return true; 2493 } 2494 return false; 2495 } 2496 2497 void Scop::incrementNumberOfAliasingAssumptions(unsigned step) { 2498 AssumptionsAliasing += step; 2499 } 2500 2501 Scop::ScopStatistics Scop::getStatistics() const { 2502 ScopStatistics Result; 2503 #if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS) 2504 auto LoopStat = ScopDetection::countBeneficialLoops(&R, *SE, *getLI(), 0); 2505 2506 int NumTotalLoops = LoopStat.NumLoops; 2507 Result.NumBoxedLoops = getBoxedLoops().size(); 2508 Result.NumAffineLoops = NumTotalLoops - Result.NumBoxedLoops; 2509 2510 for (const ScopStmt &Stmt : *this) { 2511 isl::set Domain = Stmt.getDomain().intersect_params(getContext()); 2512 bool IsInLoop = Stmt.getNumIterators() >= 1; 2513 for (MemoryAccess *MA : Stmt) { 2514 if (!MA->isWrite()) 2515 continue; 2516 2517 if (MA->isLatestValueKind()) { 2518 Result.NumValueWrites += 1; 2519 if (IsInLoop) 2520 Result.NumValueWritesInLoops += 1; 2521 } 2522 2523 if (MA->isLatestAnyPHIKind()) { 2524 Result.NumPHIWrites += 1; 2525 if (IsInLoop) 2526 Result.NumPHIWritesInLoops += 1; 2527 } 2528 2529 isl::set AccSet = 2530 MA->getAccessRelation().intersect_domain(Domain).range(); 2531 if (AccSet.is_singleton()) { 2532 Result.NumSingletonWrites += 1; 2533 if (IsInLoop) 2534 Result.NumSingletonWritesInLoops += 1; 2535 } 2536 } 2537 } 2538 #endif 2539 return Result; 2540 } 2541 2542 raw_ostream &polly::operator<<(raw_ostream &OS, const Scop &scop) { 2543 scop.print(OS, PollyPrintInstructions); 2544 return OS; 2545 } 2546 2547 //===----------------------------------------------------------------------===// 2548 void ScopInfoRegionPass::getAnalysisUsage(AnalysisUsage &AU) const { 2549 AU.addRequired<LoopInfoWrapperPass>(); 2550 AU.addRequired<RegionInfoPass>(); 2551 AU.addRequired<DominatorTreeWrapperPass>(); 2552 AU.addRequiredTransitive<ScalarEvolutionWrapperPass>(); 2553 AU.addRequiredTransitive<ScopDetectionWrapperPass>(); 2554 AU.addRequired<AAResultsWrapperPass>(); 2555 AU.addRequired<AssumptionCacheTracker>(); 2556 AU.addRequired<OptimizationRemarkEmitterWrapperPass>(); 2557 AU.setPreservesAll(); 2558 } 2559 2560 void updateLoopCountStatistic(ScopDetection::LoopStats Stats, 2561 Scop::ScopStatistics ScopStats) { 2562 assert(Stats.NumLoops == ScopStats.NumAffineLoops + ScopStats.NumBoxedLoops); 2563 2564 NumScops++; 2565 NumLoopsInScop += Stats.NumLoops; 2566 MaxNumLoopsInScop = 2567 std::max(MaxNumLoopsInScop.getValue(), (uint64_t)Stats.NumLoops); 2568 2569 if (Stats.MaxDepth == 0) 2570 NumScopsDepthZero++; 2571 else if (Stats.MaxDepth == 1) 2572 NumScopsDepthOne++; 2573 else if (Stats.MaxDepth == 2) 2574 NumScopsDepthTwo++; 2575 else if (Stats.MaxDepth == 3) 2576 NumScopsDepthThree++; 2577 else if (Stats.MaxDepth == 4) 2578 NumScopsDepthFour++; 2579 else if (Stats.MaxDepth == 5) 2580 NumScopsDepthFive++; 2581 else 2582 NumScopsDepthLarger++; 2583 2584 NumAffineLoops += ScopStats.NumAffineLoops; 2585 NumBoxedLoops += ScopStats.NumBoxedLoops; 2586 2587 NumValueWrites += ScopStats.NumValueWrites; 2588 NumValueWritesInLoops += ScopStats.NumValueWritesInLoops; 2589 NumPHIWrites += ScopStats.NumPHIWrites; 2590 NumPHIWritesInLoops += ScopStats.NumPHIWritesInLoops; 2591 NumSingletonWrites += ScopStats.NumSingletonWrites; 2592 NumSingletonWritesInLoops += ScopStats.NumSingletonWritesInLoops; 2593 } 2594 2595 bool ScopInfoRegionPass::runOnRegion(Region *R, RGPassManager &RGM) { 2596 auto &SD = getAnalysis<ScopDetectionWrapperPass>().getSD(); 2597 2598 if (!SD.isMaxRegionInScop(*R)) 2599 return false; 2600 2601 Function *F = R->getEntry()->getParent(); 2602 auto &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE(); 2603 auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); 2604 auto &AA = getAnalysis<AAResultsWrapperPass>().getAAResults(); 2605 auto const &DL = F->getParent()->getDataLayout(); 2606 auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree(); 2607 auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(*F); 2608 auto &ORE = getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE(); 2609 2610 ScopBuilder SB(R, AC, AA, DL, DT, LI, SD, SE, ORE); 2611 S = SB.getScop(); // take ownership of scop object 2612 2613 #if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS) 2614 if (S) { 2615 ScopDetection::LoopStats Stats = 2616 ScopDetection::countBeneficialLoops(&S->getRegion(), SE, LI, 0); 2617 updateLoopCountStatistic(Stats, S->getStatistics()); 2618 } 2619 #endif 2620 2621 return false; 2622 } 2623 2624 void ScopInfoRegionPass::print(raw_ostream &OS, const Module *) const { 2625 if (S) 2626 S->print(OS, PollyPrintInstructions); 2627 else 2628 OS << "Invalid Scop!\n"; 2629 } 2630 2631 char ScopInfoRegionPass::ID = 0; 2632 2633 Pass *polly::createScopInfoRegionPassPass() { return new ScopInfoRegionPass(); } 2634 2635 INITIALIZE_PASS_BEGIN(ScopInfoRegionPass, "polly-scops", 2636 "Polly - Create polyhedral description of Scops", false, 2637 false); 2638 INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass); 2639 INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker); 2640 INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass); 2641 INITIALIZE_PASS_DEPENDENCY(RegionInfoPass); 2642 INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass); 2643 INITIALIZE_PASS_DEPENDENCY(ScopDetectionWrapperPass); 2644 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass); 2645 INITIALIZE_PASS_END(ScopInfoRegionPass, "polly-scops", 2646 "Polly - Create polyhedral description of Scops", false, 2647 false) 2648 2649 //===----------------------------------------------------------------------===// 2650 2651 namespace { 2652 2653 /// Print result from ScopInfoRegionPass. 2654 class ScopInfoPrinterLegacyRegionPass final : public RegionPass { 2655 public: 2656 static char ID; 2657 2658 ScopInfoPrinterLegacyRegionPass() : ScopInfoPrinterLegacyRegionPass(outs()) {} 2659 2660 explicit ScopInfoPrinterLegacyRegionPass(llvm::raw_ostream &OS) 2661 : RegionPass(ID), OS(OS) {} 2662 2663 bool runOnRegion(Region *R, RGPassManager &RGM) override { 2664 ScopInfoRegionPass &P = getAnalysis<ScopInfoRegionPass>(); 2665 2666 OS << "Printing analysis '" << P.getPassName() << "' for region: '" 2667 << R->getNameStr() << "' in function '" 2668 << R->getEntry()->getParent()->getName() << "':\n"; 2669 P.print(OS); 2670 2671 return false; 2672 } 2673 2674 void getAnalysisUsage(AnalysisUsage &AU) const override { 2675 RegionPass::getAnalysisUsage(AU); 2676 AU.addRequired<ScopInfoRegionPass>(); 2677 AU.setPreservesAll(); 2678 } 2679 2680 private: 2681 llvm::raw_ostream &OS; 2682 }; 2683 2684 char ScopInfoPrinterLegacyRegionPass::ID = 0; 2685 } // namespace 2686 2687 Pass *polly::createScopInfoPrinterLegacyRegionPass(raw_ostream &OS) { 2688 return new ScopInfoPrinterLegacyRegionPass(OS); 2689 } 2690 2691 INITIALIZE_PASS_BEGIN(ScopInfoPrinterLegacyRegionPass, "polly-print-scops", 2692 "Polly - Print polyhedral description of Scops", false, 2693 false); 2694 INITIALIZE_PASS_DEPENDENCY(ScopInfoRegionPass); 2695 INITIALIZE_PASS_END(ScopInfoPrinterLegacyRegionPass, "polly-print-scops", 2696 "Polly - Print polyhedral description of Scops", false, 2697 false) 2698 2699 //===----------------------------------------------------------------------===// 2700 2701 ScopInfo::ScopInfo(const DataLayout &DL, ScopDetection &SD, ScalarEvolution &SE, 2702 LoopInfo &LI, AliasAnalysis &AA, DominatorTree &DT, 2703 AssumptionCache &AC, OptimizationRemarkEmitter &ORE) 2704 : DL(DL), SD(SD), SE(SE), LI(LI), AA(AA), DT(DT), AC(AC), ORE(ORE) { 2705 recompute(); 2706 } 2707 2708 void ScopInfo::recompute() { 2709 RegionToScopMap.clear(); 2710 /// Create polyhedral description of scops for all the valid regions of a 2711 /// function. 2712 for (auto &It : SD) { 2713 Region *R = const_cast<Region *>(It); 2714 if (!SD.isMaxRegionInScop(*R)) 2715 continue; 2716 2717 ScopBuilder SB(R, AC, AA, DL, DT, LI, SD, SE, ORE); 2718 std::unique_ptr<Scop> S = SB.getScop(); 2719 if (!S) 2720 continue; 2721 #if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS) 2722 ScopDetection::LoopStats Stats = 2723 ScopDetection::countBeneficialLoops(&S->getRegion(), SE, LI, 0); 2724 updateLoopCountStatistic(Stats, S->getStatistics()); 2725 #endif 2726 bool Inserted = RegionToScopMap.insert({R, std::move(S)}).second; 2727 assert(Inserted && "Building Scop for the same region twice!"); 2728 (void)Inserted; 2729 } 2730 } 2731 2732 bool ScopInfo::invalidate(Function &F, const PreservedAnalyses &PA, 2733 FunctionAnalysisManager::Invalidator &Inv) { 2734 // Check whether the analysis, all analyses on functions have been preserved 2735 // or anything we're holding references to is being invalidated 2736 auto PAC = PA.getChecker<ScopInfoAnalysis>(); 2737 return !(PAC.preserved() || PAC.preservedSet<AllAnalysesOn<Function>>()) || 2738 Inv.invalidate<ScopAnalysis>(F, PA) || 2739 Inv.invalidate<ScalarEvolutionAnalysis>(F, PA) || 2740 Inv.invalidate<LoopAnalysis>(F, PA) || 2741 Inv.invalidate<AAManager>(F, PA) || 2742 Inv.invalidate<DominatorTreeAnalysis>(F, PA) || 2743 Inv.invalidate<AssumptionAnalysis>(F, PA); 2744 } 2745 2746 AnalysisKey ScopInfoAnalysis::Key; 2747 2748 ScopInfoAnalysis::Result ScopInfoAnalysis::run(Function &F, 2749 FunctionAnalysisManager &FAM) { 2750 auto &SD = FAM.getResult<ScopAnalysis>(F); 2751 auto &SE = FAM.getResult<ScalarEvolutionAnalysis>(F); 2752 auto &LI = FAM.getResult<LoopAnalysis>(F); 2753 auto &AA = FAM.getResult<AAManager>(F); 2754 auto &DT = FAM.getResult<DominatorTreeAnalysis>(F); 2755 auto &AC = FAM.getResult<AssumptionAnalysis>(F); 2756 auto &DL = F.getParent()->getDataLayout(); 2757 auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(F); 2758 return {DL, SD, SE, LI, AA, DT, AC, ORE}; 2759 } 2760 2761 PreservedAnalyses ScopInfoPrinterPass::run(Function &F, 2762 FunctionAnalysisManager &FAM) { 2763 auto &SI = FAM.getResult<ScopInfoAnalysis>(F); 2764 // Since the legacy PM processes Scops in bottom up, we print them in reverse 2765 // order here to keep the output persistent 2766 for (auto &It : reverse(SI)) { 2767 if (It.second) 2768 It.second->print(Stream, PollyPrintInstructions); 2769 else 2770 Stream << "Invalid Scop!\n"; 2771 } 2772 return PreservedAnalyses::all(); 2773 } 2774 2775 void ScopInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { 2776 AU.addRequired<LoopInfoWrapperPass>(); 2777 AU.addRequired<RegionInfoPass>(); 2778 AU.addRequired<DominatorTreeWrapperPass>(); 2779 AU.addRequiredTransitive<ScalarEvolutionWrapperPass>(); 2780 AU.addRequiredTransitive<ScopDetectionWrapperPass>(); 2781 AU.addRequired<AAResultsWrapperPass>(); 2782 AU.addRequired<AssumptionCacheTracker>(); 2783 AU.addRequired<OptimizationRemarkEmitterWrapperPass>(); 2784 AU.setPreservesAll(); 2785 } 2786 2787 bool ScopInfoWrapperPass::runOnFunction(Function &F) { 2788 auto &SD = getAnalysis<ScopDetectionWrapperPass>().getSD(); 2789 auto &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE(); 2790 auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); 2791 auto &AA = getAnalysis<AAResultsWrapperPass>().getAAResults(); 2792 auto const &DL = F.getParent()->getDataLayout(); 2793 auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree(); 2794 auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F); 2795 auto &ORE = getAnalysis<OptimizationRemarkEmitterWrapperPass>().getORE(); 2796 2797 Result.reset(new ScopInfo{DL, SD, SE, LI, AA, DT, AC, ORE}); 2798 return false; 2799 } 2800 2801 void ScopInfoWrapperPass::print(raw_ostream &OS, const Module *) const { 2802 for (auto &It : *Result) { 2803 if (It.second) 2804 It.second->print(OS, PollyPrintInstructions); 2805 else 2806 OS << "Invalid Scop!\n"; 2807 } 2808 } 2809 2810 char ScopInfoWrapperPass::ID = 0; 2811 2812 Pass *polly::createScopInfoWrapperPassPass() { 2813 return new ScopInfoWrapperPass(); 2814 } 2815 2816 INITIALIZE_PASS_BEGIN( 2817 ScopInfoWrapperPass, "polly-function-scops", 2818 "Polly - Create polyhedral description of all Scops of a function", false, 2819 false); 2820 INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass); 2821 INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker); 2822 INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass); 2823 INITIALIZE_PASS_DEPENDENCY(RegionInfoPass); 2824 INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass); 2825 INITIALIZE_PASS_DEPENDENCY(ScopDetectionWrapperPass); 2826 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass); 2827 INITIALIZE_PASS_END( 2828 ScopInfoWrapperPass, "polly-function-scops", 2829 "Polly - Create polyhedral description of all Scops of a function", false, 2830 false) 2831 2832 //===----------------------------------------------------------------------===// 2833 2834 namespace { 2835 /// Print result from ScopInfoWrapperPass. 2836 class ScopInfoPrinterLegacyFunctionPass final : public FunctionPass { 2837 public: 2838 static char ID; 2839 2840 ScopInfoPrinterLegacyFunctionPass() 2841 : ScopInfoPrinterLegacyFunctionPass(outs()) {} 2842 explicit ScopInfoPrinterLegacyFunctionPass(llvm::raw_ostream &OS) 2843 : FunctionPass(ID), OS(OS) {} 2844 2845 bool runOnFunction(Function &F) override { 2846 ScopInfoWrapperPass &P = getAnalysis<ScopInfoWrapperPass>(); 2847 2848 OS << "Printing analysis '" << P.getPassName() << "' for function '" 2849 << F.getName() << "':\n"; 2850 P.print(OS); 2851 2852 return false; 2853 } 2854 2855 void getAnalysisUsage(AnalysisUsage &AU) const override { 2856 FunctionPass::getAnalysisUsage(AU); 2857 AU.addRequired<ScopInfoWrapperPass>(); 2858 AU.setPreservesAll(); 2859 } 2860 2861 private: 2862 llvm::raw_ostream &OS; 2863 }; 2864 2865 char ScopInfoPrinterLegacyFunctionPass::ID = 0; 2866 } // namespace 2867 2868 Pass *polly::createScopInfoPrinterLegacyFunctionPass(raw_ostream &OS) { 2869 return new ScopInfoPrinterLegacyFunctionPass(OS); 2870 } 2871 2872 INITIALIZE_PASS_BEGIN( 2873 ScopInfoPrinterLegacyFunctionPass, "polly-print-function-scops", 2874 "Polly - Print polyhedral description of all Scops of a function", false, 2875 false); 2876 INITIALIZE_PASS_DEPENDENCY(ScopInfoWrapperPass); 2877 INITIALIZE_PASS_END( 2878 ScopInfoPrinterLegacyFunctionPass, "polly-print-function-scops", 2879 "Polly - Print polyhedral description of all Scops of a function", false, 2880 false) 2881