28#include "llvm/IR/IntrinsicsSPIRV.h"
40class SPIRVPrepareFunctions :
public ModulePass {
41 bool substituteIntrinsicCalls(
Function *
F);
61char SPIRVPrepareFunctions::ID = 0;
64 "SPIRV prepare functions",
false,
false)
67 Function *IntrinsicFunc = II->getCalledFunction();
68 assert(IntrinsicFunc &&
"Missing function");
69 std::string FuncName = IntrinsicFunc->
getName().
str();
70 std::replace(FuncName.begin(), FuncName.end(),
'.',
'_');
71 FuncName =
"spirv." + FuncName;
80 if (
F &&
F->getFunctionType() == FT)
94 if (
auto *MSI = dyn_cast<MemSetInst>(Intrinsic))
95 if (isa<Constant>(MSI->getValue()) && isa<ConstantInt>(MSI->getLength()))
98 Module *M = Intrinsic->getModule();
99 std::string FuncName = lowerLLVMIntrinsicName(Intrinsic);
100 if (Intrinsic->isVolatile())
101 FuncName +=
".volatile";
105 Intrinsic->setCalledFunction(
F);
110 M->getOrInsertFunction(FuncName, Intrinsic->getFunctionType());
111 auto IntrinsicID = Intrinsic->getIntrinsicID();
112 Intrinsic->setCalledFunction(FC);
114 F = dyn_cast<Function>(FC.getCallee());
115 assert(
F &&
"Callee must be a function");
117 switch (IntrinsicID) {
118 case Intrinsic::memset: {
119 auto *MSI =
static_cast<MemSetInst *
>(Intrinsic);
127 IsVolatile->setName(
"isvolatile");
130 auto *MemSet = IRB.
CreateMemSet(Dest, Val, Len, MSI->getDestAlign(),
134 MemSet->eraseFromParent();
137 case Intrinsic::bswap: {
140 auto *BSwap = IRB.
CreateIntrinsic(Intrinsic::bswap, Intrinsic->getType(),
160 Type *FSHRetTy = FSHFuncTy->getReturnType();
161 const std::string FuncName = lowerLLVMIntrinsicName(FSHIntrinsic);
165 if (!FSHFunc->
empty()) {
179 Value *BitWidthForInsts =
183 Value *RotateModVal =
185 Value *FirstShift =
nullptr, *SecShift =
nullptr;
198 Value *SubRotateVal = IRB.
CreateSub(BitWidthForInsts, RotateModVal);
216 if (!UMulFunc->
empty())
250 II->
getModule(), Intrinsic::SPVIntrinsics::spv_assume);
254 II->
getModule(), Intrinsic::SPVIntrinsics::spv_expect,
255 {II->getOperand(0)->getType()});
270 Type *FSHLRetTy = UMulFuncTy->getReturnType();
271 const std::string FuncName = lowerLLVMIntrinsicName(UMulIntrinsic);
280bool SPIRVPrepareFunctions::substituteIntrinsicCalls(
Function *
F) {
281 bool Changed =
false;
284 auto Call = dyn_cast<CallInst>(&
I);
290 auto *II = cast<IntrinsicInst>(Call);
291 if (II->getIntrinsicID() == Intrinsic::memset ||
292 II->getIntrinsicID() == Intrinsic::bswap)
294 else if (II->getIntrinsicID() == Intrinsic::fshl ||
295 II->getIntrinsicID() == Intrinsic::fshr) {
298 }
else if (II->getIntrinsicID() == Intrinsic::umul_with_overflow) {
301 }
else if (II->getIntrinsicID() == Intrinsic::assume ||
302 II->getIntrinsicID() == Intrinsic::expect) {
315SPIRVPrepareFunctions::removeAggregateTypesFromSignature(
Function *
F) {
318 bool IsRetAggr =
F->getReturnType()->isAggregateType();
320 std::any_of(
F->arg_begin(),
F->arg_end(), [](
Argument &Arg) {
321 return Arg.getType()->isAggregateType();
323 bool DoClone = IsRetAggr || HasAggrArg;
327 Type *RetType = IsRetAggr ?
B.getInt32Ty() :
F->getReturnType();
329 ChangedTypes.
push_back(std::pair<int, Type *>(-1,
F->getReturnType()));
331 for (
const auto &Arg :
F->args()) {
332 if (Arg.getType()->isAggregateType()) {
335 std::pair<int, Type *>(Arg.getArgNo(), Arg.getType()));
340 FunctionType::get(RetType, ArgTypes,
F->getFunctionType()->isVarArg());
346 for (
auto &Arg :
F->args()) {
348 NewFArgIt->setName(ArgName);
349 VMap[&Arg] = &(*NewFArgIt++);
358 F->getParent()->getOrInsertNamedMetadata(
"spv.cloned_funcs");
361 for (
auto &ChangedTyP : ChangedTypes)
364 {ConstantAsMetadata::get(B.getInt32(ChangedTyP.first)),
365 ValueAsMetadata::get(Constant::getNullValue(ChangedTyP.second))}));
370 if (
auto *CI = dyn_cast<CallInst>(U))
372 U->replaceUsesOfWith(
F, NewF);
377bool SPIRVPrepareFunctions::runOnModule(
Module &M) {
378 bool Changed =
false;
380 Changed |= substituteIntrinsicCalls(&
F);
382 std::vector<Function *> FuncsWorklist;
384 FuncsWorklist.push_back(&
F);
386 for (
auto *
F : FuncsWorklist) {
387 Function *NewF = removeAggregateTypesFromSignature(
F);
390 F->eraseFromParent();
398 return new SPIRVPrepareFunctions();
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static void lowerFunnelShifts(IntrinsicInst *FSHIntrinsic)
static bool lowerIntrinsicToFunction(IntrinsicInst *Intrinsic)
static void lowerUMulWithOverflow(IntrinsicInst *UMulIntrinsic)
static void lowerExpectAssume(IntrinsicInst *II)
static void buildUMulWithOverflowFunc(Function *UMulFunc)
static Function * getOrCreateFunction(Module *M, Type *RetTy, ArrayRef< Type * > ArgTypes, StringRef Name)
Represent the analysis usage information of a pass.
This class represents an incoming formal argument to a Function.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
LLVM Basic Block Representation.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
FunctionType * getFunctionType() const
void setCalledFunction(Function *Fn)
Sets the function called, including updating the function type.
This is the shared class of boolean and integer constants.
Class to represent fixed width SIMD vectors.
unsigned getNumElements() const
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
FunctionType * getFunctionType() const
Returns the FunctionType for me.
bool isIntrinsic() const
isIntrinsic - Returns true if the function's name starts with "llvm.".
Type * getReturnType() const
Returns the type of the ret val.
void setCallingConv(CallingConv::ID CC)
Argument * getArg(unsigned i) const
Module * getParent()
Get the module that this global value is contained inside of...
void setDSOLocal(bool Local)
@ ExternalLinkage
Externally visible function.
Value * CreateNUWMul(Value *LHS, Value *RHS, const Twine &Name="")
Value * CreateInsertValue(Value *Agg, Value *Val, ArrayRef< unsigned > Idxs, const Twine &Name="")
Value * CreateVectorSplat(unsigned NumElts, Value *V, const Twine &Name="")
Return a vector value that contains.
CallInst * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > Types, ArrayRef< Value * > Args, Instruction *FMFSource=nullptr, const Twine &Name="")
Create a call to intrinsic ID with Args, mangled using Types.
CallInst * CreateMemSet(Value *Ptr, Value *Val, uint64_t Size, MaybeAlign Align, bool isVolatile=false, MDNode *TBAATag=nullptr, MDNode *ScopeTag=nullptr, MDNode *NoAliasTag=nullptr)
Create and insert a memset to the specified pointer and the specified value.
Value * CreateLShr(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
ReturnInst * CreateRet(Value *V)
Create a 'ret <val>' instruction.
Value * CreateUDiv(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
Value * CreateICmpNE(Value *LHS, Value *RHS, const Twine &Name="")
Value * CreateSub(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Value * CreateShl(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
ReturnInst * CreateRetVoid()
Create a 'ret void' instruction.
Value * CreateOr(Value *LHS, Value *RHS, const Twine &Name="")
ConstantInt * getInt(const APInt &AI)
Get a constant integer value.
Value * CreateURem(Value *LHS, Value *RHS, const Twine &Name="")
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
A wrapper class for inspecting calls to intrinsic functions.
Intrinsic::ID getIntrinsicID() const
Return the intrinsic ID of this intrinsic.
void LowerIntrinsicCall(CallInst *CI)
Replace a call to the specified intrinsic function.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
static MDString * get(LLVMContext &Context, StringRef Str)
This class wraps the llvm.memset and llvm.memset.inline intrinsics.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
virtual bool runOnModule(Module &M)=0
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
A Module instance is used to store all the information related to an LLVM module.
LLVMContext & getContext() const
Get the global data context.
void addOperand(MDNode *M)
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
static PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
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.
std::string str() const
str - Get the contents as an std::string.
The instances of the Type class are immutable: once they are created, they are never changed.
unsigned getIntegerBitWidth() const
LLVM Value Representation.
void setName(const Twine &Name)
Change the name of the value.
StringRef getName() const
Return a constant reference to the value's name.
void takeName(Value *V)
Transfer the name from V to this value.
Type * getElementType() const
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
@ SPIR_FUNC
Used for SPIR non-kernel device functions.
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=std::nullopt)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
This is an optimization pass for GlobalISel generic memory operations.
void initializeSPIRVPrepareFunctionsPass(PassRegistry &)
ModulePass * createSPIRVPrepareFunctionsPass()
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
constexpr unsigned BitWidth
void CloneFunctionInto(Function *NewFunc, const Function *OldFunc, ValueToValueMapTy &VMap, CloneFunctionChangeType Changes, SmallVectorImpl< ReturnInst * > &Returns, const char *NameSuffix="", ClonedCodeInfo *CodeInfo=nullptr, ValueMapTypeRemapper *TypeMapper=nullptr, ValueMaterializer *Materializer=nullptr)
Clone OldFunc into NewFunc, transforming the old arguments into references to VMap values.
void expandMemSetAsLoop(MemSetInst *MemSet)
Expand MemSet as a loop. MemSet is not deleted.
Implement std::hash so that hash_code can be used in STL containers.