brintos

brintos / llvm-project-archived public Read only

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