Commit 71544135 authored by Dominik Adamski's avatar Dominik Adamski
Browse files

[NFC][ScopBuilder] Move RecordedAssumptions vector to ScopBuilder

Scope of changes:

1) Moved RecordedAssumptions vector to ScopBuilder. RecordedAssumptions are used only for Scop constructions.
2) Moved definition of RecordedAssumptionsTy to ScopHelper. It is required both by ScopBuilder and SCEVAffinator.
3) Add new function recordAssumption to ScopHelper. One of its argument is a reference to RecordedAssumption vector. This function is used by ScopBuilder and SCEVAffinator.
4) All RecordedAssumptions are created by ScopBuilder. isl::pw_aff
objects for corresponding SCEVs are created inside ScopBuilder. Scop
functions do not record any assumptions. Scop can use isl::pw_aff
objects which were created by ScopBuilder.
5) Removed functions for handling RecordedAssumptions from Scop class.
6) Removed constness from getScopArrayInfo functions.
7) Replaced SCEVVisitor struct from SCEVAffinator with taylored version, which allow to pass pointer to RecordedAssumptions as function argument.

Differential Revision: https://reviews.llvm.org/D68056
parent af3c243e
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -61,6 +61,18 @@ class ScopBuilder {
  // The Scop
  std::unique_ptr<Scop> scop;

  /// Collection to hold taken assumptions.
  ///
  /// There are two reasons why we want to record assumptions first before we
  /// add them to the assumed/invalid context:
  ///   1) If the SCoP is not profitable or otherwise invalid without the
  ///      assumed/invalid context we do not have to compute it.
  ///   2) Information about the context are gathered rather late in the SCoP
  ///      construction (basically after we know all parameters), thus the user
  ///      might see overly complicated assumptions to be taken while they will
  ///      only be simplified later on.
  RecordedAssumptionsTy RecordedAssumptions;

  // Methods for pattern matching against Fortran code generated by dragonegg.
  // @{

+17 −81
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@

#include "polly/ScopDetection.h"
#include "polly/Support/SCEVAffinator.h"
#include "polly/Support/ScopHelper.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SetVector.h"
@@ -54,23 +55,6 @@ extern bool UseInstructionNames;
// are also unlikely to result in good code.
extern int const MaxDisjunctsInDomain;

/// Enumeration of assumptions Polly can take.
enum AssumptionKind {
  ALIASING,
  INBOUNDS,
  WRAPPING,
  UNSIGNED,
  PROFITABLE,
  ERRORBLOCK,
  COMPLEXITY,
  INFINITELOOP,
  INVARIANTLOAD,
  DELINEARIZATION,
};

/// Enum to distinguish between assumptions and restrictions.
enum AssumptionSign { AS_ASSUMPTION, AS_RESTRICTION };

/// The different memory kinds used in Polly.
///
/// We distinguish between arrays and various scalar memory objects. We use
@@ -479,6 +463,8 @@ public:
    RT_BAND, ///< Bitwise And
  };

  using SubscriptsTy = SmallVector<const SCEV *, 4>;

private:
  /// A unique identifier for this memory access.
  ///
@@ -590,7 +576,7 @@ private:
  bool IsAffine = true;

  /// Subscript expression for each dimension.
  SmallVector<const SCEV *, 4> Subscripts;
  SubscriptsTy Subscripts;

  /// Relation from statement instances to the accessed array elements.
  ///
@@ -633,7 +619,7 @@ private:

  isl::basic_map createBasicAccessMap(ScopStmt *Statement);

  void assumeNoOutOfBound();
  isl::set assumeNoOutOfBound();

  /// Compute bounds on an over approximated  access relation.
  ///
@@ -894,6 +880,11 @@ public:
  /// Return the access instruction of this memory access.
  Instruction *getAccessInstruction() const { return AccessInstruction; }

  ///  Return an iterator range containing the subscripts.
  iterator_range<SubscriptsTy::const_iterator> subscripts() const {
    return make_range(Subscripts.begin(), Subscripts.end());
  }

  /// Return the number of access function subscript.
  unsigned getNumSubscripts() const { return Subscripts.size(); }

