1 //=== ReplaceWithVeclib.cpp - Replace vector instrinsics with veclib calls ===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Replaces calls to LLVM vector intrinsics (i.e., calls to LLVM intrinsics
10 // with vector operands) with matching calls to functions from a vector
11 // library (e.g., libmvec, SVML) according to TargetLibraryInfo.
13 //===----------------------------------------------------------------------===//
15 #include "llvm/CodeGen/ReplaceWithVeclib.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/ADT/Statistic.h"
18 #include "llvm/Analysis/DemandedBits.h"
19 #include "llvm/Analysis/GlobalsModRef.h"
20 #include "llvm/Analysis/OptimizationRemarkEmitter.h"
21 #include "llvm/Analysis/TargetLibraryInfo.h"
22 #include "llvm/Analysis/VectorUtils.h"
23 #include "llvm/CodeGen/Passes.h"
24 #include "llvm/IR/IRBuilder.h"
25 #include "llvm/IR/InstIterator.h"
26 #include "llvm/IR/IntrinsicInst.h"
27 #include "llvm/Transforms/Utils/ModuleUtils.h"
31 #define DEBUG_TYPE "replace-with-veclib"
33 STATISTIC(NumCallsReplaced
,
34 "Number of calls to intrinsics that have been replaced.");
36 STATISTIC(NumTLIFuncDeclAdded
,
37 "Number of vector library function declarations added.");
39 STATISTIC(NumFuncUsedAdded
,
40 "Number of functions added to `llvm.compiler.used`");
42 static bool replaceWithTLIFunction(CallInst
&CI
, const StringRef TLIName
) {
43 Module
*M
= CI
.getModule();
45 Function
*OldFunc
= CI
.getCalledFunction();
47 // Check if the vector library function is already declared in this module,
48 // otherwise insert it.
49 Function
*TLIFunc
= M
->getFunction(TLIName
);
51 TLIFunc
= Function::Create(OldFunc
->getFunctionType(),
52 Function::ExternalLinkage
, TLIName
, *M
);
53 TLIFunc
->copyAttributesFrom(OldFunc
);
55 LLVM_DEBUG(dbgs() << DEBUG_TYPE
<< ": Added vector library function `"
56 << TLIName
<< "` of type `" << *(TLIFunc
->getType())
59 ++NumTLIFuncDeclAdded
;
61 // Add the freshly created function to llvm.compiler.used,
62 // similar to as it is done in InjectTLIMappings
63 appendToCompilerUsed(*M
, {TLIFunc
});
65 LLVM_DEBUG(dbgs() << DEBUG_TYPE
<< ": Adding `" << TLIName
66 << "` to `@llvm.compiler.used`.\n");
70 // Replace the call to the vector intrinsic with a call
71 // to the corresponding function from the vector library.
72 IRBuilder
<> IRBuilder(&CI
);
73 SmallVector
<Value
*> Args(CI
.arg_operands());
74 // Preserve the operand bundles.
75 SmallVector
<OperandBundleDef
, 1> OpBundles
;
76 CI
.getOperandBundlesAsDefs(OpBundles
);
77 CallInst
*Replacement
= IRBuilder
.CreateCall(TLIFunc
, Args
, OpBundles
);
78 assert(OldFunc
->getFunctionType() == TLIFunc
->getFunctionType() &&
79 "Expecting function types to be identical");
80 CI
.replaceAllUsesWith(Replacement
);
81 if (isa
<FPMathOperator
>(Replacement
)) {
82 // Preserve fast math flags for FP math.
83 Replacement
->copyFastMathFlags(&CI
);
86 LLVM_DEBUG(dbgs() << DEBUG_TYPE
<< ": Replaced call to `"
87 << OldFunc
->getName() << "` with call to `" << TLIName
93 static bool replaceWithCallToVeclib(const TargetLibraryInfo
&TLI
,
95 if (!CI
.getCalledFunction()) {
99 auto IntrinsicID
= CI
.getCalledFunction()->getIntrinsicID();
100 if (IntrinsicID
== Intrinsic::not_intrinsic
) {
101 // Replacement is only performed for intrinsic functions
105 // Convert vector arguments to scalar type and check that
106 // all vector operands have identical vector width.
107 ElementCount VF
= ElementCount::getFixed(0);
108 SmallVector
<Type
*> ScalarTypes
;
109 for (auto Arg
: enumerate(CI
.arg_operands())) {
110 auto *ArgType
= Arg
.value()->getType();
111 // Vector calls to intrinsics can still have
112 // scalar operands for specific arguments.
113 if (hasVectorInstrinsicScalarOpd(IntrinsicID
, Arg
.index())) {
114 ScalarTypes
.push_back(ArgType
);
116 // The argument in this place should be a vector if
117 // this is a call to a vector intrinsic.
118 auto *VectorArgTy
= dyn_cast
<VectorType
>(ArgType
);
120 // The argument is not a vector, do not perform
124 ElementCount NumElements
= VectorArgTy
->getElementCount();
125 if (NumElements
.isScalable()) {
126 // The current implementation does not support
130 if (VF
.isNonZero() && VF
!= NumElements
) {
131 // The different arguments differ in vector size.
136 ScalarTypes
.push_back(VectorArgTy
->getElementType());
140 // Try to reconstruct the name for the scalar version of this
141 // intrinsic using the intrinsic ID and the argument types
142 // converted to scalar above.
143 std::string ScalarName
;
144 if (Intrinsic::isOverloaded(IntrinsicID
)) {
145 ScalarName
= Intrinsic::getName(IntrinsicID
, ScalarTypes
, CI
.getModule());
147 ScalarName
= Intrinsic::getName(IntrinsicID
).str();
150 if (!TLI
.isFunctionVectorizable(ScalarName
)) {
151 // The TargetLibraryInfo does not contain a vectorized version of
152 // the scalar function.
156 // Try to find the mapping for the scalar version of this intrinsic
157 // and the exact vector width of the call operands in the
158 // TargetLibraryInfo.
159 const std::string TLIName
=
160 std::string(TLI
.getVectorizedFunction(ScalarName
, VF
));
162 LLVM_DEBUG(dbgs() << DEBUG_TYPE
<< ": Looking up TLI mapping for `"
163 << ScalarName
<< "` and vector width " << VF
<< ".\n");
165 if (!TLIName
.empty()) {
166 // Found the correct mapping in the TargetLibraryInfo,
167 // replace the call to the intrinsic with a call to
168 // the vector library function.
169 LLVM_DEBUG(dbgs() << DEBUG_TYPE
<< ": Found TLI function `" << TLIName
171 return replaceWithTLIFunction(CI
, TLIName
);
177 static bool runImpl(const TargetLibraryInfo
&TLI
, Function
&F
) {
178 bool Changed
= false;
179 SmallVector
<CallInst
*> ReplacedCalls
;
180 for (auto &I
: instructions(F
)) {
181 if (auto *CI
= dyn_cast
<CallInst
>(&I
)) {
182 if (replaceWithCallToVeclib(TLI
, *CI
)) {
183 ReplacedCalls
.push_back(CI
);
188 // Erase the calls to the intrinsics that have been replaced
189 // with calls to the vector library.
190 for (auto *CI
: ReplacedCalls
) {
191 CI
->eraseFromParent();
196 ////////////////////////////////////////////////////////////////////////////////
197 // New pass manager implementation.
198 ////////////////////////////////////////////////////////////////////////////////
199 PreservedAnalyses
ReplaceWithVeclib::run(Function
&F
,
200 FunctionAnalysisManager
&AM
) {
201 const TargetLibraryInfo
&TLI
= AM
.getResult
<TargetLibraryAnalysis
>(F
);
202 auto Changed
= runImpl(TLI
, F
);
204 PreservedAnalyses PA
;
205 PA
.preserveSet
<CFGAnalyses
>();
206 PA
.preserve
<TargetLibraryAnalysis
>();
207 PA
.preserve
<ScalarEvolutionAnalysis
>();
208 PA
.preserve
<LoopAccessAnalysis
>();
209 PA
.preserve
<DemandedBitsAnalysis
>();
210 PA
.preserve
<OptimizationRemarkEmitterAnalysis
>();
213 // The pass did not replace any calls, hence it preserves all analyses.
214 return PreservedAnalyses::all();
218 ////////////////////////////////////////////////////////////////////////////////
219 // Legacy PM Implementation.
220 ////////////////////////////////////////////////////////////////////////////////
221 bool ReplaceWithVeclibLegacy::runOnFunction(Function
&F
) {
222 const TargetLibraryInfo
&TLI
=
223 getAnalysis
<TargetLibraryInfoWrapperPass
>().getTLI(F
);
224 return runImpl(TLI
, F
);
227 void ReplaceWithVeclibLegacy::getAnalysisUsage(AnalysisUsage
&AU
) const {
228 AU
.setPreservesCFG();
229 AU
.addRequired
<TargetLibraryInfoWrapperPass
>();
230 AU
.addPreserved
<TargetLibraryInfoWrapperPass
>();
231 AU
.addPreserved
<ScalarEvolutionWrapperPass
>();
232 AU
.addPreserved
<AAResultsWrapperPass
>();
233 AU
.addPreserved
<LoopAccessLegacyAnalysis
>();
234 AU
.addPreserved
<DemandedBitsWrapperPass
>();
235 AU
.addPreserved
<OptimizationRemarkEmitterWrapperPass
>();
236 AU
.addPreserved
<GlobalsAAWrapperPass
>();
239 ////////////////////////////////////////////////////////////////////////////////
240 // Legacy Pass manager initialization
241 ////////////////////////////////////////////////////////////////////////////////
242 char ReplaceWithVeclibLegacy::ID
= 0;
244 INITIALIZE_PASS_BEGIN(ReplaceWithVeclibLegacy
, DEBUG_TYPE
,
245 "Replace intrinsics with calls to vector library", false,
247 INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass
)
248 INITIALIZE_PASS_END(ReplaceWithVeclibLegacy
, DEBUG_TYPE
,
249 "Replace intrinsics with calls to vector library", false,
252 FunctionPass
*llvm::createReplaceWithVeclibLegacyPass() {
253 return new ReplaceWithVeclibLegacy();