Skip to content

Commit

Permalink
[SCEV][LV] Add SCEV Predicates and use them to re-implement stride ve…
Browse files Browse the repository at this point in the history
…rsioning

Summary:
SCEV Predicates represent conditions that typically cannot be derived from
static analysis, but can be used to reduce SCEV expressions to forms which are
usable for different optimizers.

ScalarEvolution now has the rewriteUsingPredicate method which can simplify a
SCEV expression using a SCEVPredicateSet. The normal workflow of a pass using
SCEVPredicates would be to hold a SCEVPredicateSet and every time assumptions
need to be made a new SCEV Predicate would be created and added to the set.
Each time after calling getSCEV, the user will call the rewriteUsingPredicate
method.

We add two types of predicates
SCEVPredicateSet - implements a set of predicates
SCEVEqualPredicate - tests for equality between two SCEV expressions

We use the SCEVEqualPredicate to re-implement stride versioning. Every time we
version a stride, we will add a SCEVEqualPredicate to the context.
Instead of adding specific stride checks, LoopVectorize now adds a more
generic SCEV check.

We only need to add support for this in the LoopVectorizer since this is the
only pass that will do stride versioning.

Reviewers: mzolotukhin, anemet, hfinkel, sanjoy

Subscribers: sanjoy, hfinkel, rengolin, jmolloy, llvm-commits

Differential Revision: http://reviews.llvm.org/D13595

llvm-svn: 251800
  • Loading branch information
sbaranga-arm committed Nov 2, 2015
1 parent 31f8888 commit e3c0534
Show file tree
Hide file tree
Showing 7 changed files with 516 additions and 132 deletions.
46 changes: 39 additions & 7 deletions llvm/include/llvm/Analysis/LoopAccessAnalysis.h
Expand Up @@ -32,6 +32,7 @@ class DataLayout;
class ScalarEvolution;
class Loop;
class SCEV;
class SCEVUnionPredicate;

/// Optimization analysis message produced during vectorization. Messages inform
/// the user why vectorization did not occur.
Expand Down Expand Up @@ -176,10 +177,11 @@ class MemoryDepChecker {
const SmallVectorImpl<Instruction *> &Instrs) const;
};

MemoryDepChecker(ScalarEvolution *Se, const Loop *L)
MemoryDepChecker(ScalarEvolution *Se, const Loop *L,
SCEVUnionPredicate &Preds)
: SE(Se), InnermostLoop(L), AccessIdx(0),
ShouldRetryWithRuntimeCheck(false), SafeForVectorization(true),
RecordInterestingDependences(true) {}
RecordInterestingDependences(true), Preds(Preds) {}

/// \brief Register the location (instructions are given increasing numbers)
/// of a write access.
Expand Down Expand Up @@ -289,6 +291,15 @@ class MemoryDepChecker {
/// \brief Check whether the data dependence could prevent store-load
/// forwarding.
bool couldPreventStoreLoadForward(unsigned Distance, unsigned TypeByteSize);

/// The SCEV predicate containing all the SCEV-related assumptions.
/// The dependence checker needs this in order to convert SCEVs of pointers
/// to more accurate expressions in the context of existing assumptions.
/// We also need this in case assumptions about SCEV expressions need to
/// be made in order to avoid unknown dependences. For example we might
/// assume a unit stride for a pointer in order to prove that a memory access
/// is strided and doesn't wrap.
SCEVUnionPredicate &Preds;
};

/// \brief Holds information about the memory runtime legality checks to verify
Expand Down Expand Up @@ -330,8 +341,13 @@ class RuntimePointerChecking {
}

/// Insert a pointer and calculate the start and end SCEVs.
/// \p We need Preds in order to compute the SCEV expression of the pointer
/// according to the assumptions that we've made during the analysis.
/// The method might also version the pointer stride according to \p Strides,
/// and change \p Preds.
void insert(Loop *Lp, Value *Ptr, bool WritePtr, unsigned DepSetId,
unsigned ASId, const ValueToValueMap &Strides);
unsigned ASId, const ValueToValueMap &Strides,
SCEVUnionPredicate &Preds);

/// \brief No run-time memory checking is necessary.
bool empty() const { return Pointers.empty(); }
Expand Down Expand Up @@ -537,6 +553,15 @@ class LoopAccessInfo {
return StoreToLoopInvariantAddress;
}

/// The SCEV predicate contains all the SCEV-related assumptions.
/// The is used to keep track of the minimal set of assumptions on SCEV
/// expressions that the analysis needs to make in order to return a
/// meaningful result. All SCEV expressions during the analysis should be
/// re-written (and therefore simplified) according to Preds.
/// A user of LoopAccessAnalysis will need to emit the runtime checks
/// associated with this predicate.
SCEVUnionPredicate Preds;

