Skip to content

Commit

Permalink
[SLPVectorizer] handle vectorizeable library functions
Browse files Browse the repository at this point in the history
Teaches the SLPVectorizer to use vectorized library functions for
non-intrinsic calls.

This already worked for intrinsics that have vectorized library
functions, thanks to D75878, but schedules with library functions with a
vector variant were being rejected early.

-   assume that there are no load/store dependencies between lib
    functions with a vector variant; this would otherwise prevent the
    bundle from becoming "ready"

-   check during legalization that the vector variant can be used

-   fix-up where we previously assumed that a call would be an intrinsic

Differential Revision: https://reviews.llvm.org/D82550
  • Loading branch information
snnw committed Jul 13, 2020
1 parent e909f6b commit 7b84045
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 181 deletions.
27 changes: 18 additions & 9 deletions llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
Expand Up @@ -3022,12 +3022,17 @@ void BoUpSLP::buildTree_rec(ArrayRef<Value *> VL, unsigned Depth,
return;
}
case Instruction::Call: {
// Check if the calls are all to the same vectorizable intrinsic.
// Check if the calls are all to the same vectorizable intrinsic or
// library function.
CallInst *CI = cast<CallInst>(VL0);
// Check if this is an Intrinsic call or something that can be
// represented by an intrinsic call
Intrinsic::ID ID = getVectorIntrinsicIDForCall(CI, TLI);
if (!isTriviallyVectorizable(ID)) {

VFShape Shape = VFShape::get(
*CI, {static_cast<unsigned int>(VL.size()), false /*Scalable*/},
false /*HasGlobalPred*/);
Function *VecFunc = VFDatabase(*CI).getVectorizedFunction(Shape);

if (!VecFunc && !isTriviallyVectorizable(ID)) {
BS.cancelScheduling(VL, VL0);
newTreeEntry(VL, None /*not vectorized*/, S, UserTreeIdx,
ReuseShuffleIndicies);
Expand All @@ -3044,6 +3049,8 @@ void BoUpSLP::buildTree_rec(ArrayRef<Value *> VL, unsigned Depth,
CallInst *CI2 = dyn_cast<CallInst>(V);
if (!CI2 || CI2->getCalledFunction() != Int ||
getVectorIntrinsicIDForCall(CI2, TLI) != ID ||
(VecFunc &&
VecFunc != VFDatabase(*CI2).getVectorizedFunction(Shape)) ||
!CI->hasIdenticalOperandBundleSchema(*CI2)) {
BS.cancelScheduling(VL, VL0);
newTreeEntry(VL, None /*not vectorized*/, S, UserTreeIdx,
Expand Down Expand Up @@ -4507,7 +4514,8 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E) {
Intrinsic::ID ID = getVectorIntrinsicIDForCall(CI, TLI);

auto VecCallCosts = getVectorCallCosts(CI, VecTy, TTI, TLI);
bool UseIntrinsic = VecCallCosts.first <= VecCallCosts.second;
bool UseIntrinsic = ID != Intrinsic::not_intrinsic &&
VecCallCosts.first <= VecCallCosts.second;

Value *ScalarArg = nullptr;
std::vector<Value *> OpVecs;
Expand All @@ -4527,15 +4535,16 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E) {
OpVecs.push_back(OpVec);
}

Module *M = F->getParent();
Type *Tys[] = {FixedVectorType::get(CI->getType(), E->Scalars.size())};
Function *CF = Intrinsic::getDeclaration(M, ID, Tys);

Function *CF;
if (!UseIntrinsic) {
VFShape Shape = VFShape::get(
*CI, {static_cast<unsigned>(VecTy->getNumElements()), false},
false /*HasGlobalPred*/);
CF = VFDatabase(*CI).getVectorizedFunction(Shape);
} else {
Module *M = F->getParent();
Type *Tys[] = {FixedVectorType::get(CI->getType(), E->Scalars.size())};
CF = Intrinsic::getDeclaration(M, ID, Tys);
}

SmallVector<OperandBundleDef, 1> OpBundles;
Expand Down

0 comments on commit 7b84045

Please sign in to comment.