diff options
author | David Majnemer <david.majnemer@gmail.com> | 2016-04-19 19:10:21 +0000 |
---|---|---|
committer | David Majnemer <david.majnemer@gmail.com> | 2016-04-19 19:10:21 +0000 |
commit | b4b27230bfe2f709aac4a82522a160981472c954 (patch) | |
tree | 054736e0d3b0b3d7f0705ed8c1939d62bac88b98 /llvm/lib/Analysis | |
parent | 01b705e9c05316fd5cfce9115449b72f5f8610c5 (diff) | |
download | bcm5719-llvm-b4b27230bfe2f709aac4a82522a160981472c954.tar.gz bcm5719-llvm-b4b27230bfe2f709aac4a82522a160981472c954.zip |
[ValueTracking, VectorUtils] Refactor getIntrinsicIDForCall
The functionality contained within getIntrinsicIDForCall is two-fold: it
checks if a CallInst's callee is a vectorizable intrinsic. If it isn't
an intrinsic, it attempts to map the call's target to a suitable
intrinsic.
Move the mapping functionality into getIntrinsicForCallSite and rename
getIntrinsicIDForCall to getVectorIntrinsicIDForCall while
reimplementing it in terms of getIntrinsicForCallSite.
llvm-svn: 266801
Diffstat (limited to 'llvm/lib/Analysis')
-rw-r--r-- | llvm/lib/Analysis/LoopAccessAnalysis.cpp | 2 | ||||
-rw-r--r-- | llvm/lib/Analysis/ValueTracking.cpp | 151 | ||||
-rw-r--r-- | llvm/lib/Analysis/VectorUtils.cpp | 153 |
3 files changed, 158 insertions, 148 deletions
diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp index 222005f6f00..a7122982212 100644 --- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp +++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp @@ -1505,7 +1505,7 @@ void LoopAccessInfo::analyzeLoop(const ValueToValueMap &Strides) { // vectorize a loop if it contains known function calls that don't set // the flag. Therefore, it is safe to ignore this read from memory. CallInst *Call = dyn_cast<CallInst>(it); - if (Call && getIntrinsicIDForCall(Call, TLI)) + if (Call && getVectorIntrinsicIDForCall(Call, TLI)) continue; // If the function has an explicit vectorized counterpart, we can safely diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index bea414a34b3..f6a713f89ad 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -2262,6 +2262,153 @@ bool llvm::ComputeMultiple(Value *V, unsigned Base, Value *&Multiple, return false; } +/// \brief Check call has a unary float signature +/// It checks following: +/// a) call should have a single argument +/// b) argument type should be floating point type +/// c) call instruction type and argument type should be same +/// d) call should only reads memory. +/// If all these condition is met then return ValidIntrinsicID +/// else return not_intrinsic. +static Intrinsic::ID checkUnaryFloatSignature(ImmutableCallSite ICS, + Intrinsic::ID ValidIntrinsicID) { + if (ICS.getNumArgOperands() != 1 || + !ICS.getArgOperand(0)->getType()->isFloatingPointTy() || + ICS.getType() != ICS.getArgOperand(0)->getType() || + !ICS.onlyReadsMemory()) + return Intrinsic::not_intrinsic; + + return ValidIntrinsicID; +} + +/// \brief Check call has a binary float signature +/// It checks following: +/// a) call should have 2 arguments. +/// b) arguments type should be floating point type +/// c) call instruction type and arguments type should be same +/// d) call should only reads memory. +/// If all these condition is met then return ValidIntrinsicID +/// else return not_intrinsic. +static Intrinsic::ID checkBinaryFloatSignature(ImmutableCallSite ICS, + Intrinsic::ID ValidIntrinsicID) { + if (ICS.getNumArgOperands() != 2 || + !ICS.getArgOperand(0)->getType()->isFloatingPointTy() || + !ICS.getArgOperand(1)->getType()->isFloatingPointTy() || + ICS.getType() != ICS.getArgOperand(0)->getType() || + ICS.getType() != ICS.getArgOperand(1)->getType() || + !ICS.onlyReadsMemory()) + return Intrinsic::not_intrinsic; + + return ValidIntrinsicID; +} + +Intrinsic::ID llvm::getIntrinsicForCallSite(ImmutableCallSite ICS, + const TargetLibraryInfo *TLI) { + const Function *F = ICS.getCalledFunction(); + if (!F) + return Intrinsic::not_intrinsic; + + if (F->isIntrinsic()) + return F->getIntrinsicID(); + + if (!TLI) + return Intrinsic::not_intrinsic; + + LibFunc::Func Func; + // We're going to make assumptions on the semantics of the functions, check + // that the target knows that it's available in this environment and it does + // not have local linkage. + if (!F || F->hasLocalLinkage() || !TLI->getLibFunc(F->getName(), Func)) + return Intrinsic::not_intrinsic; + + // Otherwise check if we have a call to a function that can be turned into a + // vector intrinsic. + switch (Func) { + default: + break; + case LibFunc::sin: + case LibFunc::sinf: + case LibFunc::sinl: + return checkUnaryFloatSignature(ICS, Intrinsic::sin); + case LibFunc::cos: + case LibFunc::cosf: + case LibFunc::cosl: + return checkUnaryFloatSignature(ICS, Intrinsic::cos); + case LibFunc::exp: + case LibFunc::expf: + case LibFunc::expl: + return checkUnaryFloatSignature(ICS, Intrinsic::exp); + case LibFunc::exp2: + case LibFunc::exp2f: + case LibFunc::exp2l: + return checkUnaryFloatSignature(ICS, Intrinsic::exp2); + case LibFunc::log: + case LibFunc::logf: + case LibFunc::logl: + return checkUnaryFloatSignature(ICS, Intrinsic::log); + case LibFunc::log10: + case LibFunc::log10f: + case LibFunc::log10l: + return checkUnaryFloatSignature(ICS, Intrinsic::log10); + case LibFunc::log2: + case LibFunc::log2f: + case LibFunc::log2l: + return checkUnaryFloatSignature(ICS, Intrinsic::log2); + case LibFunc::fabs: + case LibFunc::fabsf: + case LibFunc::fabsl: + return checkUnaryFloatSignature(ICS, Intrinsic::fabs); + case LibFunc::fmin: + case LibFunc::fminf: + case LibFunc::fminl: + return checkBinaryFloatSignature(ICS, Intrinsic::minnum); + case LibFunc::fmax: + case LibFunc::fmaxf: + case LibFunc::fmaxl: + return checkBinaryFloatSignature(ICS, Intrinsic::maxnum); + case LibFunc::copysign: + case LibFunc::copysignf: + case LibFunc::copysignl: + return checkBinaryFloatSignature(ICS, Intrinsic::copysign); + case LibFunc::floor: + case LibFunc::floorf: + case LibFunc::floorl: + return checkUnaryFloatSignature(ICS, Intrinsic::floor); + case LibFunc::ceil: + case LibFunc::ceilf: + case LibFunc::ceill: + return checkUnaryFloatSignature(ICS, Intrinsic::ceil); + case LibFunc::trunc: + case LibFunc::truncf: + case LibFunc::truncl: + return checkUnaryFloatSignature(ICS, Intrinsic::trunc); + case LibFunc::rint: + case LibFunc::rintf: + case LibFunc::rintl: + return checkUnaryFloatSignature(ICS, Intrinsic::rint); + case LibFunc::nearbyint: + case LibFunc::nearbyintf: + case LibFunc::nearbyintl: + return checkUnaryFloatSignature(ICS, Intrinsic::nearbyint); + case LibFunc::round: + case LibFunc::roundf: + case LibFunc::roundl: + return checkUnaryFloatSignature(ICS, Intrinsic::round); + case LibFunc::pow: + case LibFunc::powf: + case LibFunc::powl: + return checkBinaryFloatSignature(ICS, Intrinsic::pow); + case LibFunc::sqrt: + case LibFunc::sqrtf: + case LibFunc::sqrtl: + if (ICS->hasNoNaNs()) + return checkUnaryFloatSignature(ICS, Intrinsic::sqrt); + return Intrinsic::not_intrinsic; + } + + return Intrinsic::not_intrinsic; +} + /// Return true if we can prove that the specified FP value is never equal to /// -0.0. /// @@ -2298,7 +2445,7 @@ bool llvm::CannotBeNegativeZero(const Value *V, const TargetLibraryInfo *TLI, return true; if (const CallInst *CI = dyn_cast<CallInst>(I)) { - Intrinsic::ID IID = getIntrinsicIDForCall(CI, TLI); + Intrinsic::ID IID = getIntrinsicForCallSite(CI, TLI); switch (IID) { default: break; @@ -2352,7 +2499,7 @@ bool llvm::CannotBeOrderedLessThanZero(const Value *V, // Widening/narrowing never change sign. return CannotBeOrderedLessThanZero(I->getOperand(0), TLI, Depth + 1); case Instruction::Call: - Intrinsic::ID IID = getIntrinsicIDForCall(cast<CallInst>(I), TLI); + Intrinsic::ID IID = getIntrinsicForCallSite(cast<CallInst>(I), TLI); switch (IID) { default: break; diff --git a/llvm/lib/Analysis/VectorUtils.cpp b/llvm/lib/Analysis/VectorUtils.cpp index cffe033ee65..23a0de856bc 100644 --- a/llvm/lib/Analysis/VectorUtils.cpp +++ b/llvm/lib/Analysis/VectorUtils.cpp @@ -17,6 +17,7 @@ #include "llvm/Analysis/ScalarEvolutionExpressions.h" #include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/Analysis/VectorUtils.h" #include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/PatternMatch.h" @@ -78,156 +79,18 @@ bool llvm::hasVectorInstrinsicScalarOpd(Intrinsic::ID ID, } } -/// \brief Check call has a unary float signature -/// It checks following: -/// a) call should have a single argument -/// b) argument type should be floating point type -/// c) call instruction type and argument type should be same -/// d) call should only reads memory. -/// If all these condition is met then return ValidIntrinsicID -/// else return not_intrinsic. -Intrinsic::ID -llvm::checkUnaryFloatSignature(const CallInst &I, - Intrinsic::ID ValidIntrinsicID) { - if (I.getNumArgOperands() != 1 || - !I.getArgOperand(0)->getType()->isFloatingPointTy() || - I.getType() != I.getArgOperand(0)->getType() || !I.onlyReadsMemory()) - return Intrinsic::not_intrinsic; - - return ValidIntrinsicID; -} - -/// \brief Check call has a binary float signature -/// It checks following: -/// a) call should have 2 arguments. -/// b) arguments type should be floating point type -/// c) call instruction type and arguments type should be same -/// d) call should only reads memory. -/// If all these condition is met then return ValidIntrinsicID -/// else return not_intrinsic. -Intrinsic::ID -llvm::checkBinaryFloatSignature(const CallInst &I, - Intrinsic::ID ValidIntrinsicID) { - if (I.getNumArgOperands() != 2 || - !I.getArgOperand(0)->getType()->isFloatingPointTy() || - !I.getArgOperand(1)->getType()->isFloatingPointTy() || - I.getType() != I.getArgOperand(0)->getType() || - I.getType() != I.getArgOperand(1)->getType() || !I.onlyReadsMemory()) - return Intrinsic::not_intrinsic; - - return ValidIntrinsicID; -} - /// \brief Returns intrinsic ID for call. /// For the input call instruction it finds mapping intrinsic and returns /// its ID, in case it does not found it return not_intrinsic. -Intrinsic::ID llvm::getIntrinsicIDForCall(const CallInst *CI, - const TargetLibraryInfo *TLI) { - // If we have an intrinsic call, check if it is trivially vectorizable. - if (const auto *II = dyn_cast<IntrinsicInst>(CI)) { - Intrinsic::ID ID = II->getIntrinsicID(); - if (isTriviallyVectorizable(ID) || ID == Intrinsic::lifetime_start || - ID == Intrinsic::lifetime_end || ID == Intrinsic::assume) - return ID; +Intrinsic::ID llvm::getVectorIntrinsicIDForCall(const CallInst *CI, + const TargetLibraryInfo *TLI) { + Intrinsic::ID ID = getIntrinsicForCallSite(CI, TLI); + if (ID == Intrinsic::not_intrinsic) return Intrinsic::not_intrinsic; - } - - if (!TLI) - return Intrinsic::not_intrinsic; - - LibFunc::Func Func; - Function *F = CI->getCalledFunction(); - // We're going to make assumptions on the semantics of the functions, check - // that the target knows that it's available in this environment and it does - // not have local linkage. - if (!F || F->hasLocalLinkage() || !TLI->getLibFunc(F->getName(), Func)) - return Intrinsic::not_intrinsic; - - // Otherwise check if we have a call to a function that can be turned into a - // vector intrinsic. - switch (Func) { - default: - break; - case LibFunc::sin: - case LibFunc::sinf: - case LibFunc::sinl: - return checkUnaryFloatSignature(*CI, Intrinsic::sin); - case LibFunc::cos: - case LibFunc::cosf: - case LibFunc::cosl: - return checkUnaryFloatSignature(*CI, Intrinsic::cos); - case LibFunc::exp: - case LibFunc::expf: - case LibFunc::expl: - return checkUnaryFloatSignature(*CI, Intrinsic::exp); - case LibFunc::exp2: - case LibFunc::exp2f: - case LibFunc::exp2l: - return checkUnaryFloatSignature(*CI, Intrinsic::exp2); - case LibFunc::log: - case LibFunc::logf: - case LibFunc::logl: - return checkUnaryFloatSignature(*CI, Intrinsic::log); - case LibFunc::log10: - case LibFunc::log10f: - case LibFunc::log10l: - return checkUnaryFloatSignature(*CI, Intrinsic::log10); - case LibFunc::log2: - case LibFunc::log2f: - case LibFunc::log2l: - return checkUnaryFloatSignature(*CI, Intrinsic::log2); - case LibFunc::fabs: - case LibFunc::fabsf: - case LibFunc::fabsl: - return checkUnaryFloatSignature(*CI, Intrinsic::fabs); - case LibFunc::fmin: - case LibFunc::fminf: - case LibFunc::fminl: - return checkBinaryFloatSignature(*CI, Intrinsic::minnum); - case LibFunc::fmax: - case LibFunc::fmaxf: - case LibFunc::fmaxl: - return checkBinaryFloatSignature(*CI, Intrinsic::maxnum); - case LibFunc::copysign: - case LibFunc::copysignf: - case LibFunc::copysignl: - return checkBinaryFloatSignature(*CI, Intrinsic::copysign); - case LibFunc::floor: - case LibFunc::floorf: - case LibFunc::floorl: - return checkUnaryFloatSignature(*CI, Intrinsic::floor); - case LibFunc::ceil: - case LibFunc::ceilf: - case LibFunc::ceill: - return checkUnaryFloatSignature(*CI, Intrinsic::ceil); - case LibFunc::trunc: - case LibFunc::truncf: - case LibFunc::truncl: - return checkUnaryFloatSignature(*CI, Intrinsic::trunc); - case LibFunc::rint: - case LibFunc::rintf: - case LibFunc::rintl: - return checkUnaryFloatSignature(*CI, Intrinsic::rint); - case LibFunc::nearbyint: - case LibFunc::nearbyintf: - case LibFunc::nearbyintl: - return checkUnaryFloatSignature(*CI, Intrinsic::nearbyint); - case LibFunc::round: - case LibFunc::roundf: - case LibFunc::roundl: - return checkUnaryFloatSignature(*CI, Intrinsic::round); - case LibFunc::pow: - case LibFunc::powf: - case LibFunc::powl: - return checkBinaryFloatSignature(*CI, Intrinsic::pow); - case LibFunc::sqrt: - case LibFunc::sqrtf: - case LibFunc::sqrtl: - if (CI->hasNoNaNs()) - return checkUnaryFloatSignature(*CI, Intrinsic::sqrt); - return Intrinsic::not_intrinsic; - } + if (isTriviallyVectorizable(ID) || ID == Intrinsic::lifetime_start || + ID == Intrinsic::lifetime_end || ID == Intrinsic::assume) + return ID; return Intrinsic::not_intrinsic; } |