Skip to content

Commit

Permalink
Re-commit r255115, with the PredicatedScalarEvolution class moved to
Browse files Browse the repository at this point in the history
ScalarEvolution.h, in order to avoid cyclic dependencies between the Transform
and Analysis modules:

[LV][LAA] Add a layer over SCEV to apply run-time checked knowledge on SCEV expressions

Summary:
This change creates a layer over ScalarEvolution for LAA and LV, and centralizes the
usage of SCEV predicates. The SCEVPredicatedLayer takes the statically deduced knowledge
by ScalarEvolution and applies the knowledge from the SCEV predicates. The end goal is
that both LAA and LV should use this interface everywhere.

This also solves a problem involving the result of SCEV expression rewritting when
the predicate changes. Suppose we have the expression (sext {a,+,b}) and two predicates
  P1: {a,+,b} has nsw
  P2: b = 1.

Applying P1 and then P2 gives us {a,+,1}, while applying P2 and the P1 gives us
sext({a,+,1}) (the AddRec expression was changed by P2 so P1 no longer applies).
The SCEVPredicatedLayer maintains the order of transformations by feeding back
the results of previous transformations into new transformations, and therefore
avoiding this issue.

The SCEVPredicatedLayer maintains a cache to remember the results of previous
SCEV rewritting results. This also has the benefit of reducing the overall number
of expression rewrites.

Reviewers: mzolotukhin, anemet

Subscribers: jmolloy, sanjoy, llvm-commits

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

llvm-svn: 255122
  • Loading branch information
sbaranga-arm committed Dec 9, 2015
1 parent e69df38 commit 9cd9a7e
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 165 deletions.
50 changes: 21 additions & 29 deletions llvm/include/llvm/Analysis/LoopAccessAnalysis.h
Expand Up @@ -193,11 +193,10 @@ class MemoryDepChecker {
const SmallVectorImpl<Instruction *> &Instrs) const;
};

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

/// \brief Register the location (instructions are given increasing numbers)
/// of a write access.
Expand Down Expand Up @@ -266,7 +265,13 @@ class MemoryDepChecker {
bool isWrite) const;

private:
ScalarEvolution *SE;
/// A wrapper around ScalarEvolution, used to add runtime SCEV checks, and
/// applies dynamic knowledge to simplify SCEV expressions and convert them
/// to a more usable form. We 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.
PredicatedScalarEvolution &PSE;
const Loop *InnermostLoop;

/// \brief Maps access locations (ptr, read/write) to program order.
Expand Down Expand Up @@ -317,15 +322,6 @@ 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 @@ -373,7 +369,7 @@ class RuntimePointerChecking {
/// and change \p Preds.
void insert(Loop *Lp, Value *Ptr, bool WritePtr, unsigned DepSetId,
unsigned ASId, const ValueToValueMap &Strides,
SCEVUnionPredicate &Preds);
PredicatedScalarEvolution &PSE);