private:
/// \brief Analyze the loop. Substitute symbolic strides using Strides.
void analyzeLoop(const ValueToValueMap &Strides);
Expand Down Expand Up @@ -583,19 +608,26 @@ class LoopAccessInfo {
Value *stripIntegerCast(Value *V);

///\brief Return the SCEV corresponding to a pointer with the symbolic stride
///replaced with constant one.
/// replaced with constant one, assuming \p Preds is true.
///
/// If necessary this method will version the stride of the pointer according
/// to \p PtrToStride and therefore add a new predicate to \p Preds.
///
/// If \p OrigPtr is not null, use it to look up the stride value instead of \p
/// Ptr. \p PtrToStride provides the mapping between the pointer value and its
/// stride as collected by LoopVectorizationLegality::collectStridedAccess.
const SCEV *replaceSymbolicStrideSCEV(ScalarEvolution *SE,
const ValueToValueMap &PtrToStride,
Value *Ptr, Value *OrigPtr = nullptr);
SCEVUnionPredicate &Preds, Value *Ptr,
Value *OrigPtr = nullptr);

/// \brief Check the stride of the pointer and ensure that it does not wrap in
/// the address space.
/// the address space, assuming \p Preds is true.
///
/// If necessary this method will version the stride of the pointer according
/// to \p PtrToStride and therefore add a new predicate to \p Preds.
int isStridedPtr(ScalarEvolution *SE, Value *Ptr, const Loop *Lp,
const ValueToValueMap &StridesMap);
const ValueToValueMap &StridesMap, SCEVUnionPredicate &Preds);

/// \brief This analysis provides dependence information for the memory accesses
/// of a loop.
Expand Down
160 changes: 157 additions & 3 deletions llvm/include/llvm/Analysis/ScalarEvolution.h
Expand Up @@ -48,10 +48,15 @@ namespace llvm {
class Loop;
class LoopInfo;
class Operator;
class SCEVUnknown;
class SCEVAddRecExpr;
class SCEV;
template<> struct FoldingSetTrait<SCEV>;
class SCEVAddRecExpr;
class SCEVConstant;
class SCEVExpander;
class SCEVPredicate;
class SCEVUnknown;

template <> struct FoldingSetTrait<SCEV>;
template <> struct FoldingSetTrait<SCEVPredicate>;

/// This class represents an analyzed expression in the program. These are
/// opaque objects that the client is not allowed to do much with directly.
Expand Down Expand Up @@ -164,6 +169,148 @@ namespace llvm {
static bool classof(const SCEV *S);
};

/// SCEVPredicate - This class represents an assumption made using SCEV
/// expressions which can be checked at run-time.
class SCEVPredicate : public FoldingSetNode {
friend struct FoldingSetTrait<SCEVPredicate>;

/// A reference to an Interned FoldingSetNodeID for this node. The
/// ScalarEvolution's BumpPtrAllocator holds the data.
FoldingSetNodeIDRef FastID;

public:
enum SCEVPredicateKind { P_Union, P_Equal };

protected:
SCEVPredicateKind Kind;

public:
SCEVPredicate(const FoldingSetNodeIDRef ID, SCEVPredicateKind Kind);

virtual ~SCEVPredicate() {}

SCEVPredicateKind getKind() const { return Kind; }

/// \brief Returns the estimated complexity of this predicate.
/// This is roughly measured in the number of run-time checks required.
virtual unsigned getComplexity() { return 1; }

/// \brief Returns true if the predicate is always true. This means that no
/// assumptions were made and nothing needs to be checked at run-time.
virtual bool isAlwaysTrue() const = 0;

/// \brief Returns true if this predicate implies \p N.
virtual bool implies(const SCEVPredicate *N) const = 0;

/// \brief Prints a textual representation of this predicate with an
/// indentation of \p Depth.
virtual void print(raw_ostream &OS, unsigned Depth = 0) const = 0;

/// \brief Returns the SCEV to which this predicate applies, or nullptr
/// if this is a SCEVUnionPredicate.
virtual const SCEV *getExpr() const = 0;
};

inline raw_ostream &operator<<(raw_ostream &OS, const SCEVPredicate &P) {
P.print(OS);
return OS;
}

// Specialize FoldingSetTrait for SCEVPredicate to avoid needing to compute
// temporary FoldingSetNodeID values.
template <>
struct FoldingSetTrait<SCEVPredicate>
: DefaultFoldingSetTrait<SCEVPredicate> {

static void Profile(const SCEVPredicate &X, FoldingSetNodeID &ID) {
ID = X.FastID;
}

static bool Equals(const SCEVPredicate &X, const FoldingSetNodeID &ID,
unsigned IDHash, FoldingSetNodeID &TempID) {
return ID == X.FastID;
}
static unsigned ComputeHash(const SCEVPredicate &X,
FoldingSetNodeID &TempID) {
return X.FastID.ComputeHash();
}
};

/// SCEVEqualPredicate - This class represents an assumption that two SCEV
/// expressions are equal, and this can be checked at run-time. We assume
/// that the left hand side is a SCEVUnknown and the right hand side a
/// constant.
class SCEVEqualPredicate : public SCEVPredicate {
/// We assume that LHS == RHS, where LHS is a SCEVUnknown and RHS a
/// constant.
const SCEVUnknown *LHS;
const SCEVConstant *RHS;

public:
SCEVEqualPredicate(const FoldingSetNodeIDRef ID, const SCEVUnknown *LHS,
const SCEVConstant *RHS);

/// Implementation of the SCEVPredicate interface
bool implies(const SCEVPredicate *N) const override;
void print(raw_ostream &OS, unsigned Depth = 0) const override;
bool isAlwaysTrue() const override;
const SCEV *getExpr() const;

/// \brief Returns the left hand side of the equality.
const SCEVUnknown *getLHS() const { return LHS; }

/// \brief Returns the right hand side of the equality.
const SCEVConstant *getRHS() const { return RHS; }

/// Methods for support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const SCEVPredicate *P) {
return P->getKind() == P_Equal;
}
};

