Skip to content

Commit

Permalink
[LAA] Merge memchecks for accesses separated by a constant offset
Browse files Browse the repository at this point in the history
Summary:
Often filter-like loops will do memory accesses that are
separated by constant offsets. In these cases it is
common that we will exceed the threshold for the
allowable number of checks.

However, it should be possible to merge such checks,
sice a check of any interval againt two other intervals separated
by a constant offset (a,b), (a+c, b+c) will be equivalent with
a check againt (a, b+c), as long as (a,b) and (a+c, b+c) overlap.
Assuming the loop will be executed for a sufficient number of
iterations, this will be true. If not true, checking against
(a, b+c) is still safe (although not equivalent).

As long as there are no dependencies between two accesses,
we can merge their checks into a single one. We use this
technique to construct groups of accesses, and then check
the intervals associated with the groups instead of
checking the accesses directly.

Reviewers: anemet

Subscribers: llvm-commits

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

llvm-svn: 241673
  • Loading branch information
sbaranga-arm committed Jul 8, 2015
1 parent 235c840 commit 1b6b50a
Show file tree
Hide file tree
Showing 6 changed files with 447 additions and 53 deletions.
59 changes: 55 additions & 4 deletions llvm/include/llvm/Analysis/LoopAccessAnalysis.h
Expand Up @@ -311,7 +311,7 @@ class LoopAccessInfo {
/// This struct holds information about the memory runtime legality check that
/// a group of pointers do not overlap.
struct RuntimePointerCheck {
RuntimePointerCheck() : Need(false) {}
RuntimePointerCheck(ScalarEvolution *SE) : Need(false), SE(SE) {}

/// Reset the state of the pointer runtime information.
void reset() {
Expand All @@ -322,16 +322,55 @@ class LoopAccessInfo {
IsWritePtr.clear();
DependencySetId.clear();
AliasSetId.clear();
Exprs.clear();
}

/// Insert a pointer and calculate the start and end SCEVs.
void insert(ScalarEvolution *SE, Loop *Lp, Value *Ptr, bool WritePtr,
unsigned DepSetId, unsigned ASId,
const ValueToValueMap &Strides);
void insert(Loop *Lp, Value *Ptr, bool WritePtr, unsigned DepSetId,
unsigned ASId, const ValueToValueMap &Strides);

/// \brief No run-time memory checking is necessary.
bool empty() const { return Pointers.empty(); }

/// A grouping of pointers. A single memcheck is required between
/// two groups.
struct CheckingPtrGroup {
/// \brief Create a new pointer checking group containing a single
/// pointer, with index \p Index in RtCheck.
CheckingPtrGroup(unsigned Index, RuntimePointerCheck &RtCheck)
: RtCheck(RtCheck), High(RtCheck.Ends[Index]),
Low(RtCheck.Starts[Index]) {
Members.push_back(Index);
}

/// \brief Tries to add the pointer recorded in RtCheck at index
/// \p Index to this pointer checking group. We can only add a pointer
/// to a checking group if we will still be able to get
/// the upper and lower bounds of the check. Returns true in case
/// of success, false otherwise.
bool addPointer(unsigned Index);

/// Constitutes the context of this pointer checking group. For each
/// pointer that is a member of this group we will retain the index
/// at which it appears in RtCheck.
RuntimePointerCheck &RtCheck;
/// The SCEV expression which represents the upper bound of all the
/// pointers in this group.
const SCEV *High;
/// The SCEV expression which represents the lower bound of all the
/// pointers in this group.
const SCEV *Low;
/// Indices of all the pointers that constitute this grouping.
SmallVector<unsigned, 2> Members;
};

/// \brief Groups pointers such that a single memcheck is required
/// between two different groups. This will clear the CheckingGroups vector
/// and re-compute it. We will only group dependecies if \p UseDependencies
/// is true, otherwise we will create a separate group for each pointer.
void groupChecks(MemoryDepChecker::DepCandidates &DepCands,
bool UseDependencies);

/// \brief Decide whether we need to issue a run-time check for pointer at
/// index \p I and \p J to prove their independence.
///
Expand All @@ -341,6 +380,12 @@ class LoopAccessInfo {
bool needsChecking(unsigned I, unsigned J,
const SmallVectorImpl<int> *PtrPartition) const;

/// \brief Decide if we need to add a check between two groups of pointers,
/// according to needsChecking.
bool needsChecking(const CheckingPtrGroup &M,
const CheckingPtrGroup &N,
const SmallVectorImpl<int> *PtrPartition) const;

/// \brief Return true if any pointer requires run-time checking according
/// to needsChecking.
bool needsAnyChecking(const SmallVectorImpl<int> *PtrPartition) const;
Expand Down Expand Up @@ -372,6 +417,12 @@ class LoopAccessInfo {
SmallVector<unsigned, 2> DependencySetId;
/// Holds the id of the disjoint alias set to which this pointer belongs.
SmallVector<unsigned, 2> AliasSetId;
/// Holds at position i the SCEV for the access i
SmallVector<const SCEV *, 2> Exprs;
/// Holds a partitioning of pointers into "check groups".
SmallVector<CheckingPtrGroup, 2> CheckingGroups;
/// Holds a pointer to the ScalarEvolution analysis.
ScalarEvolution *SE;
};

LoopAccessInfo(Loop *L, ScalarEvolution *SE, const DataLayout &DL,
Expand Down

0 comments on commit 1b6b50a

Please sign in to comment.