@@ -1624,24 +1615,6 @@ public:
/// Print ScopStmt S to raw_ostream OS.
raw_ostream &operator<<(raw_ostream &OS, const ScopStmt &S);

/// Helper struct to remember assumptions.
struct Assumption {
  /// The kind of the assumption (e.g., WRAPPING).
  AssumptionKind Kind;

  /// Flag to distinguish assumptions and restrictions.
  AssumptionSign Sign;

  /// The valid/invalid context if this is an assumption/restriction.
  isl::set Set;

  /// The location that caused this assumption.
  DebugLoc Loc;

  /// An optional block whose domain can simplify the assumption.
  BasicBlock *BB;
};

/// Build the conditions sets for the branch condition @p Condition in
/// the @p Domain.
///
@@ -1838,19 +1811,6 @@ private:
  /// need to be "false". Otherwise they behave the same.
  isl::set InvalidContext;

  using RecordedAssumptionsTy = SmallVector<Assumption, 8>;
  /// Collection to hold taken assumptions.
  ///
  /// There are two reasons why we want to record assumptions first before we
  /// add them to the assumed/invalid context:
  ///   1) If the SCoP is not profitable or otherwise invalid without the
  ///      assumed/invalid context we do not have to compute it.
  ///   2) Information about the context are gathered rather late in the SCoP
  ///      construction (basically after we know all parameters), thus the user
  ///      might see overly complicated assumptions to be taken while they will
  ///      only be simplified later on.
  RecordedAssumptionsTy RecordedAssumptions;

  /// The schedule of the SCoP
  ///
  /// The schedule of the SCoP describes the execution order of the statements
@@ -2129,12 +2089,6 @@ public:
                      InvariantEquivClasses.end());
  }

  /// Return an iterator range containing hold assumptions.
  iterator_range<RecordedAssumptionsTy::const_iterator>
  recorded_assumptions() const {
    return make_range(RecordedAssumptions.begin(), RecordedAssumptions.end());
  }

  /// Return an iterator range containing all the MemoryAccess objects of the
  /// Scop.
  iterator_range<AccFuncVector::iterator> access_functions() {
@@ -2297,9 +2251,6 @@ public:
  /// @returns True if the optimized SCoP can be executed.
  bool hasFeasibleRuntimeContext() const;

  /// Clear assumptions which have been already processed.
  void clearRecordedAssumptions() { return RecordedAssumptions.clear(); }

  /// Check if the assumption in @p Set is trivial or not.
  ///
  /// @param Set  The relations between parameters that are assumed to hold.
@@ -2347,24 +2298,6 @@ public:
  void addAssumption(AssumptionKind Kind, isl::set Set, DebugLoc Loc,
                     AssumptionSign Sign, BasicBlock *BB);

  /// Record an assumption for later addition to the assumed context.
  ///
  /// This function will add the assumption to the RecordedAssumptions. This
  /// collection will be added (@see addAssumption) to the assumed context once
  /// all paramaters are known and the context is fully built.
  ///
  /// @param Kind The assumption kind describing the underlying cause.
  /// @param Set  The relations between parameters that are assumed to hold.
  /// @param Loc  The location in the source that caused this assumption.
  /// @param Sign Enum to indicate if the assumptions in @p Set are positive
  ///             (needed/assumptions) or negative (invalid/restrictions).
  /// @param BB   The block in which this assumption was taken. If it is
  ///             set, the domain of that block will be used to simplify the
  ///             actual assumption in @p Set once it is added. This is useful
  ///             if the assumption was created prior to the domain.
  void recordAssumption(AssumptionKind Kind, isl::set Set, DebugLoc Loc,
                        AssumptionSign Sign, BasicBlock *BB = nullptr);

  /// Mark the scop as invalid.
  ///
  /// This method adds an assumption to the scop that is always invalid. As a
@@ -2504,7 +2437,7 @@ public:
  ///
  /// @returns The ScopArrayInfo pointer or NULL if no such pointer is
  ///          available.
  const ScopArrayInfo *getScopArrayInfoOrNull(Value *BasePtr, MemoryKind Kind);
  ScopArrayInfo *getScopArrayInfoOrNull(Value *BasePtr, MemoryKind Kind);

  /// Return the cached ScopArrayInfo object for @p BasePtr.
  ///
@@ -2513,7 +2446,7 @@ public:
  ///
  /// @returns The ScopArrayInfo pointer (may assert if no such pointer is
  ///          available).
  const ScopArrayInfo *getScopArrayInfo(Value *BasePtr, MemoryKind Kind);
  ScopArrayInfo *getScopArrayInfo(Value *BasePtr, MemoryKind Kind);

  /// Invalidate ScopArrayInfo object for base address.
  ///
@@ -2589,13 +2522,16 @@ public:
  /// a dummy value of appropriate dimension is returned. This allows to bail
  /// for complex cases without "error handling code" needed on the users side.
  PWACtx getPwAff(const SCEV *E, BasicBlock *BB = nullptr,
                  bool NonNegative = false);
                  bool NonNegative = false,
                  RecordedAssumptionsTy *RecordedAssumptions = nullptr);

  /// Compute the isl representation for the SCEV @p E
  ///
  /// This function is like @see Scop::getPwAff() but strips away the invalid
  /// domain part associated with the piecewise affine function.
  isl::pw_aff getPwAffOnly(const SCEV *E, BasicBlock *BB = nullptr);
  isl::pw_aff
  getPwAffOnly(const SCEV *E, BasicBlock *BB = nullptr,
               RecordedAssumptionsTy *RecordedAssumptions = nullptr);

  /// Check if an <nsw> AddRec for the loop L is cached.
  bool hasNSWAddRecForLoop(Loop *L) { return Affinator.hasNSWAddRecForLoop(L); }
