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