26#include "llvm/IR/IntrinsicsSPIRV.h"
40 if (IndirectCalls.
size() > 0) {
41 produceIndirectPtrTypes(MIRBuilder);
42 IndirectCalls.
clear();
51 return MIRBuilder.
buildInstr(SPIRV::OpReturnValue)
54 *STI.getRegBankInfo());
66 if (
F.hasFnAttribute(Attribute::AttrKind::NoInline))
67 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::DontInline);
68 else if (
F.hasFnAttribute(Attribute::AttrKind::AlwaysInline))
69 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::Inline);
72 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::Pure);
74 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::Const);
81 auto *CMeta = dyn_cast<ConstantAsMetadata>(MD->
getOperand(NumOp));
83 return dyn_cast<ConstantInt>(CMeta->getValue());
97 if (
F.getParent()->getNamedMetadata(
"spv.cloned_funcs"))
100 bool hasArgPtrs =
false;
101 for (
auto &Arg :
F.args()) {
103 if (Arg.getType()->isPointerTy()) {
111 if (!
RetTy->isPointerTy())
119 for (
auto SArgTy : SArgTys)
128 auto *NamedMD =
F.getParent()->getNamedMetadata(
"spv.cloned_funcs");
129 if (NamedMD ==
nullptr)
130 return F.getFunctionType();
132 Type *
RetTy =
F.getFunctionType()->getReturnType();
134 for (
auto &Arg :
F.args())
138 std::find_if(NamedMD->op_begin(), NamedMD->op_end(), [&
F](
MDNode *
N) {
139 return isa<MDString>(N->getOperand(0)) &&
140 cast<MDString>(N->getOperand(0))->getString() == F.getName();
144 if (ThisFuncMDIt != NamedMD->op_end()) {
145 auto *ThisFuncMD = *ThisFuncMDIt;
146 MDNode *MD = dyn_cast<MDNode>(ThisFuncMD->getOperand(1));
147 assert(MD &&
"MDNode operand is expected");
150 auto *CMeta = dyn_cast<ConstantAsMetadata>(MD->
getOperand(1));
151 assert(CMeta &&
"ConstantAsMetadata operand is expected");
152 assert(Const->getSExtValue() >= -1);
155 if (Const->getSExtValue() == -1)
156 RetTy = CMeta->getType();
158 ArgTypes[Const->getSExtValue()] = CMeta->getType();
165static SPIRV::AccessQualifier::AccessQualifier
168 return SPIRV::AccessQualifier::ReadWrite;
172 return SPIRV::AccessQualifier::ReadWrite;
175 return SPIRV::AccessQualifier::ReadOnly;
177 return SPIRV::AccessQualifier::WriteOnly;
178 return SPIRV::AccessQualifier::ReadWrite;
181static std::vector<SPIRV::Decoration::Decoration>
185 return {SPIRV::Decoration::Volatile};
194 SPIRV::AccessQualifier::AccessQualifier ArgAccessQual =
208 cast<TypedPointerType>(ArgType)->getElementType(), MIRBuilder);
210 ElementType, MIRBuilder,
226 ElementType, MIRBuilder,
231 auto *II = dyn_cast<IntrinsicInst>(
User);
233 if (II && II->getIntrinsicID() == Intrinsic::spv_assign_type) {
236 cast<ConstantAsMetadata>(VMD->
getMetadata())->getType();
237 assert(BuiltinType->isTargetExtTy() &&
"Expected TargetExtType");
242 if (!II || II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type)
246 Type *ElementTy = cast<ConstantAsMetadata>(VMD->
getMetadata())->getType();
253 ElementType, MIRBuilder,
255 cast<ConstantInt>(II->getOperand(2))->getZExtValue(), ST));
268static SPIRV::ExecutionModel::ExecutionModel
271 return SPIRV::ExecutionModel::Kernel;
273 auto attribute =
F.getFnAttribute(
"hlsl.shader");
274 if (!attribute.isValid()) {
276 "This entry point lacks mandatory hlsl.shader attribute.");
279 const auto value = attribute.getValueAsString();
280 if (
value ==
"compute")
281 return SPIRV::ExecutionModel::GLCompute;
290 assert(GR &&
"Must initialize the SPIRV type registry before lowering args.");
299 if (VRegs.size() > 0) {
301 for (
const auto &Arg :
F.args()) {
304 if (VRegs[i].
size() > 1)
311 buildOpName(VRegs[i][0], Arg.getName(), MIRBuilder);
313 auto DerefBytes =
static_cast<unsigned>(Arg.getDereferenceableBytes());
316 SPIRV::Decoration::MaxByteOffset, {DerefBytes});
318 if (Arg.hasAttribute(Attribute::Alignment)) {
319 auto Alignment =
static_cast<unsigned>(
320 Arg.getAttribute(Attribute::Alignment).getValueAsInt());
324 if (Arg.hasAttribute(Attribute::ReadOnly)) {
326 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoWrite);
328 SPIRV::Decoration::FuncParamAttr, {Attr});
330 if (Arg.hasAttribute(Attribute::ZExt)) {
332 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::Zext);
334 SPIRV::Decoration::FuncParamAttr, {Attr});
336 if (Arg.hasAttribute(Attribute::NoAlias)) {
338 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoAlias);
340 SPIRV::Decoration::FuncParamAttr, {Attr});
342 if (Arg.hasAttribute(Attribute::ByVal)) {
344 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::ByVal);
346 SPIRV::Decoration::FuncParamAttr, {Attr});
350 std::vector<SPIRV::Decoration::Decoration> ArgTypeQualDecs =
352 for (SPIRV::Decoration::Decoration Decoration : ArgTypeQualDecs)
356 MDNode *Node =
F.getMetadata(
"spirv.ParameterDecorations");
357 if (Node && i < Node->getNumOperands() &&
358 isa<MDNode>(Node->getOperand(i))) {
359 MDNode *MD = cast<MDNode>(Node->getOperand(i));
361 MDNode *MD2 = dyn_cast<MDNode>(MDOp);
362 assert(MD2 &&
"Metadata operand is expected");
364 assert(Const &&
"MDOperand should be ConstantInt");
366 static_cast<SPIRV::Decoration::Decoration
>(Const->getZExtValue());
367 std::vector<uint32_t> DecVec;
370 assert(Const &&
"MDOperand should be ConstantInt");
371 DecVec.push_back(
static_cast<uint32_t>(Const->getZExtValue()));
382 MRI->setRegClass(FuncVReg, &SPIRV::IDRegClass);
383 if (
F.isDeclaration())
384 GR->
add(&
F, &MIRBuilder.
getMF(), FuncVReg);
398 FTy,
RetTy, ArgTypeVRegs, MIRBuilder);
411 for (
const auto &Arg :
F.args()) {
412 assert(VRegs[i].
size() == 1 &&
"Formal arg has multiple vregs");
413 MRI->setRegClass(VRegs[i][0], &SPIRV::IDRegClass);
414 MIRBuilder.
buildInstr(SPIRV::OpFunctionParameter)
417 if (
F.isDeclaration())
418 GR->
add(&Arg, &MIRBuilder.
getMF(), VRegs[i][0]);
429 auto MIB = MIRBuilder.
buildInstr(SPIRV::OpEntryPoint)
435 SPIRV::LinkageType::LinkageType LnkTy =
437 ? SPIRV::LinkageType::Import
440 SPIRV::Extension::SPV_KHR_linkonce_odr)
441 ? SPIRV::LinkageType::LinkOnceODR
442 : SPIRV::LinkageType::Export);
443 buildOpDecorate(FuncVReg, MIRBuilder, SPIRV::Decoration::LinkageAttributes,
444 {
static_cast<uint32_t>(LnkTy)},
F.getGlobalIdentifier());
448 bool hasFunctionPointers =
449 ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
450 if (hasFunctionPointers) {
451 if (
F.hasFnAttribute(
"referenced-indirectly")) {
453 "Unexpected 'referenced-indirectly' attribute of the kernel "
456 SPIRV::Decoration::ReferencedIndirectlyINTEL, {});
469void SPIRVCallLowering::produceIndirectPtrTypes(
473 for (
auto const &IC : IndirectCalls) {
476 for (
size_t i = 0; i < IC.ArgTys.size(); ++i) {
486 FTy, SpirvRetTy, SpirvArgTypes, MIRBuilder);
489 SpirvFuncTy, MIRBuilder, SPIRV::StorageClass::Function);
499 if (
Info.OrigRet.Regs.size() > 1)
504 std::string DemangledName;
505 const Type *OrigRetTy =
Info.OrigRet.Ty;
510 if (
Info.Callee.isGlobal()) {
511 std::string FuncName =
Info.Callee.getGlobal()->getName().str();
513 CF = dyn_cast_or_null<const Function>(
Info.Callee.getGlobal());
518 OrigRetTy = FTy->getReturnType();
521 OrigRetTy = DerivedRetTy;
532 bool canUseOpenCL = ST->canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std);
533 bool canUseGLSL = ST->canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450);
534 assert(canUseGLSL != canUseOpenCL &&
535 "Scenario where both sets are enabled is not supported.");
537 if (isFunctionDecl && !DemangledName.empty() &&
538 (canUseGLSL || canUseOpenCL)) {
540 for (
auto Arg :
Info.OrigArgs) {
541 assert(Arg.Regs.size() == 1 &&
"Call arg has multiple VRegs");
547 auto instructionSet = canUseOpenCL ? SPIRV::InstructionSet::OpenCL_std
548 : SPIRV::InstructionSet::GLSL_std_450;
551 ResVReg, OrigRetTy, ArgVRegs, GR))
555 if (isFunctionDecl && !GR->
find(CF, &MF).
isValid()) {
559 FirstBlockBuilder.
setMF(MF);
568 MRI->setRegClass(Reg, &SPIRV::IDRegClass);
578 if (
Info.CB->isIndirectCall()) {
579 if (!ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers))
581 "extensions does not support it",
584 CallOp = SPIRV::OpFunctionPointerCallINTEL;
592 for (
const auto &Arg :
Info.OrigArgs) {
593 assert(Arg.Regs.size() == 1 &&
"Call arg has multiple VRegs");
601 CallOp = SPIRV::OpFunctionCall;
615 for (
const auto &Arg :
Info.OrigArgs) {
617 if (Arg.Regs.size() > 1)
622 *ST->getRegBankInfo());
unsigned const MachineRegisterInfo * MRI
Analysis containing CSE Info
Given that RA is a live value
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static ConstantInt * getConstInt(MDNode *MD, unsigned NumOp)
static uint32_t getFunctionControl(const Function &F)
static SPIRV::ExecutionModel::ExecutionModel getExecutionModel(const SPIRVSubtarget &STI, const Function &F)
static FunctionType * getOriginalFunctionType(const Function &F)
static SPIRV::AccessQualifier::AccessQualifier getArgAccessQual(const Function &F, unsigned ArgIdx)
static SPIRVType * getArgSPIRVType(const Function &F, unsigned ArgIdx, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIRBuilder, const SPIRVSubtarget &ST)
static FunctionType * fixFunctionTypeIfPtrArgs(SPIRVGlobalRegistry *GR, const Function &F, FunctionType *FTy, const SPIRVType *SRetTy, const SmallVector< SPIRVType *, 4 > &SArgTys)
static std::vector< SPIRV::Decoration::Decoration > getKernelArgTypeQual(const Function &F, unsigned ArgIdx)
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),...
size_t size() const
size - Get the array size.
This is the shared class of boolean and integer constants.
TypeSize getTypeStoreSize(Type *Ty) const
Returns the maximum number of bytes that may be overwritten by storing the specified type.
FunctionLoweringInfo - This contains information that is global to a function that is used when lower...
Class to represent function types.
Type * getParamType(unsigned i) const
Parameter type accessors.
Type * getReturnType() const
static FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
iterator_range< arg_iterator > args()
bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
@ ExternalLinkage
Externally visible function.
@ LinkOnceODRLinkage
Same, but only replaced by something equivalent.
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
const MDOperand & getOperand(unsigned I) const
ArrayRef< MDOperand > operands() const
unsigned getNumOperands() const
Return number of MDNode operands.
Tracking metadata reference owned by Metadata.
StringRef getString() const
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineBasicBlock * getBlockNumbered(unsigned N) const
getBlockNumbered - MachineBasicBlocks are automatically numbered when they are inserted into the mach...
Helper class to build MachineInstr.
const TargetInstrInfo & getTII()
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
void setMBB(MachineBasicBlock &MBB)
Set the insertion point to the end of MBB.
MachineRegisterInfo * getMRI()
Getter for MRI.
const DataLayout & getDataLayout() const
void setMF(MachineFunction &MF)
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
bool constrainAllUses(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
const MachineOperand & getOperand(unsigned i) const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
bool doesNotAccessMemory() const
Whether this function accesses no memory.
bool onlyReadsMemory() const
Whether this function only (at most) reads memory.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
bool lowerCall(MachineIRBuilder &MIRBuilder, CallLoweringInfo &Info) const override
This hook must be implemented to lower the given call instruction, including argument and return valu...
bool lowerReturn(MachineIRBuilder &MIRBuiler, const Value *Val, ArrayRef< Register > VRegs, FunctionLoweringInfo &FLI, Register SwiftErrorVReg) const override
This hook must be implemented to lower outgoing return values, described by Val, into the specified v...
SPIRVCallLowering(const SPIRVTargetLowering &TLI, SPIRVGlobalRegistry *GR)
bool lowerFormalArguments(MachineIRBuilder &MIRBuilder, const Function &F, ArrayRef< ArrayRef< Register > > VRegs, FunctionLoweringInfo &FLI) const override
This hook must be implemented to lower the incoming (formal) arguments, described by VRegs,...
void recordFunctionDefinition(const Function *F, const MachineOperand *MO)
SPIRVType * getSPIRVTypeForVReg(Register VReg, const MachineFunction *MF=nullptr) const
const TypedPointerType * findReturnType(const Function *ArgF)
void add(const Constant *C, MachineFunction *MF, Register R)
const Type * getTypeForSPIRVType(const SPIRVType *Ty) const
void addReturnType(const Function *ArgF, TypedPointerType *DerivedTy)
Register getSPIRVTypeID(const SPIRVType *SpirvType) const
SPIRVType * getOrCreateSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder, SPIRV::AccessQualifier::AccessQualifier AQ=SPIRV::AccessQualifier::ReadWrite, bool EmitIR=true)
void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg, MachineFunction &MF)
SPIRVType * assignTypeToVReg(const Type *Type, Register VReg, MachineIRBuilder &MIRBuilder, SPIRV::AccessQualifier::AccessQualifier AQ=SPIRV::AccessQualifier::ReadWrite, bool EmitIR=true)
SPIRVType * getOrCreateOpTypeFunctionWithArgs(const Type *Ty, SPIRVType *RetType, const SmallVectorImpl< SPIRVType * > &ArgTypes, MachineIRBuilder &MIRBuilder)
MachineFunction * setCurrentFunc(MachineFunction &MF)
Register find(const MachineInstr *MI, MachineFunction *MF)
SPIRVType * getOrCreateSPIRVPointerType(SPIRVType *BaseType, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SClass=SPIRV::StorageClass::Function)
Type * findDeducedElementType(const Value *Val)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
int compare(StringRef RHS) const
compare - Compare two strings; the result is negative, zero, or positive if this string is lexicograp...
The instances of the Type class are immutable: once they are created, they are never changed.
static IntegerType * getInt8Ty(LLVMContext &C)
A few GPU targets, such as DXIL and SPIR-V, have typed pointers.
static TypedPointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
iterator_range< user_iterator > users()
constexpr bool isZero() const
@ SPIR_KERNEL
Used for SPIR kernel functions.
std::optional< bool > lowerBuiltin(const StringRef DemangledCall, SPIRV::InstructionSet::InstructionSet Set, MachineIRBuilder &MIRBuilder, const Register OrigRet, const Type *OrigRetTy, const SmallVectorImpl< Register > &Args, SPIRVGlobalRegistry *GR)
This is an optimization pass for GlobalISel generic memory operations.
void buildOpName(Register Target, const StringRef &Name, MachineIRBuilder &MIRBuilder)
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
unsigned getPointerAddressSpace(const Type *T)
MDString * getOCLKernelArgAccessQual(const Function &F, unsigned ArgIdx)
std::string getOclOrSpirvBuiltinDemangledName(StringRef Name)
bool isTypedPointerTy(const Type *T)
void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, SPIRV::Decoration::Decoration Dec, const std::vector< uint32_t > &DecArgs, StringRef StrImm)
bool isPointerTy(const Type *T)
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
bool isEntryPoint(const Function &F)
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI)
MDString * getOCLKernelArgTypeQual(const Function &F, unsigned ArgIdx)
Type * getPointeeTypeByAttr(Argument *Arg)
bool hasPointeeTypeAttr(Argument *Arg)
void addStringImm(const StringRef &Str, MCInst &Inst)
bool isUntypedPointerTy(const Type *T)