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