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 Function *ScalarFunc = nullptr) {
52 Function *TLIFunc = M->getFunction(TLIName);
53 if (!TLIFunc) {
54 TLIFunc =
55 Function::Create(VectorFTy, Function::ExternalLinkage, TLIName, *M);
56 if (ScalarFunc)
57 TLIFunc->copyAttributesFrom(ScalarFunc);
58
59 LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Added vector library function `"
60 << TLIName << "` of type `" << *(TLIFunc->getType())
61 << "` to module.\n");
62
63 ++NumTLIFuncDeclAdded;
64 // Add the freshly created function to llvm.compiler.used, similar to as it
65 // is done in InjectTLIMappings.
66 appendToCompilerUsed(*M, {TLIFunc});
67 LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Adding `" << TLIName
68 << "` to `@llvm.compiler.used`.\n");
69 ++NumFuncUsedAdded;
70 }
71 return TLIFunc;
72}
73
74/// Replace the intrinsic call \p II to \p TLIVecFunc, which is the
75/// corresponding function from the vector library.
77 Function *TLIVecFunc) {
79 SmallVector<Value *> Args(II->args());
80 if (auto OptMaskpos = Info.getParamIndexForOptionalMask()) {
81 auto *MaskTy =
82 VectorType::get(Type::getInt1Ty(II->getContext()), Info.Shape.VF);
83 Args.insert(Args.begin() + OptMaskpos.value(),
85 }
86
87 // Preserve the operand bundles.
89 II->getOperandBundlesAsDefs(OpBundles);
90
91 auto *Replacement = IRBuilder.CreateCall(TLIVecFunc, Args, OpBundles);
92 II->replaceAllUsesWith(Replacement);
93 // Preserve fast math flags for FP math.
94 if (isa<FPMathOperator>(Replacement))
95 Replacement->copyFastMathFlags(II);
96}
97
98/// Returns true when successfully replaced \p II, which is a call to a
99/// vectorized intrinsic, with a suitable function taking vector arguments,
100/// based on available mappings in the \p TLI.
102 IntrinsicInst *II) {
103 assert(II != nullptr && "Intrinsic cannot be null");
104 Intrinsic::ID IID = II->getIntrinsicID();
105 Type *RetTy = II->getType();
106 Type *ScalarRetTy = RetTy->getScalarType();
107 // At the moment VFABI assumes the return type is always widened unless it is
108 // a void type.
109 auto *VTy = dyn_cast<VectorType>(RetTy);
110 ElementCount EC(VTy ? VTy->getElementCount() : ElementCount::getFixed(0));
111
112 // OloadTys collects types used in scalar intrinsic overload name.
113 SmallVector<Type *, 3> OloadTys;
114 if (!RetTy->isVoidTy() &&
115 isVectorIntrinsicWithOverloadTypeAtArg(IID, -1, /*TTI=*/nullptr))
116 OloadTys.push_back(ScalarRetTy);
117
118 // Compute the argument types of the corresponding scalar call and check that
119 // all vector operands match the previously found EC.
120 SmallVector<Type *, 8> ScalarArgTypes;
121 for (auto Arg : enumerate(II->args())) {
122 auto *ArgTy = Arg.value()->getType();
123 bool IsOloadTy = isVectorIntrinsicWithOverloadTypeAtArg(IID, Arg.index(),
124 /*TTI=*/nullptr);
125 if (isVectorIntrinsicWithScalarOpAtArg(IID, Arg.index(), /*TTI=*/nullptr)) {
126 ScalarArgTypes.push_back(ArgTy);
127 if (IsOloadTy)
128 OloadTys.push_back(ArgTy);
129 } else if (auto *VectorArgTy = dyn_cast<VectorType>(ArgTy)) {
130 auto *ScalarArgTy = VectorArgTy->getElementType();
131 ScalarArgTypes.push_back(ScalarArgTy);
132 if (IsOloadTy)
133 OloadTys.push_back(ScalarArgTy);
134 // When return type is void, set EC to the first vector argument, and
135 // disallow vector arguments with different ECs.
136 if (EC.isZero())
137 EC = VectorArgTy->getElementCount();
138 else if (EC != VectorArgTy->getElementCount())
139 return false;
140 } else
141 // Exit when it is supposed to be a vector argument but it isn't.
142 return false;
143 }
144
145 // Try to reconstruct the name for the scalar version of the instruction,
146 // using scalar argument types.
147 std::string ScalarName =
149 ? Intrinsic::getName(IID, OloadTys, II->getModule())
150 : Intrinsic::getName(IID).str();
151
152 // Try to find the mapping for the scalar version of this intrinsic and the
153 // exact vector width of the call operands in the TargetLibraryInfo. First,
154 // check with a non-masked variant, and if that fails try with a masked one.
155 const VecDesc *VD =
156 TLI.getVectorMappingInfo(ScalarName, EC, /*Masked*/ false);
157 if (!VD && !(VD = TLI.getVectorMappingInfo(ScalarName, EC, /*Masked*/ true)))
158 return false;
159
160 LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Found TLI mapping from: `" << ScalarName
161 << "` and vector width " << EC << " to: `"
162 << VD->getVectorFnName() << "`.\n");
163
164 // Replace the call to the intrinsic with a call to the vector library
165 // function.
166 FunctionType *ScalarFTy =
167 FunctionType::get(ScalarRetTy, ScalarArgTypes, /*isVarArg*/ false);
168 const std::string MangledName = VD->getVectorFunctionABIVariantString();
169 auto OptInfo = VFABI::tryDemangleForVFABI(MangledName, ScalarFTy);
170 if (!OptInfo)
171 return false;
172
173 // There is no guarantee that the vectorized instructions followed the VFABI
174 // specification when being created, this is why we need to add extra check to
175 // make sure that the operands of the vector function obtained via VFABI match
176 // the operands of the original vector instruction.
177 for (auto &VFParam : OptInfo->Shape.Parameters) {
178 if (VFParam.ParamKind == VFParamKind::GlobalPredicate)
179 continue;
180
181 // tryDemangleForVFABI must return valid ParamPos, otherwise it could be
182 // a bug in the VFABI parser.
183 assert(VFParam.ParamPos < II->arg_size() && "ParamPos has invalid range");
184 Type *OrigTy = II->getArgOperand(VFParam.ParamPos)->getType();
185 if (OrigTy->isVectorTy() != (VFParam.ParamKind == VFParamKind::Vector)) {
186 LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Will not replace: " << ScalarName
187 << ". Wrong type at index " << VFParam.ParamPos << ": "
188 << *OrigTy << "\n");
189 return false;
190 }
191 }
192
193 FunctionType *VectorFTy = VFABI::createFunctionType(*OptInfo, ScalarFTy);
194 if (!VectorFTy)
195 return false;
196
197 Function *TLIFunc =
198 getTLIFunction(II->getModule(), VectorFTy, VD->getVectorFnName(),
199 II->getCalledFunction());
200 replaceWithTLIFunction(II, *OptInfo, TLIFunc);
201 LLVM_DEBUG(dbgs() << DEBUG_TYPE << ": Replaced call to `" << ScalarName
202 << "` with call to `" << TLIFunc->getName() << "`.\n");
203 ++NumCallsReplaced;
204 return true;
205}
206
207static bool runImpl(const TargetLibraryInfo &TLI, Function &F) {
208 SmallVector<Instruction *> ReplacedCalls;
209 for (auto &I : instructions(F)) {
210 // Process only intrinsic calls that return void or a vector.
211 if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
212 if (II->getIntrinsicID() == Intrinsic::not_intrinsic)
213 continue;
214 if (!II->getType()->isVectorTy() && !II->getType()->isVoidTy())
215 continue;
216
217 if (replaceWithCallToVeclib(TLI, II))
218 ReplacedCalls.push_back(&I);
219 }
220 }
221 // Erase any intrinsic calls that were replaced with vector library calls.
222 for (auto *I : ReplacedCalls)
223 I->eraseFromParent();
224 return !ReplacedCalls.empty();
225}
226
227////////////////////////////////////////////////////////////////////////////////
228// New pass manager implementation.
229////////////////////////////////////////////////////////////////////////////////
233 auto Changed = runImpl(TLI, F);
234 if (Changed) {
235 LLVM_DEBUG(dbgs() << "Intrinsic calls replaced with vector libraries: "
236 << NumCallsReplaced << "\n");
237
245 return PA;
246 }
247
248 // The pass did not replace any calls, hence it preserves all analyses.
249 return PreservedAnalyses::all();
250}
251
252////////////////////////////////////////////////////////////////////////////////
253// Legacy PM Implementation.
254////////////////////////////////////////////////////////////////////////////////
260
270
271////////////////////////////////////////////////////////////////////////////////
272// Legacy Pass manager initialization
273////////////////////////////////////////////////////////////////////////////////
275
277 "Replace intrinsics with calls to vector library", false,
278 false)
281 "Replace intrinsics with calls to vector library", false,
282 false)
283
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
Function * getTLIFunction(Module *M, FunctionType *VectorFTy, const StringRef TLIName, Function *ScalarFunc=nullptr)
Returns a vector Function that it adds to the Module M.
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...
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:166
const Function & getFunction() const
Definition Function.h:164
void copyAttributesFrom(const Function *Src)
copyAttributesFrom - copy all additional attributes (those not needed to create a Function) from the ...
Definition Function.cpp:858
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:2481
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2776
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.
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:2544
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.