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