34#include "llvm/IR/IntrinsicsSPIRV.h"
43class SPIRVPrepareFunctions :
public ModulePass {
44 const SPIRVTargetMachine &TM;
45 bool substituteIntrinsicCalls(Function *
F);
46 Function *removeAggregateTypesFromSignature(Function *
F);
47 bool removeAggregateTypesFromCalls(Function *
F);
51 SPIRVPrepareFunctions(
const SPIRVTargetMachine &TM)
52 : ModulePass(ID), TM(TM) {}
54 bool runOnModule(
Module &M)
override;
56 StringRef getPassName()
const override {
return "SPIRV prepare functions"; }
58 void getAnalysisUsage(AnalysisUsage &AU)
const override {
59 ModulePass::getAnalysisUsage(AU);
65 cl::desc(
"Emit unknown intrinsics as calls to external functions. A "
66 "comma-separated input list of intrinsic prefixes must be "
67 "provided, and only intrinsics carrying a listed prefix get "
68 "emitted as described."),
72char SPIRVPrepareFunctions::ID = 0;
75 "SPIRV prepare functions",
false,
false)
78 Function *IntrinsicFunc =
II->getCalledFunction();
79 assert(IntrinsicFunc &&
"Missing function");
80 std::string FuncName = IntrinsicFunc->
getName().
str();
82 FuncName =
"spirv." + FuncName;
91 if (
F &&
F->getFunctionType() == FT)
111 std::string FuncName = lowerLLVMIntrinsicName(
Intrinsic);
113 FuncName +=
".volatile";
122 M->getOrInsertFunction(FuncName,
Intrinsic->getFunctionType());
123 auto IntrinsicID =
Intrinsic->getIntrinsicID();
127 assert(
F &&
"Callee must be a function");
129 switch (IntrinsicID) {
130 case Intrinsic::memset: {
139 IsVolatile->setName(
"isvolatile");
142 auto *MemSet = IRB.
CreateMemSet(Dest, Val, Len, MSI->getDestAlign(),
146 MemSet->eraseFromParent();
149 case Intrinsic::bswap: {
167 AnnoVal =
Ref->getOperand(0);
169 OptAnnoVal =
Ref->getOperand(0);
180 C &&
C->getNumOperands()) {
181 Value *MaybeStruct =
C->getOperand(0);
183 for (
unsigned I = 0,
E = Struct->getNumOperands();
I !=
E; ++
I) {
185 Anno += (
I == 0 ?
": " :
", ") +
186 std::to_string(CInt->getType()->getIntegerBitWidth() == 1
187 ? CInt->getZExtValue()
188 : CInt->getSExtValue());
192 for (
unsigned I = 0,
E = Struct->getType()->getStructNumElements();
194 Anno +=
I == 0 ?
": 0" :
", 0";
201 const std::string &Anno,
208 static const std::regex R(
209 "\\{(\\d+)(?:[:,](\\d+|\"[^\"]*\")(?:,(\\d+|\"[^\"]*\"))*)?\\}");
212 for (std::sregex_iterator
213 It = std::sregex_iterator(Anno.begin(), Anno.end(), R),
214 ItEnd = std::sregex_iterator();
216 if (It->position() != Pos)
218 Pos = It->position() + It->length();
219 std::smatch Match = *It;
221 for (std::size_t i = 1; i < Match.size(); ++i) {
222 std::ssub_match SMatch = Match[i];
223 std::string Item = SMatch.str();
224 if (Item.length() == 0)
226 if (Item[0] ==
'"') {
227 Item = Item.substr(1, Item.length() - 2);
229 static const std::regex RStr(
"^(\\d+)(?:,(\\d+))*$");
230 if (std::smatch MatchStr; std::regex_match(Item, MatchStr, RStr)) {
231 for (std::size_t SubIdx = 1; SubIdx < MatchStr.size(); ++SubIdx)
232 if (std::string SubStr = MatchStr[SubIdx].str(); SubStr.length())
234 ConstantInt::get(
Int32Ty, std::stoi(SubStr))));
245 if (MDsItem.
size() == 0)
249 return Pos ==
static_cast<int>(Anno.length()) ? std::move(MDs)
258 Value *PtrArg =
nullptr;
260 PtrArg = BI->getOperand(0);
262 PtrArg =
II->getOperand(0);
265 4 <
II->arg_size() ?
II->getArgOperand(4) :
nullptr);
274 if (MDs.
size() == 0) {
284 Intrinsic::spv_assign_decoration, {PtrArg->
getType()},
286 II->replaceAllUsesWith(
II->getOperand(0));
296 Type *FSHRetTy = FSHFuncTy->getReturnType();
297 const std::string FuncName = lowerLLVMIntrinsicName(FSHIntrinsic);
301 if (!FSHFunc->
empty()) {
313 unsigned BitWidth = IntTy->getIntegerBitWidth();
315 Value *BitWidthForInsts =
319 Value *RotateModVal =
321 Value *FirstShift =
nullptr, *SecShift =
nullptr;
334 Value *SubRotateVal = IRB.
CreateSub(BitWidthForInsts, RotateModVal);
353 if (!ConstrainedCmpIntrinsic)
375 if (
II->getIntrinsicID() == Intrinsic::assume) {
377 II->getModule(), Intrinsic::SPVIntrinsics::spv_assume);
378 II->setCalledFunction(
F);
379 }
else if (
II->getIntrinsicID() == Intrinsic::expect) {
381 II->getModule(), Intrinsic::SPVIntrinsics::spv_expect,
382 {II->getOperand(0)->getType()});
383 II->setCalledFunction(
F);
390 auto *LifetimeArg0 =
II->getArgOperand(0);
394 II->eraseFromParent();
400 std::optional<TypeSize>
Size =
401 Alloca->getAllocationSize(Alloca->getDataLayout());
403 Builder.CreateIntrinsic(NewID, Alloca->getType(), {SizeVal, LifetimeArg0});
404 II->eraseFromParent();
412 Value *
A = FPI->getArgOperand(0);
416 Builder.SetInsertPoint(
II);
417 std::optional<RoundingMode> Rounding = FPI->getRoundingMode();
418 Value *Product = Builder.CreateFMul(
A,
Mul,
II->getName() +
".mul");
419 Value *Result = Builder.CreateConstrainedFPBinOp(
420 Intrinsic::experimental_constrained_fadd, Product,
Add, {},
421 II->getName() +
".add",
nullptr, Rounding);
422 II->replaceAllUsesWith(Result);
428bool SPIRVPrepareFunctions::substituteIntrinsicCalls(
Function *
F) {
430 const SPIRVSubtarget &STI = TM.
getSubtarget<SPIRVSubtarget>(*F);
433 for (BasicBlock &BB : *
F) {
443 II->getCalledOperand()->getName().starts_with(
"llvm.spv"))
445 switch (
II->getIntrinsicID()) {
446 case Intrinsic::memset:
447 case Intrinsic::bswap:
450 case Intrinsic::fshl:
451 case Intrinsic::fshr:
455 case Intrinsic::assume:
456 case Intrinsic::expect:
461 case Intrinsic::lifetime_start:
464 II, Intrinsic::SPVIntrinsics::spv_lifetime_start);
466 II->eraseFromParent();
470 case Intrinsic::lifetime_end:
473 II, Intrinsic::SPVIntrinsics::spv_lifetime_end);
475 II->eraseFromParent();
479 case Intrinsic::ptr_annotation:
483 case Intrinsic::experimental_constrained_fmuladd:
487 case Intrinsic::experimental_constrained_fcmp:
488 case Intrinsic::experimental_constrained_fcmps:
495 any_of(SPVAllowUnknownIntrinsics, [
II](
auto &&Prefix) {
498 return II->getCalledFunction()->getName().starts_with(Prefix);
505 for (
auto *
I : EraseFromParent)
506 I->eraseFromParent();
520 transform(ChangedTys, std::back_inserter(MDArgs), [=, &Ctx](
auto &&CTy) {
531SPIRVPrepareFunctions::removeAggregateTypesFromSignature(Function *
F) {
532 bool IsRetAggr =
F->getReturnType()->isAggregateType();
534 if (
F->isIntrinsic() && IsRetAggr)
539 bool HasAggrArg =
llvm::any_of(
F->args(), [](Argument &Arg) {
540 return Arg.getType()->isAggregateType();
542 bool DoClone = IsRetAggr || HasAggrArg;
546 Type *RetType = IsRetAggr ?
B.getInt32Ty() :
F->getReturnType();
548 ChangedTypes.
push_back(std::pair<int, Type *>(-1,
F->getReturnType()));
550 for (
const auto &Arg :
F->args()) {
551 if (Arg.getType()->isAggregateType()) {
554 std::pair<int, Type *>(Arg.getArgNo(), Arg.getType()));
558 FunctionType *NewFTy =
559 FunctionType::get(RetType, ArgTypes,
F->getFunctionType()->isVarArg());
562 F->getName(),
F->getParent());
566 for (
auto &Arg :
F->args()) {
567 StringRef ArgName = Arg.getName();
568 NewFArgIt->setName(ArgName);
569 VMap[&Arg] = &(*NewFArgIt++);
579 std::move(ChangedTypes), NewF->
getName());
586 C->handleOperandChange(
F, NewF);
588 U->replaceUsesOfWith(
F, NewF);
592 if (RetType !=
F->getReturnType())
593 TM.
getSubtarget<SPIRVSubtarget>(*F).getSPIRVGlobalRegistry()->addMutated(
594 NewF,
F->getReturnType());
601bool SPIRVPrepareFunctions::removeAggregateTypesFromCalls(Function *
F) {
602 if (
F->isDeclaration() ||
F->isIntrinsic())
608 if (!CB->getCalledOperand() || CB->getCalledFunction())
610 if (CB->getType()->isAggregateType() ||
612 [](
auto &&Arg) { return Arg->getType()->isAggregateType(); }))
622 for (
auto &&[CB, NewFnTy] : Calls) {
626 Type *RetTy = CB->getType();
632 for (
auto &&Arg : CB->args()) {
633 if (Arg->getType()->isAggregateType()) {
635 ChangedTypes.
emplace_back(Arg.getOperandNo(), Arg->getType());
640 NewFnTy = FunctionType::get(RetTy, NewArgTypes,
641 CB->getFunctionType()->isVarArg());
644 CB->setName(
"spv.mutated_callsite." +
F->getName());
646 CB->setName(
"spv.named_mutated_callsite." +
F->getName() +
"." +
650 F->getParent()->getOrInsertNamedMetadata(
"spv.mutated_callsites"),
651 std::move(ChangedTypes), CB->getName());
654 for (
auto &&[CB, NewFTy] : Calls) {
655 if (NewFTy->getReturnType() != CB->getType())
656 TM.
getSubtarget<SPIRVSubtarget>(*F).getSPIRVGlobalRegistry()->addMutated(
658 CB->mutateFunctionType(NewFTy);
664bool SPIRVPrepareFunctions::runOnModule(
Module &M) {
668 const_cast<SPIRVTargetMachine &
>(TM)
669 .getMutableSubtargetImpl()
670 ->resolveEnvFromModule(M);
673 if (
M.functions().empty()) {
685 for (Function &
F : M) {
686 Changed |= substituteIntrinsicCalls(&
F);
688 Changed |= removeAggregateTypesFromCalls(&
F);
691 std::vector<Function *> FuncsWorklist;
693 FuncsWorklist.push_back(&
F);
695 for (
auto *
F : FuncsWorklist) {
696 Function *NewF = removeAggregateTypesFromSignature(
F);
699 F->eraseFromParent();
708 return new SPIRVPrepareFunctions(TM);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Expand Atomic instructions
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Machine Check Debug Module
uint64_t IntrinsicInst * II
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
static void lowerFunnelShifts(IntrinsicInst *FSHIntrinsic)
static std::string getAnnotation(Value *AnnoVal, Value *OptAnnoVal)
static void lowerConstrainedFPCmpIntrinsic(ConstrainedFPCmpIntrinsic *ConstrainedCmpIntrinsic, SmallVector< Instruction * > &EraseFromParent)
static void lowerConstrainedFmuladd(IntrinsicInst *II, SmallVector< Instruction * > &EraseFromParent)
static void lowerPtrAnnotation(IntrinsicInst *II)
static bool lowerIntrinsicToFunction(IntrinsicInst *Intrinsic, const TargetTransformInfo &TTI)
static SmallVector< Metadata * > parseAnnotation(Value *I, const std::string &Anno, LLVMContext &Ctx, Type *Int32Ty)
static bool toSpvLifetimeIntrinsic(IntrinsicInst *II, Intrinsic::ID NewID)
static void lowerExpectAssume(IntrinsicInst *II)
static void addFunctionTypeMutation(NamedMDNode *NMD, SmallVector< std::pair< int, Type * > > ChangedTys, StringRef Name)
static Function * getOrCreateFunction(Module *M, Type *RetTy, ArrayRef< Type * > ArgTypes, StringRef Name)
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.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
Value * getArgOperand(unsigned i) const
FunctionType * getFunctionType() const
void setCalledFunction(Function *Fn)
Sets the function called, including updating the function type.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
This is the shared class of boolean and integer constants.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
Constrained floating point compare intrinsics.
LLVM_ABI FCmpInst::Predicate getPredicate() const
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 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)
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.
LLVM_ABI Value * CreateVectorSplat(unsigned NumElts, Value *V, const Twine &Name="")
Return a vector value that contains.
Value * CreateLShr(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
ReturnInst * CreateRet(Value *V)
Create a 'ret <val>' instruction.
LLVM_ABI CallInst * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > Types, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="")
Create a call to intrinsic ID with Args, mangled using Types.
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)
CallInst * CreateMemSet(Value *Ptr, Value *Val, uint64_t Size, MaybeAlign Align, bool isVolatile=false, const AAMDNodes &AAInfo=AAMDNodes())
Create and insert a memset to the specified pointer and the specified value.
ReturnInst * CreateRetVoid()
Create a 'ret void' instruction.
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Value * CreateOr(Value *LHS, Value *RHS, const Twine &Name="", bool IsDisjoint=false)
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...
LLVM_ABI 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.
This is an important class for using LLVM in a threaded context.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
static LLVM_ABI 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...
A Module instance is used to store all the information related to an LLVM module.
LLVMContext & getContext() const
Get the global data context.
NamedMDNode * getOrInsertNamedMetadata(StringRef Name)
Return the named MDNode in the module with the specified name.
Module * getParent()
Get the module that holds this named metadata collection.
LLVM_ABI void addOperand(MDNode *M)
bool canUseExtension(SPIRV::Extension::Extension E) const
TargetTransformInfo getTargetTransformInfo(const Function &F) const override
Get a TargetTransformInfo implementation for the target.
reference emplace_back(ArgTypes &&... Args)
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.
const Triple & getTargetTriple() const
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
VendorType getVendor() const
Get the parsed vendor type of this triple.
The instances of the Type class are immutable: once they are created, they are never changed.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
bool isAggregateType() const
Return true if the type is an aggregate type.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void setName(const Twine &Name)
Change the name of the value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
LLVM_ABI 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.
@ SPIR_FUNC
Used for SPIR non-kernel device functions.
@ C
The default llvm calling convention, compatible with C.
@ BasicBlock
Various leaf nodes.
This namespace contains an enum with a value for every intrinsic/builtin function known by LLVM.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
LLVM_ABI bool isTargetIntrinsic(ID IID)
isTargetIntrinsic - Returns true if IID is an intrinsic specific to a certain target.
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
FunctionAddr VTableAddr uintptr_t uintptr_t Int32Ty
LLVM_ABI bool getConstantStringInfo(const Value *V, StringRef &Str, bool TrimAtNul=true)
This function computes the length of a null-terminated C string pointed to by V.
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...
bool sortBlocks(Function &F)
Function * getOrCreateBackendServiceFunction(Module &M)
auto dyn_cast_or_null(const Y &Val)
OutputIt transform(R &&Range, OutputIt d_first, UnaryFunction F)
Wrapper function around std::transform to apply a function to a range and store the result elsewhere.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
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...
@ Ref
The access may reference the value stored in memory.
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
void replace(R &&Range, const T &OldValue, const T &NewValue)
Provide wrappers to std::replace which take ranges instead of having to pass begin/end explicitly.
constexpr unsigned BitWidth
ValueMap< const Value *, WeakTrackingVH > ValueToValueMapTy
LLVM_ABI void expandMemSetAsLoop(MemSetInst *MemSet, const TargetTransformInfo *TTI=nullptr)
Expand MemSet as a loop.
LLVM_ABI 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.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
bool to_integer(StringRef S, N &Num, unsigned Base=0)
Convert the string S to an integer of the specified type using the radix Base. If Base is 0,...
ModulePass * createSPIRVPrepareFunctionsPass(const SPIRVTargetMachine &TM)
Implement std::hash so that hash_code can be used in STL containers.