/// \brief No run-time memory checking is necessary.
bool empty() const { return Pointers.empty(); }
Expand Down Expand Up @@ -508,8 +504,8 @@ class RuntimePointerChecking {
/// ScalarEvolution, we will generate run-time checks by emitting a
/// SCEVUnionPredicate.
///
/// Checks for both memory dependences and SCEV predicates must be emitted in
/// order for the results of this analysis to be valid.
/// Checks for both memory dependences and the SCEV predicates contained in the
/// PSE must be emitted in order for the results of this analysis to be valid.
class LoopAccessInfo {
public:
LoopAccessInfo(Loop *L, ScalarEvolution *SE, const DataLayout &DL,
Expand Down Expand Up @@ -591,14 +587,12 @@ 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.
/// Used to add runtime SCEV checks. Simplifies SCEV expressions and converts
/// them to a more usable form. All SCEV expressions during the analysis
/// should be re-written (and therefore simplified) according to PSE.
/// A user of LoopAccessAnalysis will need to emit the runtime checks
/// associated with this predicate.
SCEVUnionPredicate Preds;
PredicatedScalarEvolution PSE;

private:
/// \brief Analyze the loop. Substitute symbolic strides using Strides.
Expand All @@ -619,7 +613,6 @@ class LoopAccessInfo {
MemoryDepChecker DepChecker;

Loop *TheLoop;
ScalarEvolution *SE;
const DataLayout &DL;
const TargetLibraryInfo *TLI;
AliasAnalysis *AA;
Expand Down Expand Up @@ -654,18 +647,17 @@ Value *stripIntegerCast(Value *V);
/// 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 SCEV *replaceSymbolicStrideSCEV(PredicatedScalarEvolution &PSE,
const ValueToValueMap &PtrToStride,
SCEVUnionPredicate &Preds, Value *Ptr,
Value *OrigPtr = nullptr);
Value *Ptr, Value *OrigPtr = nullptr);

/// \brief Check the stride of the pointer and ensure that it does not wrap in
/// 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, SCEVUnionPredicate &Preds);
int isStridedPtr(PredicatedScalarEvolution &PSE, Value *Ptr, const Loop *Lp,
const ValueToValueMap &StridesMap);

/// \brief This analysis provides dependence information for the memory accesses
/// of a loop.
Expand Down
53 changes: 53 additions & 0 deletions llvm/include/llvm/Analysis/ScalarEvolution.h
Expand Up @@ -1324,6 +1324,59 @@ namespace llvm {
void print(raw_ostream &OS, const Module * = nullptr) const override;
void verifyAnalysis() const override;
};

/// An interface layer with SCEV used to manage how we see SCEV expressions
/// for values in the context of existing predicates. We can add new
/// predicates, but we cannot remove them.
///
/// This layer has multiple purposes:
/// - provides a simple interface for SCEV versioning.
/// - guarantees that the order of transformations applied on a SCEV
/// expression for a single Value is consistent across two different
/// getSCEV calls. This means that, for example, once we've obtained
/// an AddRec expression for a certain value through expression
/// rewriting, we will continue to get an AddRec expression for that
/// Value.
/// - lowers the number of expression rewrites.
class PredicatedScalarEvolution {
public:
PredicatedScalarEvolution(ScalarEvolution &SE);
const SCEVUnionPredicate &getUnionPredicate() const;
/// \brief Returns the SCEV expression of V, in the context of the current
/// SCEV predicate.
/// The order of transformations applied on the expression of V returned
/// by ScalarEvolution is guaranteed to be preserved, even when adding new
/// predicates.
const SCEV *getSCEV(Value *V);
/// \brief Adds a new predicate.
void addPredicate(const SCEVPredicate &Pred);
/// \brief Returns the ScalarEvolution analysis used.
ScalarEvolution *getSE() const { return &SE; }

private:
/// \brief Increments the version number of the predicate.
/// This needs to be called every time the SCEV predicate changes.
void updateGeneration();
/// Holds a SCEV and the version number of the SCEV predicate used to
/// perform the rewrite of the expression.
typedef std::pair<unsigned, const SCEV *> RewriteEntry;
/// Maps a SCEV to the rewrite result of that SCEV at a certain version
/// number. If this number doesn't match the current Generation, we will
/// need to do a rewrite. To preserve the transformation order of previous
/// rewrites, we will rewrite the previous result instead of the original
/// SCEV.
DenseMap<const SCEV *, RewriteEntry> RewriteMap;
/// The ScalarEvolution analysis.
ScalarEvolution &SE;
/// The SCEVPredicate that forms our context. We will rewrite all
/// expressions assuming that this predicate true.
SCEVUnionPredicate Preds;
/// Marks the version of the SCEV predicate used. When rewriting a SCEV
/// expression we mark it with the version of the predicate. We use this to
/// figure out if the predicate has changed from the last rewrite of the
/// SCEV. If so, we need to perform a new rewrite.
unsigned Generation;
};
}

#endif

0 comments on commit 9cd9a7e

Please sign in to comment.