/// SCEVUnionPredicate - This class represents a composition of other
/// SCEV predicates, and is the class that most clients will interact with.
/// This is equivalent to a logical "AND" of all the predicates in the union.
class SCEVUnionPredicate : public SCEVPredicate {
private:
typedef DenseMap<const SCEV *, SmallVector<const SCEVPredicate *, 4>>
PredicateMap;

/// Vector with references to all predicates in this union.
SmallVector<const SCEVPredicate *, 16> Preds;
/// Maps SCEVs to predicates for quick look-ups.
PredicateMap SCEVToPreds;

public:
SCEVUnionPredicate();

const SmallVectorImpl<const SCEVPredicate *> &getPredicates() const {
return Preds;
}

/// \brief Adds a predicate to this union.
void add(const SCEVPredicate *N);

/// \brief Returns a reference to a vector containing all predicates
/// which apply to \p Expr.
ArrayRef<const SCEVPredicate *> getPredicatesForExpr(const SCEV *Expr);

/// Implementation of the SCEVPredicate interface
bool isAlwaysTrue() const override;
bool implies(const SCEVPredicate *N) const override;
void print(raw_ostream &OS, unsigned Depth) const;
const SCEV *getExpr() const override;

/// \brief We estimate the complexity of a union predicate as the size
/// number of predicates in the union.
unsigned getComplexity() override { return Preds.size(); }

/// Methods for support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const SCEVPredicate *P) {
return P->getKind() == P_Union;
}
};

/// The main scalar evolution driver. Because client code (intentionally)
/// can't do much with the SCEV objects directly, they must ask this class
/// for services.
Expand Down Expand Up @@ -1108,6 +1255,12 @@ namespace llvm {
return F.getParent()->getDataLayout();
}

const SCEVPredicate *getEqualPredicate(const SCEVUnknown *LHS,
const SCEVConstant *RHS);

/// Re-writes the SCEV according to the Predicates in \p Preds.
const SCEV *rewriteUsingPredicate(const SCEV *Scev, SCEVUnionPredicate &A);

private:
/// Compute the backedge taken count knowing the interval difference, the
/// stride and presence of the equality in the comparison.
Expand All @@ -1128,6 +1281,7 @@ namespace llvm {

private:
FoldingSet<SCEV> UniqueSCEVs;
FoldingSet<SCEVPredicate> UniquePreds;
BumpPtrAllocator SCEVAllocator;

/// The head of a linked list of all SCEVUnknown values that have been
Expand Down
16 changes: 16 additions & 0 deletions llvm/include/llvm/Analysis/ScalarEvolutionExpander.h
Expand Up @@ -151,6 +151,22 @@ namespace llvm {
/// block.
Value *expandCodeFor(const SCEV *SH, Type *Ty, Instruction *I);

/// \brief Generates a code sequence that evaluates this predicate.
/// The inserted instructions will be at position \p Loc.
/// The result will be of type i1 and will have a value of 0 when the
/// predicate is false and 1 otherwise.
Value *expandCodeForPredicate(const SCEVPredicate *Pred, Instruction *Loc);

/// \brief A specialized variant of expandCodeForPredicate, handling the
/// case when we are expanding code for a SCEVEqualPredicate.
Value *expandEqualPredicate(const SCEVEqualPredicate *Pred,
Instruction *Loc);

/// \brief A specialized variant of expandCodeForPredicate, handling the
/// case when we are expanding code for a SCEVUnionPredicate.
Value *expandUnionPredicate(const SCEVUnionPredicate *Pred,
Instruction *Loc);

/// \brief Set the current IV increment loop and position.
void setIVIncInsertPos(const Loop *L, Instruction *Pos) {
assert(!CanonicalMode &&
Expand Down

0 comments on commit e3c0534

Please sign in to comment.