Skip to content

Commit

Permalink
[SLP] Fix PR36481: vectorize reassociated instructions.
Browse files Browse the repository at this point in the history
Summary:
If the load/extractelement/extractvalue instructions are not originally
consecutive, the SLP vectorizer is unable to vectorize them. Patch
allows reordering of such instructions.

Patch does not support reordering of the repeated instruction, this must
be handled in the separate patch.

Reviewers: RKSimon, spatel, hfinkel, mkuper, Ayal, ashahid

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D43776

llvm-svn: 329085
  • Loading branch information
alexey-bataev committed Apr 3, 2018
1 parent be1e262 commit 428e9d9
Show file tree
Hide file tree
Showing 12 changed files with 429 additions and 278 deletions.
14 changes: 14 additions & 0 deletions llvm/include/llvm/Analysis/LoopAccessAnalysis.h
Expand Up @@ -667,6 +667,20 @@ int64_t getPtrStride(PredicatedScalarEvolution &PSE, Value *Ptr, const Loop *Lp,
const ValueToValueMap &StridesMap = ValueToValueMap(),
bool Assume = false, bool ShouldCheckWrap = true);

/// \brief Attempt to sort the pointers in \p VL and return the sorted indices
/// in \p SortedIndices, if reordering is required.
///
/// Returns 'true' if sorting is legal, otherwise returns 'false'.
///
/// For example, for a given \p VL of memory accesses in program order, a[i+4],
/// a[i+0], a[i+1] and a[i+7], this function will sort the \p VL and save the
/// sorted indices in \p SortedIndices as a[i+0], a[i+1], a[i+4], a[i+7] and
/// saves the mask for actual memory accesses in program order in
/// \p SortedIndices as <1,2,0,3>
bool sortPtrAccesses(ArrayRef<Value *> VL, const DataLayout &DL,
ScalarEvolution &SE,
SmallVectorImpl<unsigned> &SortedIndices);

/// \brief Returns true if the memory operations \p A and \p B are consecutive.
/// This is a simple API that does not depend on the analysis pass.
bool isConsecutiveAccess(Value *A, Value *B, const DataLayout &DL,
Expand Down
61 changes: 61 additions & 0 deletions llvm/lib/Analysis/LoopAccessAnalysis.cpp
Expand Up @@ -1087,6 +1087,67 @@ int64_t llvm::getPtrStride(PredicatedScalarEvolution &PSE, Value *Ptr,
return Stride;
}

bool llvm::sortPtrAccesses(ArrayRef<Value *> VL, const DataLayout &DL,
ScalarEvolution &SE,
SmallVectorImpl<unsigned> &SortedIndices) {
assert(llvm::all_of(
VL, [](const Value *V) { return V->getType()->isPointerTy(); }) &&
"Expected list of pointer operands.");
SmallVector<std::pair<int64_t, Value *>, 4> OffValPairs;
OffValPairs.reserve(VL.size());

// Walk over the pointers, and map each of them to an offset relative to
// first pointer in the array.
Value *Ptr0 = VL[0];
const SCEV *Scev0 = SE.getSCEV(Ptr0);
Value *Obj0 = GetUnderlyingObject(Ptr0, DL);

llvm::SmallSet<int64_t, 4> Offsets;
for (auto *Ptr : VL) {
// TODO: Outline this code as a special, more time consuming, version of
// computeConstantDifference() function.
if (Ptr->getType()->getPointerAddressSpace() !=
Ptr0->getType()->getPointerAddressSpace())
return false;
// If a pointer refers to a different underlying object, bail - the
// pointers are by definition incomparable.
Value *CurrObj = GetUnderlyingObject(Ptr, DL);
if (CurrObj != Obj0)
return false;

const SCEV *Scev = SE.getSCEV(Ptr);
const auto *Diff = dyn_cast<SCEVConstant>(SE.getMinusSCEV(Scev, Scev0));
// The pointers may not have a constant offset from each other, or SCEV
// may just not be smart enough to figure out they do. Regardless,
// there's nothing we can do.
if (!Diff)
return false;

// Check if the pointer with the same offset is found.
int64_t Offset = Diff->getAPInt().getSExtValue();
if (!Offsets.insert(Offset).second)
return false;
OffValPairs.emplace_back(Offset, Ptr);
}
SortedIndices.clear();
SortedIndices.resize(VL.size());
std::iota(SortedIndices.begin(), SortedIndices.end(), 0);

// Sort the memory accesses and keep the order of their uses in UseOrder.
std::stable_sort(SortedIndices.begin(), SortedIndices.end(),
[&OffValPairs](unsigned Left, unsigned Right) {
return OffValPairs[Left].first < OffValPairs[Right].first;
});

// Check if the order is consecutive already.
if (llvm::all_of(SortedIndices, [&SortedIndices](const unsigned I) {
return I == SortedIndices[I];
}))
SortedIndices.clear();

return true;
}

/// Take the address space operand from the Load/Store instruction.
/// Returns -1 if this is not a valid Load/Store instruction.
static unsigned getAddressSpaceOperand(Value *I) {
Expand Down

0 comments on commit 428e9d9

Please sign in to comment.