19727c77dSDavid Green //=== ReplaceWithVeclib.cpp - Replace vector intrinsics with veclib calls -===//
26577cef9SLukas Sommer //
36577cef9SLukas Sommer // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
46577cef9SLukas Sommer // See https://llvm.org/LICENSE.txt for license information.
56577cef9SLukas Sommer // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66577cef9SLukas Sommer //
76577cef9SLukas Sommer //===----------------------------------------------------------------------===//
86577cef9SLukas Sommer //
96577cef9SLukas Sommer // Replaces calls to LLVM vector intrinsics (i.e., calls to LLVM intrinsics
106577cef9SLukas Sommer // with vector operands) with matching calls to functions from a vector
116577cef9SLukas Sommer // library (e.g., libmvec, SVML) according to TargetLibraryInfo.
126577cef9SLukas Sommer //
136577cef9SLukas Sommer //===----------------------------------------------------------------------===//
146577cef9SLukas Sommer 
156577cef9SLukas Sommer #include "llvm/CodeGen/ReplaceWithVeclib.h"
166577cef9SLukas Sommer #include "llvm/ADT/STLExtras.h"
176577cef9SLukas Sommer #include "llvm/ADT/Statistic.h"
186577cef9SLukas Sommer #include "llvm/Analysis/DemandedBits.h"
196577cef9SLukas Sommer #include "llvm/Analysis/GlobalsModRef.h"
206577cef9SLukas Sommer #include "llvm/Analysis/OptimizationRemarkEmitter.h"
216577cef9SLukas Sommer #include "llvm/Analysis/TargetLibraryInfo.h"
226577cef9SLukas Sommer #include "llvm/Analysis/VectorUtils.h"
236577cef9SLukas Sommer #include "llvm/CodeGen/Passes.h"
246577cef9SLukas Sommer #include "llvm/IR/IRBuilder.h"
256577cef9SLukas Sommer #include "llvm/IR/InstIterator.h"
266577cef9SLukas Sommer #include "llvm/Transforms/Utils/ModuleUtils.h"
276577cef9SLukas Sommer 
286577cef9SLukas Sommer using namespace llvm;
296577cef9SLukas Sommer 
306577cef9SLukas Sommer #define DEBUG_TYPE "replace-with-veclib"
316577cef9SLukas Sommer 
326577cef9SLukas Sommer STATISTIC(NumCallsReplaced,
336577cef9SLukas Sommer           "Number of calls to intrinsics that have been replaced.");
346577cef9SLukas Sommer 
356577cef9SLukas Sommer STATISTIC(NumTLIFuncDeclAdded,
366577cef9SLukas Sommer           "Number of vector library function declarations added.");
376577cef9SLukas Sommer 
386577cef9SLukas Sommer STATISTIC(NumFuncUsedAdded,
396577cef9SLukas Sommer           "Number of functions added to `llvm.compiler.used`");
406577cef9SLukas Sommer 
replaceWithTLIFunction(CallInst & CI,const StringRef TLIName)416577cef9SLukas Sommer static bool replaceWithTLIFunction(CallInst &CI, const StringRef TLIName) {
426577cef9SLukas Sommer   Module *M = CI.getModule();
436577cef9SLukas Sommer 
446577cef9SLukas Sommer   Function *OldFunc = CI.getCalledFunction();
456577cef9SLukas Sommer 
466577cef9SLukas Sommer   // Check if the vector library function is already declared in this module,
476577cef9SLukas Sommer   // otherwise insert it.
486577cef9SLukas Sommer   Function *TLIFunc = M->getFunction(TLIName);
496577cef9SLukas Sommer   if (!TLIFunc) {
506577cef9SLukas Sommer     TLIFunc = Function::Create(OldFunc->getFunctionType(),
516577cef9SLukas Sommer                                Function::ExternalLinkage, TLIName, *M);
526577cef9SLukas Sommer     TLIFunc->copyAttributesFrom(OldFunc);
536577cef9SLukas Sommer 
546577cef9SLukas Sommer     LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Added vector library function `"
556577cef9SLukas Sommer                       << TLIName << "` of type `" << *(TLIFunc->getType())
566577cef9SLukas Sommer                       << "` to module.\n");
576577cef9SLukas Sommer 
586577cef9SLukas Sommer     ++NumTLIFuncDeclAdded;
596577cef9SLukas Sommer 
606577cef9SLukas Sommer     // Add the freshly created function to llvm.compiler.used,
616577cef9SLukas Sommer     // similar to as it is done in InjectTLIMappings
626577cef9SLukas Sommer     appendToCompilerUsed(*M, {TLIFunc});
636577cef9SLukas Sommer 
646577cef9SLukas Sommer     LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Adding `" << TLIName
656577cef9SLukas Sommer                       << "` to `@llvm.compiler.used`.\n");
666577cef9SLukas Sommer     ++NumFuncUsedAdded;
676577cef9SLukas Sommer   }
686577cef9SLukas Sommer 
696577cef9SLukas Sommer   // Replace the call to the vector intrinsic with a call
706577cef9SLukas Sommer   // to the corresponding function from the vector library.
716577cef9SLukas Sommer   IRBuilder<> IRBuilder(&CI);
72f631173dSKazu Hirata   SmallVector<Value *> Args(CI.args());
736577cef9SLukas Sommer   // Preserve the operand bundles.
746577cef9SLukas Sommer   SmallVector<OperandBundleDef, 1> OpBundles;
756577cef9SLukas Sommer   CI.getOperandBundlesAsDefs(OpBundles);
766577cef9SLukas Sommer   CallInst *Replacement = IRBuilder.CreateCall(TLIFunc, Args, OpBundles);
776577cef9SLukas Sommer   assert(OldFunc->getFunctionType() == TLIFunc->getFunctionType() &&
786577cef9SLukas Sommer          "Expecting function types to be identical");
796577cef9SLukas Sommer   CI.replaceAllUsesWith(Replacement);
806577cef9SLukas Sommer   if (isa<FPMathOperator>(Replacement)) {
816577cef9SLukas Sommer     // Preserve fast math flags for FP math.
826577cef9SLukas Sommer     Replacement->copyFastMathFlags(&CI);
836577cef9SLukas Sommer   }
846577cef9SLukas Sommer 
856577cef9SLukas Sommer   LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Replaced call to `"
866577cef9SLukas Sommer                     << OldFunc->getName() << "` with call to `" << TLIName
876577cef9SLukas Sommer                     << "`.\n");
886577cef9SLukas Sommer   ++NumCallsReplaced;
896577cef9SLukas Sommer   return true;
906577cef9SLukas Sommer }
916577cef9SLukas Sommer 
replaceWithCallToVeclib(const TargetLibraryInfo & TLI,CallInst & CI)926577cef9SLukas Sommer static bool replaceWithCallToVeclib(const TargetLibraryInfo &TLI,
936577cef9SLukas Sommer                                     CallInst &CI) {
946577cef9SLukas Sommer   if (!CI.getCalledFunction()) {
956577cef9SLukas Sommer     return false;
966577cef9SLukas Sommer   }
976577cef9SLukas Sommer 
986577cef9SLukas Sommer   auto IntrinsicID = CI.getCalledFunction()->getIntrinsicID();
996577cef9SLukas Sommer   if (IntrinsicID == Intrinsic::not_intrinsic) {
1006577cef9SLukas Sommer     // Replacement is only performed for intrinsic functions
1016577cef9SLukas Sommer     return false;
1026577cef9SLukas Sommer   }
1036577cef9SLukas Sommer 
1046577cef9SLukas Sommer   // Convert vector arguments to scalar type and check that
1056577cef9SLukas Sommer   // all vector operands have identical vector width.
1066577cef9SLukas Sommer   ElementCount VF = ElementCount::getFixed(0);
1076577cef9SLukas Sommer   SmallVector<Type *> ScalarTypes;
108f631173dSKazu Hirata   for (auto Arg : enumerate(CI.args())) {
1096577cef9SLukas Sommer     auto *ArgType = Arg.value()->getType();
1106577cef9SLukas Sommer     // Vector calls to intrinsics can still have
1116577cef9SLukas Sommer     // scalar operands for specific arguments.
112*6f81903eSDavid Green     if (isVectorIntrinsicWithScalarOpAtArg(IntrinsicID, Arg.index())) {
1136577cef9SLukas Sommer       ScalarTypes.push_back(ArgType);
1146577cef9SLukas Sommer     } else {
1156577cef9SLukas Sommer       // The argument in this place should be a vector if
1166577cef9SLukas Sommer       // this is a call to a vector intrinsic.
1176577cef9SLukas Sommer       auto *VectorArgTy = dyn_cast<VectorType>(ArgType);
1186577cef9SLukas Sommer       if (!VectorArgTy) {
1196577cef9SLukas Sommer         // The argument is not a vector, do not perform
1206577cef9SLukas Sommer         // the replacement.
1216577cef9SLukas Sommer         return false;
1226577cef9SLukas Sommer       }
1236577cef9SLukas Sommer       ElementCount NumElements = VectorArgTy->getElementCount();
1246577cef9SLukas Sommer       if (NumElements.isScalable()) {
1256577cef9SLukas Sommer         // The current implementation does not support
1266577cef9SLukas Sommer         // scalable vectors.
1276577cef9SLukas Sommer         return false;
1286577cef9SLukas Sommer       }
1296577cef9SLukas Sommer       if (VF.isNonZero() && VF != NumElements) {
1306577cef9SLukas Sommer         // The different arguments differ in vector size.
1316577cef9SLukas Sommer         return false;
1326577cef9SLukas Sommer       } else {
1336577cef9SLukas Sommer         VF = NumElements;
1346577cef9SLukas Sommer       }
1356577cef9SLukas Sommer       ScalarTypes.push_back(VectorArgTy->getElementType());
1366577cef9SLukas Sommer     }
1376577cef9SLukas Sommer   }
1386577cef9SLukas Sommer 
1396577cef9SLukas Sommer   // Try to reconstruct the name for the scalar version of this
1406577cef9SLukas Sommer   // intrinsic using the intrinsic ID and the argument types
1416577cef9SLukas Sommer   // converted to scalar above.
1426577cef9SLukas Sommer   std::string ScalarName;
1436577cef9SLukas Sommer   if (Intrinsic::isOverloaded(IntrinsicID)) {
144bb8ce25eSJeroen Dobbelaere     ScalarName = Intrinsic::getName(IntrinsicID, ScalarTypes, CI.getModule());
1456577cef9SLukas Sommer   } else {
1466577cef9SLukas Sommer     ScalarName = Intrinsic::getName(IntrinsicID).str();
1476577cef9SLukas Sommer   }
1486577cef9SLukas Sommer 
1496577cef9SLukas Sommer   if (!TLI.isFunctionVectorizable(ScalarName)) {
1506577cef9SLukas Sommer     // The TargetLibraryInfo does not contain a vectorized version of
1516577cef9SLukas Sommer     // the scalar function.
1526577cef9SLukas Sommer     return false;
1536577cef9SLukas Sommer   }
1546577cef9SLukas Sommer 
1556577cef9SLukas Sommer   // Try to find the mapping for the scalar version of this intrinsic
1566577cef9SLukas Sommer   // and the exact vector width of the call operands in the
1576577cef9SLukas Sommer   // TargetLibraryInfo.
1586577cef9SLukas Sommer   const std::string TLIName =
1596577cef9SLukas Sommer       std::string(TLI.getVectorizedFunction(ScalarName, VF));
1606577cef9SLukas Sommer 
1616577cef9SLukas Sommer   LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Looking up TLI mapping for `"
1626577cef9SLukas Sommer                     << ScalarName << "` and vector width " << VF << ".\n");
1636577cef9SLukas Sommer 
1646577cef9SLukas Sommer   if (!TLIName.empty()) {
1656577cef9SLukas Sommer     // Found the correct mapping in the TargetLibraryInfo,
1666577cef9SLukas Sommer     // replace the call to the intrinsic with a call to
1676577cef9SLukas Sommer     // the vector library function.
1686577cef9SLukas Sommer     LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Found TLI function `" << TLIName
1696577cef9SLukas Sommer                       << "`.\n");
1706577cef9SLukas Sommer     return replaceWithTLIFunction(CI, TLIName);
1716577cef9SLukas Sommer   }
1726577cef9SLukas Sommer 
1736577cef9SLukas Sommer   return false;
1746577cef9SLukas Sommer }
1756577cef9SLukas Sommer 
runImpl(const TargetLibraryInfo & TLI,Function & F)1766577cef9SLukas Sommer static bool runImpl(const TargetLibraryInfo &TLI, Function &F) {
1776577cef9SLukas Sommer   bool Changed = false;
1786577cef9SLukas Sommer   SmallVector<CallInst *> ReplacedCalls;
1796577cef9SLukas Sommer   for (auto &I : instructions(F)) {
1806577cef9SLukas Sommer     if (auto *CI = dyn_cast<CallInst>(&I)) {
1816577cef9SLukas Sommer       if (replaceWithCallToVeclib(TLI, *CI)) {
1826577cef9SLukas Sommer         ReplacedCalls.push_back(CI);
1836577cef9SLukas Sommer         Changed = true;
1846577cef9SLukas Sommer       }
1856577cef9SLukas Sommer     }
1866577cef9SLukas Sommer   }
1876577cef9SLukas Sommer   // Erase the calls to the intrinsics that have been replaced
1886577cef9SLukas Sommer   // with calls to the vector library.
1896577cef9SLukas Sommer   for (auto *CI : ReplacedCalls) {
1906577cef9SLukas Sommer     CI->eraseFromParent();
1916577cef9SLukas Sommer   }
1926577cef9SLukas Sommer   return Changed;
1936577cef9SLukas Sommer }
1946577cef9SLukas Sommer 
1956577cef9SLukas Sommer ////////////////////////////////////////////////////////////////////////////////
1966577cef9SLukas Sommer // New pass manager implementation.
1976577cef9SLukas Sommer ////////////////////////////////////////////////////////////////////////////////
run(Function & F,FunctionAnalysisManager & AM)1986577cef9SLukas Sommer PreservedAnalyses ReplaceWithVeclib::run(Function &F,
1996577cef9SLukas Sommer                                          FunctionAnalysisManager &AM) {
2006577cef9SLukas Sommer   const TargetLibraryInfo &TLI = AM.getResult<TargetLibraryAnalysis>(F);
2016577cef9SLukas Sommer   auto Changed = runImpl(TLI, F);
2026577cef9SLukas Sommer   if (Changed) {
2036577cef9SLukas Sommer     PreservedAnalyses PA;
2046577cef9SLukas Sommer     PA.preserveSet<CFGAnalyses>();
2056577cef9SLukas Sommer     PA.preserve<TargetLibraryAnalysis>();
2066577cef9SLukas Sommer     PA.preserve<ScalarEvolutionAnalysis>();
2076577cef9SLukas Sommer     PA.preserve<LoopAccessAnalysis>();
2086577cef9SLukas Sommer     PA.preserve<DemandedBitsAnalysis>();
2096577cef9SLukas Sommer     PA.preserve<OptimizationRemarkEmitterAnalysis>();
2106577cef9SLukas Sommer     return PA;
2116577cef9SLukas Sommer   } else {
2126577cef9SLukas Sommer     // The pass did not replace any calls, hence it preserves all analyses.
2136577cef9SLukas Sommer     return PreservedAnalyses::all();
2146577cef9SLukas Sommer   }
2156577cef9SLukas Sommer }
2166577cef9SLukas Sommer 
2176577cef9SLukas Sommer ////////////////////////////////////////////////////////////////////////////////
2186577cef9SLukas Sommer // Legacy PM Implementation.
2196577cef9SLukas Sommer ////////////////////////////////////////////////////////////////////////////////
runOnFunction(Function & F)2206577cef9SLukas Sommer bool ReplaceWithVeclibLegacy::runOnFunction(Function &F) {
2216577cef9SLukas Sommer   const TargetLibraryInfo &TLI =
2226577cef9SLukas Sommer       getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
2236577cef9SLukas Sommer   return runImpl(TLI, F);
2246577cef9SLukas Sommer }
2256577cef9SLukas Sommer 
getAnalysisUsage(AnalysisUsage & AU) const2266577cef9SLukas Sommer void ReplaceWithVeclibLegacy::getAnalysisUsage(AnalysisUsage &AU) const {
2276577cef9SLukas Sommer   AU.setPreservesCFG();
2286577cef9SLukas Sommer   AU.addRequired<TargetLibraryInfoWrapperPass>();
2296577cef9SLukas Sommer   AU.addPreserved<TargetLibraryInfoWrapperPass>();
2306577cef9SLukas Sommer   AU.addPreserved<ScalarEvolutionWrapperPass>();
2316577cef9SLukas Sommer   AU.addPreserved<AAResultsWrapperPass>();
2326577cef9SLukas Sommer   AU.addPreserved<LoopAccessLegacyAnalysis>();
2336577cef9SLukas Sommer   AU.addPreserved<DemandedBitsWrapperPass>();
2346577cef9SLukas Sommer   AU.addPreserved<OptimizationRemarkEmitterWrapperPass>();
2356577cef9SLukas Sommer   AU.addPreserved<GlobalsAAWrapperPass>();
2366577cef9SLukas Sommer }
2376577cef9SLukas Sommer 
2386577cef9SLukas Sommer ////////////////////////////////////////////////////////////////////////////////
2396577cef9SLukas Sommer // Legacy Pass manager initialization
2406577cef9SLukas Sommer ////////////////////////////////////////////////////////////////////////////////
2416577cef9SLukas Sommer char ReplaceWithVeclibLegacy::ID = 0;
2426577cef9SLukas Sommer 
2436577cef9SLukas Sommer INITIALIZE_PASS_BEGIN(ReplaceWithVeclibLegacy, DEBUG_TYPE,
2446577cef9SLukas Sommer                       "Replace intrinsics with calls to vector library", false,
2456577cef9SLukas Sommer                       false)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)2466577cef9SLukas Sommer INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
2476577cef9SLukas Sommer INITIALIZE_PASS_END(ReplaceWithVeclibLegacy, DEBUG_TYPE,
2486577cef9SLukas Sommer                     "Replace intrinsics with calls to vector library", false,
2496577cef9SLukas Sommer                     false)
2506577cef9SLukas Sommer 
2516577cef9SLukas Sommer FunctionPass *llvm::createReplaceWithVeclibLegacyPass() {
2526577cef9SLukas Sommer   return new ReplaceWithVeclibLegacy();
2536577cef9SLukas Sommer }
254