LLVM 23.0.0git
ReplaceWithVeclib.cpp
Go to the documentation of this file.
1//=== ReplaceWithVeclib.cpp - Replace vector intrinsics with veclib calls -===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8//
9// Replaces calls to LLVM Intrinsics with matching calls to functions from a
10// vector library (e.g libmvec, SVML) using TargetLibraryInfo interface.
11//
12//===----------------------------------------------------------------------===//
13
15#include "llvm/ADT/STLExtras.h"
16#include "llvm/ADT/Statistic.h"
17#include "llvm/ADT/StringRef.h"
23#include "llvm/CodeGen/Passes.h"
25#include "llvm/IR/IRBuilder.h"
32
33using namespace llvm;
34
35#define DEBUG_TYPE "replace-with-veclib"
36
37STATISTIC(NumCallsReplaced,
38 "Number of calls to intrinsics that have been replaced.");
39
40STATISTIC(NumTLIFuncDeclAdded,
41 "Number of vector library function declarations added.");
42
43STATISTIC(NumFuncUsedAdded,
44 "Number of functions added to `llvm.compiler.used`");
45
46/// Returns a vector Function that it adds to the Module \p M. When an \p
47/// ScalarFunc is not null, it copies its attributes to the newly created
48/// Function.
50 const StringRef TLIName,
51 std::optional<CallingConv::ID> CC,
52 Function *ScalarFunc = nullptr) {
53 Function *TLIFunc = M->getFunction(TLIName);
54 if (!TLIFunc) {
55 TLIFunc =
56 Function::Create(VectorFTy, Function::ExternalLinkage, TLIName, *M);
57 if (ScalarFunc)
58 TLIFunc->copyAttributesFrom(ScalarFunc);
59 if (CC)
60 TLIFunc->setCallingConv(*CC);
61
62 LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Added vector library function `"
63 << TLIName << "` of type `" << *(TLIFunc->getType())
64 << "` to module.\n");
65
66 ++NumTLIFuncDeclAdded;
67 // Add the freshly created function to llvm.compiler.used, similar to as it
68 // is done in InjectTLIMappings.
69 appendToCompilerUsed(*M, {TLIFunc});
70 LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Adding `" << TLIName
71 << "` to `@llvm.compiler.used`.\n");
72 ++NumFuncUsedAdded;
73 }
74 return TLIFunc;
75}
76
77/// Replace the intrinsic call \p II to \p TLIVecFunc, which is the
78/// corresponding function from the vector library.
80 Function *TLIVecFunc) {
82 SmallVector<Value *> Args(II->args());
83 if (auto OptMaskpos = Info.getParamIndexForOptionalMask()) {
84 auto *MaskTy =
85 VectorType::get(Type::getInt1Ty(II->getContext()), Info.Shape.VF);
86 Args.insert(Args.begin() + OptMaskpos.value(),
88 }
89
90 // Preserve the operand bundles.
92 II->getOperandBundlesAsDefs(OpBundles);
93
94 auto *Replacement = IRBuilder.CreateCall(TLIVecFunc, Args, OpBundles);
95 II->replaceAllUsesWith(Replacement);
96 // Preserve fast math flags for FP math.
97 if (isa<FPMathOperator>(Replacement))
98 Replacement->copyFastMathFlags(II);
99 Replacement->setCallingConv(TLIVecFunc->getCallingConv());
100}
101
102/// Returns true when successfully replaced \p II, which is a call to a
103/// vectorized intrinsic, with a suitable function taking vector arguments,
104/// based on available mappings in the \p TLI.
106 IntrinsicInst *II) {
107 assert(II != nullptr && "Intrinsic cannot be null");
108 Intrinsic::ID IID = II->getIntrinsicID();
109 Type *RetTy = II->getType();
110 Type *ScalarRetTy = RetTy->getScalarType();
111 // At the moment VFABI assumes the return type is always widened unless it is
112 // a void type.
113 auto *VTy = dyn_cast<VectorType>(RetTy);
114 ElementCount EC(VTy ? VTy->getElementCount() : ElementCount::getFixed(0));
115
116 // OloadTys collects types used in scalar intrinsic overload name.
117 SmallVector<Type *, 3> OloadTys;
118 if (!RetTy->isVoidTy() &&
119 isVectorIntrinsicWithOverloadTypeAtArg(IID, -1, /*TTI=*/nullptr))
120 OloadTys.push_back(ScalarRetTy);
121
122 // Compute the argument types of the corresponding scalar call and check that
123 // all vector operands match the previously found EC.
124 SmallVector<Type *, 8> ScalarArgTypes;
125 for (auto Arg : enumerate(II->args())) {
126 auto *ArgTy = Arg.value()->getType();
127 bool IsOloadTy = isVectorIntrinsicWithOverloadTypeAtArg(IID, Arg.index(),
128 /*TTI=*/nullptr);
129 if (isVectorIntrinsicWithScalarOpAtArg(IID, Arg.index(), /*TTI=*/nullptr)) {
130 ScalarArgTypes.push_back(ArgTy);
131 if (IsOloadTy)
132 OloadTys.push_back(ArgTy);
133 } else if (auto *VectorArgTy = dyn_cast<VectorType>(ArgTy)) {
134 auto *ScalarArgTy = VectorArgTy->getElementType();
135 ScalarArgTypes.push_back(ScalarArgTy);
136 if (IsOloadTy)
137 OloadTys.push_back(ScalarArgTy);
138 // When return type is void, set EC to the first vector argument, and
139 // disallow vector arguments with different ECs.
140 if (EC.isZero())
141 EC = VectorArgTy->getElementCount();
142 else if (EC != VectorArgTy->getElementCount())
143 return false;
144 } else
145 // Exit when it is supposed to be a vector argument but it isn't.
146 return false;
147 }
148
149 // Try to reconstruct the name for the scalar version of the instruction,
150 // using scalar argument types.
151 std::string ScalarName =
153 ? Intrinsic::getName(IID, OloadTys, II->getModule())
154 : Intrinsic::getName(IID).str();
155
156 // Try to find the mapping for the scalar version of this intrinsic and the
157 // exact vector width of the call operands in the TargetLibraryInfo. First,
158 // check with a non-masked variant, and if that fails try with a masked one.
159 const VecDesc *VD =
160 TLI.getVectorMappingInfo(ScalarName, EC, /*Masked*/ false);
161 if (!VD && !(VD = TLI.getVectorMappingInfo(ScalarName, EC, /*Masked*/ true)))
162 return false;
163
164 LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Found TLI mapping from: `" << ScalarName
165 << "` and vector width " << EC << " to: `"
166 << VD->getVectorFnName() << "`.\n");
167
168 // Replace the call to the intrinsic with a call to the vector library
169 // function.
170 FunctionType *ScalarFTy =
171 FunctionType::get(ScalarRetTy, ScalarArgTypes, /*isVarArg*/ false);
172 const std::string MangledName = VD->getVectorFunctionABIVariantString();
173 auto OptInfo = VFABI::tryDemangleForVFABI(MangledName, ScalarFTy);
174 if (!OptInfo)
175 return false;
176
177 // There is no guarantee that the vectorized instructions followed the VFABI
178 // specification when being created, this is why we need to add extra check to
179 // make sure that the operands of the vector function obtained via VFABI match
180 // the operands of the original vector instruction.
181 for (auto &VFParam : OptInfo->Shape.Parameters) {
182 if (VFParam.ParamKind == VFParamKind::GlobalPredicate)
183 continue;
184
185 // tryDemangleForVFABI must return valid ParamPos, otherwise it could be
186 // a bug in the VFABI parser.
187 assert(VFParam.ParamPos < II->arg_size() && "ParamPos has invalid range");
188 Type *OrigTy = II->getArgOperand(VFParam.ParamPos)->getType();
189 if (OrigTy->isVectorTy() != (VFParam.ParamKind == VFParamKind::Vector)) {
190 LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Will not replace: " << ScalarName
191 << ". Wrong type at index " << VFParam.ParamPos << ": "
192 << *OrigTy << "\n");
193 return false;
194 }
195 }
196
197 FunctionType *VectorFTy = VFABI::createFunctionType(*OptInfo, ScalarFTy);
198 if (!VectorFTy)
199 return false;
200
201 Function *TLIFunc =
202 getTLIFunction(II->getModule(), VectorFTy, VD->getVectorFnName(),
203 VD->getCallingConv(), II->getCalledFunction());
204 replaceWithTLIFunction(II, *OptInfo, TLIFunc);
205 LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Replaced call to `" << ScalarName
206 << "` with call to `" << TLIFunc->getName() << "`.\n");
207 ++NumCallsReplaced;
208 return true;
209}
210
211static bool runImpl(const TargetLibraryInfo &TLI, Function &F) {
212 SmallVector<Instruction *> ReplacedCalls;
213 for (auto &I : instructions(F)) {
214 // Process only intrinsic calls that return void or a vector.
215 if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
216 if (II->getIntrinsicID() == Intrinsic::not_intrinsic)
217 continue;
218 if (!II->getType()->isVectorTy() && !II->getType()->isVoidTy())
219 continue;
220
221 if (replaceWithCallToVeclib(TLI, II))
222 ReplacedCalls.push_back(&I);
223 }
224 }
225 // Erase any intrinsic calls that were replaced with vector library calls.
226 for (auto *I : ReplacedCalls)
227 I->eraseFromParent();
228 return !ReplacedCalls.empty();
229}
230
231////////////////////////////////////////////////////////////////////////////////
232// New pass manager implementation.
233////////////////////////////////////////////////////////////////////////////////
237 auto Changed = runImpl(TLI, F);
238 if (Changed) {
239 LLVM_DEBUG(dbgs() << "Intrinsic calls replaced with vector libraries: "
240 << NumCallsReplaced << "\n");
241
249 return PA;
250 }
251
252 // The pass did not replace any calls, hence it preserves all analyses.
253 return PreservedAnalyses::all();
254}
255
256////////////////////////////////////////////////////////////////////////////////
257// Legacy PM Implementation.
258////////////////////////////////////////////////////////////////////////////////
264
274
275////////////////////////////////////////////////////////////////////////////////
276// Legacy Pass manager initialization
277////////////////////////////////////////////////////////////////////////////////
279
281 "Replace intrinsics with calls to vector library", false,
282 false)
285 "Replace intrinsics with calls to vector library", false,
286 false)
287
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Expand Atomic instructions
static bool runImpl(Function &F, const TargetLowering &TLI, const LibcallLoweringInfo &Libcalls, AssumptionCache *AC)
#define DEBUG_TYPE
This is the interface for a simple mod/ref and alias analysis over globals.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
static bool replaceWithCallToVeclib(const TargetLibraryInfo &TLI, IntrinsicInst *II)
Returns true when successfully replaced II, which is a call to a vectorized intrinsic,...
static void replaceWithTLIFunction(IntrinsicInst *II, VFInfo &Info, Function *TLIVecFunc)
Replace the intrinsic call II to TLIVecFunc, which is the corresponding function from the vector libr...
Function * getTLIFunction(Module *M, FunctionType *VectorFTy, const StringRef TLIName, std::optional< CallingConv::ID > CC, Function *ScalarFunc=nullptr)
Returns a vector Function that it adds to the Module M.
static bool runImpl(const TargetLibraryInfo &TLI, Function &F)
This file contains some templates that are useful if you are working with the STL at all.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
#define LLVM_DEBUG(...)
Definition Debug.h:114
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:270
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
static LLVM_ABI Constant * getAllOnesValue(Type *Ty)
An analysis that produces DemandedBits for a function.
static constexpr ElementCount getFixed(ScalarTy MinVal)
Definition TypeSize.h:309
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
Definition Function.h:168
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
Definition Function.h:272
const Function & getFunction() const
Definition Function.h:166
void setCallingConv(CallingConv::ID CC)
Definition Function.h:276
void copyAttributesFrom(const Function *Src)
copyAttributesFrom - copy all additional attributes (those not needed to create a Function) from the ...
Definition Function.cpp:844
PointerType * getType() const
Global values are always pointers.
@ ExternalLinkage
Externally visible function.
Definition GlobalValue.h:53
Legacy wrapper pass to provide the GlobalsAAResult object.
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
Definition IRBuilder.h:2487
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2787
A wrapper class for inspecting calls to intrinsic functions.
This analysis provides dependence information for the memory accesses of a loop.
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
OptimizationRemarkEmitter legacy analysis pass.
AnalysisType & getAnalysis() const
getAnalysis<AnalysisType>() - This function is used by subclasses to get to the analysis information ...
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
PreservedAnalyses & preserve()
Mark an analysis as preserved.
Definition Analysis.h:132
Analysis pass that exposes the ScalarEvolution for a function.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
std::string str() const
str - Get the contents as an std::string.
Definition StringRef.h:225
Analysis pass providing the TargetLibraryInfo.
Provides information about what library functions are available for the current target.
const VecDesc * getVectorMappingInfo(StringRef F, const ElementCount &VF, bool Masked) const
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:45
bool isVectorTy() const
True if this is an instance of VectorType.
Definition Type.h:273
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
Definition Type.h:352
static LLVM_ABI IntegerType * getInt1Ty(LLVMContext &C)
Definition Type.cpp:293
bool isVoidTy() const
Return true if this is 'void'.
Definition Type.h:139
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:322
Provides info so a possible vectorization of a function can be computed.
std::optional< CallingConv::ID > getCallingConv() const
LLVM_ABI std::string getVectorFunctionABIVariantString() const
Returns a vector function ABI variant string on the form: ZGV<isa><mask><vlen><vparams><scalarname>(<...
StringRef getVectorFnName() const
static LLVM_ABI VectorType * get(Type *ElementType, ElementCount EC)
This static method is the primary way to construct an VectorType.
Changed
LLVM_ABI StringRef getName(ID id)
Return the LLVM name for an intrinsic, such as "llvm.ppc.altivec.lvx".
LLVM_ABI bool isOverloaded(ID id)
Returns true if the intrinsic can be overloaded.
LLVM_ABI std::optional< VFInfo > tryDemangleForVFABI(StringRef MangledName, const FunctionType *FTy)
Function to construct a VFInfo out of a mangled names in the following format:
LLVM_ABI FunctionType * createFunctionType(const VFInfo &Info, const FunctionType *ScalarFTy)
Constructs a FunctionType by applying vector function information to the type of a matching scalar fu...
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2554
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
LLVM_ABI void appendToCompilerUsed(Module &M, ArrayRef< GlobalValue * > Values)
Adds global values to the llvm.compiler.used list.
LLVM_ABI bool isVectorIntrinsicWithScalarOpAtArg(Intrinsic::ID ID, unsigned ScalarOpdIdx, const TargetTransformInfo *TTI)
Identifies if the vector form of the intrinsic has a scalar operand.
LLVM_ABI FunctionPass * createReplaceWithVeclibLegacyPass()
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI bool isVectorIntrinsicWithOverloadTypeAtArg(Intrinsic::ID ID, int OpdIdx, const TargetTransformInfo *TTI)
Identifies if the vector form of the intrinsic is overloaded on the type of the operand at index OpdI...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
bool runOnFunction(Function &F) override
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
Holds the VFShape for a specific scalar to vector function mapping.