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 (Info.isMasked()) {
84 auto *MaskTy =
85 VectorType::get(Type::getInt1Ty(II->getContext()), Info.Shape.VF);
86 Args.push_back(Constant::getAllOnesValue(MaskTy));
87 }
88
89 // Preserve the operand bundles.
91 II->getOperandBundlesAsDefs(OpBundles);
92
93 auto *Replacement = IRBuilder.CreateCall(TLIVecFunc, Args, OpBundles);
94 II->replaceAllUsesWith(Replacement);
95 // Preserve fast math flags for FP math.
96 if (isa<FPMathOperator>(Replacement))
97 Replacement->copyFastMathFlags(II);
98 Replacement->setCallingConv(TLIVecFunc->getCallingConv());
99}
100
101/// Returns true when successfully replaced \p II, which is a call to a
102/// vectorized intrinsic, with a suitable function taking vector arguments,
103/// based on available mappings in the \p TLI.
105 IntrinsicInst *II) {
106 assert(II != nullptr && "Intrinsic cannot be null");
107 Intrinsic::ID IID = II->getIntrinsicID();
108 Type *RetTy = II->getType();
109 Type *ScalarRetTy = RetTy->getScalarType();
110 // At the moment VFABI assumes the return type is always widened unless it is
111 // a void type.
112 auto *VTy = dyn_cast<VectorType>(RetTy);
113 ElementCount EC(VTy ? VTy->getElementCount() : ElementCount::getFixed(0));
114
115 // OloadTys collects types used in scalar intrinsic overload name.
116 SmallVector<Type *, 3> OloadTys;
117 if (!RetTy->isVoidTy() &&
118 isVectorIntrinsicWithOverloadTypeAtArg(IID, -1, /*TTI=*/nullptr))
119 OloadTys.push_back(ScalarRetTy);
120
121 // Compute the argument types of the corresponding scalar call and check that
122 // all vector operands match the previously found EC.
123 SmallVector<Type *, 8> ScalarArgTypes;
124 for (auto Arg : enumerate(II->args())) {
125 auto *ArgTy = Arg.value()->getType();
126 bool IsOloadTy = isVectorIntrinsicWithOverloadTypeAtArg(IID, Arg.index(),
127 /*TTI=*/nullptr);
128 if (isVectorIntrinsicWithScalarOpAtArg(IID, Arg.index(), /*TTI=*/nullptr)) {
129 ScalarArgTypes.push_back(ArgTy);
130 if (IsOloadTy)
131 OloadTys.push_back(ArgTy);
132 } else if (auto *VectorArgTy = dyn_cast<VectorType>(ArgTy)) {
133 auto *ScalarArgTy = VectorArgTy->getElementType();
134 ScalarArgTypes.push_back(ScalarArgTy);
135 if (IsOloadTy)
136 OloadTys.push_back(ScalarArgTy);
137 // When return type is void, set EC to the first vector argument, and
138 // disallow vector arguments with different ECs.
139 if (EC.isZero())
140 EC = VectorArgTy->getElementCount();
141 else if (EC != VectorArgTy->getElementCount())
142 return false;
143 } else
144 // Exit when it is supposed to be a vector argument but it isn't.
145 return false;
146 }
147
148 // Try to reconstruct the name for the scalar version of the instruction,
149 // using scalar argument types.
150 std::string ScalarName =
152 ? Intrinsic::getName(IID, OloadTys, II->getModule())
153 : Intrinsic::getName(IID).str();
154
155 // Try to find the mapping for the scalar version of this intrinsic and the
156 // exact vector width of the call operands in the TargetLibraryInfo. First,
157 // check with a non-masked variant, and if that fails try with a masked one.
158 const VecDesc *VD =
159 TLI.getVectorMappingInfo(ScalarName, EC, /*Masked*/ false);
160 if (!VD && !(VD = TLI.getVectorMappingInfo(ScalarName, EC, /*Masked*/ true)))
161 return false;
162
163 LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Found TLI mapping from: `" << ScalarName
164 << "` and vector width " << EC << " to: `"
165 << VD->getVectorFnName() << "`.\n");
166
167 // Replace the call to the intrinsic with a call to the vector library
168 // function.
169 FunctionType *ScalarFTy =
170 FunctionType::get(ScalarRetTy, ScalarArgTypes, /*isVarArg*/ false);
171 const std::string MangledName = VD->getVectorFunctionABIVariantString();
172 auto OptInfo = VFABI::tryDemangleForVFABI(MangledName, ScalarFTy);
173 if (!OptInfo)
174 return false;
175
176 // There is no guarantee that the vectorized instructions followed the VFABI
177 // specification when being created, this is why we need to add extra check to
178 // make sure that the operands of the vector function obtained via VFABI match
179 // the operands of the original vector instruction.
180 for (auto &VFParam : OptInfo->Shape.Parameters) {
181 if (VFParam.ParamKind == VFParamKind::GlobalPredicate)
182 continue;
183
184 // tryDemangleForVFABI must return valid ParamPos, otherwise it could be
185 // a bug in the VFABI parser.
186 assert(VFParam.ParamPos < II->arg_size() && "ParamPos has invalid range");
187 Type *OrigTy = II->getArgOperand(VFParam.ParamPos)->getType();
188 if (OrigTy->isVectorTy() != (VFParam.ParamKind == VFParamKind::Vector)) {
189 LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Will not replace: " << ScalarName
190 << ". Wrong type at index " << VFParam.ParamPos << ": "
191 << *OrigTy << "\n");
192 return false;
193 }
194 }
195
196 FunctionType *VectorFTy = VFABI::createFunctionType(*OptInfo, ScalarFTy);
197 if (!VectorFTy)
198 return false;
199
200 Function *TLIFunc =
201 getTLIFunction(II->getModule(), VectorFTy, VD->getVectorFnName(),
202 VD->getCallingConv(), II->getCalledFunction());
203 replaceWithTLIFunction(II, *OptInfo, TLIFunc);
204 LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Replaced call to `" << ScalarName
205 << "` with call to `" << TLIFunc->getName() << "`.\n");
206 ++NumCallsReplaced;
207 return true;
208}
209
210static bool runImpl(const TargetLibraryInfo &TLI, Function &F) {
211 SmallVector<Instruction *> ReplacedCalls;
212 for (auto &I : instructions(F)) {
213 // Process only intrinsic calls that return void or a vector.
214 if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
215 if (II->getIntrinsicID() == Intrinsic::not_intrinsic)
216 continue;
217 if (!II->getType()->isVectorTy() && !II->getType()->isVoidTy())
218 continue;
219
220 if (replaceWithCallToVeclib(TLI, II))
221 ReplacedCalls.push_back(&I);
222 }
223 }
224 // Erase any intrinsic calls that were replaced with vector library calls.
225 for (auto *I : ReplacedCalls)
226 I->eraseFromParent();
227 return !ReplacedCalls.empty();
228}
229
230////////////////////////////////////////////////////////////////////////////////
231// New pass manager implementation.
232////////////////////////////////////////////////////////////////////////////////
236 auto Changed = runImpl(TLI, F);
237 if (Changed) {
238 LLVM_DEBUG(dbgs() << "Intrinsic calls replaced with vector libraries: "
239 << NumCallsReplaced << "\n");
240
248 return PA;
249 }
250
251 // The pass did not replace any calls, hence it preserves all analyses.
252 return PreservedAnalyses::all();
253}
254
255////////////////////////////////////////////////////////////////////////////////
256// Legacy PM Implementation.
257////////////////////////////////////////////////////////////////////////////////
263
273
274////////////////////////////////////////////////////////////////////////////////
275// Legacy Pass manager initialization
276////////////////////////////////////////////////////////////////////////////////
278
280 "Replace intrinsics with calls to vector library", false,
281 false)
284 "Replace intrinsics with calls to vector library", false,
285 false)
286
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:119
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:843
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:2553
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2858
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.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::string str() const
Get the contents as an std::string.
Definition StringRef.h:222
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:46
bool isVectorTy() const
True if this is an instance of VectorType.
Definition Type.h:290
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
Definition Type.h:370
static LLVM_ABI IntegerType * getInt1Ty(LLVMContext &C)
Definition Type.cpp:310
bool isVoidTy() const
Return true if this is 'void'.
Definition Type.h:141
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:318
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.
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:2553
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:209
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.