1 //===--------- ScopInfo.cpp ----------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // Create a polyhedral description for a static control flow region. 11 // 12 // The pass creates a polyhedral description of the Scops detected by the Scop 13 // detection derived from their LLVM-IR code. 14 // 15 // This representation is shared among several tools in the polyhedral 16 // community, which are e.g. Cloog, Pluto, Loopo, Graphite. 17 // 18 //===----------------------------------------------------------------------===// 19 20 #include "polly/ScopInfo.h" 21 #include "polly/LinkAllPasses.h" 22 #include "polly/Options.h" 23 #include "polly/ScopBuilder.h" 24 #include "polly/Support/GICHelper.h" 25 #include "polly/Support/SCEVValidator.h" 26 #include "polly/Support/ScopHelper.h" 27 #include "llvm/ADT/DepthFirstIterator.h" 28 #include "llvm/ADT/MapVector.h" 29 #include "llvm/ADT/PostOrderIterator.h" 30 #include "llvm/ADT/STLExtras.h" 31 #include "llvm/ADT/SetVector.h" 32 #include "llvm/ADT/SmallSet.h" 33 #include "llvm/ADT/Statistic.h" 34 #include "llvm/ADT/StringExtras.h" 35 #include "llvm/Analysis/AliasAnalysis.h" 36 #include "llvm/Analysis/Loads.h" 37 #include "llvm/Analysis/LoopInfo.h" 38 #include "llvm/Analysis/LoopIterator.h" 39 #include "llvm/Analysis/RegionIterator.h" 40 #include "llvm/Analysis/ScalarEvolutionExpressions.h" 41 #include "llvm/IR/DiagnosticInfo.h" 42 #include "llvm/Support/Debug.h" 43 #include "isl/aff.h" 44 #include "isl/constraint.h" 45 #include "isl/local_space.h" 46 #include "isl/map.h" 47 #include "isl/options.h" 48 #include "isl/printer.h" 49 #include "isl/schedule.h" 50 #include "isl/schedule_node.h" 51 #include "isl/set.h" 52 #include "isl/union_map.h" 53 #include "isl/union_set.h" 54 #include "isl/val.h" 55 #include <sstream> 56 #include <string> 57 #include <vector> 58 59 using namespace llvm; 60 using namespace polly; 61 62 #define DEBUG_TYPE "polly-scops" 63 64 STATISTIC(AssumptionsAliasing, "Number of aliasing assumptions taken."); 65 STATISTIC(AssumptionsInbounds, "Number of inbounds assumptions taken."); 66 STATISTIC(AssumptionsWrapping, "Number of wrapping assumptions taken."); 67 STATISTIC(AssumptionsUnsigned, "Number of unsigned assumptions taken."); 68 STATISTIC(AssumptionsComplexity, "Number of too complex SCoPs."); 69 STATISTIC(AssumptionsUnprofitable, "Number of unprofitable SCoPs."); 70 STATISTIC(AssumptionsErrorBlock, "Number of error block assumptions taken."); 71 STATISTIC(AssumptionsInfiniteLoop, "Number of bounded loop assumptions taken."); 72 STATISTIC(AssumptionsInvariantLoad, 73 "Number of invariant loads assumptions taken."); 74 STATISTIC(AssumptionsDelinearization, 75 "Number of delinearization assumptions taken."); 76 77 STATISTIC(NumLoopsInScop, "Number of loops in scops"); 78 STATISTIC(NumScopsDepthOne, "Number of scops with maximal loop depth 1"); 79 STATISTIC(NumScopsDepthTwo, "Number of scops with maximal loop depth 2"); 80 STATISTIC(NumScopsDepthThree, "Number of scops with maximal loop depth 3"); 81 STATISTIC(NumScopsDepthFour, "Number of scops with maximal loop depth 4"); 82 STATISTIC(NumScopsDepthFive, "Number of scops with maximal loop depth 5"); 83 STATISTIC(NumScopsDepthLarger, 84 "Number of scops with maximal loop depth 6 and larger"); 85 STATISTIC(MaxNumLoopsInScop, "Maximal number of loops in scops"); 86 87 // The maximal number of basic sets we allow during domain construction to 88 // be created. More complex scops will result in very high compile time and 89 // are also unlikely to result in good code 90 static int const MaxDisjunctsInDomain = 20; 91 92 // The number of disjunct in the context after which we stop to add more 93 // disjuncts. This parameter is there to avoid exponential growth in the 94 // number of disjunct when adding non-convex sets to the context. 95 static int const MaxDisjunctsInContext = 4; 96 97 static cl::opt<bool> PollyRemarksMinimal( 98 "polly-remarks-minimal", 99 cl::desc("Do not emit remarks about assumptions that are known"), 100 cl::Hidden, cl::ZeroOrMore, cl::init(false), cl::cat(PollyCategory)); 101 102 // Multiplicative reductions can be disabled separately as these kind of 103 // operations can overflow easily. Additive reductions and bit operations 104 // are in contrast pretty stable. 105 static cl::opt<bool> DisableMultiplicativeReductions( 106 "polly-disable-multiplicative-reductions", 107 cl::desc("Disable multiplicative reductions"), cl::Hidden, cl::ZeroOrMore, 108 cl::init(false), cl::cat(PollyCategory)); 109 110 static cl::opt<unsigned> RunTimeChecksMaxParameters( 111 "polly-rtc-max-parameters", 112 cl::desc("The maximal number of parameters allowed in RTCs."), cl::Hidden, 113 cl::ZeroOrMore, cl::init(8), cl::cat(PollyCategory)); 114 115 static cl::opt<unsigned> RunTimeChecksMaxArraysPerGroup( 116 "polly-rtc-max-arrays-per-group", 117 cl::desc("The maximal number of arrays to compare in each alias group."), 118 cl::Hidden, cl::ZeroOrMore, cl::init(20), cl::cat(PollyCategory)); 119 120 static cl::opt<std::string> UserContextStr( 121 "polly-context", cl::value_desc("isl parameter set"), 122 cl::desc("Provide additional constraints on the context parameters"), 123 cl::init(""), cl::cat(PollyCategory)); 124 125 static cl::opt<bool> DetectReductions("polly-detect-reductions", 126 cl::desc("Detect and exploit reductions"), 127 cl::Hidden, cl::ZeroOrMore, 128 cl::init(true), cl::cat(PollyCategory)); 129 130 static cl::opt<bool> 131 IslOnErrorAbort("polly-on-isl-error-abort", 132 cl::desc("Abort if an isl error is encountered"), 133 cl::init(true), cl::cat(PollyCategory)); 134 135 static cl::opt<bool> UnprofitableScalarAccs( 136 "polly-unprofitable-scalar-accs", 137 cl::desc("Count statements with scalar accesses as not optimizable"), 138 cl::Hidden, cl::init(true), cl::cat(PollyCategory)); 139 140 static cl::opt<bool> PollyPreciseInbounds( 141 "polly-precise-inbounds", 142 cl::desc("Take more precise inbounds assumptions (do not scale well)"), 143 cl::Hidden, cl::init(false), cl::cat(PollyCategory)); 144 145 static cl::opt<bool> PollyPreciseFoldAccesses( 146 "polly-precise-fold-accesses", 147 cl::desc("Fold memory accesses to modele more possible delinearizations " 148 "(do not scale well)"), 149 cl::Hidden, cl::init(false), cl::cat(PollyCategory)); 150 //===----------------------------------------------------------------------===// 151 152 // Create a sequence of two schedules. Either argument may be null and is 153 // interpreted as the empty schedule. Can also return null if both schedules are 154 // empty. 155 static __isl_give isl_schedule * 156 combineInSequence(__isl_take isl_schedule *Prev, 157 __isl_take isl_schedule *Succ) { 158 if (!Prev) 159 return Succ; 160 if (!Succ) 161 return Prev; 162 163 return isl_schedule_sequence(Prev, Succ); 164 } 165 166 static __isl_give isl_set *addRangeBoundsToSet(__isl_take isl_set *S, 167 const ConstantRange &Range, 168 int dim, 169 enum isl_dim_type type) { 170 isl_val *V; 171 isl_ctx *Ctx = isl_set_get_ctx(S); 172 173 // The upper and lower bound for a parameter value is derived either from 174 // the data type of the parameter or from the - possibly more restrictive - 175 // range metadata. 176 V = isl_valFromAPInt(Ctx, Range.getSignedMin(), true); 177 S = isl_set_lower_bound_val(S, type, dim, V); 178 V = isl_valFromAPInt(Ctx, Range.getSignedMax(), true); 179 S = isl_set_upper_bound_val(S, type, dim, V); 180 181 if (Range.isFullSet()) 182 return S; 183 184 if (isl_set_n_basic_set(S) > MaxDisjunctsInContext) 185 return S; 186 187 // In case of signed wrapping, we can refine the set of valid values by 188 // excluding the part not covered by the wrapping range. 189 if (Range.isSignWrappedSet()) { 190 V = isl_valFromAPInt(Ctx, Range.getLower(), true); 191 isl_set *SLB = isl_set_lower_bound_val(isl_set_copy(S), type, dim, V); 192 193 V = isl_valFromAPInt(Ctx, Range.getUpper(), true); 194 V = isl_val_sub_ui(V, 1); 195 isl_set *SUB = isl_set_upper_bound_val(S, type, dim, V); 196 S = isl_set_union(SLB, SUB); 197 } 198 199 return S; 200 } 201 202 static const ScopArrayInfo *identifyBasePtrOriginSAI(Scop *S, Value *BasePtr) { 203 LoadInst *BasePtrLI = dyn_cast<LoadInst>(BasePtr); 204 if (!BasePtrLI) 205 return nullptr; 206 207 if (!S->contains(BasePtrLI)) 208 return nullptr; 209 210 ScalarEvolution &SE = *S->getSE(); 211 212 auto *OriginBaseSCEV = 213 SE.getPointerBase(SE.getSCEV(BasePtrLI->getPointerOperand())); 214 if (!OriginBaseSCEV) 215 return nullptr; 216 217 auto *OriginBaseSCEVUnknown = dyn_cast<SCEVUnknown>(OriginBaseSCEV); 218 if (!OriginBaseSCEVUnknown) 219 return nullptr; 220 221 return S->getScopArrayInfo(OriginBaseSCEVUnknown->getValue(), 222 MemoryKind::Array); 223 } 224 225 ScopArrayInfo::ScopArrayInfo(Value *BasePtr, Type *ElementType, isl_ctx *Ctx, 226 ArrayRef<const SCEV *> Sizes, MemoryKind Kind, 227 const DataLayout &DL, Scop *S, 228 const char *BaseName) 229 : BasePtr(BasePtr), ElementType(ElementType), Kind(Kind), DL(DL), S(*S) { 230 std::string BasePtrName = 231 BaseName ? BaseName 232 : getIslCompatibleName("MemRef_", BasePtr, 233 Kind == MemoryKind::PHI ? "__phi" : ""); 234 Id = isl_id_alloc(Ctx, BasePtrName.c_str(), this); 235 236 updateSizes(Sizes); 237 238 if (!BasePtr || Kind != MemoryKind::Array) { 239 BasePtrOriginSAI = nullptr; 240 return; 241 } 242 243 BasePtrOriginSAI = identifyBasePtrOriginSAI(S, BasePtr); 244 if (BasePtrOriginSAI) 245 const_cast<ScopArrayInfo *>(BasePtrOriginSAI)->addDerivedSAI(this); 246 } 247 248 __isl_give isl_space *ScopArrayInfo::getSpace() const { 249 auto *Space = 250 isl_space_set_alloc(isl_id_get_ctx(Id), 0, getNumberOfDimensions()); 251 Space = isl_space_set_tuple_id(Space, isl_dim_set, isl_id_copy(Id)); 252 return Space; 253 } 254 255 bool ScopArrayInfo::isReadOnly() { 256 isl_union_set *WriteSet = isl_union_map_range(S.getWrites()); 257 isl_space *Space = getSpace(); 258 WriteSet = isl_union_set_intersect( 259 WriteSet, isl_union_set_from_set(isl_set_universe(Space))); 260 261 bool IsReadOnly = isl_union_set_is_empty(WriteSet); 262 isl_union_set_free(WriteSet); 263 264 return IsReadOnly; 265 } 266 267 void ScopArrayInfo::updateElementType(Type *NewElementType) { 268 if (NewElementType == ElementType) 269 return; 270 271 auto OldElementSize = DL.getTypeAllocSizeInBits(ElementType); 272 auto NewElementSize = DL.getTypeAllocSizeInBits(NewElementType); 273 274 if (NewElementSize == OldElementSize || NewElementSize == 0) 275 return; 276 277 if (NewElementSize % OldElementSize == 0 && NewElementSize < OldElementSize) { 278 ElementType = NewElementType; 279 } else { 280 auto GCD = GreatestCommonDivisor64(NewElementSize, OldElementSize); 281 ElementType = IntegerType::get(ElementType->getContext(), GCD); 282 } 283 } 284 285 bool ScopArrayInfo::updateSizes(ArrayRef<const SCEV *> NewSizes, 286 bool CheckConsistency) { 287 int SharedDims = std::min(NewSizes.size(), DimensionSizes.size()); 288 int ExtraDimsNew = NewSizes.size() - SharedDims; 289 int ExtraDimsOld = DimensionSizes.size() - SharedDims; 290 291 if (CheckConsistency) { 292 for (int i = 0; i < SharedDims; i++) { 293 auto *NewSize = NewSizes[i + ExtraDimsNew]; 294 auto *KnownSize = DimensionSizes[i + ExtraDimsOld]; 295 if (NewSize && KnownSize && NewSize != KnownSize) 296 return false; 297 } 298 299 if (DimensionSizes.size() >= NewSizes.size()) 300 return true; 301 } 302 303 DimensionSizes.clear(); 304 DimensionSizes.insert(DimensionSizes.begin(), NewSizes.begin(), 305 NewSizes.end()); 306 for (isl_pw_aff *Size : DimensionSizesPw) 307 isl_pw_aff_free(Size); 308 DimensionSizesPw.clear(); 309 for (const SCEV *Expr : DimensionSizes) { 310 if (!Expr) { 311 DimensionSizesPw.push_back(nullptr); 312 continue; 313 } 314 isl_pw_aff *Size = S.getPwAffOnly(Expr); 315 DimensionSizesPw.push_back(Size); 316 } 317 return true; 318 } 319 320 ScopArrayInfo::~ScopArrayInfo() { 321 isl_id_free(Id); 322 for (isl_pw_aff *Size : DimensionSizesPw) 323 isl_pw_aff_free(Size); 324 } 325 326 std::string ScopArrayInfo::getName() const { return isl_id_get_name(Id); } 327 328 int ScopArrayInfo::getElemSizeInBytes() const { 329 return DL.getTypeAllocSize(ElementType); 330 } 331 332 __isl_give isl_id *ScopArrayInfo::getBasePtrId() const { 333 return isl_id_copy(Id); 334 } 335 336 void ScopArrayInfo::dump() const { print(errs()); } 337 338 void ScopArrayInfo::print(raw_ostream &OS, bool SizeAsPwAff) const { 339 OS.indent(8) << *getElementType() << " " << getName(); 340 unsigned u = 0; 341 if (getNumberOfDimensions() > 0 && !getDimensionSize(0)) { 342 OS << "[*]"; 343 u++; 344 } 345 for (; u < getNumberOfDimensions(); u++) { 346 OS << "["; 347 348 if (SizeAsPwAff) { 349 auto *Size = getDimensionSizePw(u); 350 OS << " " << Size << " "; 351 isl_pw_aff_free(Size); 352 } else { 353 OS << *getDimensionSize(u); 354 } 355 356 OS << "]"; 357 } 358 359 OS << ";"; 360 361 if (BasePtrOriginSAI) 362 OS << " [BasePtrOrigin: " << BasePtrOriginSAI->getName() << "]"; 363 364 OS << " // Element size " << getElemSizeInBytes() << "\n"; 365 } 366 367 const ScopArrayInfo * 368 ScopArrayInfo::getFromAccessFunction(__isl_keep isl_pw_multi_aff *PMA) { 369 isl_id *Id = isl_pw_multi_aff_get_tuple_id(PMA, isl_dim_out); 370 assert(Id && "Output dimension didn't have an ID"); 371 return getFromId(Id); 372 } 373 374 const ScopArrayInfo *ScopArrayInfo::getFromId(__isl_take isl_id *Id) { 375 void *User = isl_id_get_user(Id); 376 const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User); 377 isl_id_free(Id); 378 return SAI; 379 } 380 381 void MemoryAccess::wrapConstantDimensions() { 382 auto *SAI = getScopArrayInfo(); 383 auto *ArraySpace = SAI->getSpace(); 384 auto *Ctx = isl_space_get_ctx(ArraySpace); 385 unsigned DimsArray = SAI->getNumberOfDimensions(); 386 387 auto *DivModAff = isl_multi_aff_identity(isl_space_map_from_domain_and_range( 388 isl_space_copy(ArraySpace), isl_space_copy(ArraySpace))); 389 auto *LArraySpace = isl_local_space_from_space(ArraySpace); 390 391 // Begin with last dimension, to iteratively carry into higher dimensions. 392 for (int i = DimsArray - 1; i > 0; i--) { 393 auto *DimSize = SAI->getDimensionSize(i); 394 auto *DimSizeCst = dyn_cast<SCEVConstant>(DimSize); 395 396 // This transformation is not applicable to dimensions with dynamic size. 397 if (!DimSizeCst) 398 continue; 399 400 // This transformation is not applicable to dimensions of size zero. 401 if (DimSize->isZero()) 402 continue; 403 404 auto *DimSizeVal = isl_valFromAPInt(Ctx, DimSizeCst->getAPInt(), false); 405 auto *Var = isl_aff_var_on_domain(isl_local_space_copy(LArraySpace), 406 isl_dim_set, i); 407 auto *PrevVar = isl_aff_var_on_domain(isl_local_space_copy(LArraySpace), 408 isl_dim_set, i - 1); 409 410 // Compute: index % size 411 // Modulo must apply in the divide of the previous iteration, if any. 412 auto *Modulo = isl_aff_copy(Var); 413 Modulo = isl_aff_mod_val(Modulo, isl_val_copy(DimSizeVal)); 414 Modulo = isl_aff_pullback_multi_aff(Modulo, isl_multi_aff_copy(DivModAff)); 415 416 // Compute: floor(index / size) 417 auto *Divide = Var; 418 Divide = isl_aff_div( 419 Divide, 420 isl_aff_val_on_domain(isl_local_space_copy(LArraySpace), DimSizeVal)); 421 Divide = isl_aff_floor(Divide); 422 Divide = isl_aff_add(Divide, PrevVar); 423 Divide = isl_aff_pullback_multi_aff(Divide, isl_multi_aff_copy(DivModAff)); 424 425 // Apply Modulo and Divide. 426 DivModAff = isl_multi_aff_set_aff(DivModAff, i, Modulo); 427 DivModAff = isl_multi_aff_set_aff(DivModAff, i - 1, Divide); 428 } 429 430 // Apply all modulo/divides on the accesses. 431 AccessRelation = 432 isl_map_apply_range(AccessRelation, isl_map_from_multi_aff(DivModAff)); 433 AccessRelation = isl_map_detect_equalities(AccessRelation); 434 isl_local_space_free(LArraySpace); 435 } 436 437 void MemoryAccess::updateDimensionality() { 438 auto *SAI = getScopArrayInfo(); 439 auto *ArraySpace = SAI->getSpace(); 440 auto *AccessSpace = isl_space_range(isl_map_get_space(AccessRelation)); 441 auto *Ctx = isl_space_get_ctx(AccessSpace); 442 443 auto DimsArray = isl_space_dim(ArraySpace, isl_dim_set); 444 auto DimsAccess = isl_space_dim(AccessSpace, isl_dim_set); 445 auto DimsMissing = DimsArray - DimsAccess; 446 447 auto *BB = getStatement()->getEntryBlock(); 448 auto &DL = BB->getModule()->getDataLayout(); 449 unsigned ArrayElemSize = SAI->getElemSizeInBytes(); 450 unsigned ElemBytes = DL.getTypeAllocSize(getElementType()); 451 452 auto *Map = isl_map_from_domain_and_range( 453 isl_set_universe(AccessSpace), 454 isl_set_universe(isl_space_copy(ArraySpace))); 455 456 for (unsigned i = 0; i < DimsMissing; i++) 457 Map = isl_map_fix_si(Map, isl_dim_out, i, 0); 458 459 for (unsigned i = DimsMissing; i < DimsArray; i++) 460 Map = isl_map_equate(Map, isl_dim_in, i - DimsMissing, isl_dim_out, i); 461 462 AccessRelation = isl_map_apply_range(AccessRelation, Map); 463 464 // For the non delinearized arrays, divide the access function of the last 465 // subscript by the size of the elements in the array. 466 // 467 // A stride one array access in C expressed as A[i] is expressed in 468 // LLVM-IR as something like A[i * elementsize]. This hides the fact that 469 // two subsequent values of 'i' index two values that are stored next to 470 // each other in memory. By this division we make this characteristic 471 // obvious again. If the base pointer was accessed with offsets not divisible 472 // by the accesses element size, we will have chosen a smaller ArrayElemSize 473 // that divides the offsets of all accesses to this base pointer. 474 if (DimsAccess == 1) { 475 isl_val *V = isl_val_int_from_si(Ctx, ArrayElemSize); 476 AccessRelation = isl_map_floordiv_val(AccessRelation, V); 477 } 478 479 // We currently do this only if we added at least one dimension, which means 480 // some dimension's indices have not been specified, an indicator that some 481 // index values have been added together. 482 // TODO: Investigate general usefulness; Effect on unit tests is to make index 483 // expressions more complicated. 484 if (DimsMissing) 485 wrapConstantDimensions(); 486 487 if (!isAffine()) 488 computeBoundsOnAccessRelation(ArrayElemSize); 489 490 // Introduce multi-element accesses in case the type loaded by this memory 491 // access is larger than the canonical element type of the array. 492 // 493 // An access ((float *)A)[i] to an array char *A is modeled as 494 // {[i] -> A[o] : 4 i <= o <= 4 i + 3 495 if (ElemBytes > ArrayElemSize) { 496 assert(ElemBytes % ArrayElemSize == 0 && 497 "Loaded element size should be multiple of canonical element size"); 498 auto *Map = isl_map_from_domain_and_range( 499 isl_set_universe(isl_space_copy(ArraySpace)), 500 isl_set_universe(isl_space_copy(ArraySpace))); 501 for (unsigned i = 0; i < DimsArray - 1; i++) 502 Map = isl_map_equate(Map, isl_dim_in, i, isl_dim_out, i); 503 504 isl_constraint *C; 505 isl_local_space *LS; 506 507 LS = isl_local_space_from_space(isl_map_get_space(Map)); 508 int Num = ElemBytes / getScopArrayInfo()->getElemSizeInBytes(); 509 510 C = isl_constraint_alloc_inequality(isl_local_space_copy(LS)); 511 C = isl_constraint_set_constant_val(C, isl_val_int_from_si(Ctx, Num - 1)); 512 C = isl_constraint_set_coefficient_si(C, isl_dim_in, DimsArray - 1, 1); 513 C = isl_constraint_set_coefficient_si(C, isl_dim_out, DimsArray - 1, -1); 514 Map = isl_map_add_constraint(Map, C); 515 516 C = isl_constraint_alloc_inequality(LS); 517 C = isl_constraint_set_coefficient_si(C, isl_dim_in, DimsArray - 1, -1); 518 C = isl_constraint_set_coefficient_si(C, isl_dim_out, DimsArray - 1, 1); 519 C = isl_constraint_set_constant_val(C, isl_val_int_from_si(Ctx, 0)); 520 Map = isl_map_add_constraint(Map, C); 521 AccessRelation = isl_map_apply_range(AccessRelation, Map); 522 } 523 524 isl_space_free(ArraySpace); 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 return ""; 546 } 547 548 /// Return the reduction type for a given binary operator. 549 static MemoryAccess::ReductionType getReductionType(const BinaryOperator *BinOp, 550 const Instruction *Load) { 551 if (!BinOp) 552 return MemoryAccess::RT_NONE; 553 switch (BinOp->getOpcode()) { 554 case Instruction::FAdd: 555 if (!BinOp->hasUnsafeAlgebra()) 556 return MemoryAccess::RT_NONE; 557 // Fall through 558 case Instruction::Add: 559 return MemoryAccess::RT_ADD; 560 case Instruction::Or: 561 return MemoryAccess::RT_BOR; 562 case Instruction::Xor: 563 return MemoryAccess::RT_BXOR; 564 case Instruction::And: 565 return MemoryAccess::RT_BAND; 566 case Instruction::FMul: 567 if (!BinOp->hasUnsafeAlgebra()) 568 return MemoryAccess::RT_NONE; 569 // Fall through 570 case Instruction::Mul: 571 if (DisableMultiplicativeReductions) 572 return MemoryAccess::RT_NONE; 573 return MemoryAccess::RT_MUL; 574 default: 575 return MemoryAccess::RT_NONE; 576 } 577 } 578 579 MemoryAccess::~MemoryAccess() { 580 isl_id_free(Id); 581 isl_set_free(InvalidDomain); 582 isl_map_free(AccessRelation); 583 isl_map_free(NewAccessRelation); 584 } 585 586 const ScopArrayInfo *MemoryAccess::getOriginalScopArrayInfo() const { 587 isl_id *ArrayId = getArrayId(); 588 void *User = isl_id_get_user(ArrayId); 589 const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User); 590 isl_id_free(ArrayId); 591 return SAI; 592 } 593 594 const ScopArrayInfo *MemoryAccess::getLatestScopArrayInfo() const { 595 isl_id *ArrayId = getLatestArrayId(); 596 void *User = isl_id_get_user(ArrayId); 597 const ScopArrayInfo *SAI = static_cast<ScopArrayInfo *>(User); 598 isl_id_free(ArrayId); 599 return SAI; 600 } 601 602 __isl_give isl_id *MemoryAccess::getOriginalArrayId() const { 603 return isl_map_get_tuple_id(AccessRelation, isl_dim_out); 604 } 605 606 __isl_give isl_id *MemoryAccess::getLatestArrayId() const { 607 if (!hasNewAccessRelation()) 608 return getOriginalArrayId(); 609 return isl_map_get_tuple_id(NewAccessRelation, isl_dim_out); 610 } 611 612 __isl_give isl_map *MemoryAccess::getAddressFunction() const { 613 return isl_map_lexmin(getAccessRelation()); 614 } 615 616 __isl_give isl_pw_multi_aff *MemoryAccess::applyScheduleToAccessRelation( 617 __isl_take isl_union_map *USchedule) const { 618 isl_map *Schedule, *ScheduledAccRel; 619 isl_union_set *UDomain; 620 621 UDomain = isl_union_set_from_set(getStatement()->getDomain()); 622 USchedule = isl_union_map_intersect_domain(USchedule, UDomain); 623 Schedule = isl_map_from_union_map(USchedule); 624 ScheduledAccRel = isl_map_apply_domain(getAddressFunction(), Schedule); 625 return isl_pw_multi_aff_from_map(ScheduledAccRel); 626 } 627 628 __isl_give isl_map *MemoryAccess::getOriginalAccessRelation() const { 629 return isl_map_copy(AccessRelation); 630 } 631 632 std::string MemoryAccess::getOriginalAccessRelationStr() const { 633 return stringFromIslObj(AccessRelation); 634 } 635 636 __isl_give isl_space *MemoryAccess::getOriginalAccessRelationSpace() const { 637 return isl_map_get_space(AccessRelation); 638 } 639 640 __isl_give isl_map *MemoryAccess::getNewAccessRelation() const { 641 return isl_map_copy(NewAccessRelation); 642 } 643 644 std::string MemoryAccess::getNewAccessRelationStr() const { 645 return stringFromIslObj(NewAccessRelation); 646 } 647 648 __isl_give isl_basic_map * 649 MemoryAccess::createBasicAccessMap(ScopStmt *Statement) { 650 isl_space *Space = isl_space_set_alloc(Statement->getIslCtx(), 0, 1); 651 Space = isl_space_align_params(Space, Statement->getDomainSpace()); 652 653 return isl_basic_map_from_domain_and_range( 654 isl_basic_set_universe(Statement->getDomainSpace()), 655 isl_basic_set_universe(Space)); 656 } 657 658 // Formalize no out-of-bound access assumption 659 // 660 // When delinearizing array accesses we optimistically assume that the 661 // delinearized accesses do not access out of bound locations (the subscript 662 // expression of each array evaluates for each statement instance that is 663 // executed to a value that is larger than zero and strictly smaller than the 664 // size of the corresponding dimension). The only exception is the outermost 665 // dimension for which we do not need to assume any upper bound. At this point 666 // we formalize this assumption to ensure that at code generation time the 667 // relevant run-time checks can be generated. 668 // 669 // To find the set of constraints necessary to avoid out of bound accesses, we 670 // first build the set of data locations that are not within array bounds. We 671 // then apply the reverse access relation to obtain the set of iterations that 672 // may contain invalid accesses and reduce this set of iterations to the ones 673 // that are actually executed by intersecting them with the domain of the 674 // statement. If we now project out all loop dimensions, we obtain a set of 675 // parameters that may cause statement instances to be executed that may 676 // possibly yield out of bound memory accesses. The complement of these 677 // constraints is the set of constraints that needs to be assumed to ensure such 678 // statement instances are never executed. 679 void MemoryAccess::assumeNoOutOfBound() { 680 auto *SAI = getScopArrayInfo(); 681 isl_space *Space = isl_space_range(getOriginalAccessRelationSpace()); 682 isl_set *Outside = isl_set_empty(isl_space_copy(Space)); 683 for (int i = 1, Size = isl_space_dim(Space, isl_dim_set); i < Size; ++i) { 684 isl_local_space *LS = isl_local_space_from_space(isl_space_copy(Space)); 685 isl_pw_aff *Var = 686 isl_pw_aff_var_on_domain(isl_local_space_copy(LS), isl_dim_set, i); 687 isl_pw_aff *Zero = isl_pw_aff_zero_on_domain(LS); 688 689 isl_set *DimOutside; 690 691 DimOutside = isl_pw_aff_lt_set(isl_pw_aff_copy(Var), Zero); 692 isl_pw_aff *SizeE = SAI->getDimensionSizePw(i); 693 SizeE = isl_pw_aff_add_dims(SizeE, isl_dim_in, 694 isl_space_dim(Space, isl_dim_set)); 695 SizeE = isl_pw_aff_set_tuple_id(SizeE, isl_dim_in, 696 isl_space_get_tuple_id(Space, isl_dim_set)); 697 698 DimOutside = isl_set_union(DimOutside, isl_pw_aff_le_set(SizeE, Var)); 699 700 Outside = isl_set_union(Outside, DimOutside); 701 } 702 703 Outside = isl_set_apply(Outside, isl_map_reverse(getAccessRelation())); 704 Outside = isl_set_intersect(Outside, Statement->getDomain()); 705 Outside = isl_set_params(Outside); 706 707 // Remove divs to avoid the construction of overly complicated assumptions. 708 // Doing so increases the set of parameter combinations that are assumed to 709 // not appear. This is always save, but may make the resulting run-time check 710 // bail out more often than strictly necessary. 711 Outside = isl_set_remove_divs(Outside); 712 Outside = isl_set_complement(Outside); 713 const auto &Loc = getAccessInstruction() 714 ? getAccessInstruction()->getDebugLoc() 715 : DebugLoc(); 716 if (!PollyPreciseInbounds) 717 Outside = isl_set_gist(Outside, isl_set_params(Statement->getDomain())); 718 Statement->getParent()->recordAssumption(INBOUNDS, Outside, Loc, 719 AS_ASSUMPTION); 720 isl_space_free(Space); 721 } 722 723 void MemoryAccess::buildMemIntrinsicAccessRelation() { 724 assert(isMemoryIntrinsic()); 725 assert(Subscripts.size() == 2 && Sizes.size() == 1); 726 727 auto *SubscriptPWA = getPwAff(Subscripts[0]); 728 auto *SubscriptMap = isl_map_from_pw_aff(SubscriptPWA); 729 730 isl_map *LengthMap; 731 if (Subscripts[1] == nullptr) { 732 LengthMap = isl_map_universe(isl_map_get_space(SubscriptMap)); 733 } else { 734 auto *LengthPWA = getPwAff(Subscripts[1]); 735 LengthMap = isl_map_from_pw_aff(LengthPWA); 736 auto *RangeSpace = isl_space_range(isl_map_get_space(LengthMap)); 737 LengthMap = isl_map_apply_range(LengthMap, isl_map_lex_gt(RangeSpace)); 738 } 739 LengthMap = isl_map_lower_bound_si(LengthMap, isl_dim_out, 0, 0); 740 LengthMap = isl_map_align_params(LengthMap, isl_map_get_space(SubscriptMap)); 741 SubscriptMap = 742 isl_map_align_params(SubscriptMap, isl_map_get_space(LengthMap)); 743 LengthMap = isl_map_sum(LengthMap, SubscriptMap); 744 AccessRelation = isl_map_set_tuple_id(LengthMap, isl_dim_in, 745 getStatement()->getDomainId()); 746 } 747 748 void MemoryAccess::computeBoundsOnAccessRelation(unsigned ElementSize) { 749 ScalarEvolution *SE = Statement->getParent()->getSE(); 750 751 auto MAI = MemAccInst(getAccessInstruction()); 752 if (isa<MemIntrinsic>(MAI)) 753 return; 754 755 Value *Ptr = MAI.getPointerOperand(); 756 if (!Ptr || !SE->isSCEVable(Ptr->getType())) 757 return; 758 759 auto *PtrSCEV = SE->getSCEV(Ptr); 760 if (isa<SCEVCouldNotCompute>(PtrSCEV)) 761 return; 762 763 auto *BasePtrSCEV = SE->getPointerBase(PtrSCEV); 764 if (BasePtrSCEV && !isa<SCEVCouldNotCompute>(BasePtrSCEV)) 765 PtrSCEV = SE->getMinusSCEV(PtrSCEV, BasePtrSCEV); 766 767 const ConstantRange &Range = SE->getSignedRange(PtrSCEV); 768 if (Range.isFullSet()) 769 return; 770 771 if (Range.isWrappedSet()) 772 return; 773 774 bool isWrapping = Range.isSignWrappedSet(); 775 776 unsigned BW = Range.getBitWidth(); 777 const auto One = APInt(BW, 1); 778 const auto LB = isWrapping ? Range.getLower() : Range.getSignedMin(); 779 const auto UB = isWrapping ? (Range.getUpper() - One) : Range.getSignedMax(); 780 781 auto Min = LB.sdiv(APInt(BW, ElementSize)); 782 auto Max = UB.sdiv(APInt(BW, ElementSize)) + One; 783 784 assert(Min.sle(Max) && "Minimum expected to be less or equal than max"); 785 786 isl_set *AccessRange = isl_map_range(isl_map_copy(AccessRelation)); 787 AccessRange = 788 addRangeBoundsToSet(AccessRange, ConstantRange(Min, Max), 0, isl_dim_set); 789 AccessRelation = isl_map_intersect_range(AccessRelation, AccessRange); 790 } 791 792 void MemoryAccess::foldAccessRelation() { 793 if (Sizes.size() < 2 || isa<SCEVConstant>(Sizes[1])) 794 return; 795 796 int Size = Subscripts.size(); 797 798 isl_map *OldAccessRelation = isl_map_copy(AccessRelation); 799 800 for (int i = Size - 2; i >= 0; --i) { 801 isl_space *Space; 802 isl_map *MapOne, *MapTwo; 803 isl_pw_aff *DimSize = getPwAff(Sizes[i + 1]); 804 805 isl_space *SpaceSize = isl_pw_aff_get_space(DimSize); 806 isl_pw_aff_free(DimSize); 807 isl_id *ParamId = isl_space_get_dim_id(SpaceSize, isl_dim_param, 0); 808 809 Space = isl_map_get_space(AccessRelation); 810 Space = isl_space_map_from_set(isl_space_range(Space)); 811 Space = isl_space_align_params(Space, SpaceSize); 812 813 int ParamLocation = isl_space_find_dim_by_id(Space, isl_dim_param, ParamId); 814 isl_id_free(ParamId); 815 816 MapOne = isl_map_universe(isl_space_copy(Space)); 817 for (int j = 0; j < Size; ++j) 818 MapOne = isl_map_equate(MapOne, isl_dim_in, j, isl_dim_out, j); 819 MapOne = isl_map_lower_bound_si(MapOne, isl_dim_in, i + 1, 0); 820 821 MapTwo = isl_map_universe(isl_space_copy(Space)); 822 for (int j = 0; j < Size; ++j) 823 if (j < i || j > i + 1) 824 MapTwo = isl_map_equate(MapTwo, isl_dim_in, j, isl_dim_out, j); 825 826 isl_local_space *LS = isl_local_space_from_space(Space); 827 isl_constraint *C; 828 C = isl_equality_alloc(isl_local_space_copy(LS)); 829 C = isl_constraint_set_constant_si(C, -1); 830 C = isl_constraint_set_coefficient_si(C, isl_dim_in, i, 1); 831 C = isl_constraint_set_coefficient_si(C, isl_dim_out, i, -1); 832 MapTwo = isl_map_add_constraint(MapTwo, C); 833 C = isl_equality_alloc(LS); 834 C = isl_constraint_set_coefficient_si(C, isl_dim_in, i + 1, 1); 835 C = isl_constraint_set_coefficient_si(C, isl_dim_out, i + 1, -1); 836 C = isl_constraint_set_coefficient_si(C, isl_dim_param, ParamLocation, 1); 837 MapTwo = isl_map_add_constraint(MapTwo, C); 838 MapTwo = isl_map_upper_bound_si(MapTwo, isl_dim_in, i + 1, -1); 839 840 MapOne = isl_map_union(MapOne, MapTwo); 841 AccessRelation = isl_map_apply_range(AccessRelation, MapOne); 842 } 843 844 isl_id *BaseAddrId = getScopArrayInfo()->getBasePtrId(); 845 auto Space = Statement->getDomainSpace(); 846 AccessRelation = isl_map_set_tuple_id( 847 AccessRelation, isl_dim_in, isl_space_get_tuple_id(Space, isl_dim_set)); 848 AccessRelation = 849 isl_map_set_tuple_id(AccessRelation, isl_dim_out, BaseAddrId); 850 AccessRelation = isl_map_gist_domain(AccessRelation, Statement->getDomain()); 851 852 // Access dimension folding might in certain cases increase the number of 853 // disjuncts in the memory access, which can possibly complicate the generated 854 // run-time checks and can lead to costly compilation. 855 if (!PollyPreciseFoldAccesses && isl_map_n_basic_map(AccessRelation) > 856 isl_map_n_basic_map(OldAccessRelation)) { 857 isl_map_free(AccessRelation); 858 AccessRelation = OldAccessRelation; 859 } else { 860 isl_map_free(OldAccessRelation); 861 } 862 863 isl_space_free(Space); 864 } 865 866 /// Check if @p Expr is divisible by @p Size. 867 static bool isDivisible(const SCEV *Expr, unsigned Size, ScalarEvolution &SE) { 868 assert(Size != 0); 869 if (Size == 1) 870 return true; 871 872 // Only one factor needs to be divisible. 873 if (auto *MulExpr = dyn_cast<SCEVMulExpr>(Expr)) { 874 for (auto *FactorExpr : MulExpr->operands()) 875 if (isDivisible(FactorExpr, Size, SE)) 876 return true; 877 return false; 878 } 879 880 // For other n-ary expressions (Add, AddRec, Max,...) all operands need 881 // to be divisble. 882 if (auto *NAryExpr = dyn_cast<SCEVNAryExpr>(Expr)) { 883 for (auto *OpExpr : NAryExpr->operands()) 884 if (!isDivisible(OpExpr, Size, SE)) 885 return false; 886 return true; 887 } 888 889 auto *SizeSCEV = SE.getConstant(Expr->getType(), Size); 890 auto *UDivSCEV = SE.getUDivExpr(Expr, SizeSCEV); 891 auto *MulSCEV = SE.getMulExpr(UDivSCEV, SizeSCEV); 892 return MulSCEV == Expr; 893 } 894 895 void MemoryAccess::buildAccessRelation(const ScopArrayInfo *SAI) { 896 assert(!AccessRelation && "AccessReltation already built"); 897 898 // Initialize the invalid domain which describes all iterations for which the 899 // access relation is not modeled correctly. 900 auto *StmtInvalidDomain = getStatement()->getInvalidDomain(); 901 InvalidDomain = isl_set_empty(isl_set_get_space(StmtInvalidDomain)); 902 isl_set_free(StmtInvalidDomain); 903 904 isl_ctx *Ctx = isl_id_get_ctx(Id); 905 isl_id *BaseAddrId = SAI->getBasePtrId(); 906 907 if (getAccessInstruction() && isa<MemIntrinsic>(getAccessInstruction())) { 908 buildMemIntrinsicAccessRelation(); 909 AccessRelation = 910 isl_map_set_tuple_id(AccessRelation, isl_dim_out, BaseAddrId); 911 return; 912 } 913 914 if (!isAffine()) { 915 // We overapproximate non-affine accesses with a possible access to the 916 // whole array. For read accesses it does not make a difference, if an 917 // access must or may happen. However, for write accesses it is important to 918 // differentiate between writes that must happen and writes that may happen. 919 if (!AccessRelation) 920 AccessRelation = isl_map_from_basic_map(createBasicAccessMap(Statement)); 921 922 AccessRelation = 923 isl_map_set_tuple_id(AccessRelation, isl_dim_out, BaseAddrId); 924 return; 925 } 926 927 isl_space *Space = isl_space_alloc(Ctx, 0, Statement->getNumIterators(), 0); 928 AccessRelation = isl_map_universe(Space); 929 930 for (int i = 0, Size = Subscripts.size(); i < Size; ++i) { 931 isl_pw_aff *Affine = getPwAff(Subscripts[i]); 932 isl_map *SubscriptMap = isl_map_from_pw_aff(Affine); 933 AccessRelation = isl_map_flat_range_product(AccessRelation, SubscriptMap); 934 } 935 936 Space = Statement->getDomainSpace(); 937 AccessRelation = isl_map_set_tuple_id( 938 AccessRelation, isl_dim_in, isl_space_get_tuple_id(Space, isl_dim_set)); 939 AccessRelation = 940 isl_map_set_tuple_id(AccessRelation, isl_dim_out, BaseAddrId); 941 942 AccessRelation = isl_map_gist_domain(AccessRelation, Statement->getDomain()); 943 isl_space_free(Space); 944 } 945 946 MemoryAccess::MemoryAccess(ScopStmt *Stmt, Instruction *AccessInst, 947 AccessType AccType, Value *BaseAddress, 948 Type *ElementType, bool Affine, 949 ArrayRef<const SCEV *> Subscripts, 950 ArrayRef<const SCEV *> Sizes, Value *AccessValue, 951 MemoryKind Kind, StringRef BaseName) 952 : Kind(Kind), AccType(AccType), RedType(RT_NONE), Statement(Stmt), 953 InvalidDomain(nullptr), BaseAddr(BaseAddress), BaseName(BaseName), 954 ElementType(ElementType), Sizes(Sizes.begin(), Sizes.end()), 955 AccessInstruction(AccessInst), AccessValue(AccessValue), IsAffine(Affine), 956 Subscripts(Subscripts.begin(), Subscripts.end()), AccessRelation(nullptr), 957 NewAccessRelation(nullptr) { 958 static const std::string TypeStrings[] = {"", "_Read", "_Write", "_MayWrite"}; 959 const std::string Access = TypeStrings[AccType] + utostr(Stmt->size()) + "_"; 960 961 std::string IdName = 962 getIslCompatibleName(Stmt->getBaseName(), Access, BaseName); 963 Id = isl_id_alloc(Stmt->getParent()->getIslCtx(), IdName.c_str(), this); 964 } 965 966 MemoryAccess::MemoryAccess(ScopStmt *Stmt, AccessType AccType, 967 __isl_take isl_map *AccRel) 968 : Kind(MemoryKind::Array), AccType(AccType), RedType(RT_NONE), 969 Statement(Stmt), InvalidDomain(nullptr), AccessInstruction(nullptr), 970 IsAffine(true), AccessRelation(nullptr), NewAccessRelation(AccRel) { 971 auto *ArrayInfoId = isl_map_get_tuple_id(NewAccessRelation, isl_dim_out); 972 auto *SAI = ScopArrayInfo::getFromId(ArrayInfoId); 973 Sizes.push_back(nullptr); 974 for (unsigned i = 1; i < SAI->getNumberOfDimensions(); i++) 975 Sizes.push_back(SAI->getDimensionSize(i)); 976 ElementType = SAI->getElementType(); 977 BaseAddr = SAI->getBasePtr(); 978 BaseName = SAI->getName(); 979 static const std::string TypeStrings[] = {"", "_Read", "_Write", "_MayWrite"}; 980 const std::string Access = TypeStrings[AccType] + utostr(Stmt->size()) + "_"; 981 982 std::string IdName = 983 getIslCompatibleName(Stmt->getBaseName(), Access, BaseName); 984 Id = isl_id_alloc(Stmt->getParent()->getIslCtx(), IdName.c_str(), this); 985 } 986 987 void MemoryAccess::realignParams() { 988 auto *Ctx = Statement->getParent()->getContext(); 989 InvalidDomain = isl_set_gist_params(InvalidDomain, isl_set_copy(Ctx)); 990 AccessRelation = isl_map_gist_params(AccessRelation, Ctx); 991 } 992 993 const std::string MemoryAccess::getReductionOperatorStr() const { 994 return MemoryAccess::getReductionOperatorStr(getReductionType()); 995 } 996 997 __isl_give isl_id *MemoryAccess::getId() const { return isl_id_copy(Id); } 998 999 raw_ostream &polly::operator<<(raw_ostream &OS, 1000 MemoryAccess::ReductionType RT) { 1001 if (RT == MemoryAccess::RT_NONE) 1002 OS << "NONE"; 1003 else 1004 OS << MemoryAccess::getReductionOperatorStr(RT); 1005 return OS; 1006 } 1007 1008 void MemoryAccess::print(raw_ostream &OS) const { 1009 switch (AccType) { 1010 case READ: 1011 OS.indent(12) << "ReadAccess :=\t"; 1012 break; 1013 case MUST_WRITE: 1014 OS.indent(12) << "MustWriteAccess :=\t"; 1015 break; 1016 case MAY_WRITE: 1017 OS.indent(12) << "MayWriteAccess :=\t"; 1018 break; 1019 } 1020 OS << "[Reduction Type: " << getReductionType() << "] "; 1021 OS << "[Scalar: " << isScalarKind() << "]\n"; 1022 OS.indent(16) << getOriginalAccessRelationStr() << ";\n"; 1023 if (hasNewAccessRelation()) 1024 OS.indent(11) << "new: " << getNewAccessRelationStr() << ";\n"; 1025 } 1026 1027 void MemoryAccess::dump() const { print(errs()); } 1028 1029 __isl_give isl_pw_aff *MemoryAccess::getPwAff(const SCEV *E) { 1030 auto *Stmt = getStatement(); 1031 PWACtx PWAC = Stmt->getParent()->getPwAff(E, Stmt->getEntryBlock()); 1032 isl_set *StmtDom = isl_set_reset_tuple_id(getStatement()->getDomain()); 1033 isl_set *NewInvalidDom = isl_set_intersect(StmtDom, PWAC.second); 1034 InvalidDomain = isl_set_union(InvalidDomain, NewInvalidDom); 1035 return PWAC.first; 1036 } 1037 1038 // Create a map in the size of the provided set domain, that maps from the 1039 // one element of the provided set domain to another element of the provided 1040 // set domain. 1041 // The mapping is limited to all points that are equal in all but the last 1042 // dimension and for which the last dimension of the input is strict smaller 1043 // than the last dimension of the output. 1044 // 1045 // getEqualAndLarger(set[i0, i1, ..., iX]): 1046 // 1047 // set[i0, i1, ..., iX] -> set[o0, o1, ..., oX] 1048 // : i0 = o0, i1 = o1, ..., i(X-1) = o(X-1), iX < oX 1049 // 1050 static isl_map *getEqualAndLarger(__isl_take isl_space *setDomain) { 1051 isl_space *Space = isl_space_map_from_set(setDomain); 1052 isl_map *Map = isl_map_universe(Space); 1053 unsigned lastDimension = isl_map_dim(Map, isl_dim_in) - 1; 1054 1055 // Set all but the last dimension to be equal for the input and output 1056 // 1057 // input[i0, i1, ..., iX] -> output[o0, o1, ..., oX] 1058 // : i0 = o0, i1 = o1, ..., i(X-1) = o(X-1) 1059 for (unsigned i = 0; i < lastDimension; ++i) 1060 Map = isl_map_equate(Map, isl_dim_in, i, isl_dim_out, i); 1061 1062 // Set the last dimension of the input to be strict smaller than the 1063 // last dimension of the output. 1064 // 1065 // input[?,?,?,...,iX] -> output[?,?,?,...,oX] : iX < oX 1066 Map = isl_map_order_lt(Map, isl_dim_in, lastDimension, isl_dim_out, 1067 lastDimension); 1068 return Map; 1069 } 1070 1071 __isl_give isl_set * 1072 MemoryAccess::getStride(__isl_take const isl_map *Schedule) const { 1073 isl_map *S = const_cast<isl_map *>(Schedule); 1074 isl_map *AccessRelation = getAccessRelation(); 1075 isl_space *Space = isl_space_range(isl_map_get_space(S)); 1076 isl_map *NextScatt = getEqualAndLarger(Space); 1077 1078 S = isl_map_reverse(S); 1079 NextScatt = isl_map_lexmin(NextScatt); 1080 1081 NextScatt = isl_map_apply_range(NextScatt, isl_map_copy(S)); 1082 NextScatt = isl_map_apply_range(NextScatt, isl_map_copy(AccessRelation)); 1083 NextScatt = isl_map_apply_domain(NextScatt, S); 1084 NextScatt = isl_map_apply_domain(NextScatt, AccessRelation); 1085 1086 isl_set *Deltas = isl_map_deltas(NextScatt); 1087 return Deltas; 1088 } 1089 1090 bool MemoryAccess::isStrideX(__isl_take const isl_map *Schedule, 1091 int StrideWidth) const { 1092 isl_set *Stride, *StrideX; 1093 bool IsStrideX; 1094 1095 Stride = getStride(Schedule); 1096 StrideX = isl_set_universe(isl_set_get_space(Stride)); 1097 for (unsigned i = 0; i < isl_set_dim(StrideX, isl_dim_set) - 1; i++) 1098 StrideX = isl_set_fix_si(StrideX, isl_dim_set, i, 0); 1099 StrideX = isl_set_fix_si(StrideX, isl_dim_set, 1100 isl_set_dim(StrideX, isl_dim_set) - 1, StrideWidth); 1101 IsStrideX = isl_set_is_subset(Stride, StrideX); 1102 1103 isl_set_free(StrideX); 1104 isl_set_free(Stride); 1105 1106 return IsStrideX; 1107 } 1108 1109 bool MemoryAccess::isStrideZero(__isl_take const isl_map *Schedule) const { 1110 return isStrideX(Schedule, 0); 1111 } 1112 1113 bool MemoryAccess::isStrideOne(__isl_take const isl_map *Schedule) const { 1114 return isStrideX(Schedule, 1); 1115 } 1116 1117 void MemoryAccess::setAccessRelation(__isl_take isl_map *NewAccess) { 1118 isl_map_free(AccessRelation); 1119 AccessRelation = NewAccess; 1120 } 1121 1122 void MemoryAccess::setNewAccessRelation(__isl_take isl_map *NewAccess) { 1123 assert(NewAccess); 1124 1125 #ifndef NDEBUG 1126 // Check domain space compatibility. 1127 auto *NewSpace = isl_map_get_space(NewAccess); 1128 auto *NewDomainSpace = isl_space_domain(isl_space_copy(NewSpace)); 1129 auto *OriginalDomainSpace = getStatement()->getDomainSpace(); 1130 assert(isl_space_has_equal_tuples(OriginalDomainSpace, NewDomainSpace)); 1131 isl_space_free(NewDomainSpace); 1132 isl_space_free(OriginalDomainSpace); 1133 1134 // Check whether there is an access for every statement instance. 1135 auto *StmtDomain = getStatement()->getDomain(); 1136 StmtDomain = isl_set_intersect_params( 1137 StmtDomain, getStatement()->getParent()->getContext()); 1138 auto *NewDomain = isl_map_domain(isl_map_copy(NewAccess)); 1139 assert(isl_set_is_subset(StmtDomain, NewDomain) && 1140 "Partial accesses not supported"); 1141 isl_set_free(NewDomain); 1142 isl_set_free(StmtDomain); 1143 1144 auto *NewAccessSpace = isl_space_range(NewSpace); 1145 assert(isl_space_has_tuple_id(NewAccessSpace, isl_dim_set) && 1146 "Must specify the array that is accessed"); 1147 auto *NewArrayId = isl_space_get_tuple_id(NewAccessSpace, isl_dim_set); 1148 auto *SAI = static_cast<ScopArrayInfo *>(isl_id_get_user(NewArrayId)); 1149 assert(SAI && "Must set a ScopArrayInfo"); 1150 1151 if (SAI->isArrayKind() && SAI->getBasePtrOriginSAI()) { 1152 InvariantEquivClassTy *EqClass = 1153 getStatement()->getParent()->lookupInvariantEquivClass( 1154 SAI->getBasePtr()); 1155 assert(EqClass && 1156 "Access functions to indirect arrays must have an invariant and " 1157 "hoisted base pointer"); 1158 } 1159 1160 // Check whether access dimensions correspond to number of dimensions of the 1161 // accesses array. 1162 auto Dims = SAI->getNumberOfDimensions(); 1163 assert(isl_space_dim(NewAccessSpace, isl_dim_set) == Dims && 1164 "Access dims must match array dims"); 1165 isl_space_free(NewAccessSpace); 1166 isl_id_free(NewArrayId); 1167 #endif 1168 1169 isl_map_free(NewAccessRelation); 1170 NewAccessRelation = NewAccess; 1171 } 1172 1173 //===----------------------------------------------------------------------===// 1174 1175 __isl_give isl_map *ScopStmt::getSchedule() const { 1176 isl_set *Domain = getDomain(); 1177 if (isl_set_is_empty(Domain)) { 1178 isl_set_free(Domain); 1179 return isl_map_from_aff( 1180 isl_aff_zero_on_domain(isl_local_space_from_space(getDomainSpace()))); 1181 } 1182 auto *Schedule = getParent()->getSchedule(); 1183 if (!Schedule) { 1184 isl_set_free(Domain); 1185 return nullptr; 1186 } 1187 Schedule = isl_union_map_intersect_domain( 1188 Schedule, isl_union_set_from_set(isl_set_copy(Domain))); 1189 if (isl_union_map_is_empty(Schedule)) { 1190 isl_set_free(Domain); 1191 isl_union_map_free(Schedule); 1192 return isl_map_from_aff( 1193 isl_aff_zero_on_domain(isl_local_space_from_space(getDomainSpace()))); 1194 } 1195 auto *M = isl_map_from_union_map(Schedule); 1196 M = isl_map_coalesce(M); 1197 M = isl_map_gist_domain(M, Domain); 1198 M = isl_map_coalesce(M); 1199 return M; 1200 } 1201 1202 __isl_give isl_pw_aff *ScopStmt::getPwAff(const SCEV *E, bool NonNegative) { 1203 PWACtx PWAC = getParent()->getPwAff(E, getEntryBlock(), NonNegative); 1204 InvalidDomain = isl_set_union(InvalidDomain, PWAC.second); 1205 return PWAC.first; 1206 } 1207 1208 void ScopStmt::restrictDomain(__isl_take isl_set *NewDomain) { 1209 assert(isl_set_is_subset(NewDomain, Domain) && 1210 "New domain is not a subset of old domain!"); 1211 isl_set_free(Domain); 1212 Domain = NewDomain; 1213 } 1214 1215 void ScopStmt::buildAccessRelations() { 1216 Scop &S = *getParent(); 1217 for (MemoryAccess *Access : MemAccs) { 1218 Type *ElementType = Access->getElementType(); 1219 1220 MemoryKind Ty; 1221 if (Access->isPHIKind()) 1222 Ty = MemoryKind::PHI; 1223 else if (Access->isExitPHIKind()) 1224 Ty = MemoryKind::ExitPHI; 1225 else if (Access->isValueKind()) 1226 Ty = MemoryKind::Value; 1227 else 1228 Ty = MemoryKind::Array; 1229 1230 auto *SAI = S.getOrCreateScopArrayInfo(Access->getOriginalBaseAddr(), 1231 ElementType, Access->Sizes, Ty); 1232 Access->buildAccessRelation(SAI); 1233 } 1234 } 1235 1236 void ScopStmt::addAccess(MemoryAccess *Access) { 1237 Instruction *AccessInst = Access->getAccessInstruction(); 1238 1239 if (Access->isArrayKind()) { 1240 MemoryAccessList &MAL = InstructionToAccess[AccessInst]; 1241 MAL.emplace_front(Access); 1242 } else if (Access->isValueKind() && Access->isWrite()) { 1243 Instruction *AccessVal = cast<Instruction>(Access->getAccessValue()); 1244 assert(Parent.getStmtFor(AccessVal) == this); 1245 assert(!ValueWrites.lookup(AccessVal)); 1246 1247 ValueWrites[AccessVal] = Access; 1248 } else if (Access->isValueKind() && Access->isRead()) { 1249 Value *AccessVal = Access->getAccessValue(); 1250 assert(!ValueReads.lookup(AccessVal)); 1251 1252 ValueReads[AccessVal] = Access; 1253 } else if (Access->isAnyPHIKind() && Access->isWrite()) { 1254 PHINode *PHI = cast<PHINode>(Access->getAccessValue()); 1255 assert(!PHIWrites.lookup(PHI)); 1256 1257 PHIWrites[PHI] = Access; 1258 } 1259 1260 MemAccs.push_back(Access); 1261 } 1262 1263 void ScopStmt::realignParams() { 1264 for (MemoryAccess *MA : *this) 1265 MA->realignParams(); 1266 1267 auto *Ctx = Parent.getContext(); 1268 InvalidDomain = isl_set_gist_params(InvalidDomain, isl_set_copy(Ctx)); 1269 Domain = isl_set_gist_params(Domain, Ctx); 1270 } 1271 1272 /// Add @p BSet to the set @p User if @p BSet is bounded. 1273 static isl_stat collectBoundedParts(__isl_take isl_basic_set *BSet, 1274 void *User) { 1275 isl_set **BoundedParts = static_cast<isl_set **>(User); 1276 if (isl_basic_set_is_bounded(BSet)) 1277 *BoundedParts = isl_set_union(*BoundedParts, isl_set_from_basic_set(BSet)); 1278 else 1279 isl_basic_set_free(BSet); 1280 return isl_stat_ok; 1281 } 1282 1283 /// Return the bounded parts of @p S. 1284 static __isl_give isl_set *collectBoundedParts(__isl_take isl_set *S) { 1285 isl_set *BoundedParts = isl_set_empty(isl_set_get_space(S)); 1286 isl_set_foreach_basic_set(S, collectBoundedParts, &BoundedParts); 1287 isl_set_free(S); 1288 return BoundedParts; 1289 } 1290 1291 /// Compute the (un)bounded parts of @p S wrt. to dimension @p Dim. 1292 /// 1293 /// @returns A separation of @p S into first an unbounded then a bounded subset, 1294 /// both with regards to the dimension @p Dim. 1295 static std::pair<__isl_give isl_set *, __isl_give isl_set *> 1296 partitionSetParts(__isl_take isl_set *S, unsigned Dim) { 1297 1298 for (unsigned u = 0, e = isl_set_n_dim(S); u < e; u++) 1299 S = isl_set_lower_bound_si(S, isl_dim_set, u, 0); 1300 1301 unsigned NumDimsS = isl_set_n_dim(S); 1302 isl_set *OnlyDimS = isl_set_copy(S); 1303 1304 // Remove dimensions that are greater than Dim as they are not interesting. 1305 assert(NumDimsS >= Dim + 1); 1306 OnlyDimS = 1307 isl_set_project_out(OnlyDimS, isl_dim_set, Dim + 1, NumDimsS - Dim - 1); 1308 1309 // Create artificial parametric upper bounds for dimensions smaller than Dim 1310 // as we are not interested in them. 1311 OnlyDimS = isl_set_insert_dims(OnlyDimS, isl_dim_param, 0, Dim); 1312 for (unsigned u = 0; u < Dim; u++) { 1313 isl_constraint *C = isl_inequality_alloc( 1314 isl_local_space_from_space(isl_set_get_space(OnlyDimS))); 1315 C = isl_constraint_set_coefficient_si(C, isl_dim_param, u, 1); 1316 C = isl_constraint_set_coefficient_si(C, isl_dim_set, u, -1); 1317 OnlyDimS = isl_set_add_constraint(OnlyDimS, C); 1318 } 1319 1320 // Collect all bounded parts of OnlyDimS. 1321 isl_set *BoundedParts = collectBoundedParts(OnlyDimS); 1322 1323 // Create the dimensions greater than Dim again. 1324 BoundedParts = isl_set_insert_dims(BoundedParts, isl_dim_set, Dim + 1, 1325 NumDimsS - Dim - 1); 1326 1327 // Remove the artificial upper bound parameters again. 1328 BoundedParts = isl_set_remove_dims(BoundedParts, isl_dim_param, 0, Dim); 1329 1330 isl_set *UnboundedParts = isl_set_subtract(S, isl_set_copy(BoundedParts)); 1331 return std::make_pair(UnboundedParts, BoundedParts); 1332 } 1333 1334 /// Set the dimension Ids from @p From in @p To. 1335 static __isl_give isl_set *setDimensionIds(__isl_keep isl_set *From, 1336 __isl_take isl_set *To) { 1337 for (unsigned u = 0, e = isl_set_n_dim(From); u < e; u++) { 1338 isl_id *DimId = isl_set_get_dim_id(From, isl_dim_set, u); 1339 To = isl_set_set_dim_id(To, isl_dim_set, u, DimId); 1340 } 1341 return To; 1342 } 1343 1344 /// Create the conditions under which @p L @p Pred @p R is true. 1345 static __isl_give isl_set *buildConditionSet(ICmpInst::Predicate Pred, 1346 __isl_take isl_pw_aff *L, 1347 __isl_take isl_pw_aff *R) { 1348 switch (Pred) { 1349 case ICmpInst::ICMP_EQ: 1350 return isl_pw_aff_eq_set(L, R); 1351 case ICmpInst::ICMP_NE: 1352 return isl_pw_aff_ne_set(L, R); 1353 case ICmpInst::ICMP_SLT: 1354 return isl_pw_aff_lt_set(L, R); 1355 case ICmpInst::ICMP_SLE: 1356 return isl_pw_aff_le_set(L, R); 1357 case ICmpInst::ICMP_SGT: 1358 return isl_pw_aff_gt_set(L, R); 1359 case ICmpInst::ICMP_SGE: 1360 return isl_pw_aff_ge_set(L, R); 1361 case ICmpInst::ICMP_ULT: 1362 return isl_pw_aff_lt_set(L, R); 1363 case ICmpInst::ICMP_UGT: 1364 return isl_pw_aff_gt_set(L, R); 1365 case ICmpInst::ICMP_ULE: 1366 return isl_pw_aff_le_set(L, R); 1367 case ICmpInst::ICMP_UGE: 1368 return isl_pw_aff_ge_set(L, R); 1369 default: 1370 llvm_unreachable("Non integer predicate not supported"); 1371 } 1372 } 1373 1374 /// Create the conditions under which @p L @p Pred @p R is true. 1375 /// 1376 /// Helper function that will make sure the dimensions of the result have the 1377 /// same isl_id's as the @p Domain. 1378 static __isl_give isl_set *buildConditionSet(ICmpInst::Predicate Pred, 1379 __isl_take isl_pw_aff *L, 1380 __isl_take isl_pw_aff *R, 1381 __isl_keep isl_set *Domain) { 1382 isl_set *ConsequenceCondSet = buildConditionSet(Pred, L, R); 1383 return setDimensionIds(Domain, ConsequenceCondSet); 1384 } 1385 1386 /// Build the conditions sets for the switch @p SI in the @p Domain. 1387 /// 1388 /// This will fill @p ConditionSets with the conditions under which control 1389 /// will be moved from @p SI to its successors. Hence, @p ConditionSets will 1390 /// have as many elements as @p SI has successors. 1391 static bool 1392 buildConditionSets(ScopStmt &Stmt, SwitchInst *SI, Loop *L, 1393 __isl_keep isl_set *Domain, 1394 SmallVectorImpl<__isl_give isl_set *> &ConditionSets) { 1395 1396 Value *Condition = getConditionFromTerminator(SI); 1397 assert(Condition && "No condition for switch"); 1398 1399 Scop &S = *Stmt.getParent(); 1400 ScalarEvolution &SE = *S.getSE(); 1401 isl_pw_aff *LHS, *RHS; 1402 LHS = Stmt.getPwAff(SE.getSCEVAtScope(Condition, L)); 1403 1404 unsigned NumSuccessors = SI->getNumSuccessors(); 1405 ConditionSets.resize(NumSuccessors); 1406 for (auto &Case : SI->cases()) { 1407 unsigned Idx = Case.getSuccessorIndex(); 1408 ConstantInt *CaseValue = Case.getCaseValue(); 1409 1410 RHS = Stmt.getPwAff(SE.getSCEV(CaseValue)); 1411 isl_set *CaseConditionSet = 1412 buildConditionSet(ICmpInst::ICMP_EQ, isl_pw_aff_copy(LHS), RHS, Domain); 1413 ConditionSets[Idx] = isl_set_coalesce( 1414 isl_set_intersect(CaseConditionSet, isl_set_copy(Domain))); 1415 } 1416 1417 assert(ConditionSets[0] == nullptr && "Default condition set was set"); 1418 isl_set *ConditionSetUnion = isl_set_copy(ConditionSets[1]); 1419 for (unsigned u = 2; u < NumSuccessors; u++) 1420 ConditionSetUnion = 1421 isl_set_union(ConditionSetUnion, isl_set_copy(ConditionSets[u])); 1422 ConditionSets[0] = setDimensionIds( 1423 Domain, isl_set_subtract(isl_set_copy(Domain), ConditionSetUnion)); 1424 1425 isl_pw_aff_free(LHS); 1426 1427 return true; 1428 } 1429 1430 /// Build the conditions sets for the branch condition @p Condition in 1431 /// the @p Domain. 1432 /// 1433 /// This will fill @p ConditionSets with the conditions under which control 1434 /// will be moved from @p TI to its successors. Hence, @p ConditionSets will 1435 /// have as many elements as @p TI has successors. If @p TI is nullptr the 1436 /// context under which @p Condition is true/false will be returned as the 1437 /// new elements of @p ConditionSets. 1438 static bool 1439 buildConditionSets(ScopStmt &Stmt, Value *Condition, TerminatorInst *TI, 1440 Loop *L, __isl_keep isl_set *Domain, 1441 SmallVectorImpl<__isl_give isl_set *> &ConditionSets) { 1442 1443 Scop &S = *Stmt.getParent(); 1444 isl_set *ConsequenceCondSet = nullptr; 1445 if (auto *CCond = dyn_cast<ConstantInt>(Condition)) { 1446 if (CCond->isZero()) 1447 ConsequenceCondSet = isl_set_empty(isl_set_get_space(Domain)); 1448 else 1449 ConsequenceCondSet = isl_set_universe(isl_set_get_space(Domain)); 1450 } else if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(Condition)) { 1451 auto Opcode = BinOp->getOpcode(); 1452 assert(Opcode == Instruction::And || Opcode == Instruction::Or); 1453 1454 bool Valid = buildConditionSets(Stmt, BinOp->getOperand(0), TI, L, Domain, 1455 ConditionSets) && 1456 buildConditionSets(Stmt, BinOp->getOperand(1), TI, L, Domain, 1457 ConditionSets); 1458 if (!Valid) { 1459 while (!ConditionSets.empty()) 1460 isl_set_free(ConditionSets.pop_back_val()); 1461 return false; 1462 } 1463 1464 isl_set_free(ConditionSets.pop_back_val()); 1465 isl_set *ConsCondPart0 = ConditionSets.pop_back_val(); 1466 isl_set_free(ConditionSets.pop_back_val()); 1467 isl_set *ConsCondPart1 = ConditionSets.pop_back_val(); 1468 1469 if (Opcode == Instruction::And) 1470 ConsequenceCondSet = isl_set_intersect(ConsCondPart0, ConsCondPart1); 1471 else 1472 ConsequenceCondSet = isl_set_union(ConsCondPart0, ConsCondPart1); 1473 } else { 1474 auto *ICond = dyn_cast<ICmpInst>(Condition); 1475 assert(ICond && 1476 "Condition of exiting branch was neither constant nor ICmp!"); 1477 1478 ScalarEvolution &SE = *S.getSE(); 1479 isl_pw_aff *LHS, *RHS; 1480 // For unsigned comparisons we assumed the signed bit of neither operand 1481 // to be set. The comparison is equal to a signed comparison under this 1482 // assumption. 1483 bool NonNeg = ICond->isUnsigned(); 1484 LHS = Stmt.getPwAff(SE.getSCEVAtScope(ICond->getOperand(0), L), NonNeg); 1485 RHS = Stmt.getPwAff(SE.getSCEVAtScope(ICond->getOperand(1), L), NonNeg); 1486 ConsequenceCondSet = 1487 buildConditionSet(ICond->getPredicate(), LHS, RHS, Domain); 1488 } 1489 1490 // If no terminator was given we are only looking for parameter constraints 1491 // under which @p Condition is true/false. 1492 if (!TI) 1493 ConsequenceCondSet = isl_set_params(ConsequenceCondSet); 1494 assert(ConsequenceCondSet); 1495 ConsequenceCondSet = isl_set_coalesce( 1496 isl_set_intersect(ConsequenceCondSet, isl_set_copy(Domain))); 1497 1498 isl_set *AlternativeCondSet = nullptr; 1499 bool TooComplex = 1500 isl_set_n_basic_set(ConsequenceCondSet) >= MaxDisjunctsInDomain; 1501 1502 if (!TooComplex) { 1503 AlternativeCondSet = isl_set_subtract(isl_set_copy(Domain), 1504 isl_set_copy(ConsequenceCondSet)); 1505 TooComplex = 1506 isl_set_n_basic_set(AlternativeCondSet) >= MaxDisjunctsInDomain; 1507 } 1508 1509 if (TooComplex) { 1510 S.invalidate(COMPLEXITY, TI ? TI->getDebugLoc() : DebugLoc()); 1511 isl_set_free(AlternativeCondSet); 1512 isl_set_free(ConsequenceCondSet); 1513 return false; 1514 } 1515 1516 ConditionSets.push_back(ConsequenceCondSet); 1517 ConditionSets.push_back(isl_set_coalesce(AlternativeCondSet)); 1518 1519 return true; 1520 } 1521 1522 /// Build the conditions sets for the terminator @p TI in the @p Domain. 1523 /// 1524 /// This will fill @p ConditionSets with the conditions under which control 1525 /// will be moved from @p TI to its successors. Hence, @p ConditionSets will 1526 /// have as many elements as @p TI has successors. 1527 static bool 1528 buildConditionSets(ScopStmt &Stmt, TerminatorInst *TI, Loop *L, 1529 __isl_keep isl_set *Domain, 1530 SmallVectorImpl<__isl_give isl_set *> &ConditionSets) { 1531 1532 if (SwitchInst *SI = dyn_cast<SwitchInst>(TI)) 1533 return buildConditionSets(Stmt, SI, L, Domain, ConditionSets); 1534 1535 assert(isa<BranchInst>(TI) && "Terminator was neither branch nor switch."); 1536 1537 if (TI->getNumSuccessors() == 1) { 1538 ConditionSets.push_back(isl_set_copy(Domain)); 1539 return true; 1540 } 1541 1542 Value *Condition = getConditionFromTerminator(TI); 1543 assert(Condition && "No condition for Terminator"); 1544 1545 return buildConditionSets(Stmt, Condition, TI, L, Domain, ConditionSets); 1546 } 1547 1548 void ScopStmt::buildDomain() { 1549 isl_id *Id = isl_id_alloc(getIslCtx(), getBaseName(), this); 1550 1551 Domain = getParent()->getDomainConditions(this); 1552 Domain = isl_set_set_tuple_id(Domain, Id); 1553 } 1554 1555 void ScopStmt::collectSurroundingLoops() { 1556 for (unsigned u = 0, e = isl_set_n_dim(Domain); u < e; u++) { 1557 isl_id *DimId = isl_set_get_dim_id(Domain, isl_dim_set, u); 1558 NestLoops.push_back(static_cast<Loop *>(isl_id_get_user(DimId))); 1559 isl_id_free(DimId); 1560 } 1561 } 1562 1563 ScopStmt::ScopStmt(Scop &parent, Region &R) 1564 : Parent(parent), InvalidDomain(nullptr), Domain(nullptr), BB(nullptr), 1565 R(&R), Build(nullptr) { 1566 1567 BaseName = getIslCompatibleName("Stmt_", R.getNameStr(), ""); 1568 } 1569 1570 ScopStmt::ScopStmt(Scop &parent, BasicBlock &bb) 1571 : Parent(parent), InvalidDomain(nullptr), Domain(nullptr), BB(&bb), 1572 R(nullptr), Build(nullptr) { 1573 1574 BaseName = getIslCompatibleName("Stmt_", &bb, ""); 1575 } 1576 1577 ScopStmt::ScopStmt(Scop &parent, __isl_take isl_map *SourceRel, 1578 __isl_take isl_map *TargetRel, __isl_take isl_set *NewDomain) 1579 : Parent(parent), InvalidDomain(nullptr), Domain(NewDomain), BB(nullptr), 1580 R(nullptr), Build(nullptr) { 1581 BaseName = getIslCompatibleName("CopyStmt_", "", 1582 std::to_string(parent.getCopyStmtsNum())); 1583 auto *Id = isl_id_alloc(getIslCtx(), getBaseName(), this); 1584 Domain = isl_set_set_tuple_id(Domain, isl_id_copy(Id)); 1585 TargetRel = isl_map_set_tuple_id(TargetRel, isl_dim_in, Id); 1586 auto *Access = 1587 new MemoryAccess(this, MemoryAccess::AccessType::MUST_WRITE, TargetRel); 1588 parent.addAccessFunction(Access); 1589 addAccess(Access); 1590 SourceRel = isl_map_set_tuple_id(SourceRel, isl_dim_in, isl_id_copy(Id)); 1591 Access = new MemoryAccess(this, MemoryAccess::AccessType::READ, SourceRel); 1592 parent.addAccessFunction(Access); 1593 addAccess(Access); 1594 } 1595 1596 void ScopStmt::init(LoopInfo &LI) { 1597 assert(!Domain && "init must be called only once"); 1598 1599 buildDomain(); 1600 collectSurroundingLoops(); 1601 buildAccessRelations(); 1602 1603 if (DetectReductions) 1604 checkForReductions(); 1605 } 1606 1607 /// Collect loads which might form a reduction chain with @p StoreMA. 1608 /// 1609 /// Check if the stored value for @p StoreMA is a binary operator with one or 1610 /// two loads as operands. If the binary operand is commutative & associative, 1611 /// used only once (by @p StoreMA) and its load operands are also used only 1612 /// once, we have found a possible reduction chain. It starts at an operand 1613 /// load and includes the binary operator and @p StoreMA. 1614 /// 1615 /// Note: We allow only one use to ensure the load and binary operator cannot 1616 /// escape this block or into any other store except @p StoreMA. 1617 void ScopStmt::collectCandiateReductionLoads( 1618 MemoryAccess *StoreMA, SmallVectorImpl<MemoryAccess *> &Loads) { 1619 auto *Store = dyn_cast<StoreInst>(StoreMA->getAccessInstruction()); 1620 if (!Store) 1621 return; 1622 1623 // Skip if there is not one binary operator between the load and the store 1624 auto *BinOp = dyn_cast<BinaryOperator>(Store->getValueOperand()); 1625 if (!BinOp) 1626 return; 1627 1628 // Skip if the binary operators has multiple uses 1629 if (BinOp->getNumUses() != 1) 1630 return; 1631 1632 // Skip if the opcode of the binary operator is not commutative/associative 1633 if (!BinOp->isCommutative() || !BinOp->isAssociative()) 1634 return; 1635 1636 // Skip if the binary operator is outside the current SCoP 1637 if (BinOp->getParent() != Store->getParent()) 1638 return; 1639 1640 // Skip if it is a multiplicative reduction and we disabled them 1641 if (DisableMultiplicativeReductions && 1642 (BinOp->getOpcode() == Instruction::Mul || 1643 BinOp->getOpcode() == Instruction::FMul)) 1644 return; 1645 1646 // Check the binary operator operands for a candidate load 1647 auto *PossibleLoad0 = dyn_cast<LoadInst>(BinOp->getOperand(0)); 1648 auto *PossibleLoad1 = dyn_cast<LoadInst>(BinOp->getOperand(1)); 1649 if (!PossibleLoad0 && !PossibleLoad1) 1650 return; 1651 1652 // A load is only a candidate if it cannot escape (thus has only this use) 1653 if (PossibleLoad0 && PossibleLoad0->getNumUses() == 1) 1654 if (PossibleLoad0->getParent() == Store->getParent()) 1655 Loads.push_back(&getArrayAccessFor(PossibleLoad0)); 1656 if (PossibleLoad1 && PossibleLoad1->getNumUses() == 1) 1657 if (PossibleLoad1->getParent() == Store->getParent()) 1658 Loads.push_back(&getArrayAccessFor(PossibleLoad1)); 1659 } 1660 1661 /// Check for reductions in this ScopStmt. 1662 /// 1663 /// Iterate over all store memory accesses and check for valid binary reduction 1664 /// like chains. For all candidates we check if they have the same base address 1665 /// and there are no other accesses which overlap with them. The base address 1666 /// check rules out impossible reductions candidates early. The overlap check, 1667 /// together with the "only one user" check in collectCandiateReductionLoads, 1668 /// guarantees that none of the intermediate results will escape during 1669 /// execution of the loop nest. We basically check here that no other memory 1670 /// access can access the same memory as the potential reduction. 1671 void ScopStmt::checkForReductions() { 1672 SmallVector<MemoryAccess *, 2> Loads; 1673 SmallVector<std::pair<MemoryAccess *, MemoryAccess *>, 4> Candidates; 1674 1675 // First collect candidate load-store reduction chains by iterating over all 1676 // stores and collecting possible reduction loads. 1677 for (MemoryAccess *StoreMA : MemAccs) { 1678 if (StoreMA->isRead()) 1679 continue; 1680 1681 Loads.clear(); 1682 collectCandiateReductionLoads(StoreMA, Loads); 1683 for (MemoryAccess *LoadMA : Loads) 1684 Candidates.push_back(std::make_pair(LoadMA, StoreMA)); 1685 } 1686 1687 // Then check each possible candidate pair. 1688 for (const auto &CandidatePair : Candidates) { 1689 bool Valid = true; 1690 isl_map *LoadAccs = CandidatePair.first->getAccessRelation(); 1691 isl_map *StoreAccs = CandidatePair.second->getAccessRelation(); 1692 1693 // Skip those with obviously unequal base addresses. 1694 if (!isl_map_has_equal_space(LoadAccs, StoreAccs)) { 1695 isl_map_free(LoadAccs); 1696 isl_map_free(StoreAccs); 1697 continue; 1698 } 1699 1700 // And check if the remaining for overlap with other memory accesses. 1701 isl_map *AllAccsRel = isl_map_union(LoadAccs, StoreAccs); 1702 AllAccsRel = isl_map_intersect_domain(AllAccsRel, getDomain()); 1703 isl_set *AllAccs = isl_map_range(AllAccsRel); 1704 1705 for (MemoryAccess *MA : MemAccs) { 1706 if (MA == CandidatePair.first || MA == CandidatePair.second) 1707 continue; 1708 1709 isl_map *AccRel = 1710 isl_map_intersect_domain(MA->getAccessRelation(), getDomain()); 1711 isl_set *Accs = isl_map_range(AccRel); 1712 1713 if (isl_set_has_equal_space(AllAccs, Accs)) { 1714 isl_set *OverlapAccs = isl_set_intersect(Accs, isl_set_copy(AllAccs)); 1715 Valid = Valid && isl_set_is_empty(OverlapAccs); 1716 isl_set_free(OverlapAccs); 1717 } else { 1718 isl_set_free(Accs); 1719 } 1720 } 1721 1722 isl_set_free(AllAccs); 1723 if (!Valid) 1724 continue; 1725 1726 const LoadInst *Load = 1727 dyn_cast<const LoadInst>(CandidatePair.first->getAccessInstruction()); 1728 MemoryAccess::ReductionType RT = 1729 getReductionType(dyn_cast<BinaryOperator>(Load->user_back()), Load); 1730 1731 // If no overlapping access was found we mark the load and store as 1732 // reduction like. 1733 CandidatePair.first->markAsReductionLike(RT); 1734 CandidatePair.second->markAsReductionLike(RT); 1735 } 1736 } 1737 1738 std::string ScopStmt::getDomainStr() const { return stringFromIslObj(Domain); } 1739 1740 std::string ScopStmt::getScheduleStr() const { 1741 auto *S = getSchedule(); 1742 if (!S) 1743 return ""; 1744 auto Str = stringFromIslObj(S); 1745 isl_map_free(S); 1746 return Str; 1747 } 1748 1749 void ScopStmt::setInvalidDomain(__isl_take isl_set *ID) { 1750 isl_set_free(InvalidDomain); 1751 InvalidDomain = ID; 1752 } 1753 1754 BasicBlock *ScopStmt::getEntryBlock() const { 1755 if (isBlockStmt()) 1756 return getBasicBlock(); 1757 return getRegion()->getEntry(); 1758 } 1759 1760 unsigned ScopStmt::getNumIterators() const { return NestLoops.size(); } 1761 1762 const char *ScopStmt::getBaseName() const { return BaseName.c_str(); } 1763 1764 Loop *ScopStmt::getLoopForDimension(unsigned Dimension) const { 1765 return NestLoops[Dimension]; 1766 } 1767 1768 isl_ctx *ScopStmt::getIslCtx() const { return Parent.getIslCtx(); } 1769 1770 __isl_give isl_set *ScopStmt::getDomain() const { return isl_set_copy(Domain); } 1771 1772 __isl_give isl_space *ScopStmt::getDomainSpace() const { 1773 return isl_set_get_space(Domain); 1774 } 1775 1776 __isl_give isl_id *ScopStmt::getDomainId() const { 1777 return isl_set_get_tuple_id(Domain); 1778 } 1779 1780 ScopStmt::~ScopStmt() { 1781 isl_set_free(Domain); 1782 isl_set_free(InvalidDomain); 1783 } 1784 1785 void ScopStmt::print(raw_ostream &OS) const { 1786 OS << "\t" << getBaseName() << "\n"; 1787 OS.indent(12) << "Domain :=\n"; 1788 1789 if (Domain) { 1790 OS.indent(16) << getDomainStr() << ";\n"; 1791 } else 1792 OS.indent(16) << "n/a\n"; 1793 1794 OS.indent(12) << "Schedule :=\n"; 1795 1796 if (Domain) { 1797 OS.indent(16) << getScheduleStr() << ";\n"; 1798 } else 1799 OS.indent(16) << "n/a\n"; 1800 1801 for (MemoryAccess *Access : MemAccs) 1802 Access->print(OS); 1803 } 1804 1805 void ScopStmt::dump() const { print(dbgs()); } 1806 1807 void ScopStmt::removeMemoryAccess(MemoryAccess *MA) { 1808 // Remove the memory accesses from this statement together with all scalar 1809 // accesses that were caused by it. MemoryKind::Value READs have no access 1810 // instruction, hence would not be removed by this function. However, it is 1811 // only used for invariant LoadInst accesses, its arguments are always affine, 1812 // hence synthesizable, and therefore there are no MemoryKind::Value READ 1813 // accesses to be removed. 1814 auto Predicate = [&](MemoryAccess *Acc) { 1815 return Acc->getAccessInstruction() == MA->getAccessInstruction(); 1816 }; 1817 MemAccs.erase(std::remove_if(MemAccs.begin(), MemAccs.end(), Predicate), 1818 MemAccs.end()); 1819 InstructionToAccess.erase(MA->getAccessInstruction()); 1820 } 1821 1822 //===----------------------------------------------------------------------===// 1823 /// Scop class implement 1824 1825 void Scop::setContext(__isl_take isl_set *NewContext) { 1826 NewContext = isl_set_align_params(NewContext, isl_set_get_space(Context)); 1827 isl_set_free(Context); 1828 Context = NewContext; 1829 } 1830 1831 /// Remap parameter values but keep AddRecs valid wrt. invariant loads. 1832 struct SCEVSensitiveParameterRewriter 1833 : public SCEVRewriteVisitor<SCEVSensitiveParameterRewriter> { 1834 ValueToValueMap &VMap; 1835 1836 public: 1837 SCEVSensitiveParameterRewriter(ValueToValueMap &VMap, ScalarEvolution &SE) 1838 : SCEVRewriteVisitor(SE), VMap(VMap) {} 1839 1840 static const SCEV *rewrite(const SCEV *E, ScalarEvolution &SE, 1841 ValueToValueMap &VMap) { 1842 SCEVSensitiveParameterRewriter SSPR(VMap, SE); 1843 return SSPR.visit(E); 1844 } 1845 1846 const SCEV *visitAddRecExpr(const SCEVAddRecExpr *E) { 1847 auto *Start = visit(E->getStart()); 1848 auto *AddRec = SE.getAddRecExpr(SE.getConstant(E->getType(), 0), 1849 visit(E->getStepRecurrence(SE)), 1850 E->getLoop(), SCEV::FlagAnyWrap); 1851 return SE.getAddExpr(Start, AddRec); 1852 } 1853 1854 const SCEV *visitUnknown(const SCEVUnknown *E) { 1855 if (auto *NewValue = VMap.lookup(E->getValue())) 1856 return SE.getUnknown(NewValue); 1857 return E; 1858 } 1859 }; 1860 1861 const SCEV *Scop::getRepresentingInvariantLoadSCEV(const SCEV *S) { 1862 return SCEVSensitiveParameterRewriter::rewrite(S, *SE, InvEquivClassVMap); 1863 } 1864 1865 void Scop::createParameterId(const SCEV *Parameter) { 1866 assert(Parameters.count(Parameter)); 1867 assert(!ParameterIds.count(Parameter)); 1868 1869 std::string ParameterName = "p_" + std::to_string(getNumParams() - 1); 1870 1871 if (const SCEVUnknown *ValueParameter = dyn_cast<SCEVUnknown>(Parameter)) { 1872 Value *Val = ValueParameter->getValue(); 1873 1874 // If this parameter references a specific Value and this value has a name 1875 // we use this name as it is likely to be unique and more useful than just 1876 // a number. 1877 if (Val->hasName()) 1878 ParameterName = Val->getName(); 1879 else if (LoadInst *LI = dyn_cast<LoadInst>(Val)) { 1880 auto *LoadOrigin = LI->getPointerOperand()->stripInBoundsOffsets(); 1881 if (LoadOrigin->hasName()) { 1882 ParameterName += "_loaded_from_"; 1883 ParameterName += 1884 LI->getPointerOperand()->stripInBoundsOffsets()->getName(); 1885 } 1886 } 1887 } 1888 1889 ParameterName = getIslCompatibleName("", ParameterName, ""); 1890 1891 auto *Id = isl_id_alloc(getIslCtx(), ParameterName.c_str(), 1892 const_cast<void *>((const void *)Parameter)); 1893 ParameterIds[Parameter] = Id; 1894 } 1895 1896 void Scop::addParams(const ParameterSetTy &NewParameters) { 1897 for (const SCEV *Parameter : NewParameters) { 1898 // Normalize the SCEV to get the representing element for an invariant load. 1899 Parameter = extractConstantFactor(Parameter, *SE).second; 1900 Parameter = getRepresentingInvariantLoadSCEV(Parameter); 1901 1902 if (Parameters.insert(Parameter)) 1903 createParameterId(Parameter); 1904 } 1905 } 1906 1907 __isl_give isl_id *Scop::getIdForParam(const SCEV *Parameter) { 1908 // Normalize the SCEV to get the representing element for an invariant load. 1909 Parameter = getRepresentingInvariantLoadSCEV(Parameter); 1910 return isl_id_copy(ParameterIds.lookup(Parameter)); 1911 } 1912 1913 __isl_give isl_set * 1914 Scop::addNonEmptyDomainConstraints(__isl_take isl_set *C) const { 1915 isl_set *DomainContext = isl_union_set_params(getDomains()); 1916 return isl_set_intersect_params(C, DomainContext); 1917 } 1918 1919 bool Scop::isDominatedBy(const DominatorTree &DT, BasicBlock *BB) const { 1920 return DT.dominates(BB, getEntry()); 1921 } 1922 1923 void Scop::addUserAssumptions(DominatorTree &DT, LoopInfo &LI) { 1924 auto &F = getFunction(); 1925 1926 // TODO: Walk the DominatorTree from getRegion().getExit() to its root in 1927 // order to not iterate over blocks we skip anyways. 1928 for (auto &BB : F) { 1929 bool InScop = contains(&BB); 1930 if (!InScop && !isDominatedBy(DT, &BB)) 1931 continue; 1932 1933 for (auto &Assumption : BB) { 1934 auto *CI = dyn_cast_or_null<IntrinsicInst>(&Assumption); 1935 if (!CI || CI->getNumArgOperands() != 1 || 1936 CI->getIntrinsicID() != Intrinsic::assume) 1937 continue; 1938 1939 auto *L = LI.getLoopFor(CI->getParent()); 1940 auto *Val = CI->getArgOperand(0); 1941 ParameterSetTy DetectedParams; 1942 if (!isAffineConstraint(Val, &R, L, *SE, DetectedParams)) { 1943 emitOptimizationRemarkAnalysis(F.getContext(), DEBUG_TYPE, F, 1944 CI->getDebugLoc(), 1945 "Non-affine user assumption ignored."); 1946 continue; 1947 } 1948 1949 // Collect all newly introduced parameters. 1950 ParameterSetTy NewParams; 1951 for (auto *Param : DetectedParams) { 1952 Param = extractConstantFactor(Param, *SE).second; 1953 Param = getRepresentingInvariantLoadSCEV(Param); 1954 if (Parameters.count(Param)) 1955 continue; 1956 NewParams.insert(Param); 1957 } 1958 1959 SmallVector<isl_set *, 2> ConditionSets; 1960 auto *TI = InScop ? CI->getParent()->getTerminator() : nullptr; 1961 auto &Stmt = InScop ? *getStmtFor(CI->getParent()) : *Stmts.begin(); 1962 auto *Dom = InScop ? getDomainConditions(&Stmt) : isl_set_copy(Context); 1963 bool Valid = buildConditionSets(Stmt, Val, TI, L, Dom, ConditionSets); 1964 isl_set_free(Dom); 1965 1966 if (!Valid) 1967 continue; 1968 1969 isl_set *AssumptionCtx = nullptr; 1970 if (InScop) { 1971 AssumptionCtx = isl_set_complement(isl_set_params(ConditionSets[1])); 1972 isl_set_free(ConditionSets[0]); 1973 } else { 1974 AssumptionCtx = isl_set_complement(ConditionSets[1]); 1975 AssumptionCtx = isl_set_intersect(AssumptionCtx, ConditionSets[0]); 1976 } 1977 1978 // Project out newly introduced parameters as they are not otherwise 1979 // useful. 1980 if (!NewParams.empty()) { 1981 for (unsigned u = 0; u < isl_set_n_param(AssumptionCtx); u++) { 1982 auto *Id = isl_set_get_dim_id(AssumptionCtx, isl_dim_param, u); 1983 auto *Param = static_cast<const SCEV *>(isl_id_get_user(Id)); 1984 isl_id_free(Id); 1985 1986 if (!NewParams.count(Param)) 1987 continue; 1988 1989 AssumptionCtx = 1990 isl_set_project_out(AssumptionCtx, isl_dim_param, u--, 1); 1991 } 1992 } 1993 1994 emitOptimizationRemarkAnalysis( 1995 F.getContext(), DEBUG_TYPE, F, CI->getDebugLoc(), 1996 "Use user assumption: " + stringFromIslObj(AssumptionCtx)); 1997 Context = isl_set_intersect(Context, AssumptionCtx); 1998 } 1999 } 2000 } 2001 2002 void Scop::addUserContext() { 2003 if (UserContextStr.empty()) 2004 return; 2005 2006 isl_set *UserContext = 2007 isl_set_read_from_str(getIslCtx(), UserContextStr.c_str()); 2008 isl_space *Space = getParamSpace(); 2009 if (isl_space_dim(Space, isl_dim_param) != 2010 isl_set_dim(UserContext, isl_dim_param)) { 2011 auto SpaceStr = isl_space_to_str(Space); 2012 errs() << "Error: the context provided in -polly-context has not the same " 2013 << "number of dimensions than the computed context. Due to this " 2014 << "mismatch, the -polly-context option is ignored. Please provide " 2015 << "the context in the parameter space: " << SpaceStr << ".\n"; 2016 free(SpaceStr); 2017 isl_set_free(UserContext); 2018 isl_space_free(Space); 2019 return; 2020 } 2021 2022 for (unsigned i = 0; i < isl_space_dim(Space, isl_dim_param); i++) { 2023 auto *NameContext = isl_set_get_dim_name(Context, isl_dim_param, i); 2024 auto *NameUserContext = isl_set_get_dim_name(UserContext, isl_dim_param, i); 2025 2026 if (strcmp(NameContext, NameUserContext) != 0) { 2027 auto SpaceStr = isl_space_to_str(Space); 2028 errs() << "Error: the name of dimension " << i 2029 << " provided in -polly-context " 2030 << "is '" << NameUserContext << "', but the name in the computed " 2031 << "context is '" << NameContext 2032 << "'. Due to this name mismatch, " 2033 << "the -polly-context option is ignored. Please provide " 2034 << "the context in the parameter space: " << SpaceStr << ".\n"; 2035 free(SpaceStr); 2036 isl_set_free(UserContext); 2037 isl_space_free(Space); 2038 return; 2039 } 2040 2041 UserContext = 2042 isl_set_set_dim_id(UserContext, isl_dim_param, i, 2043 isl_space_get_dim_id(Space, isl_dim_param, i)); 2044 } 2045 2046 Context = isl_set_intersect(Context, UserContext); 2047 isl_space_free(Space); 2048 } 2049 2050 void Scop::buildInvariantEquivalenceClasses() { 2051 DenseMap<std::pair<const SCEV *, Type *>, LoadInst *> EquivClasses; 2052 2053 const InvariantLoadsSetTy &RIL = getRequiredInvariantLoads(); 2054 for (LoadInst *LInst : RIL) { 2055 const SCEV *PointerSCEV = SE->getSCEV(LInst->getPointerOperand()); 2056 2057 Type *Ty = LInst->getType(); 2058 LoadInst *&ClassRep = EquivClasses[std::make_pair(PointerSCEV, Ty)]; 2059 if (ClassRep) { 2060 InvEquivClassVMap[LInst] = ClassRep; 2061 continue; 2062 } 2063 2064 ClassRep = LInst; 2065 InvariantEquivClasses.emplace_back( 2066 InvariantEquivClassTy{PointerSCEV, MemoryAccessList(), nullptr, Ty}); 2067 } 2068 } 2069 2070 void Scop::buildContext() { 2071 isl_space *Space = isl_space_params_alloc(getIslCtx(), 0); 2072 Context = isl_set_universe(isl_space_copy(Space)); 2073 InvalidContext = isl_set_empty(isl_space_copy(Space)); 2074 AssumedContext = isl_set_universe(Space); 2075 } 2076 2077 void Scop::addParameterBounds() { 2078 unsigned PDim = 0; 2079 for (auto *Parameter : Parameters) { 2080 ConstantRange SRange = SE->getSignedRange(Parameter); 2081 Context = addRangeBoundsToSet(Context, SRange, PDim++, isl_dim_param); 2082 } 2083 } 2084 2085 void Scop::realignParams() { 2086 // Add all parameters into a common model. 2087 isl_space *Space = isl_space_params_alloc(getIslCtx(), ParameterIds.size()); 2088 2089 unsigned PDim = 0; 2090 for (const auto *Parameter : Parameters) { 2091 isl_id *id = getIdForParam(Parameter); 2092 Space = isl_space_set_dim_id(Space, isl_dim_param, PDim++, id); 2093 } 2094 2095 // Align the parameters of all data structures to the model. 2096 Context = isl_set_align_params(Context, Space); 2097 2098 // As all parameters are known add bounds to them. 2099 addParameterBounds(); 2100 2101 for (ScopStmt &Stmt : *this) 2102 Stmt.realignParams(); 2103 2104 // Simplify the schedule according to the context too. 2105 Schedule = isl_schedule_gist_domain_params(Schedule, getContext()); 2106 } 2107 2108 static __isl_give isl_set * 2109 simplifyAssumptionContext(__isl_take isl_set *AssumptionContext, 2110 const Scop &S) { 2111 // If we have modeled all blocks in the SCoP that have side effects we can 2112 // simplify the context with the constraints that are needed for anything to 2113 // be executed at all. However, if we have error blocks in the SCoP we already 2114 // assumed some parameter combinations cannot occur and removed them from the 2115 // domains, thus we cannot use the remaining domain to simplify the 2116 // assumptions. 2117 if (!S.hasErrorBlock()) { 2118 isl_set *DomainParameters = isl_union_set_params(S.getDomains()); 2119 AssumptionContext = 2120 isl_set_gist_params(AssumptionContext, DomainParameters); 2121 } 2122 2123 AssumptionContext = isl_set_gist_params(AssumptionContext, S.getContext()); 2124 return AssumptionContext; 2125 } 2126 2127 void Scop::simplifyContexts() { 2128 // The parameter constraints of the iteration domains give us a set of 2129 // constraints that need to hold for all cases where at least a single 2130 // statement iteration is executed in the whole scop. We now simplify the 2131 // assumed context under the assumption that such constraints hold and at 2132 // least a single statement iteration is executed. For cases where no 2133 // statement instances are executed, the assumptions we have taken about 2134 // the executed code do not matter and can be changed. 2135 // 2136 // WARNING: This only holds if the assumptions we have taken do not reduce 2137 // the set of statement instances that are executed. Otherwise we 2138 // may run into a case where the iteration domains suggest that 2139 // for a certain set of parameter constraints no code is executed, 2140 // but in the original program some computation would have been 2141 // performed. In such a case, modifying the run-time conditions and 2142 // possibly influencing the run-time check may cause certain scops 2143 // to not be executed. 2144 // 2145 // Example: 2146 // 2147 // When delinearizing the following code: 2148 // 2149 // for (long i = 0; i < 100; i++) 2150 // for (long j = 0; j < m; j++) 2151 // A[i+p][j] = 1.0; 2152 // 2153 // we assume that the condition m <= 0 or (m >= 1 and p >= 0) holds as 2154 // otherwise we would access out of bound data. Now, knowing that code is 2155 // only executed for the case m >= 0, it is sufficient to assume p >= 0. 2156 AssumedContext = simplifyAssumptionContext(AssumedContext, *this); 2157 InvalidContext = isl_set_align_params(InvalidContext, getParamSpace()); 2158 } 2159 2160 /// Add the minimal/maximal access in @p Set to @p User. 2161 static isl_stat buildMinMaxAccess(__isl_take isl_set *Set, void *User) { 2162 Scop::MinMaxVectorTy *MinMaxAccesses = (Scop::MinMaxVectorTy *)User; 2163 isl_pw_multi_aff *MinPMA, *MaxPMA; 2164 isl_pw_aff *LastDimAff; 2165 isl_aff *OneAff; 2166 unsigned Pos; 2167 2168 Set = isl_set_remove_divs(Set); 2169 2170 if (isl_set_n_basic_set(Set) >= MaxDisjunctsInDomain) { 2171 isl_set_free(Set); 2172 return isl_stat_error; 2173 } 2174 2175 // Restrict the number of parameters involved in the access as the lexmin/ 2176 // lexmax computation will take too long if this number is high. 2177 // 2178 // Experiments with a simple test case using an i7 4800MQ: 2179 // 2180 // #Parameters involved | Time (in sec) 2181 // 6 | 0.01 2182 // 7 | 0.04 2183 // 8 | 0.12 2184 // 9 | 0.40 2185 // 10 | 1.54 2186 // 11 | 6.78 2187 // 12 | 30.38 2188 // 2189 if (isl_set_n_param(Set) > RunTimeChecksMaxParameters) { 2190 unsigned InvolvedParams = 0; 2191 for (unsigned u = 0, e = isl_set_n_param(Set); u < e; u++) 2192 if (isl_set_involves_dims(Set, isl_dim_param, u, 1)) 2193 InvolvedParams++; 2194 2195 if (InvolvedParams > RunTimeChecksMaxParameters) { 2196 isl_set_free(Set); 2197 return isl_stat_error; 2198 } 2199 } 2200 2201 MinPMA = isl_set_lexmin_pw_multi_aff(isl_set_copy(Set)); 2202 MaxPMA = isl_set_lexmax_pw_multi_aff(isl_set_copy(Set)); 2203 2204 MinPMA = isl_pw_multi_aff_coalesce(MinPMA); 2205 MaxPMA = isl_pw_multi_aff_coalesce(MaxPMA); 2206 2207 // Adjust the last dimension of the maximal access by one as we want to 2208 // enclose the accessed memory region by MinPMA and MaxPMA. The pointer 2209 // we test during code generation might now point after the end of the 2210 // allocated array but we will never dereference it anyway. 2211 assert(isl_pw_multi_aff_dim(MaxPMA, isl_dim_out) && 2212 "Assumed at least one output dimension"); 2213 Pos = isl_pw_multi_aff_dim(MaxPMA, isl_dim_out) - 1; 2214 LastDimAff = isl_pw_multi_aff_get_pw_aff(MaxPMA, Pos); 2215 OneAff = isl_aff_zero_on_domain( 2216 isl_local_space_from_space(isl_pw_aff_get_domain_space(LastDimAff))); 2217 OneAff = isl_aff_add_constant_si(OneAff, 1); 2218 LastDimAff = isl_pw_aff_add(LastDimAff, isl_pw_aff_from_aff(OneAff)); 2219 MaxPMA = isl_pw_multi_aff_set_pw_aff(MaxPMA, Pos, LastDimAff); 2220 2221 MinMaxAccesses->push_back(std::make_pair(MinPMA, MaxPMA)); 2222 2223 isl_set_free(Set); 2224 return isl_stat_ok; 2225 } 2226 2227 static __isl_give isl_set *getAccessDomain(MemoryAccess *MA) { 2228 isl_set *Domain = MA->getStatement()->getDomain(); 2229 Domain = isl_set_project_out(Domain, isl_dim_set, 0, isl_set_n_dim(Domain)); 2230 return isl_set_reset_tuple_id(Domain); 2231 } 2232 2233 /// Wrapper function to calculate minimal/maximal accesses to each array. 2234 static bool calculateMinMaxAccess(Scop::AliasGroupTy AliasGroup, Scop &S, 2235 Scop::MinMaxVectorTy &MinMaxAccesses) { 2236 2237 MinMaxAccesses.reserve(AliasGroup.size()); 2238 2239 isl_union_set *Domains = S.getDomains(); 2240 isl_union_map *Accesses = isl_union_map_empty(S.getParamSpace()); 2241 2242 for (MemoryAccess *MA : AliasGroup) 2243 Accesses = isl_union_map_add_map(Accesses, MA->getAccessRelation()); 2244 2245 Accesses = isl_union_map_intersect_domain(Accesses, Domains); 2246 isl_union_set *Locations = isl_union_map_range(Accesses); 2247 Locations = isl_union_set_coalesce(Locations); 2248 Locations = isl_union_set_detect_equalities(Locations); 2249 bool Valid = (0 == isl_union_set_foreach_set(Locations, buildMinMaxAccess, 2250 &MinMaxAccesses)); 2251 isl_union_set_free(Locations); 2252 return Valid; 2253 } 2254 2255 /// Helper to treat non-affine regions and basic blocks the same. 2256 /// 2257 ///{ 2258 2259 /// Return the block that is the representing block for @p RN. 2260 static inline BasicBlock *getRegionNodeBasicBlock(RegionNode *RN) { 2261 return RN->isSubRegion() ? RN->getNodeAs<Region>()->getEntry() 2262 : RN->getNodeAs<BasicBlock>(); 2263 } 2264 2265 /// Return the @p idx'th block that is executed after @p RN. 2266 static inline BasicBlock * 2267 getRegionNodeSuccessor(RegionNode *RN, TerminatorInst *TI, unsigned idx) { 2268 if (RN->isSubRegion()) { 2269 assert(idx == 0); 2270 return RN->getNodeAs<Region>()->getExit(); 2271 } 2272 return TI->getSuccessor(idx); 2273 } 2274 2275 /// Return the smallest loop surrounding @p RN. 2276 static inline Loop *getRegionNodeLoop(RegionNode *RN, LoopInfo &LI) { 2277 if (!RN->isSubRegion()) 2278 return LI.getLoopFor(RN->getNodeAs<BasicBlock>()); 2279 2280 Region *NonAffineSubRegion = RN->getNodeAs<Region>(); 2281 Loop *L = LI.getLoopFor(NonAffineSubRegion->getEntry()); 2282 while (L && NonAffineSubRegion->contains(L)) 2283 L = L->getParentLoop(); 2284 return L; 2285 } 2286 2287 static inline unsigned getNumBlocksInRegionNode(RegionNode *RN) { 2288 if (!RN->isSubRegion()) 2289 return 1; 2290 2291 Region *R = RN->getNodeAs<Region>(); 2292 return std::distance(R->block_begin(), R->block_end()); 2293 } 2294 2295 static bool containsErrorBlock(RegionNode *RN, const Region &R, LoopInfo &LI, 2296 const DominatorTree &DT) { 2297 if (!RN->isSubRegion()) 2298 return isErrorBlock(*RN->getNodeAs<BasicBlock>(), R, LI, DT); 2299 for (BasicBlock *BB : RN->getNodeAs<Region>()->blocks()) 2300 if (isErrorBlock(*BB, R, LI, DT)) 2301 return true; 2302 return false; 2303 } 2304 2305 ///} 2306 2307 static inline __isl_give isl_set *addDomainDimId(__isl_take isl_set *Domain, 2308 unsigned Dim, Loop *L) { 2309 Domain = isl_set_lower_bound_si(Domain, isl_dim_set, Dim, -1); 2310 isl_id *DimId = 2311 isl_id_alloc(isl_set_get_ctx(Domain), nullptr, static_cast<void *>(L)); 2312 return isl_set_set_dim_id(Domain, isl_dim_set, Dim, DimId); 2313 } 2314 2315 __isl_give isl_set *Scop::getDomainConditions(const ScopStmt *Stmt) const { 2316 return getDomainConditions(Stmt->getEntryBlock()); 2317 } 2318 2319 __isl_give isl_set *Scop::getDomainConditions(BasicBlock *BB) const { 2320 auto DIt = DomainMap.find(BB); 2321 if (DIt != DomainMap.end()) 2322 return isl_set_copy(DIt->getSecond()); 2323 2324 auto &RI = *R.getRegionInfo(); 2325 auto *BBR = RI.getRegionFor(BB); 2326 while (BBR->getEntry() == BB) 2327 BBR = BBR->getParent(); 2328 return getDomainConditions(BBR->getEntry()); 2329 } 2330 2331 bool Scop::buildDomains(Region *R, DominatorTree &DT, LoopInfo &LI) { 2332 2333 bool IsOnlyNonAffineRegion = isNonAffineSubRegion(R); 2334 auto *EntryBB = R->getEntry(); 2335 auto *L = IsOnlyNonAffineRegion ? nullptr : LI.getLoopFor(EntryBB); 2336 int LD = getRelativeLoopDepth(L); 2337 auto *S = isl_set_universe(isl_space_set_alloc(getIslCtx(), 0, LD + 1)); 2338 2339 while (LD-- >= 0) { 2340 S = addDomainDimId(S, LD + 1, L); 2341 L = L->getParentLoop(); 2342 } 2343 2344 // Initialize the invalid domain. 2345 auto *EntryStmt = getStmtFor(EntryBB); 2346 EntryStmt->setInvalidDomain(isl_set_empty(isl_set_get_space(S))); 2347 2348 DomainMap[EntryBB] = S; 2349 2350 if (IsOnlyNonAffineRegion) 2351 return !containsErrorBlock(R->getNode(), *R, LI, DT); 2352 2353 if (!buildDomainsWithBranchConstraints(R, DT, LI)) 2354 return false; 2355 2356 if (!propagateDomainConstraints(R, DT, LI)) 2357 return false; 2358 2359 // Error blocks and blocks dominated by them have been assumed to never be 2360 // executed. Representing them in the Scop does not add any value. In fact, 2361 // it is likely to cause issues during construction of the ScopStmts. The 2362 // contents of error blocks have not been verified to be expressible and 2363 // will cause problems when building up a ScopStmt for them. 2364 // Furthermore, basic blocks dominated by error blocks may reference 2365 // instructions in the error block which, if the error block is not modeled, 2366 // can themselves not be constructed properly. To this end we will replace 2367 // the domains of error blocks and those only reachable via error blocks 2368 // with an empty set. Additionally, we will record for each block under which 2369 // parameter combination it would be reached via an error block in its 2370 // InvalidDomain. This information is needed during load hoisting. 2371 if (!propagateInvalidStmtDomains(R, DT, LI)) 2372 return false; 2373 2374 return true; 2375 } 2376 2377 /// Adjust the dimensions of @p Dom that was constructed for @p OldL 2378 /// to be compatible to domains constructed for loop @p NewL. 2379 /// 2380 /// This function assumes @p NewL and @p OldL are equal or there is a CFG 2381 /// edge from @p OldL to @p NewL. 2382 static __isl_give isl_set *adjustDomainDimensions(Scop &S, 2383 __isl_take isl_set *Dom, 2384 Loop *OldL, Loop *NewL) { 2385 2386 // If the loops are the same there is nothing to do. 2387 if (NewL == OldL) 2388 return Dom; 2389 2390 int OldDepth = S.getRelativeLoopDepth(OldL); 2391 int NewDepth = S.getRelativeLoopDepth(NewL); 2392 // If both loops are non-affine loops there is nothing to do. 2393 if (OldDepth == -1 && NewDepth == -1) 2394 return Dom; 2395 2396 // Distinguish three cases: 2397 // 1) The depth is the same but the loops are not. 2398 // => One loop was left one was entered. 2399 // 2) The depth increased from OldL to NewL. 2400 // => One loop was entered, none was left. 2401 // 3) The depth decreased from OldL to NewL. 2402 // => Loops were left were difference of the depths defines how many. 2403 if (OldDepth == NewDepth) { 2404 assert(OldL->getParentLoop() == NewL->getParentLoop()); 2405 Dom = isl_set_project_out(Dom, isl_dim_set, NewDepth, 1); 2406 Dom = isl_set_add_dims(Dom, isl_dim_set, 1); 2407 Dom = addDomainDimId(Dom, NewDepth, NewL); 2408 } else if (OldDepth < NewDepth) { 2409 assert(OldDepth + 1 == NewDepth); 2410 auto &R = S.getRegion(); 2411 (void)R; 2412 assert(NewL->getParentLoop() == OldL || 2413 ((!OldL || !R.contains(OldL)) && R.contains(NewL))); 2414 Dom = isl_set_add_dims(Dom, isl_dim_set, 1); 2415 Dom = addDomainDimId(Dom, NewDepth, NewL); 2416 } else { 2417 assert(OldDepth > NewDepth); 2418 int Diff = OldDepth - NewDepth; 2419 int NumDim = isl_set_n_dim(Dom); 2420 assert(NumDim >= Diff); 2421 Dom = isl_set_project_out(Dom, isl_dim_set, NumDim - Diff, Diff); 2422 } 2423 2424 return Dom; 2425 } 2426 2427 bool Scop::propagateInvalidStmtDomains(Region *R, DominatorTree &DT, 2428 LoopInfo &LI) { 2429 auto &BoxedLoops = getBoxedLoops(); 2430 2431 ReversePostOrderTraversal<Region *> RTraversal(R); 2432 for (auto *RN : RTraversal) { 2433 2434 // Recurse for affine subregions but go on for basic blocks and non-affine 2435 // subregions. 2436 if (RN->isSubRegion()) { 2437 Region *SubRegion = RN->getNodeAs<Region>(); 2438 if (!isNonAffineSubRegion(SubRegion)) { 2439 propagateInvalidStmtDomains(SubRegion, DT, LI); 2440 continue; 2441 } 2442 } 2443 2444 bool ContainsErrorBlock = containsErrorBlock(RN, getRegion(), LI, DT); 2445 BasicBlock *BB = getRegionNodeBasicBlock(RN); 2446 ScopStmt *Stmt = getStmtFor(BB); 2447 isl_set *&Domain = DomainMap[BB]; 2448 assert(Domain && "Cannot propagate a nullptr"); 2449 2450 auto *InvalidDomain = Stmt->getInvalidDomain(); 2451 bool IsInvalidBlock = 2452 ContainsErrorBlock || isl_set_is_subset(Domain, InvalidDomain); 2453 2454 if (!IsInvalidBlock) { 2455 InvalidDomain = isl_set_intersect(InvalidDomain, isl_set_copy(Domain)); 2456 } else { 2457 isl_set_free(InvalidDomain); 2458 InvalidDomain = Domain; 2459 isl_set *DomPar = isl_set_params(isl_set_copy(Domain)); 2460 recordAssumption(ERRORBLOCK, DomPar, BB->getTerminator()->getDebugLoc(), 2461 AS_RESTRICTION); 2462 Domain = nullptr; 2463 } 2464 2465 if (isl_set_is_empty(InvalidDomain)) { 2466 Stmt->setInvalidDomain(InvalidDomain); 2467 continue; 2468 } 2469 2470 auto *BBLoop = getRegionNodeLoop(RN, LI); 2471 auto *TI = BB->getTerminator(); 2472 unsigned NumSuccs = RN->isSubRegion() ? 1 : TI->getNumSuccessors(); 2473 for (unsigned u = 0; u < NumSuccs; u++) { 2474 auto *SuccBB = getRegionNodeSuccessor(RN, TI, u); 2475 auto *SuccStmt = getStmtFor(SuccBB); 2476 2477 // Skip successors outside the SCoP. 2478 if (!SuccStmt) 2479 continue; 2480 2481 // Skip backedges. 2482 if (DT.dominates(SuccBB, BB)) 2483 continue; 2484 2485 auto *SuccBBLoop = getFirstNonBoxedLoopFor(SuccBB, LI, BoxedLoops); 2486 auto *AdjustedInvalidDomain = adjustDomainDimensions( 2487 *this, isl_set_copy(InvalidDomain), BBLoop, SuccBBLoop); 2488 auto *SuccInvalidDomain = SuccStmt->getInvalidDomain(); 2489 SuccInvalidDomain = 2490 isl_set_union(SuccInvalidDomain, AdjustedInvalidDomain); 2491 SuccInvalidDomain = isl_set_coalesce(SuccInvalidDomain); 2492 unsigned NumConjucts = isl_set_n_basic_set(SuccInvalidDomain); 2493 SuccStmt->setInvalidDomain(SuccInvalidDomain); 2494 2495 // Check if the maximal number of domain disjunctions was reached. 2496 // In case this happens we will bail. 2497 if (NumConjucts < MaxDisjunctsInDomain) 2498 continue; 2499 2500 isl_set_free(InvalidDomain); 2501 invalidate(COMPLEXITY, TI->getDebugLoc()); 2502 return false; 2503 } 2504 2505 Stmt->setInvalidDomain(InvalidDomain); 2506 } 2507 2508 return true; 2509 } 2510 2511 void Scop::propagateDomainConstraintsToRegionExit( 2512 BasicBlock *BB, Loop *BBLoop, 2513 SmallPtrSetImpl<BasicBlock *> &FinishedExitBlocks, LoopInfo &LI) { 2514 2515 // Check if the block @p BB is the entry of a region. If so we propagate it's 2516 // domain to the exit block of the region. Otherwise we are done. 2517 auto *RI = R.getRegionInfo(); 2518 auto *BBReg = RI ? RI->getRegionFor(BB) : nullptr; 2519 auto *ExitBB = BBReg ? BBReg->getExit() : nullptr; 2520 if (!BBReg || BBReg->getEntry() != BB || !contains(ExitBB)) 2521 return; 2522 2523 auto &BoxedLoops = getBoxedLoops(); 2524 // Do not propagate the domain if there is a loop backedge inside the region 2525 // that would prevent the exit block from being executed. 2526 auto *L = BBLoop; 2527 while (L && contains(L)) { 2528 SmallVector<BasicBlock *, 4> LatchBBs; 2529 BBLoop->getLoopLatches(LatchBBs); 2530 for (auto *LatchBB : LatchBBs) 2531 if (BB != LatchBB && BBReg->contains(LatchBB)) 2532 return; 2533 L = L->getParentLoop(); 2534 } 2535 2536 auto *Domain = DomainMap[BB]; 2537 assert(Domain && "Cannot propagate a nullptr"); 2538 2539 auto *ExitBBLoop = getFirstNonBoxedLoopFor(ExitBB, LI, BoxedLoops); 2540 2541 // Since the dimensions of @p BB and @p ExitBB might be different we have to 2542 // adjust the domain before we can propagate it. 2543 auto *AdjustedDomain = 2544 adjustDomainDimensions(*this, isl_set_copy(Domain), BBLoop, ExitBBLoop); 2545 auto *&ExitDomain = DomainMap[ExitBB]; 2546 2547 // If the exit domain is not yet created we set it otherwise we "add" the 2548 // current domain. 2549 ExitDomain = 2550 ExitDomain ? isl_set_union(AdjustedDomain, ExitDomain) : AdjustedDomain; 2551 2552 // Initialize the invalid domain. 2553 auto *ExitStmt = getStmtFor(ExitBB); 2554 ExitStmt->setInvalidDomain(isl_set_empty(isl_set_get_space(ExitDomain))); 2555 2556 FinishedExitBlocks.insert(ExitBB); 2557 } 2558 2559 bool Scop::buildDomainsWithBranchConstraints(Region *R, DominatorTree &DT, 2560 LoopInfo &LI) { 2561 // To create the domain for each block in R we iterate over all blocks and 2562 // subregions in R and propagate the conditions under which the current region 2563 // element is executed. To this end we iterate in reverse post order over R as 2564 // it ensures that we first visit all predecessors of a region node (either a 2565 // basic block or a subregion) before we visit the region node itself. 2566 // Initially, only the domain for the SCoP region entry block is set and from 2567 // there we propagate the current domain to all successors, however we add the 2568 // condition that the successor is actually executed next. 2569 // As we are only interested in non-loop carried constraints here we can 2570 // simply skip loop back edges. 2571 2572 SmallPtrSet<BasicBlock *, 8> FinishedExitBlocks; 2573 ReversePostOrderTraversal<Region *> RTraversal(R); 2574 for (auto *RN : RTraversal) { 2575 2576 // Recurse for affine subregions but go on for basic blocks and non-affine 2577 // subregions. 2578 if (RN->isSubRegion()) { 2579 Region *SubRegion = RN->getNodeAs<Region>(); 2580 if (!isNonAffineSubRegion(SubRegion)) { 2581 if (!buildDomainsWithBranchConstraints(SubRegion, DT, LI)) 2582 return false; 2583 continue; 2584 } 2585 } 2586 2587 if (containsErrorBlock(RN, getRegion(), LI, DT)) 2588 HasErrorBlock = true; 2589 2590 BasicBlock *BB = getRegionNodeBasicBlock(RN); 2591 TerminatorInst *TI = BB->getTerminator(); 2592 2593 if (isa<UnreachableInst>(TI)) 2594 continue; 2595 2596 isl_set *Domain = DomainMap.lookup(BB); 2597 if (!Domain) 2598 continue; 2599 MaxLoopDepth = std::max(MaxLoopDepth, isl_set_n_dim(Domain)); 2600 2601 auto *BBLoop = getRegionNodeLoop(RN, LI); 2602 // Propagate the domain from BB directly to blocks that have a superset 2603 // domain, at the moment only region exit nodes of regions that start in BB. 2604 propagateDomainConstraintsToRegionExit(BB, BBLoop, FinishedExitBlocks, LI); 2605 2606 // If all successors of BB have been set a domain through the propagation 2607 // above we do not need to build condition sets but can just skip this 2608 // block. However, it is important to note that this is a local property 2609 // with regards to the region @p R. To this end FinishedExitBlocks is a 2610 // local variable. 2611 auto IsFinishedRegionExit = [&FinishedExitBlocks](BasicBlock *SuccBB) { 2612 return FinishedExitBlocks.count(SuccBB); 2613 }; 2614 if (std::all_of(succ_begin(BB), succ_end(BB), IsFinishedRegionExit)) 2615 continue; 2616 2617 // Build the condition sets for the successor nodes of the current region 2618 // node. If it is a non-affine subregion we will always execute the single 2619 // exit node, hence the single entry node domain is the condition set. For 2620 // basic blocks we use the helper function buildConditionSets. 2621 SmallVector<isl_set *, 8> ConditionSets; 2622 if (RN->isSubRegion()) 2623 ConditionSets.push_back(isl_set_copy(Domain)); 2624 else if (!buildConditionSets(*getStmtFor(BB), TI, BBLoop, Domain, 2625 ConditionSets)) 2626 return false; 2627 2628 // Now iterate over the successors and set their initial domain based on 2629 // their condition set. We skip back edges here and have to be careful when 2630 // we leave a loop not to keep constraints over a dimension that doesn't 2631 // exist anymore. 2632 assert(RN->isSubRegion() || TI->getNumSuccessors() == ConditionSets.size()); 2633 for (unsigned u = 0, e = ConditionSets.size(); u < e; u++) { 2634 isl_set *CondSet = ConditionSets[u]; 2635 BasicBlock *SuccBB = getRegionNodeSuccessor(RN, TI, u); 2636 2637 auto *SuccStmt = getStmtFor(SuccBB); 2638 // Skip blocks outside the region. 2639 if (!SuccStmt) { 2640 isl_set_free(CondSet); 2641 continue; 2642 } 2643 2644 // If we propagate the domain of some block to "SuccBB" we do not have to 2645 // adjust the domain. 2646 if (FinishedExitBlocks.count(SuccBB)) { 2647 isl_set_free(CondSet); 2648 continue; 2649 } 2650 2651 // Skip back edges. 2652 if (DT.dominates(SuccBB, BB)) { 2653 isl_set_free(CondSet); 2654 continue; 2655 } 2656 2657 auto &BoxedLoops = getBoxedLoops(); 2658 auto *SuccBBLoop = getFirstNonBoxedLoopFor(SuccBB, LI, BoxedLoops); 2659 CondSet = adjustDomainDimensions(*this, CondSet, BBLoop, SuccBBLoop); 2660 2661 // Set the domain for the successor or merge it with an existing domain in 2662 // case there are multiple paths (without loop back edges) to the 2663 // successor block. 2664 isl_set *&SuccDomain = DomainMap[SuccBB]; 2665 2666 if (SuccDomain) { 2667 SuccDomain = isl_set_coalesce(isl_set_union(SuccDomain, CondSet)); 2668 } else { 2669 // Initialize the invalid domain. 2670 SuccStmt->setInvalidDomain(isl_set_empty(isl_set_get_space(CondSet))); 2671 SuccDomain = CondSet; 2672 } 2673 2674 // Check if the maximal number of domain disjunctions was reached. 2675 // In case this happens we will clean up and bail. 2676 if (isl_set_n_basic_set(SuccDomain) < MaxDisjunctsInDomain) 2677 continue; 2678 2679 invalidate(COMPLEXITY, DebugLoc()); 2680 while (++u < ConditionSets.size()) 2681 isl_set_free(ConditionSets[u]); 2682 return false; 2683 } 2684 } 2685 2686 return true; 2687 } 2688 2689 __isl_give isl_set * 2690 Scop::getPredecessorDomainConstraints(BasicBlock *BB, 2691 __isl_keep isl_set *Domain, 2692 DominatorTree &DT, LoopInfo &LI) { 2693 // If @p BB is the ScopEntry we are done 2694 if (R.getEntry() == BB) 2695 return isl_set_universe(isl_set_get_space(Domain)); 2696 2697 // The set of boxed loops (loops in non-affine subregions) for this SCoP. 2698 auto &BoxedLoops = getBoxedLoops(); 2699 2700 // The region info of this function. 2701 auto &RI = *R.getRegionInfo(); 2702 2703 auto *BBLoop = getFirstNonBoxedLoopFor(BB, LI, BoxedLoops); 2704 2705 // A domain to collect all predecessor domains, thus all conditions under 2706 // which the block is executed. To this end we start with the empty domain. 2707 isl_set *PredDom = isl_set_empty(isl_set_get_space(Domain)); 2708 2709 // Set of regions of which the entry block domain has been propagated to BB. 2710 // all predecessors inside any of the regions can be skipped. 2711 SmallSet<Region *, 8> PropagatedRegions; 2712 2713 for (auto *PredBB : predecessors(BB)) { 2714 // Skip backedges. 2715 if (DT.dominates(BB, PredBB)) 2716 continue; 2717 2718 // If the predecessor is in a region we used for propagation we can skip it. 2719 auto PredBBInRegion = [PredBB](Region *PR) { return PR->contains(PredBB); }; 2720 if (std::any_of(PropagatedRegions.begin(), PropagatedRegions.end(), 2721 PredBBInRegion)) { 2722 continue; 2723 } 2724 2725 // Check if there is a valid region we can use for propagation, thus look 2726 // for a region that contains the predecessor and has @p BB as exit block. 2727 auto *PredR = RI.getRegionFor(PredBB); 2728 while (PredR->getExit() != BB && !PredR->contains(BB)) 2729 PredR->getParent(); 2730 2731 // If a valid region for propagation was found use the entry of that region 2732 // for propagation, otherwise the PredBB directly. 2733 if (PredR->getExit() == BB) { 2734 PredBB = PredR->getEntry(); 2735 PropagatedRegions.insert(PredR); 2736 } 2737 2738 auto *PredBBDom = getDomainConditions(PredBB); 2739 auto *PredBBLoop = getFirstNonBoxedLoopFor(PredBB, LI, BoxedLoops); 2740 PredBBDom = adjustDomainDimensions(*this, PredBBDom, PredBBLoop, BBLoop); 2741 2742 PredDom = isl_set_union(PredDom, PredBBDom); 2743 } 2744 2745 return PredDom; 2746 } 2747 2748 bool Scop::propagateDomainConstraints(Region *R, DominatorTree &DT, 2749 LoopInfo &LI) { 2750 // Iterate over the region R and propagate the domain constrains from the 2751 // predecessors to the current node. In contrast to the 2752 // buildDomainsWithBranchConstraints function, this one will pull the domain 2753 // information from the predecessors instead of pushing it to the successors. 2754 // Additionally, we assume the domains to be already present in the domain 2755 // map here. However, we iterate again in reverse post order so we know all 2756 // predecessors have been visited before a block or non-affine subregion is 2757 // visited. 2758 2759 ReversePostOrderTraversal<Region *> RTraversal(R); 2760 for (auto *RN : RTraversal) { 2761 2762 // Recurse for affine subregions but go on for basic blocks and non-affine 2763 // subregions. 2764 if (RN->isSubRegion()) { 2765 Region *SubRegion = RN->getNodeAs<Region>(); 2766 if (!isNonAffineSubRegion(SubRegion)) { 2767 if (!propagateDomainConstraints(SubRegion, DT, LI)) 2768 return false; 2769 continue; 2770 } 2771 } 2772 2773 BasicBlock *BB = getRegionNodeBasicBlock(RN); 2774 isl_set *&Domain = DomainMap[BB]; 2775 assert(Domain); 2776 2777 // Under the union of all predecessor conditions we can reach this block. 2778 auto *PredDom = getPredecessorDomainConstraints(BB, Domain, DT, LI); 2779 Domain = isl_set_coalesce(isl_set_intersect(Domain, PredDom)); 2780 Domain = isl_set_align_params(Domain, getParamSpace()); 2781 2782 Loop *BBLoop = getRegionNodeLoop(RN, LI); 2783 if (BBLoop && BBLoop->getHeader() == BB && contains(BBLoop)) 2784 if (!addLoopBoundsToHeaderDomain(BBLoop, LI)) 2785 return false; 2786 } 2787 2788 return true; 2789 } 2790 2791 /// Create a map to map from a given iteration to a subsequent iteration. 2792 /// 2793 /// This map maps from SetSpace -> SetSpace where the dimensions @p Dim 2794 /// is incremented by one and all other dimensions are equal, e.g., 2795 /// [i0, i1, i2, i3] -> [i0, i1, i2 + 1, i3] 2796 /// 2797 /// if @p Dim is 2 and @p SetSpace has 4 dimensions. 2798 static __isl_give isl_map * 2799 createNextIterationMap(__isl_take isl_space *SetSpace, unsigned Dim) { 2800 auto *MapSpace = isl_space_map_from_set(SetSpace); 2801 auto *NextIterationMap = isl_map_universe(isl_space_copy(MapSpace)); 2802 for (unsigned u = 0; u < isl_map_n_in(NextIterationMap); u++) 2803 if (u != Dim) 2804 NextIterationMap = 2805 isl_map_equate(NextIterationMap, isl_dim_in, u, isl_dim_out, u); 2806 auto *C = isl_constraint_alloc_equality(isl_local_space_from_space(MapSpace)); 2807 C = isl_constraint_set_constant_si(C, 1); 2808 C = isl_constraint_set_coefficient_si(C, isl_dim_in, Dim, 1); 2809 C = isl_constraint_set_coefficient_si(C, isl_dim_out, Dim, -1); 2810 NextIterationMap = isl_map_add_constraint(NextIterationMap, C); 2811 return NextIterationMap; 2812 } 2813 2814 bool Scop::addLoopBoundsToHeaderDomain(Loop *L, LoopInfo &LI) { 2815 int LoopDepth = getRelativeLoopDepth(L); 2816 assert(LoopDepth >= 0 && "Loop in region should have at least depth one"); 2817 2818 BasicBlock *HeaderBB = L->getHeader(); 2819 assert(DomainMap.count(HeaderBB)); 2820 isl_set *&HeaderBBDom = DomainMap[HeaderBB]; 2821 2822 isl_map *NextIterationMap = 2823 createNextIterationMap(isl_set_get_space(HeaderBBDom), LoopDepth); 2824 2825 isl_set *UnionBackedgeCondition = 2826 isl_set_empty(isl_set_get_space(HeaderBBDom)); 2827 2828 SmallVector<llvm::BasicBlock *, 4> LatchBlocks; 2829 L->getLoopLatches(LatchBlocks); 2830 2831 for (BasicBlock *LatchBB : LatchBlocks) { 2832 2833 // If the latch is only reachable via error statements we skip it. 2834 isl_set *LatchBBDom = DomainMap.lookup(LatchBB); 2835 if (!LatchBBDom) 2836 continue; 2837 2838 isl_set *BackedgeCondition = nullptr; 2839 2840 TerminatorInst *TI = LatchBB->getTerminator(); 2841 BranchInst *BI = dyn_cast<BranchInst>(TI); 2842 assert(BI && "Only branch instructions allowed in loop latches"); 2843 2844 if (BI->isUnconditional()) 2845 BackedgeCondition = isl_set_copy(LatchBBDom); 2846 else { 2847 SmallVector<isl_set *, 8> ConditionSets; 2848 int idx = BI->getSuccessor(0) != HeaderBB; 2849 if (!buildConditionSets(*getStmtFor(LatchBB), TI, L, LatchBBDom, 2850 ConditionSets)) { 2851 isl_map_free(NextIterationMap); 2852 isl_set_free(UnionBackedgeCondition); 2853 return false; 2854 } 2855 2856 // Free the non back edge condition set as we do not need it. 2857 isl_set_free(ConditionSets[1 - idx]); 2858 2859 BackedgeCondition = ConditionSets[idx]; 2860 } 2861 2862 int LatchLoopDepth = getRelativeLoopDepth(LI.getLoopFor(LatchBB)); 2863 assert(LatchLoopDepth >= LoopDepth); 2864 BackedgeCondition = 2865 isl_set_project_out(BackedgeCondition, isl_dim_set, LoopDepth + 1, 2866 LatchLoopDepth - LoopDepth); 2867 UnionBackedgeCondition = 2868 isl_set_union(UnionBackedgeCondition, BackedgeCondition); 2869 } 2870 2871 isl_map *ForwardMap = isl_map_lex_le(isl_set_get_space(HeaderBBDom)); 2872 for (int i = 0; i < LoopDepth; i++) 2873 ForwardMap = isl_map_equate(ForwardMap, isl_dim_in, i, isl_dim_out, i); 2874 2875 isl_set *UnionBackedgeConditionComplement = 2876 isl_set_complement(UnionBackedgeCondition); 2877 UnionBackedgeConditionComplement = isl_set_lower_bound_si( 2878 UnionBackedgeConditionComplement, isl_dim_set, LoopDepth, 0); 2879 UnionBackedgeConditionComplement = 2880 isl_set_apply(UnionBackedgeConditionComplement, ForwardMap); 2881 HeaderBBDom = isl_set_subtract(HeaderBBDom, UnionBackedgeConditionComplement); 2882 HeaderBBDom = isl_set_apply(HeaderBBDom, NextIterationMap); 2883 2884 auto Parts = partitionSetParts(HeaderBBDom, LoopDepth); 2885 HeaderBBDom = Parts.second; 2886 2887 // Check if there is a <nsw> tagged AddRec for this loop and if so do not add 2888 // the bounded assumptions to the context as they are already implied by the 2889 // <nsw> tag. 2890 if (Affinator.hasNSWAddRecForLoop(L)) { 2891 isl_set_free(Parts.first); 2892 return true; 2893 } 2894 2895 isl_set *UnboundedCtx = isl_set_params(Parts.first); 2896 recordAssumption(INFINITELOOP, UnboundedCtx, 2897 HeaderBB->getTerminator()->getDebugLoc(), AS_RESTRICTION); 2898 return true; 2899 } 2900 2901 MemoryAccess *Scop::lookupBasePtrAccess(MemoryAccess *MA) { 2902 Value *PointerBase = MA->getOriginalBaseAddr(); 2903 2904 auto *PointerBaseInst = dyn_cast<Instruction>(PointerBase); 2905 if (!PointerBaseInst) 2906 return nullptr; 2907 2908 auto *BasePtrStmt = getStmtFor(PointerBaseInst); 2909 if (!BasePtrStmt) 2910 return nullptr; 2911 2912 return BasePtrStmt->getArrayAccessOrNULLFor(PointerBaseInst); 2913 } 2914 2915 bool Scop::hasNonHoistableBasePtrInScop(MemoryAccess *MA, 2916 __isl_keep isl_union_map *Writes) { 2917 if (auto *BasePtrMA = lookupBasePtrAccess(MA)) { 2918 auto *NHCtx = getNonHoistableCtx(BasePtrMA, Writes); 2919 bool Hoistable = NHCtx != nullptr; 2920 isl_set_free(NHCtx); 2921 return !Hoistable; 2922 } 2923 2924 Value *BaseAddr = MA->getOriginalBaseAddr(); 2925 if (auto *BasePtrInst = dyn_cast<Instruction>(BaseAddr)) 2926 if (!isa<LoadInst>(BasePtrInst)) 2927 return contains(BasePtrInst); 2928 2929 return false; 2930 } 2931 2932 bool Scop::buildAliasChecks(AliasAnalysis &AA) { 2933 if (!PollyUseRuntimeAliasChecks) 2934 return true; 2935 2936 if (buildAliasGroups(AA)) { 2937 // Aliasing assumptions do not go through addAssumption but we still want to 2938 // collect statistics so we do it here explicitly. 2939 if (MinMaxAliasGroups.size()) 2940 AssumptionsAliasing++; 2941 return true; 2942 } 2943 2944 // If a problem occurs while building the alias groups we need to delete 2945 // this SCoP and pretend it wasn't valid in the first place. To this end 2946 // we make the assumed context infeasible. 2947 invalidate(ALIASING, DebugLoc()); 2948 2949 DEBUG(dbgs() << "\n\nNOTE: Run time checks for " << getNameStr() 2950 << " could not be created as the number of parameters involved " 2951 "is too high. The SCoP will be " 2952 "dismissed.\nUse:\n\t--polly-rtc-max-parameters=X\nto adjust " 2953 "the maximal number of parameters but be advised that the " 2954 "compile time might increase exponentially.\n\n"); 2955 return false; 2956 } 2957 2958 std::tuple<Scop::AliasGroupVectorTy, DenseSet<const ScopArrayInfo *>> 2959 Scop::buildAliasGroupsForAccesses(AliasAnalysis &AA) { 2960 AliasSetTracker AST(AA); 2961 2962 DenseMap<Value *, MemoryAccess *> PtrToAcc; 2963 DenseSet<const ScopArrayInfo *> HasWriteAccess; 2964 for (ScopStmt &Stmt : *this) { 2965 2966 isl_set *StmtDomain = Stmt.getDomain(); 2967 bool StmtDomainEmpty = isl_set_is_empty(StmtDomain); 2968 isl_set_free(StmtDomain); 2969 2970 // Statements with an empty domain will never be executed. 2971 if (StmtDomainEmpty) 2972 continue; 2973 2974 for (MemoryAccess *MA : Stmt) { 2975 if (MA->isScalarKind()) 2976 continue; 2977 if (!MA->isRead()) 2978 HasWriteAccess.insert(MA->getScopArrayInfo()); 2979 MemAccInst Acc(MA->getAccessInstruction()); 2980 if (MA->isRead() && isa<MemTransferInst>(Acc)) 2981 PtrToAcc[cast<MemTransferInst>(Acc)->getRawSource()] = MA; 2982 else 2983 PtrToAcc[Acc.getPointerOperand()] = MA; 2984 AST.add(Acc); 2985 } 2986 } 2987 2988 AliasGroupVectorTy AliasGroups; 2989 for (AliasSet &AS : AST) { 2990 if (AS.isMustAlias() || AS.isForwardingAliasSet()) 2991 continue; 2992 AliasGroupTy AG; 2993 for (auto &PR : AS) 2994 AG.push_back(PtrToAcc[PR.getValue()]); 2995 if (AG.size() < 2) 2996 continue; 2997 AliasGroups.push_back(std::move(AG)); 2998 } 2999 3000 return std::make_tuple(AliasGroups, HasWriteAccess); 3001 } 3002 3003 void Scop::splitAliasGroupsByDomain(AliasGroupVectorTy &AliasGroups) { 3004 for (unsigned u = 0; u < AliasGroups.size(); u++) { 3005 AliasGroupTy NewAG; 3006 AliasGroupTy &AG = AliasGroups[u]; 3007 AliasGroupTy::iterator AGI = AG.begin(); 3008 isl_set *AGDomain = getAccessDomain(*AGI); 3009 while (AGI != AG.end()) { 3010 MemoryAccess *MA = *AGI; 3011 isl_set *MADomain = getAccessDomain(MA); 3012 if (isl_set_is_disjoint(AGDomain, MADomain)) { 3013 NewAG.push_back(MA); 3014 AGI = AG.erase(AGI); 3015 isl_set_free(MADomain); 3016 } else { 3017 AGDomain = isl_set_union(AGDomain, MADomain); 3018 AGI++; 3019 } 3020 } 3021 if (NewAG.size() > 1) 3022 AliasGroups.push_back(std::move(NewAG)); 3023 isl_set_free(AGDomain); 3024 } 3025 } 3026 3027 bool Scop::buildAliasGroups(AliasAnalysis &AA) { 3028 // To create sound alias checks we perform the following steps: 3029 // o) We partition each group into read only and non read only accesses. 3030 // o) For each group with more than one base pointer we then compute minimal 3031 // and maximal accesses to each array of a group in read only and non 3032 // read only partitions separately. 3033 AliasGroupVectorTy AliasGroups; 3034 DenseSet<const ScopArrayInfo *> HasWriteAccess; 3035 3036 std::tie(AliasGroups, HasWriteAccess) = buildAliasGroupsForAccesses(AA); 3037 3038 splitAliasGroupsByDomain(AliasGroups); 3039 3040 for (AliasGroupTy &AG : AliasGroups) { 3041 bool Valid = buildAliasGroup(AG, HasWriteAccess); 3042 if (!Valid) 3043 return false; 3044 } 3045 3046 return true; 3047 } 3048 3049 bool Scop::buildAliasGroup(Scop::AliasGroupTy &AliasGroup, 3050 DenseSet<const ScopArrayInfo *> HasWriteAccess) { 3051 AliasGroupTy ReadOnlyAccesses; 3052 AliasGroupTy ReadWriteAccesses; 3053 SmallPtrSet<const ScopArrayInfo *, 4> ReadWriteArrays; 3054 SmallPtrSet<const ScopArrayInfo *, 4> ReadOnlyArrays; 3055 3056 auto &F = getFunction(); 3057 3058 if (AliasGroup.size() < 2) 3059 return true; 3060 3061 for (MemoryAccess *Access : AliasGroup) { 3062 emitOptimizationRemarkAnalysis( 3063 F.getContext(), DEBUG_TYPE, F, 3064 Access->getAccessInstruction()->getDebugLoc(), 3065 "Possibly aliasing pointer, use restrict keyword."); 3066 3067 const ScopArrayInfo *Array = Access->getScopArrayInfo(); 3068 if (HasWriteAccess.count(Array)) { 3069 ReadWriteArrays.insert(Array); 3070 ReadWriteAccesses.push_back(Access); 3071 } else { 3072 ReadOnlyArrays.insert(Array); 3073 ReadOnlyAccesses.push_back(Access); 3074 } 3075 } 3076 3077 // If there are no read-only pointers, and less than two read-write pointers, 3078 // no alias check is needed. 3079 if (ReadOnlyAccesses.empty() && ReadWriteArrays.size() <= 1) 3080 return true; 3081 3082 // If there is no read-write pointer, no alias check is needed. 3083 if (ReadWriteArrays.empty()) 3084 return true; 3085 3086 // For non-affine accesses, no alias check can be generated as we cannot 3087 // compute a sufficiently tight lower and upper bound: bail out. 3088 for (MemoryAccess *MA : AliasGroup) { 3089 if (!MA->isAffine()) { 3090 invalidate(ALIASING, MA->getAccessInstruction()->getDebugLoc()); 3091 return false; 3092 } 3093 } 3094 3095 // Ensure that for all memory accesses for which we generate alias checks, 3096 // their base pointers are available. 3097 for (MemoryAccess *MA : AliasGroup) { 3098 if (MemoryAccess *BasePtrMA = lookupBasePtrAccess(MA)) 3099 addRequiredInvariantLoad( 3100 cast<LoadInst>(BasePtrMA->getAccessInstruction())); 3101 } 3102 3103 MinMaxAliasGroups.emplace_back(); 3104 MinMaxVectorPairTy &pair = MinMaxAliasGroups.back(); 3105 MinMaxVectorTy &MinMaxAccessesReadWrite = pair.first; 3106 MinMaxVectorTy &MinMaxAccessesReadOnly = pair.second; 3107 3108 bool Valid; 3109 3110 Valid = 3111 calculateMinMaxAccess(ReadWriteAccesses, *this, MinMaxAccessesReadWrite); 3112 3113 if (!Valid) 3114 return false; 3115 3116 // Bail out if the number of values we need to compare is too large. 3117 // This is important as the number of comparisons grows quadratically with 3118 // the number of values we need to compare. 3119 if (MinMaxAccessesReadWrite.size() + ReadOnlyArrays.size() > 3120 RunTimeChecksMaxArraysPerGroup) 3121 return false; 3122 3123 Valid = 3124 calculateMinMaxAccess(ReadOnlyAccesses, *this, MinMaxAccessesReadOnly); 3125 3126 if (!Valid) 3127 return false; 3128 3129 return true; 3130 } 3131 3132 /// Get the smallest loop that contains @p S but is not in @p S. 3133 static Loop *getLoopSurroundingScop(Scop &S, LoopInfo &LI) { 3134 // Start with the smallest loop containing the entry and expand that 3135 // loop until it contains all blocks in the region. If there is a loop 3136 // containing all blocks in the region check if it is itself contained 3137 // and if so take the parent loop as it will be the smallest containing 3138 // the region but not contained by it. 3139 Loop *L = LI.getLoopFor(S.getEntry()); 3140 while (L) { 3141 bool AllContained = true; 3142 for (auto *BB : S.blocks()) 3143 AllContained &= L->contains(BB); 3144 if (AllContained) 3145 break; 3146 L = L->getParentLoop(); 3147 } 3148 3149 return L ? (S.contains(L) ? L->getParentLoop() : L) : nullptr; 3150 } 3151 3152 Scop::Scop(Region &R, ScalarEvolution &ScalarEvolution, LoopInfo &LI, 3153 ScopDetection::DetectionContext &DC) 3154 : SE(&ScalarEvolution), R(R), IsOptimized(false), 3155 HasSingleExitEdge(R.getExitingBlock()), HasErrorBlock(false), 3156 MaxLoopDepth(0), CopyStmtsNum(0), DC(DC), 3157 IslCtx(isl_ctx_alloc(), isl_ctx_free), Context(nullptr), 3158 Affinator(this, LI), AssumedContext(nullptr), InvalidContext(nullptr), 3159 Schedule(nullptr) { 3160 if (IslOnErrorAbort) 3161 isl_options_set_on_error(getIslCtx(), ISL_ON_ERROR_ABORT); 3162 buildContext(); 3163 } 3164 3165 void Scop::foldSizeConstantsToRight() { 3166 isl_union_set *Accessed = isl_union_map_range(getAccesses()); 3167 3168 for (auto Array : arrays()) { 3169 if (Array->getNumberOfDimensions() <= 1) 3170 continue; 3171 3172 isl_space *Space = Array->getSpace(); 3173 3174 Space = isl_space_align_params(Space, isl_union_set_get_space(Accessed)); 3175 3176 if (!isl_union_set_contains(Accessed, Space)) { 3177 isl_space_free(Space); 3178 continue; 3179 } 3180 3181 isl_set *Elements = isl_union_set_extract_set(Accessed, Space); 3182 3183 isl_map *Transform = 3184 isl_map_universe(isl_space_map_from_set(Array->getSpace())); 3185 3186 std::vector<int> Int; 3187 3188 int Dims = isl_set_dim(Elements, isl_dim_set); 3189 for (int i = 0; i < Dims; i++) { 3190 isl_set *DimOnly = 3191 isl_set_project_out(isl_set_copy(Elements), isl_dim_set, 0, i); 3192 DimOnly = isl_set_project_out(DimOnly, isl_dim_set, 1, Dims - i - 1); 3193 DimOnly = isl_set_lower_bound_si(DimOnly, isl_dim_set, 0, 0); 3194 3195 isl_basic_set *DimHull = isl_set_affine_hull(DimOnly); 3196 3197 if (i == Dims - 1) { 3198 Int.push_back(1); 3199 Transform = isl_map_equate(Transform, isl_dim_in, i, isl_dim_out, i); 3200 isl_basic_set_free(DimHull); 3201 continue; 3202 } 3203 3204 if (isl_basic_set_dim(DimHull, isl_dim_div) == 1) { 3205 isl_aff *Diff = isl_basic_set_get_div(DimHull, 0); 3206 isl_val *Val = isl_aff_get_denominator_val(Diff); 3207 isl_aff_free(Diff); 3208 3209 int ValInt = 1; 3210 3211 if (isl_val_is_int(Val)) 3212 ValInt = isl_val_get_num_si(Val); 3213 isl_val_free(Val); 3214 3215 Int.push_back(ValInt); 3216 3217 isl_constraint *C = isl_constraint_alloc_equality( 3218 isl_local_space_from_space(isl_map_get_space(Transform))); 3219 C = isl_constraint_set_coefficient_si(C, isl_dim_out, i, ValInt); 3220 C = isl_constraint_set_coefficient_si(C, isl_dim_in, i, -1); 3221 Transform = isl_map_add_constraint(Transform, C); 3222 isl_basic_set_free(DimHull); 3223 continue; 3224 } 3225 3226 isl_basic_set *ZeroSet = isl_basic_set_copy(DimHull); 3227 ZeroSet = isl_basic_set_fix_si(ZeroSet, isl_dim_set, 0, 0); 3228 3229 int ValInt = 1; 3230 if (isl_basic_set_is_equal(ZeroSet, DimHull)) { 3231 ValInt = 0; 3232 } 3233 3234 Int.push_back(ValInt); 3235 Transform = isl_map_equate(Transform, isl_dim_in, i, isl_dim_out, i); 3236 isl_basic_set_free(DimHull); 3237 isl_basic_set_free(ZeroSet); 3238 } 3239 3240 isl_set *MappedElements = isl_map_domain(isl_map_copy(Transform)); 3241 3242 if (!isl_set_is_subset(Elements, MappedElements)) { 3243 isl_set_free(Elements); 3244 isl_set_free(MappedElements); 3245 isl_map_free(Transform); 3246 continue; 3247 } 3248 3249 isl_set_free(MappedElements); 3250 3251 bool CanFold = true; 3252 3253 if (Int[0] <= 1) 3254 CanFold = false; 3255 3256 unsigned NumDims = Array->getNumberOfDimensions(); 3257 for (unsigned i = 1; i < NumDims - 1; i++) 3258 if (Int[0] != Int[i] && Int[i]) 3259 CanFold = false; 3260 3261 if (!CanFold) { 3262 isl_set_free(Elements); 3263 isl_map_free(Transform); 3264 continue; 3265 } 3266 3267 for (auto &Access : AccessFunctions) 3268 if (Access->getScopArrayInfo() == Array) 3269 Access->setAccessRelation(isl_map_apply_range( 3270 Access->getAccessRelation(), isl_map_copy(Transform))); 3271 3272 isl_map_free(Transform); 3273 3274 std::vector<const SCEV *> Sizes; 3275 for (unsigned i = 0; i < NumDims; i++) { 3276 auto Size = Array->getDimensionSize(i); 3277 3278 if (i == NumDims - 1) 3279 Size = SE->getMulExpr(Size, SE->getConstant(Size->getType(), Int[0])); 3280 Sizes.push_back(Size); 3281 } 3282 3283 Array->updateSizes(Sizes, false /* CheckConsistency */); 3284 3285 isl_set_free(Elements); 3286 } 3287 isl_union_set_free(Accessed); 3288 return; 3289 } 3290 3291 void Scop::finalizeAccesses() { 3292 updateAccessDimensionality(); 3293 foldSizeConstantsToRight(); 3294 foldAccessRelations(); 3295 assumeNoOutOfBounds(); 3296 } 3297 3298 void Scop::init(AliasAnalysis &AA, DominatorTree &DT, LoopInfo &LI) { 3299 buildInvariantEquivalenceClasses(); 3300 3301 if (!buildDomains(&R, DT, LI)) 3302 return; 3303 3304 addUserAssumptions(DT, LI); 3305 3306 // Remove empty statements. 3307 // Exit early in case there are no executable statements left in this scop. 3308 simplifySCoP(false); 3309 if (Stmts.empty()) 3310 return; 3311 3312 // The ScopStmts now have enough information to initialize themselves. 3313 for (ScopStmt &Stmt : Stmts) 3314 Stmt.init(LI); 3315 3316 // Check early for a feasible runtime context. 3317 if (!hasFeasibleRuntimeContext()) 3318 return; 3319 3320 // Check early for profitability. Afterwards it cannot change anymore, 3321 // only the runtime context could become infeasible. 3322 if (!isProfitable()) { 3323 invalidate(PROFITABLE, DebugLoc()); 3324 return; 3325 } 3326 3327 buildSchedule(LI); 3328 3329 finalizeAccesses(); 3330 3331 realignParams(); 3332 addUserContext(); 3333 3334 // After the context was fully constructed, thus all our knowledge about 3335 // the parameters is in there, we add all recorded assumptions to the 3336 // assumed/invalid context. 3337 addRecordedAssumptions(); 3338 3339 simplifyContexts(); 3340 if (!buildAliasChecks(AA)) 3341 return; 3342 3343 hoistInvariantLoads(); 3344 verifyInvariantLoads(); 3345 simplifySCoP(true); 3346 3347 // Check late for a feasible runtime context because profitability did not 3348 // change. 3349 if (!hasFeasibleRuntimeContext()) 3350 return; 3351 } 3352 3353 Scop::~Scop() { 3354 isl_set_free(Context); 3355 isl_set_free(AssumedContext); 3356 isl_set_free(InvalidContext); 3357 isl_schedule_free(Schedule); 3358 3359 for (auto &It : ParameterIds) 3360 isl_id_free(It.second); 3361 3362 for (auto It : DomainMap) 3363 isl_set_free(It.second); 3364 3365 for (auto &AS : RecordedAssumptions) 3366 isl_set_free(AS.Set); 3367 3368 // Free the alias groups 3369 for (MinMaxVectorPairTy &MinMaxAccessPair : MinMaxAliasGroups) { 3370 for (MinMaxAccessTy &MMA : MinMaxAccessPair.first) { 3371 isl_pw_multi_aff_free(MMA.first); 3372 isl_pw_multi_aff_free(MMA.second); 3373 } 3374 for (MinMaxAccessTy &MMA : MinMaxAccessPair.second) { 3375 isl_pw_multi_aff_free(MMA.first); 3376 isl_pw_multi_aff_free(MMA.second); 3377 } 3378 } 3379 3380 for (const auto &IAClass : InvariantEquivClasses) 3381 isl_set_free(IAClass.ExecutionContext); 3382 3383 // Explicitly release all Scop objects and the underlying isl objects before 3384 // we release the isl context. 3385 Stmts.clear(); 3386 ScopArrayInfoSet.clear(); 3387 ScopArrayInfoMap.clear(); 3388 ScopArrayNameMap.clear(); 3389 AccessFunctions.clear(); 3390 } 3391 3392 void Scop::updateAccessDimensionality() { 3393 // Check all array accesses for each base pointer and find a (virtual) element 3394 // size for the base pointer that divides all access functions. 3395 for (ScopStmt &Stmt : *this) 3396 for (MemoryAccess *Access : Stmt) { 3397 if (!Access->isArrayKind()) 3398 continue; 3399 ScopArrayInfo *Array = 3400 const_cast<ScopArrayInfo *>(Access->getScopArrayInfo()); 3401 3402 if (Array->getNumberOfDimensions() != 1) 3403 continue; 3404 unsigned DivisibleSize = Array->getElemSizeInBytes(); 3405 const SCEV *Subscript = Access->getSubscript(0); 3406 while (!isDivisible(Subscript, DivisibleSize, *SE)) 3407 DivisibleSize /= 2; 3408 auto *Ty = IntegerType::get(SE->getContext(), DivisibleSize * 8); 3409 Array->updateElementType(Ty); 3410 } 3411 3412 for (auto &Stmt : *this) 3413 for (auto &Access : Stmt) 3414 Access->updateDimensionality(); 3415 } 3416 3417 void Scop::foldAccessRelations() { 3418 for (auto &Stmt : *this) 3419 for (auto &Access : Stmt) 3420 Access->foldAccessRelation(); 3421 } 3422 3423 void Scop::assumeNoOutOfBounds() { 3424 for (auto &Stmt : *this) 3425 for (auto &Access : Stmt) 3426 Access->assumeNoOutOfBound(); 3427 } 3428 3429 void Scop::simplifySCoP(bool AfterHoisting) { 3430 for (auto StmtIt = Stmts.begin(), StmtEnd = Stmts.end(); StmtIt != StmtEnd;) { 3431 ScopStmt &Stmt = *StmtIt; 3432 3433 bool RemoveStmt = Stmt.isEmpty(); 3434 if (!RemoveStmt) 3435 RemoveStmt = !DomainMap[Stmt.getEntryBlock()]; 3436 3437 // Remove read only statements only after invariant loop hoisting. 3438 if (!RemoveStmt && AfterHoisting) { 3439 bool OnlyRead = true; 3440 for (MemoryAccess *MA : Stmt) { 3441 if (MA->isRead()) 3442 continue; 3443 3444 OnlyRead = false; 3445 break; 3446 } 3447 3448 RemoveStmt = OnlyRead; 3449 } 3450 3451 if (!RemoveStmt) { 3452 StmtIt++; 3453 continue; 3454 } 3455 3456 // Remove the statement because it is unnecessary. 3457 if (Stmt.isRegionStmt()) 3458 for (BasicBlock *BB : Stmt.getRegion()->blocks()) 3459 StmtMap.erase(BB); 3460 else 3461 StmtMap.erase(Stmt.getBasicBlock()); 3462 3463 StmtIt = Stmts.erase(StmtIt); 3464 } 3465 } 3466 3467 InvariantEquivClassTy *Scop::lookupInvariantEquivClass(Value *Val) { 3468 LoadInst *LInst = dyn_cast<LoadInst>(Val); 3469 if (!LInst) 3470 return nullptr; 3471 3472 if (Value *Rep = InvEquivClassVMap.lookup(LInst)) 3473 LInst = cast<LoadInst>(Rep); 3474 3475 Type *Ty = LInst->getType(); 3476 const SCEV *PointerSCEV = SE->getSCEV(LInst->getPointerOperand()); 3477 for (auto &IAClass : InvariantEquivClasses) { 3478 if (PointerSCEV != IAClass.IdentifyingPointer || Ty != IAClass.AccessType) 3479 continue; 3480 3481 auto &MAs = IAClass.InvariantAccesses; 3482 for (auto *MA : MAs) 3483 if (MA->getAccessInstruction() == Val) 3484 return &IAClass; 3485 } 3486 3487 return nullptr; 3488 } 3489 3490 /// Check if @p MA can always be hoisted without execution context. 3491 static bool canAlwaysBeHoisted(MemoryAccess *MA, bool StmtInvalidCtxIsEmpty, 3492 bool MAInvalidCtxIsEmpty, 3493 bool NonHoistableCtxIsEmpty) { 3494 LoadInst *LInst = cast<LoadInst>(MA->getAccessInstruction()); 3495 const DataLayout &DL = LInst->getParent()->getModule()->getDataLayout(); 3496 // TODO: We can provide more information for better but more expensive 3497 // results. 3498 if (!isDereferenceableAndAlignedPointer(LInst->getPointerOperand(), 3499 LInst->getAlignment(), DL)) 3500 return false; 3501 3502 // If the location might be overwritten we do not hoist it unconditionally. 3503 // 3504 // TODO: This is probably to conservative. 3505 if (!NonHoistableCtxIsEmpty) 3506 return false; 3507 3508 // If a dereferencable load is in a statement that is modeled precisely we can 3509 // hoist it. 3510 if (StmtInvalidCtxIsEmpty && MAInvalidCtxIsEmpty) 3511 return true; 3512 3513 // Even if the statement is not modeled precisely we can hoist the load if it 3514 // does not involve any parameters that might have been specialized by the 3515 // statement domain. 3516 for (unsigned u = 0, e = MA->getNumSubscripts(); u < e; u++) 3517 if (!isa<SCEVConstant>(MA->getSubscript(u))) 3518 return false; 3519 return true; 3520 } 3521 3522 void Scop::addInvariantLoads(ScopStmt &Stmt, InvariantAccessesTy &InvMAs) { 3523 3524 if (InvMAs.empty()) 3525 return; 3526 3527 auto *StmtInvalidCtx = Stmt.getInvalidContext(); 3528 bool StmtInvalidCtxIsEmpty = isl_set_is_empty(StmtInvalidCtx); 3529 3530 // Get the context under which the statement is executed but remove the error 3531 // context under which this statement is reached. 3532 isl_set *DomainCtx = isl_set_params(Stmt.getDomain()); 3533 DomainCtx = isl_set_subtract(DomainCtx, StmtInvalidCtx); 3534 3535 if (isl_set_n_basic_set(DomainCtx) >= MaxDisjunctsInDomain) { 3536 auto *AccInst = InvMAs.front().MA->getAccessInstruction(); 3537 invalidate(COMPLEXITY, AccInst->getDebugLoc()); 3538 isl_set_free(DomainCtx); 3539 for (auto &InvMA : InvMAs) 3540 isl_set_free(InvMA.NonHoistableCtx); 3541 return; 3542 } 3543 3544 // Project out all parameters that relate to loads in the statement. Otherwise 3545 // we could have cyclic dependences on the constraints under which the 3546 // hoisted loads are executed and we could not determine an order in which to 3547 // pre-load them. This happens because not only lower bounds are part of the 3548 // domain but also upper bounds. 3549 for (auto &InvMA : InvMAs) { 3550 auto *MA = InvMA.MA; 3551 Instruction *AccInst = MA->getAccessInstruction(); 3552 if (SE->isSCEVable(AccInst->getType())) { 3553 SetVector<Value *> Values; 3554 for (const SCEV *Parameter : Parameters) { 3555 Values.clear(); 3556 findValues(Parameter, *SE, Values); 3557 if (!Values.count(AccInst)) 3558 continue; 3559 3560 if (isl_id *ParamId = getIdForParam(Parameter)) { 3561 int Dim = isl_set_find_dim_by_id(DomainCtx, isl_dim_param, ParamId); 3562 DomainCtx = isl_set_eliminate(DomainCtx, isl_dim_param, Dim, 1); 3563 isl_id_free(ParamId); 3564 } 3565 } 3566 } 3567 } 3568 3569 for (auto &InvMA : InvMAs) { 3570 auto *MA = InvMA.MA; 3571 auto *NHCtx = InvMA.NonHoistableCtx; 3572 3573 // Check for another invariant access that accesses the same location as 3574 // MA and if found consolidate them. Otherwise create a new equivalence 3575 // class at the end of InvariantEquivClasses. 3576 LoadInst *LInst = cast<LoadInst>(MA->getAccessInstruction()); 3577 Type *Ty = LInst->getType(); 3578 const SCEV *PointerSCEV = SE->getSCEV(LInst->getPointerOperand()); 3579 3580 auto *MAInvalidCtx = MA->getInvalidContext(); 3581 bool NonHoistableCtxIsEmpty = isl_set_is_empty(NHCtx); 3582 bool MAInvalidCtxIsEmpty = isl_set_is_empty(MAInvalidCtx); 3583 3584 isl_set *MACtx; 3585 // Check if we know that this pointer can be speculatively accessed. 3586 if (canAlwaysBeHoisted(MA, StmtInvalidCtxIsEmpty, MAInvalidCtxIsEmpty, 3587 NonHoistableCtxIsEmpty)) { 3588 MACtx = isl_set_universe(isl_set_get_space(DomainCtx)); 3589 isl_set_free(MAInvalidCtx); 3590 isl_set_free(NHCtx); 3591 } else { 3592 MACtx = isl_set_copy(DomainCtx); 3593 MACtx = isl_set_subtract(MACtx, isl_set_union(MAInvalidCtx, NHCtx)); 3594 MACtx = isl_set_gist_params(MACtx, getContext()); 3595 } 3596 3597 bool Consolidated = false; 3598 for (auto &IAClass : InvariantEquivClasses) { 3599 if (PointerSCEV != IAClass.IdentifyingPointer || Ty != IAClass.AccessType) 3600 continue; 3601 3602 // If the pointer and the type is equal check if the access function wrt. 3603 // to the domain is equal too. It can happen that the domain fixes 3604 // parameter values and these can be different for distinct part of the 3605 // SCoP. If this happens we cannot consolidate the loads but need to 3606 // create a new invariant load equivalence class. 3607 auto &MAs = IAClass.InvariantAccesses; 3608 if (!MAs.empty()) { 3609 auto *LastMA = MAs.front(); 3610 3611 auto *AR = isl_map_range(MA->getAccessRelation()); 3612 auto *LastAR = isl_map_range(LastMA->getAccessRelation()); 3613 bool SameAR = isl_set_is_equal(AR, LastAR); 3614 isl_set_free(AR); 3615 isl_set_free(LastAR); 3616 3617 if (!SameAR) 3618 continue; 3619 } 3620 3621 // Add MA to the list of accesses that are in this class. 3622 MAs.push_front(MA); 3623 3624 Consolidated = true; 3625 3626 // Unify the execution context of the class and this statement. 3627 isl_set *&IAClassDomainCtx = IAClass.ExecutionContext; 3628 if (IAClassDomainCtx) 3629 IAClassDomainCtx = 3630 isl_set_coalesce(isl_set_union(IAClassDomainCtx, MACtx)); 3631 else 3632 IAClassDomainCtx = MACtx; 3633 break; 3634 } 3635 3636 if (Consolidated) 3637 continue; 3638 3639 // If we did not consolidate MA, thus did not find an equivalence class 3640 // for it, we create a new one. 3641 InvariantEquivClasses.emplace_back( 3642 InvariantEquivClassTy{PointerSCEV, MemoryAccessList{MA}, MACtx, Ty}); 3643 } 3644 3645 isl_set_free(DomainCtx); 3646 } 3647 3648 __isl_give isl_set *Scop::getNonHoistableCtx(MemoryAccess *Access, 3649 __isl_keep isl_union_map *Writes) { 3650 // TODO: Loads that are not loop carried, hence are in a statement with 3651 // zero iterators, are by construction invariant, though we 3652 // currently "hoist" them anyway. This is necessary because we allow 3653 // them to be treated as parameters (e.g., in conditions) and our code 3654 // generation would otherwise use the old value. 3655 3656 auto &Stmt = *Access->getStatement(); 3657 BasicBlock *BB = Stmt.getEntryBlock(); 3658 3659 if (Access->isScalarKind() || Access->isWrite() || !Access->isAffine() || 3660 Access->isMemoryIntrinsic()) 3661 return nullptr; 3662 3663 // Skip accesses that have an invariant base pointer which is defined but 3664 // not loaded inside the SCoP. This can happened e.g., if a readnone call 3665 // returns a pointer that is used as a base address. However, as we want 3666 // to hoist indirect pointers, we allow the base pointer to be defined in 3667 // the region if it is also a memory access. Each ScopArrayInfo object 3668 // that has a base pointer origin has a base pointer that is loaded and 3669 // that it is invariant, thus it will be hoisted too. However, if there is 3670 // no base pointer origin we check that the base pointer is defined 3671 // outside the region. 3672 auto *LI = cast<LoadInst>(Access->getAccessInstruction()); 3673 if (hasNonHoistableBasePtrInScop(Access, Writes)) 3674 return nullptr; 3675 3676 // Skip accesses in non-affine subregions as they might not be executed 3677 // under the same condition as the entry of the non-affine subregion. 3678 if (BB != LI->getParent()) 3679 return nullptr; 3680 3681 isl_map *AccessRelation = Access->getAccessRelation(); 3682 assert(!isl_map_is_empty(AccessRelation)); 3683 3684 if (isl_map_involves_dims(AccessRelation, isl_dim_in, 0, 3685 Stmt.getNumIterators())) { 3686 isl_map_free(AccessRelation); 3687 return nullptr; 3688 } 3689 3690 AccessRelation = isl_map_intersect_domain(AccessRelation, Stmt.getDomain()); 3691 isl_set *AccessRange = isl_map_range(AccessRelation); 3692 3693 isl_union_map *Written = isl_union_map_intersect_range( 3694 isl_union_map_copy(Writes), isl_union_set_from_set(AccessRange)); 3695 auto *WrittenCtx = isl_union_map_params(Written); 3696 bool IsWritten = !isl_set_is_empty(WrittenCtx); 3697 3698 if (!IsWritten) 3699 return WrittenCtx; 3700 3701 WrittenCtx = isl_set_remove_divs(WrittenCtx); 3702 bool TooComplex = isl_set_n_basic_set(WrittenCtx) >= MaxDisjunctsInDomain; 3703 if (TooComplex || !isRequiredInvariantLoad(LI)) { 3704 isl_set_free(WrittenCtx); 3705 return nullptr; 3706 } 3707 3708 addAssumption(INVARIANTLOAD, isl_set_copy(WrittenCtx), LI->getDebugLoc(), 3709 AS_RESTRICTION); 3710 return WrittenCtx; 3711 } 3712 3713 void Scop::verifyInvariantLoads() { 3714 auto &RIL = getRequiredInvariantLoads(); 3715 for (LoadInst *LI : RIL) { 3716 assert(LI && contains(LI)); 3717 ScopStmt *Stmt = getStmtFor(LI); 3718 if (Stmt && Stmt->getArrayAccessOrNULLFor(LI)) { 3719 invalidate(INVARIANTLOAD, LI->getDebugLoc()); 3720 return; 3721 } 3722 } 3723 } 3724 3725 void Scop::hoistInvariantLoads() { 3726 if (!PollyInvariantLoadHoisting) 3727 return; 3728 3729 isl_union_map *Writes = getWrites(); 3730 for (ScopStmt &Stmt : *this) { 3731 InvariantAccessesTy InvariantAccesses; 3732 3733 for (MemoryAccess *Access : Stmt) 3734 if (auto *NHCtx = getNonHoistableCtx(Access, Writes)) 3735 InvariantAccesses.push_back({Access, NHCtx}); 3736 3737 // Transfer the memory access from the statement to the SCoP. 3738 for (auto InvMA : InvariantAccesses) 3739 Stmt.removeMemoryAccess(InvMA.MA); 3740 addInvariantLoads(Stmt, InvariantAccesses); 3741 } 3742 isl_union_map_free(Writes); 3743 } 3744 3745 const ScopArrayInfo * 3746 Scop::getOrCreateScopArrayInfo(Value *BasePtr, Type *ElementType, 3747 ArrayRef<const SCEV *> Sizes, MemoryKind Kind, 3748 const char *BaseName) { 3749 assert((BasePtr || BaseName) && 3750 "BasePtr and BaseName can not be nullptr at the same time."); 3751 assert(!(BasePtr && BaseName) && "BaseName is redundant."); 3752 auto &SAI = BasePtr ? ScopArrayInfoMap[std::make_pair(BasePtr, Kind)] 3753 : ScopArrayNameMap[BaseName]; 3754 if (!SAI) { 3755 auto &DL = getFunction().getParent()->getDataLayout(); 3756 SAI.reset(new ScopArrayInfo(BasePtr, ElementType, getIslCtx(), Sizes, Kind, 3757 DL, this, BaseName)); 3758 ScopArrayInfoSet.insert(SAI.get()); 3759 } else { 3760 SAI->updateElementType(ElementType); 3761 // In case of mismatching array sizes, we bail out by setting the run-time 3762 // context to false. 3763 if (!SAI->updateSizes(Sizes)) 3764 invalidate(DELINEARIZATION, DebugLoc()); 3765 } 3766 return SAI.get(); 3767 } 3768 3769 const ScopArrayInfo * 3770 Scop::createScopArrayInfo(Type *ElementType, const std::string &BaseName, 3771 const std::vector<unsigned> &Sizes) { 3772 auto *DimSizeType = Type::getInt64Ty(getSE()->getContext()); 3773 std::vector<const SCEV *> SCEVSizes; 3774 3775 for (auto size : Sizes) 3776 if (size) 3777 SCEVSizes.push_back(getSE()->getConstant(DimSizeType, size, false)); 3778 else 3779 SCEVSizes.push_back(nullptr); 3780 3781 auto *SAI = getOrCreateScopArrayInfo(nullptr, ElementType, SCEVSizes, 3782 MemoryKind::Array, BaseName.c_str()); 3783 return SAI; 3784 } 3785 3786 const ScopArrayInfo *Scop::getScopArrayInfo(Value *BasePtr, MemoryKind Kind) { 3787 auto *SAI = ScopArrayInfoMap[std::make_pair(BasePtr, Kind)].get(); 3788 assert(SAI && "No ScopArrayInfo available for this base pointer"); 3789 return SAI; 3790 } 3791 3792 std::string Scop::getContextStr() const { return stringFromIslObj(Context); } 3793 3794 std::string Scop::getAssumedContextStr() const { 3795 assert(AssumedContext && "Assumed context not yet built"); 3796 return stringFromIslObj(AssumedContext); 3797 } 3798 3799 std::string Scop::getInvalidContextStr() const { 3800 return stringFromIslObj(InvalidContext); 3801 } 3802 3803 std::string Scop::getNameStr() const { 3804 std::string ExitName, EntryName; 3805 raw_string_ostream ExitStr(ExitName); 3806 raw_string_ostream EntryStr(EntryName); 3807 3808 R.getEntry()->printAsOperand(EntryStr, false); 3809 EntryStr.str(); 3810 3811 if (R.getExit()) { 3812 R.getExit()->printAsOperand(ExitStr, false); 3813 ExitStr.str(); 3814 } else 3815 ExitName = "FunctionExit"; 3816 3817 return EntryName + "---" + ExitName; 3818 } 3819 3820 __isl_give isl_set *Scop::getContext() const { return isl_set_copy(Context); } 3821 __isl_give isl_space *Scop::getParamSpace() const { 3822 return isl_set_get_space(Context); 3823 } 3824 3825 __isl_give isl_set *Scop::getAssumedContext() const { 3826 assert(AssumedContext && "Assumed context not yet built"); 3827 return isl_set_copy(AssumedContext); 3828 } 3829 3830 bool Scop::isProfitable() const { 3831 if (PollyProcessUnprofitable) 3832 return true; 3833 3834 if (isEmpty()) 3835 return false; 3836 3837 unsigned OptimizableStmtsOrLoops = 0; 3838 for (auto &Stmt : *this) { 3839 if (Stmt.getNumIterators() == 0) 3840 continue; 3841 3842 bool ContainsArrayAccs = false; 3843 bool ContainsScalarAccs = false; 3844 for (auto *MA : Stmt) { 3845 if (MA->isRead()) 3846 continue; 3847 ContainsArrayAccs |= MA->isArrayKind(); 3848 ContainsScalarAccs |= MA->isScalarKind(); 3849 } 3850 3851 if (!UnprofitableScalarAccs || (ContainsArrayAccs && !ContainsScalarAccs)) 3852 OptimizableStmtsOrLoops += Stmt.getNumIterators(); 3853 } 3854 3855 return OptimizableStmtsOrLoops > 1; 3856 } 3857 3858 bool Scop::hasFeasibleRuntimeContext() const { 3859 auto *PositiveContext = getAssumedContext(); 3860 auto *NegativeContext = getInvalidContext(); 3861 PositiveContext = addNonEmptyDomainConstraints(PositiveContext); 3862 bool IsFeasible = !(isl_set_is_empty(PositiveContext) || 3863 isl_set_is_subset(PositiveContext, NegativeContext)); 3864 isl_set_free(PositiveContext); 3865 if (!IsFeasible) { 3866 isl_set_free(NegativeContext); 3867 return false; 3868 } 3869 3870 auto *DomainContext = isl_union_set_params(getDomains()); 3871 IsFeasible = !isl_set_is_subset(DomainContext, NegativeContext); 3872 IsFeasible &= !isl_set_is_subset(Context, NegativeContext); 3873 isl_set_free(NegativeContext); 3874 isl_set_free(DomainContext); 3875 3876 return IsFeasible; 3877 } 3878 3879 static std::string toString(AssumptionKind Kind) { 3880 switch (Kind) { 3881 case ALIASING: 3882 return "No-aliasing"; 3883 case INBOUNDS: 3884 return "Inbounds"; 3885 case WRAPPING: 3886 return "No-overflows"; 3887 case UNSIGNED: 3888 return "Signed-unsigned"; 3889 case COMPLEXITY: 3890 return "Low complexity"; 3891 case PROFITABLE: 3892 return "Profitable"; 3893 case ERRORBLOCK: 3894 return "No-error"; 3895 case INFINITELOOP: 3896 return "Finite loop"; 3897 case INVARIANTLOAD: 3898 return "Invariant load"; 3899 case DELINEARIZATION: 3900 return "Delinearization"; 3901 } 3902 llvm_unreachable("Unknown AssumptionKind!"); 3903 } 3904 3905 bool Scop::isEffectiveAssumption(__isl_keep isl_set *Set, AssumptionSign Sign) { 3906 if (Sign == AS_ASSUMPTION) { 3907 if (isl_set_is_subset(Context, Set)) 3908 return false; 3909 3910 if (isl_set_is_subset(AssumedContext, Set)) 3911 return false; 3912 } else { 3913 if (isl_set_is_disjoint(Set, Context)) 3914 return false; 3915 3916 if (isl_set_is_subset(Set, InvalidContext)) 3917 return false; 3918 } 3919 return true; 3920 } 3921 3922 bool Scop::trackAssumption(AssumptionKind Kind, __isl_keep isl_set *Set, 3923 DebugLoc Loc, AssumptionSign Sign) { 3924 if (PollyRemarksMinimal && !isEffectiveAssumption(Set, Sign)) 3925 return false; 3926 3927 // Do never emit trivial assumptions as they only clutter the output. 3928 if (!PollyRemarksMinimal) { 3929 isl_set *Univ = nullptr; 3930 if (Sign == AS_ASSUMPTION) 3931 Univ = isl_set_universe(isl_set_get_space(Set)); 3932 3933 bool IsTrivial = (Sign == AS_RESTRICTION && isl_set_is_empty(Set)) || 3934 (Sign == AS_ASSUMPTION && isl_set_is_equal(Univ, Set)); 3935 isl_set_free(Univ); 3936 3937 if (IsTrivial) 3938 return false; 3939 } 3940 3941 switch (Kind) { 3942 case ALIASING: 3943 AssumptionsAliasing++; 3944 break; 3945 case INBOUNDS: 3946 AssumptionsInbounds++; 3947 break; 3948 case WRAPPING: 3949 AssumptionsWrapping++; 3950 break; 3951 case UNSIGNED: 3952 AssumptionsUnsigned++; 3953 break; 3954 case COMPLEXITY: 3955 AssumptionsComplexity++; 3956 break; 3957 case PROFITABLE: 3958 AssumptionsUnprofitable++; 3959 break; 3960 case ERRORBLOCK: 3961 AssumptionsErrorBlock++; 3962 break; 3963 case INFINITELOOP: 3964 AssumptionsInfiniteLoop++; 3965 break; 3966 case INVARIANTLOAD: 3967 AssumptionsInvariantLoad++; 3968 break; 3969 case DELINEARIZATION: 3970 AssumptionsDelinearization++; 3971 break; 3972 } 3973 3974 auto &F = getFunction(); 3975 auto Suffix = Sign == AS_ASSUMPTION ? " assumption:\t" : " restriction:\t"; 3976 std::string Msg = toString(Kind) + Suffix + stringFromIslObj(Set); 3977 emitOptimizationRemarkAnalysis(F.getContext(), DEBUG_TYPE, F, Loc, Msg); 3978 return true; 3979 } 3980 3981 void Scop::addAssumption(AssumptionKind Kind, __isl_take isl_set *Set, 3982 DebugLoc Loc, AssumptionSign Sign) { 3983 // Simplify the assumptions/restrictions first. 3984 Set = isl_set_gist_params(Set, getContext()); 3985 3986 if (!trackAssumption(Kind, Set, Loc, Sign)) { 3987 isl_set_free(Set); 3988 return; 3989 } 3990 3991 if (Sign == AS_ASSUMPTION) { 3992 AssumedContext = isl_set_intersect(AssumedContext, Set); 3993 AssumedContext = isl_set_coalesce(AssumedContext); 3994 } else { 3995 InvalidContext = isl_set_union(InvalidContext, Set); 3996 InvalidContext = isl_set_coalesce(InvalidContext); 3997 } 3998 } 3999 4000 void Scop::recordAssumption(AssumptionKind Kind, __isl_take isl_set *Set, 4001 DebugLoc Loc, AssumptionSign Sign, BasicBlock *BB) { 4002 assert((isl_set_is_params(Set) || BB) && 4003 "Assumptions without a basic block must be parameter sets"); 4004 RecordedAssumptions.push_back({Kind, Sign, Set, Loc, BB}); 4005 } 4006 4007 void Scop::addRecordedAssumptions() { 4008 while (!RecordedAssumptions.empty()) { 4009 const Assumption &AS = RecordedAssumptions.pop_back_val(); 4010 4011 if (!AS.BB) { 4012 addAssumption(AS.Kind, AS.Set, AS.Loc, AS.Sign); 4013 continue; 4014 } 4015 4016 // If the domain was deleted the assumptions are void. 4017 isl_set *Dom = getDomainConditions(AS.BB); 4018 if (!Dom) { 4019 isl_set_free(AS.Set); 4020 continue; 4021 } 4022 4023 // If a basic block was given use its domain to simplify the assumption. 4024 // In case of restrictions we know they only have to hold on the domain, 4025 // thus we can intersect them with the domain of the block. However, for 4026 // assumptions the domain has to imply them, thus: 4027 // _ _____ 4028 // Dom => S <==> A v B <==> A - B 4029 // 4030 // To avoid the complement we will register A - B as a restriction not an 4031 // assumption. 4032 isl_set *S = AS.Set; 4033 if (AS.Sign == AS_RESTRICTION) 4034 S = isl_set_params(isl_set_intersect(S, Dom)); 4035 else /* (AS.Sign == AS_ASSUMPTION) */ 4036 S = isl_set_params(isl_set_subtract(Dom, S)); 4037 4038 addAssumption(AS.Kind, S, AS.Loc, AS_RESTRICTION); 4039 } 4040 } 4041 4042 void Scop::invalidate(AssumptionKind Kind, DebugLoc Loc) { 4043 addAssumption(Kind, isl_set_empty(getParamSpace()), Loc, AS_ASSUMPTION); 4044 } 4045 4046 __isl_give isl_set *Scop::getInvalidContext() const { 4047 return isl_set_copy(InvalidContext); 4048 } 4049 4050 void Scop::printContext(raw_ostream &OS) const { 4051 OS << "Context:\n"; 4052 OS.indent(4) << Context << "\n"; 4053 4054 OS.indent(4) << "Assumed Context:\n"; 4055 OS.indent(4) << AssumedContext << "\n"; 4056 4057 OS.indent(4) << "Invalid Context:\n"; 4058 OS.indent(4) << InvalidContext << "\n"; 4059 4060 unsigned Dim = 0; 4061 for (const SCEV *Parameter : Parameters) 4062 OS.indent(4) << "p" << Dim++ << ": " << *Parameter << "\n"; 4063 } 4064 4065 void Scop::printAliasAssumptions(raw_ostream &OS) const { 4066 int noOfGroups = 0; 4067 for (const MinMaxVectorPairTy &Pair : MinMaxAliasGroups) { 4068 if (Pair.second.size() == 0) 4069 noOfGroups += 1; 4070 else 4071 noOfGroups += Pair.second.size(); 4072 } 4073 4074 OS.indent(4) << "Alias Groups (" << noOfGroups << "):\n"; 4075 if (MinMaxAliasGroups.empty()) { 4076 OS.indent(8) << "n/a\n"; 4077 return; 4078 } 4079 4080 for (const MinMaxVectorPairTy &Pair : MinMaxAliasGroups) { 4081 4082 // If the group has no read only accesses print the write accesses. 4083 if (Pair.second.empty()) { 4084 OS.indent(8) << "[["; 4085 for (const MinMaxAccessTy &MMANonReadOnly : Pair.first) { 4086 OS << " <" << MMANonReadOnly.first << ", " << MMANonReadOnly.second 4087 << ">"; 4088 } 4089 OS << " ]]\n"; 4090 } 4091 4092 for (const MinMaxAccessTy &MMAReadOnly : Pair.second) { 4093 OS.indent(8) << "[["; 4094 OS << " <" << MMAReadOnly.first << ", " << MMAReadOnly.second << ">"; 4095 for (const MinMaxAccessTy &MMANonReadOnly : Pair.first) { 4096 OS << " <" << MMANonReadOnly.first << ", " << MMANonReadOnly.second 4097 << ">"; 4098 } 4099 OS << " ]]\n"; 4100 } 4101 } 4102 } 4103 4104 void Scop::printStatements(raw_ostream &OS) const { 4105 OS << "Statements {\n"; 4106 4107 for (const ScopStmt &Stmt : *this) 4108 OS.indent(4) << Stmt; 4109 4110 OS.indent(4) << "}\n"; 4111 } 4112 4113 void Scop::printArrayInfo(raw_ostream &OS) const { 4114 OS << "Arrays {\n"; 4115 4116 for (auto &Array : arrays()) 4117 Array->print(OS); 4118 4119 OS.indent(4) << "}\n"; 4120 4121 OS.indent(4) << "Arrays (Bounds as pw_affs) {\n"; 4122 4123 for (auto &Array : arrays()) 4124 Array->print(OS, /* SizeAsPwAff */ true); 4125 4126 OS.indent(4) << "}\n"; 4127 } 4128 4129 void Scop::print(raw_ostream &OS) const { 4130 OS.indent(4) << "Function: " << getFunction().getName() << "\n"; 4131 OS.indent(4) << "Region: " << getNameStr() << "\n"; 4132 OS.indent(4) << "Max Loop Depth: " << getMaxLoopDepth() << "\n"; 4133 OS.indent(4) << "Invariant Accesses: {\n"; 4134 for (const auto &IAClass : InvariantEquivClasses) { 4135 const auto &MAs = IAClass.InvariantAccesses; 4136 if (MAs.empty()) { 4137 OS.indent(12) << "Class Pointer: " << *IAClass.IdentifyingPointer << "\n"; 4138 } else { 4139 MAs.front()->print(OS); 4140 OS.indent(12) << "Execution Context: " << IAClass.ExecutionContext 4141 << "\n"; 4142 } 4143 } 4144 OS.indent(4) << "}\n"; 4145 printContext(OS.indent(4)); 4146 printArrayInfo(OS.indent(4)); 4147 printAliasAssumptions(OS); 4148 printStatements(OS.indent(4)); 4149 } 4150 4151 void Scop::dump() const { print(dbgs()); } 4152 4153 isl_ctx *Scop::getIslCtx() const { return IslCtx.get(); } 4154 4155 __isl_give PWACtx Scop::getPwAff(const SCEV *E, BasicBlock *BB, 4156 bool NonNegative) { 4157 // First try to use the SCEVAffinator to generate a piecewise defined 4158 // affine function from @p E in the context of @p BB. If that tasks becomes to 4159 // complex the affinator might return a nullptr. In such a case we invalidate 4160 // the SCoP and return a dummy value. This way we do not need to add error 4161 // handling code to all users of this function. 4162 auto PWAC = Affinator.getPwAff(E, BB); 4163 if (PWAC.first) { 4164 // TODO: We could use a heuristic and either use: 4165 // SCEVAffinator::takeNonNegativeAssumption 4166 // or 4167 // SCEVAffinator::interpretAsUnsigned 4168 // to deal with unsigned or "NonNegative" SCEVs. 4169 if (NonNegative) 4170 Affinator.takeNonNegativeAssumption(PWAC); 4171 return PWAC; 4172 } 4173 4174 auto DL = BB ? BB->getTerminator()->getDebugLoc() : DebugLoc(); 4175 invalidate(COMPLEXITY, DL); 4176 return Affinator.getPwAff(SE->getZero(E->getType()), BB); 4177 } 4178 4179 __isl_give isl_union_set *Scop::getDomains() const { 4180 isl_union_set *Domain = isl_union_set_empty(getParamSpace()); 4181 4182 for (const ScopStmt &Stmt : *this) 4183 Domain = isl_union_set_add_set(Domain, Stmt.getDomain()); 4184 4185 return Domain; 4186 } 4187 4188 __isl_give isl_pw_aff *Scop::getPwAffOnly(const SCEV *E, BasicBlock *BB) { 4189 PWACtx PWAC = getPwAff(E, BB); 4190 isl_set_free(PWAC.second); 4191 return PWAC.first; 4192 } 4193 4194 __isl_give isl_union_map * 4195 Scop::getAccessesOfType(std::function<bool(MemoryAccess &)> Predicate) { 4196 isl_union_map *Accesses = isl_union_map_empty(getParamSpace()); 4197 4198 for (ScopStmt &Stmt : *this) { 4199 for (MemoryAccess *MA : Stmt) { 4200 if (!Predicate(*MA)) 4201 continue; 4202 4203 isl_set *Domain = Stmt.getDomain(); 4204 isl_map *AccessDomain = MA->getAccessRelation(); 4205 AccessDomain = isl_map_intersect_domain(AccessDomain, Domain); 4206 Accesses = isl_union_map_add_map(Accesses, AccessDomain); 4207 } 4208 } 4209 return isl_union_map_coalesce(Accesses); 4210 } 4211 4212 __isl_give isl_union_map *Scop::getMustWrites() { 4213 return getAccessesOfType([](MemoryAccess &MA) { return MA.isMustWrite(); }); 4214 } 4215 4216 __isl_give isl_union_map *Scop::getMayWrites() { 4217 return getAccessesOfType([](MemoryAccess &MA) { return MA.isMayWrite(); }); 4218 } 4219 4220 __isl_give isl_union_map *Scop::getWrites() { 4221 return getAccessesOfType([](MemoryAccess &MA) { return MA.isWrite(); }); 4222 } 4223 4224 __isl_give isl_union_map *Scop::getReads() { 4225 return getAccessesOfType([](MemoryAccess &MA) { return MA.isRead(); }); 4226 } 4227 4228 __isl_give isl_union_map *Scop::getAccesses() { 4229 return getAccessesOfType([](MemoryAccess &MA) { return true; }); 4230 } 4231 4232 // Check whether @p Node is an extension node. 4233 // 4234 // @return true if @p Node is an extension node. 4235 isl_bool isNotExtNode(__isl_keep isl_schedule_node *Node, void *User) { 4236 if (isl_schedule_node_get_type(Node) == isl_schedule_node_extension) 4237 return isl_bool_error; 4238 else 4239 return isl_bool_true; 4240 } 4241 4242 bool Scop::containsExtensionNode(__isl_keep isl_schedule *Schedule) { 4243 return isl_schedule_foreach_schedule_node_top_down(Schedule, isNotExtNode, 4244 nullptr) == isl_stat_error; 4245 } 4246 4247 __isl_give isl_union_map *Scop::getSchedule() const { 4248 auto *Tree = getScheduleTree(); 4249 if (containsExtensionNode(Tree)) { 4250 isl_schedule_free(Tree); 4251 return nullptr; 4252 } 4253 auto *S = isl_schedule_get_map(Tree); 4254 isl_schedule_free(Tree); 4255 return S; 4256 } 4257 4258 __isl_give isl_schedule *Scop::getScheduleTree() const { 4259 return isl_schedule_intersect_domain(isl_schedule_copy(Schedule), 4260 getDomains()); 4261 } 4262 4263 void Scop::setSchedule(__isl_take isl_union_map *NewSchedule) { 4264 auto *S = isl_schedule_from_domain(getDomains()); 4265 S = isl_schedule_insert_partial_schedule( 4266 S, isl_multi_union_pw_aff_from_union_map(NewSchedule)); 4267 isl_schedule_free(Schedule); 4268 Schedule = S; 4269 } 4270 4271 void Scop::setScheduleTree(__isl_take isl_schedule *NewSchedule) { 4272 isl_schedule_free(Schedule); 4273 Schedule = NewSchedule; 4274 } 4275 4276 bool Scop::restrictDomains(__isl_take isl_union_set *Domain) { 4277 bool Changed = false; 4278 for (ScopStmt &Stmt : *this) { 4279 isl_union_set *StmtDomain = isl_union_set_from_set(Stmt.getDomain()); 4280 isl_union_set *NewStmtDomain = isl_union_set_intersect( 4281 isl_union_set_copy(StmtDomain), isl_union_set_copy(Domain)); 4282 4283 if (isl_union_set_is_subset(StmtDomain, NewStmtDomain)) { 4284 isl_union_set_free(StmtDomain); 4285 isl_union_set_free(NewStmtDomain); 4286 continue; 4287 } 4288 4289 Changed = true; 4290 4291 isl_union_set_free(StmtDomain); 4292 NewStmtDomain = isl_union_set_coalesce(NewStmtDomain); 4293 4294 if (isl_union_set_is_empty(NewStmtDomain)) { 4295 Stmt.restrictDomain(isl_set_empty(Stmt.getDomainSpace())); 4296 isl_union_set_free(NewStmtDomain); 4297 } else 4298 Stmt.restrictDomain(isl_set_from_union_set(NewStmtDomain)); 4299 } 4300 isl_union_set_free(Domain); 4301 return Changed; 4302 } 4303 4304 ScalarEvolution *Scop::getSE() const { return SE; } 4305 4306 struct MapToDimensionDataTy { 4307 int N; 4308 isl_union_pw_multi_aff *Res; 4309 }; 4310 4311 // Create a function that maps the elements of 'Set' to its N-th dimension and 4312 // add it to User->Res. 4313 // 4314 // @param Set The input set. 4315 // @param User->N The dimension to map to. 4316 // @param User->Res The isl_union_pw_multi_aff to which to add the result. 4317 // 4318 // @returns isl_stat_ok if no error occured, othewise isl_stat_error. 4319 static isl_stat mapToDimension_AddSet(__isl_take isl_set *Set, void *User) { 4320 struct MapToDimensionDataTy *Data = (struct MapToDimensionDataTy *)User; 4321 int Dim; 4322 isl_space *Space; 4323 isl_pw_multi_aff *PMA; 4324 4325 Dim = isl_set_dim(Set, isl_dim_set); 4326 Space = isl_set_get_space(Set); 4327 PMA = isl_pw_multi_aff_project_out_map(Space, isl_dim_set, Data->N, 4328 Dim - Data->N); 4329 if (Data->N > 1) 4330 PMA = isl_pw_multi_aff_drop_dims(PMA, isl_dim_out, 0, Data->N - 1); 4331 Data->Res = isl_union_pw_multi_aff_add_pw_multi_aff(Data->Res, PMA); 4332 4333 isl_set_free(Set); 4334 4335 return isl_stat_ok; 4336 } 4337 4338 // Create an isl_multi_union_aff that defines an identity mapping from the 4339 // elements of USet to their N-th dimension. 4340 // 4341 // # Example: 4342 // 4343 // Domain: { A[i,j]; B[i,j,k] } 4344 // N: 1 4345 // 4346 // Resulting Mapping: { {A[i,j] -> [(j)]; B[i,j,k] -> [(j)] } 4347 // 4348 // @param USet A union set describing the elements for which to generate a 4349 // mapping. 4350 // @param N The dimension to map to. 4351 // @returns A mapping from USet to its N-th dimension. 4352 static __isl_give isl_multi_union_pw_aff * 4353 mapToDimension(__isl_take isl_union_set *USet, int N) { 4354 assert(N >= 0); 4355 assert(USet); 4356 assert(!isl_union_set_is_empty(USet)); 4357 4358 struct MapToDimensionDataTy Data; 4359 4360 auto *Space = isl_union_set_get_space(USet); 4361 auto *PwAff = isl_union_pw_multi_aff_empty(Space); 4362 4363 Data = {N, PwAff}; 4364 4365 auto Res = isl_union_set_foreach_set(USet, &mapToDimension_AddSet, &Data); 4366 (void)Res; 4367 4368 assert(Res == isl_stat_ok); 4369 4370 isl_union_set_free(USet); 4371 return isl_multi_union_pw_aff_from_union_pw_multi_aff(Data.Res); 4372 } 4373 4374 void Scop::addScopStmt(BasicBlock *BB) { 4375 assert(BB && "Unexpected nullptr!"); 4376 Stmts.emplace_back(*this, *BB); 4377 auto *Stmt = &Stmts.back(); 4378 StmtMap[BB] = Stmt; 4379 } 4380 4381 void Scop::addScopStmt(Region *R) { 4382 assert(R && "Unexpected nullptr!"); 4383 Stmts.emplace_back(*this, *R); 4384 auto *Stmt = &Stmts.back(); 4385 for (BasicBlock *BB : R->blocks()) 4386 StmtMap[BB] = Stmt; 4387 } 4388 4389 ScopStmt *Scop::addScopStmt(__isl_take isl_map *SourceRel, 4390 __isl_take isl_map *TargetRel, 4391 __isl_take isl_set *Domain) { 4392 #ifndef NDEBUG 4393 isl_set *SourceDomain = isl_map_domain(isl_map_copy(SourceRel)); 4394 isl_set *TargetDomain = isl_map_domain(isl_map_copy(TargetRel)); 4395 assert(isl_set_is_subset(Domain, TargetDomain) && 4396 "Target access not defined for complete statement domain"); 4397 assert(isl_set_is_subset(Domain, SourceDomain) && 4398 "Source access not defined for complete statement domain"); 4399 isl_set_free(SourceDomain); 4400 isl_set_free(TargetDomain); 4401 #endif 4402 Stmts.emplace_back(*this, SourceRel, TargetRel, Domain); 4403 CopyStmtsNum++; 4404 return &(Stmts.back()); 4405 } 4406 4407 void Scop::buildSchedule(LoopInfo &LI) { 4408 Loop *L = getLoopSurroundingScop(*this, LI); 4409 LoopStackTy LoopStack({LoopStackElementTy(L, nullptr, 0)}); 4410 buildSchedule(getRegion().getNode(), LoopStack, LI); 4411 assert(LoopStack.size() == 1 && LoopStack.back().L == L); 4412 Schedule = LoopStack[0].Schedule; 4413 } 4414 4415 /// To generate a schedule for the elements in a Region we traverse the Region 4416 /// in reverse-post-order and add the contained RegionNodes in traversal order 4417 /// to the schedule of the loop that is currently at the top of the LoopStack. 4418 /// For loop-free codes, this results in a correct sequential ordering. 4419 /// 4420 /// Example: 4421 /// bb1(0) 4422 /// / \. 4423 /// bb2(1) bb3(2) 4424 /// \ / \. 4425 /// bb4(3) bb5(4) 4426 /// \ / 4427 /// bb6(5) 4428 /// 4429 /// Including loops requires additional processing. Whenever a loop header is 4430 /// encountered, the corresponding loop is added to the @p LoopStack. Starting 4431 /// from an empty schedule, we first process all RegionNodes that are within 4432 /// this loop and complete the sequential schedule at this loop-level before 4433 /// processing about any other nodes. To implement this 4434 /// loop-nodes-first-processing, the reverse post-order traversal is 4435 /// insufficient. Hence, we additionally check if the traversal yields 4436 /// sub-regions or blocks that are outside the last loop on the @p LoopStack. 4437 /// These region-nodes are then queue and only traverse after the all nodes 4438 /// within the current loop have been processed. 4439 void Scop::buildSchedule(Region *R, LoopStackTy &LoopStack, LoopInfo &LI) { 4440 Loop *OuterScopLoop = getLoopSurroundingScop(*this, LI); 4441 4442 ReversePostOrderTraversal<Region *> RTraversal(R); 4443 std::deque<RegionNode *> WorkList(RTraversal.begin(), RTraversal.end()); 4444 std::deque<RegionNode *> DelayList; 4445 bool LastRNWaiting = false; 4446 4447 // Iterate over the region @p R in reverse post-order but queue 4448 // sub-regions/blocks iff they are not part of the last encountered but not 4449 // completely traversed loop. The variable LastRNWaiting is a flag to indicate 4450 // that we queued the last sub-region/block from the reverse post-order 4451 // iterator. If it is set we have to explore the next sub-region/block from 4452 // the iterator (if any) to guarantee progress. If it is not set we first try 4453 // the next queued sub-region/blocks. 4454 while (!WorkList.empty() || !DelayList.empty()) { 4455 RegionNode *RN; 4456 4457 if ((LastRNWaiting && !WorkList.empty()) || DelayList.size() == 0) { 4458 RN = WorkList.front(); 4459 WorkList.pop_front(); 4460 LastRNWaiting = false; 4461 } else { 4462 RN = DelayList.front(); 4463 DelayList.pop_front(); 4464 } 4465 4466 Loop *L = getRegionNodeLoop(RN, LI); 4467 if (!contains(L)) 4468 L = OuterScopLoop; 4469 4470 Loop *LastLoop = LoopStack.back().L; 4471 if (LastLoop != L) { 4472 if (LastLoop && !LastLoop->contains(L)) { 4473 LastRNWaiting = true; 4474 DelayList.push_back(RN); 4475 continue; 4476 } 4477 LoopStack.push_back({L, nullptr, 0}); 4478 } 4479 buildSchedule(RN, LoopStack, LI); 4480 } 4481 4482 return; 4483 } 4484 4485 void Scop::buildSchedule(RegionNode *RN, LoopStackTy &LoopStack, LoopInfo &LI) { 4486 4487 if (RN->isSubRegion()) { 4488 auto *LocalRegion = RN->getNodeAs<Region>(); 4489 if (!isNonAffineSubRegion(LocalRegion)) { 4490 buildSchedule(LocalRegion, LoopStack, LI); 4491 return; 4492 } 4493 } 4494 4495 auto &LoopData = LoopStack.back(); 4496 LoopData.NumBlocksProcessed += getNumBlocksInRegionNode(RN); 4497 4498 if (auto *Stmt = getStmtFor(RN)) { 4499 auto *UDomain = isl_union_set_from_set(Stmt->getDomain()); 4500 auto *StmtSchedule = isl_schedule_from_domain(UDomain); 4501 LoopData.Schedule = combineInSequence(LoopData.Schedule, StmtSchedule); 4502 } 4503 4504 // Check if we just processed the last node in this loop. If we did, finalize 4505 // the loop by: 4506 // 4507 // - adding new schedule dimensions 4508 // - folding the resulting schedule into the parent loop schedule 4509 // - dropping the loop schedule from the LoopStack. 4510 // 4511 // Then continue to check surrounding loops, which might also have been 4512 // completed by this node. 4513 while (LoopData.L && 4514 LoopData.NumBlocksProcessed == LoopData.L->getNumBlocks()) { 4515 auto *Schedule = LoopData.Schedule; 4516 auto NumBlocksProcessed = LoopData.NumBlocksProcessed; 4517 4518 LoopStack.pop_back(); 4519 auto &NextLoopData = LoopStack.back(); 4520 4521 if (Schedule) { 4522 auto *Domain = isl_schedule_get_domain(Schedule); 4523 auto *MUPA = mapToDimension(Domain, LoopStack.size()); 4524 Schedule = isl_schedule_insert_partial_schedule(Schedule, MUPA); 4525 NextLoopData.Schedule = 4526 combineInSequence(NextLoopData.Schedule, Schedule); 4527 } 4528 4529 NextLoopData.NumBlocksProcessed += NumBlocksProcessed; 4530 LoopData = NextLoopData; 4531 } 4532 } 4533 4534 ScopStmt *Scop::getStmtFor(BasicBlock *BB) const { 4535 auto StmtMapIt = StmtMap.find(BB); 4536 if (StmtMapIt == StmtMap.end()) 4537 return nullptr; 4538 return StmtMapIt->second; 4539 } 4540 4541 ScopStmt *Scop::getStmtFor(RegionNode *RN) const { 4542 if (RN->isSubRegion()) 4543 return getStmtFor(RN->getNodeAs<Region>()); 4544 return getStmtFor(RN->getNodeAs<BasicBlock>()); 4545 } 4546 4547 ScopStmt *Scop::getStmtFor(Region *R) const { 4548 ScopStmt *Stmt = getStmtFor(R->getEntry()); 4549 assert(!Stmt || Stmt->getRegion() == R); 4550 return Stmt; 4551 } 4552 4553 int Scop::getRelativeLoopDepth(const Loop *L) const { 4554 Loop *OuterLoop = 4555 L ? R.outermostLoopInRegion(const_cast<Loop *>(L)) : nullptr; 4556 if (!OuterLoop) 4557 return -1; 4558 return L->getLoopDepth() - OuterLoop->getLoopDepth(); 4559 } 4560 4561 ScopArrayInfo *Scop::getArrayInfoByName(const std::string BaseName) { 4562 for (auto &SAI : arrays()) { 4563 if (SAI->getName() == BaseName) 4564 return SAI; 4565 } 4566 return nullptr; 4567 } 4568 4569 //===----------------------------------------------------------------------===// 4570 void ScopInfoRegionPass::getAnalysisUsage(AnalysisUsage &AU) const { 4571 AU.addRequired<LoopInfoWrapperPass>(); 4572 AU.addRequired<RegionInfoPass>(); 4573 AU.addRequired<DominatorTreeWrapperPass>(); 4574 AU.addRequiredTransitive<ScalarEvolutionWrapperPass>(); 4575 AU.addRequiredTransitive<ScopDetection>(); 4576 AU.addRequired<AAResultsWrapperPass>(); 4577 AU.setPreservesAll(); 4578 } 4579 4580 void updateLoopCountStatistic(ScopDetection::LoopStats Stats) { 4581 NumLoopsInScop += Stats.NumLoops; 4582 MaxNumLoopsInScop = 4583 std::max(MaxNumLoopsInScop.getValue(), (unsigned)Stats.NumLoops); 4584 4585 if (Stats.MaxDepth == 1) 4586 NumScopsDepthOne++; 4587 else if (Stats.MaxDepth == 2) 4588 NumScopsDepthTwo++; 4589 else if (Stats.MaxDepth == 3) 4590 NumScopsDepthThree++; 4591 else if (Stats.MaxDepth == 4) 4592 NumScopsDepthFour++; 4593 else if (Stats.MaxDepth == 5) 4594 NumScopsDepthFive++; 4595 else 4596 NumScopsDepthLarger++; 4597 } 4598 4599 bool ScopInfoRegionPass::runOnRegion(Region *R, RGPassManager &RGM) { 4600 auto &SD = getAnalysis<ScopDetection>(); 4601 4602 if (!SD.isMaxRegionInScop(*R)) 4603 return false; 4604 4605 Function *F = R->getEntry()->getParent(); 4606 auto &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE(); 4607 auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); 4608 auto &AA = getAnalysis<AAResultsWrapperPass>().getAAResults(); 4609 auto const &DL = F->getParent()->getDataLayout(); 4610 auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree(); 4611 4612 ScopBuilder SB(R, AA, DL, DT, LI, SD, SE); 4613 S = SB.getScop(); // take ownership of scop object 4614 4615 if (S) { 4616 ScopDetection::LoopStats Stats = 4617 ScopDetection::countBeneficialLoops(&S->getRegion(), SE, LI, 0); 4618 updateLoopCountStatistic(Stats); 4619 } 4620 4621 return false; 4622 } 4623 4624 void ScopInfoRegionPass::print(raw_ostream &OS, const Module *) const { 4625 if (S) 4626 S->print(OS); 4627 else 4628 OS << "Invalid Scop!\n"; 4629 } 4630 4631 char ScopInfoRegionPass::ID = 0; 4632 4633 Pass *polly::createScopInfoRegionPassPass() { return new ScopInfoRegionPass(); } 4634 4635 INITIALIZE_PASS_BEGIN(ScopInfoRegionPass, "polly-scops", 4636 "Polly - Create polyhedral description of Scops", false, 4637 false); 4638 INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass); 4639 INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass); 4640 INITIALIZE_PASS_DEPENDENCY(RegionInfoPass); 4641 INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass); 4642 INITIALIZE_PASS_DEPENDENCY(ScopDetection); 4643 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass); 4644 INITIALIZE_PASS_END(ScopInfoRegionPass, "polly-scops", 4645 "Polly - Create polyhedral description of Scops", false, 4646 false) 4647 4648 //===----------------------------------------------------------------------===// 4649 void ScopInfoWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { 4650 AU.addRequired<LoopInfoWrapperPass>(); 4651 AU.addRequired<RegionInfoPass>(); 4652 AU.addRequired<DominatorTreeWrapperPass>(); 4653 AU.addRequiredTransitive<ScalarEvolutionWrapperPass>(); 4654 AU.addRequiredTransitive<ScopDetection>(); 4655 AU.addRequired<AAResultsWrapperPass>(); 4656 AU.setPreservesAll(); 4657 } 4658 4659 bool ScopInfoWrapperPass::runOnFunction(Function &F) { 4660 auto &SD = getAnalysis<ScopDetection>(); 4661 4662 auto &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE(); 4663 auto &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo(); 4664 auto &AA = getAnalysis<AAResultsWrapperPass>().getAAResults(); 4665 auto const &DL = F.getParent()->getDataLayout(); 4666 auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree(); 4667 4668 /// Create polyhedral descripton of scops for all the valid regions of a 4669 /// function. 4670 for (auto &It : SD) { 4671 Region *R = const_cast<Region *>(It); 4672 if (!SD.isMaxRegionInScop(*R)) 4673 continue; 4674 4675 ScopBuilder SB(R, AA, DL, DT, LI, SD, SE); 4676 std::unique_ptr<Scop> S = SB.getScop(); 4677 if (!S) 4678 continue; 4679 bool Inserted = 4680 RegionToScopMap.insert(std::make_pair(R, std::move(S))).second; 4681 assert(Inserted && "Building Scop for the same region twice!"); 4682 (void)Inserted; 4683 } 4684 return false; 4685 } 4686 4687 void ScopInfoWrapperPass::print(raw_ostream &OS, const Module *) const { 4688 for (auto &It : RegionToScopMap) { 4689 if (It.second) 4690 It.second->print(OS); 4691 else 4692 OS << "Invalid Scop!\n"; 4693 } 4694 } 4695 4696 char ScopInfoWrapperPass::ID = 0; 4697 4698 Pass *polly::createScopInfoWrapperPassPass() { 4699 return new ScopInfoWrapperPass(); 4700 } 4701 4702 INITIALIZE_PASS_BEGIN( 4703 ScopInfoWrapperPass, "polly-function-scops", 4704 "Polly - Create polyhedral description of all Scops of a function", false, 4705 false); 4706 INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass); 4707 INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass); 4708 INITIALIZE_PASS_DEPENDENCY(RegionInfoPass); 4709 INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass); 4710 INITIALIZE_PASS_DEPENDENCY(ScopDetection); 4711 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass); 4712 INITIALIZE_PASS_END( 4713 ScopInfoWrapperPass, "polly-function-scops", 4714 "Polly - Create polyhedral description of all Scops of a function", false, 4715 false) 4716