+6 −2
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#ifndef POLLY_SCEV_AFFINATOR_H
#define POLLY_SCEV_AFFINATOR_H

#include "polly/Support/ScopHelper.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "isl/isl-noexceptions.h"

@@ -36,10 +37,12 @@ public:
  /// @param BB The block in which @p E is executed.
  ///
  /// @returns The isl representation of the SCEV @p E in @p Domain.
  PWACtx getPwAff(const llvm::SCEV *E, llvm::BasicBlock *BB = nullptr);
  PWACtx getPwAff(const llvm::SCEV *E, llvm::BasicBlock *BB = nullptr,
                  RecordedAssumptionsTy *RecordedAssumptions = nullptr);

  /// Take the assumption that @p PWAC is non-negative.
  void takeNonNegativeAssumption(PWACtx &PWAC);
  void takeNonNegativeAssumption(
      PWACtx &PWAC, RecordedAssumptionsTy *RecordedAssumptions = nullptr);

  /// Interpret the PWA in @p PWAC as an unsigned value.
  void interpretAsUnsigned(PWACtx &PWAC, unsigned Width);
@@ -63,6 +66,7 @@ private:
  llvm::ScalarEvolution &SE;
  llvm::LoopInfo &LI;
  llvm::BasicBlock *BB;
  RecordedAssumptionsTy *RecordedAssumptions = nullptr;

  /// Target data for element size computing.
  const llvm::DataLayout &TD;
+58 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/ValueHandle.h"
#include "isl/isl-noexceptions.h"

namespace llvm {
class LoopInfo;
@@ -34,6 +35,63 @@ namespace polly {
class Scop;
class ScopStmt;

/// Enumeration of assumptions Polly can take.
enum AssumptionKind {
  ALIASING,
  INBOUNDS,
  WRAPPING,
  UNSIGNED,
  PROFITABLE,
  ERRORBLOCK,
  COMPLEXITY,
  INFINITELOOP,
  INVARIANTLOAD,
  DELINEARIZATION,
};

/// Enum to distinguish between assumptions and restrictions.
enum AssumptionSign { AS_ASSUMPTION, AS_RESTRICTION };

/// Helper struct to remember assumptions.
struct Assumption {
  /// The kind of the assumption (e.g., WRAPPING).
  AssumptionKind Kind;

  /// Flag to distinguish assumptions and restrictions.
  AssumptionSign Sign;

  /// The valid/invalid context if this is an assumption/restriction.
  isl::set Set;

  /// The location that caused this assumption.
  llvm::DebugLoc Loc;

  /// An optional block whose domain can simplify the assumption.
  llvm::BasicBlock *BB;
};

using RecordedAssumptionsTy = llvm::SmallVector<Assumption, 8>;

/// Record an assumption for later addition to the assumed context.
///
/// This function will add the assumption to the RecordedAssumptions. This
/// collection will be added (@see addAssumption) to the assumed context once
/// all paramaters are known and the context is fully built.
///
/// @param RecordedAssumption container which keeps all recorded assumptions.
/// @param Kind The assumption kind describing the underlying cause.
/// @param Set  The relations between parameters that are assumed to hold.
/// @param Loc  The location in the source that caused this assumption.
/// @param Sign Enum to indicate if the assumptions in @p Set are positive
///             (needed/assumptions) or negative (invalid/restrictions).
/// @param BB   The block in which this assumption was taken. If it is
///             set, the domain of that block will be used to simplify the
///             actual assumption in @p Set once it is added. This is useful
///             if the assumption was created prior to the domain.
void recordAssumption(RecordedAssumptionsTy *RecordedAssumptions,
                      AssumptionKind Kind, isl::set Set, llvm::DebugLoc Loc,
                      AssumptionSign Sign, llvm::BasicBlock *BB = nullptr);

/// Type to remap values.
using ValueMapT = llvm::DenseMap<llvm::AssertingVH<llvm::Value>,
                                 llvm::AssertingVH<llvm::Value>>;
+42 −13
Original line number Diff line number Diff line
@@ -96,6 +96,11 @@ static cl::opt<bool> PollyAllowDereferenceOfAllFunctionParams(
        " their loads. "),
    cl::Hidden, cl::init(false), cl::cat(PollyCategory));

static cl::opt<bool>
    PollyIgnoreInbounds("polly-ignore-inbounds",
                        cl::desc("Do not take inbounds assumptions at all"),
                        cl::Hidden, cl::init(false), cl::cat(PollyCategory));

static cl::opt<unsigned> RunTimeChecksMaxArraysPerGroup(
    "polly-rtc-max-arrays-per-group",
    cl::desc("The maximal number of arrays to compare in each alias group."),
@@ -344,7 +349,7 @@ __isl_give isl_pw_aff *
ScopBuilder::getPwAff(BasicBlock *BB,
                      DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
                      const SCEV *E, bool NonNegative) {
  PWACtx PWAC = scop->getPwAff(E, BB, NonNegative);
  PWACtx PWAC = scop->getPwAff(E, BB, NonNegative, &RecordedAssumptions);
  InvalidDomainMap[BB] = InvalidDomainMap[BB].unite(PWAC.second);
  return PWAC.first.release();
}
@@ -796,9 +801,8 @@ bool ScopBuilder::addLoopBoundsToHeaderDomain(
    return true;

  isl::set UnboundedCtx = Parts.first.params();
  scop->recordAssumption(INFINITELOOP, UnboundedCtx,
                         HeaderBB->getTerminator()->getDebugLoc(),
                         AS_RESTRICTION);
  recordAssumption(&RecordedAssumptions, INFINITELOOP, UnboundedCtx,
                   HeaderBB->getTerminator()->getDebugLoc(), AS_RESTRICTION);
  return true;
}

@@ -1019,9 +1023,8 @@ bool ScopBuilder::propagateInvalidStmtDomains(
    } else {
      InvalidDomain = Domain;
      isl::set DomPar = Domain.params();
      scop->recordAssumption(ERRORBLOCK, DomPar,
                             BB->getTerminator()->getDebugLoc(),
                             AS_RESTRICTION);
      recordAssumption(&RecordedAssumptions, ERRORBLOCK, DomPar,
                       BB->getTerminator()->getDebugLoc(), AS_RESTRICTION);
      Domain = isl::set::empty(Domain.get_space());
    }

@@ -1488,7 +1491,7 @@ Value *ScopBuilder::findFADAllocationInvisible(MemAccInst Inst) {
}

void ScopBuilder::addRecordedAssumptions() {
  for (auto &AS : llvm::reverse(scop->recorded_assumptions())) {
  for (auto &AS : llvm::reverse(RecordedAssumptions)) {

    if (!AS.BB) {
      scop->addAssumption(AS.Kind, AS.Set, AS.Loc, AS.Sign,
@@ -1518,7 +1521,6 @@ void ScopBuilder::addRecordedAssumptions() {

    scop->addAssumption(AS.Kind, isl::manage(S), AS.Loc, AS_RESTRICTION, AS.BB);
  }
  scop->clearRecordedAssumptions();
}

void ScopBuilder::addUserAssumptions(
@@ -2502,9 +2504,17 @@ void ScopBuilder::foldAccessRelations() {
}

void ScopBuilder::assumeNoOutOfBounds() {
  if (PollyIgnoreInbounds)
    return;
  for (auto &Stmt : *scop)
    for (auto &Access : Stmt)
      Access->assumeNoOutOfBound();
    for (auto &Access : Stmt) {
      isl::set Outside = Access->assumeNoOutOfBound();
      const auto &Loc = Access->getAccessInstruction()
                            ? Access->getAccessInstruction()->getDebugLoc()
                            : DebugLoc();
      recordAssumption(&RecordedAssumptions, INBOUNDS, Outside, Loc,
                       AS_ASSUMPTION);
    }
}

void ScopBuilder::ensureValueWrite(Instruction *Inst) {
@@ -2959,8 +2969,8 @@ bool ScopBuilder::canAlwaysBeHoisted(MemoryAccess *MA,
  // Even if the statement is not modeled precisely we can hoist the load if it
  // does not involve any parameters that might have been specialized by the
  // statement domain.
  for (unsigned u = 0, e = MA->getNumSubscripts(); u < e; u++)
    if (!isa<SCEVConstant>(MA->getSubscript(u)))
  for (const SCEV *Subscript : MA->subscripts())
    if (!isa<SCEVConstant>(Subscript))
      return false;
  return true;
}
@@ -3214,8 +3224,26 @@ void ScopBuilder::buildAccessRelations(ScopStmt &Stmt) {
    else
      Ty = MemoryKind::Array;

    // Create isl::pw_aff for SCEVs which describe sizes. Collect all
    // assumptions which are taken. isl::pw_aff objects are cached internally
    // and they are used later by scop.
    for (const SCEV *Size : Access->Sizes) {
      if (!Size)
        continue;
      scop->getPwAff(Size, nullptr, false, &RecordedAssumptions);
    }
    auto *SAI = scop->getOrCreateScopArrayInfo(Access->getOriginalBaseAddr(),
                                               ElementType, Access->Sizes, Ty);

    // Create isl::pw_aff for SCEVs which describe subscripts. Collect all
    // assumptions which are taken. isl::pw_aff objects are cached internally
    // and they are used later by scop.
    for (const SCEV *Subscript : Access->subscripts()) {
      if (!Access->isAffine() || !Subscript)
        continue;
      scop->getPwAff(Subscript, Stmt.getEntryBlock(), false,
                     &RecordedAssumptions);
    }
    Access->buildAccessRelation(SAI);
    scop->addAccessData(Access);
  }
@@ -3768,6 +3796,7 @@ ScopBuilder::ScopBuilder(Region *R, AssumptionCache &AC, AliasAnalysis &AA,
    InfeasibleScops++;
    Msg = "SCoP ends here but was dismissed.";
    LLVM_DEBUG(dbgs() << "SCoP detected but dismissed\n");
    RecordedAssumptions.clear();
    scop.reset();
  } else {
    Msg = "SCoP ends here.";
Loading