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;
174 if (ArgAttribute->
getString() ==
"read_only")
175 return SPIRV::AccessQualifier::ReadOnly;
176 if (ArgAttribute->
getString() ==
"write_only")
177 return SPIRV::AccessQualifier::WriteOnly;
178 return SPIRV::AccessQualifier::ReadWrite;
181static std::vector<SPIRV::Decoration::Decoration>
184 if (ArgAttribute && ArgAttribute->
getString() ==
"volatile")
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)
250 ElementType, MIRBuilder,
252 cast<ConstantInt>(
II->getOperand(2))->getZExtValue(), ST));
261static SPIRV::ExecutionModel::ExecutionModel
264 return SPIRV::ExecutionModel::Kernel;
266 auto attribute =
F.getFnAttribute(
"hlsl.shader");
267 if (!attribute.isValid()) {
269 "This entry point lacks mandatory hlsl.shader attribute.");
272 const auto value = attribute.getValueAsString();
273 if (
value ==
"compute")
274 return SPIRV::ExecutionModel::GLCompute;
283 assert(GR &&
"Must initialize the SPIRV type registry before lowering args.");
292 if (VRegs.size() > 0) {
294 for (
const auto &Arg :
F.args()) {
297 if (VRegs[i].
size() > 1)
304 buildOpName(VRegs[i][0], Arg.getName(), MIRBuilder);
306 auto DerefBytes =
static_cast<unsigned>(Arg.getDereferenceableBytes());
309 SPIRV::Decoration::MaxByteOffset, {DerefBytes});
311 if (Arg.hasAttribute(Attribute::Alignment)) {
312 auto Alignment =
static_cast<unsigned>(
313 Arg.getAttribute(Attribute::Alignment).getValueAsInt());
317 if (Arg.hasAttribute(Attribute::ReadOnly)) {
319 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoWrite);
321 SPIRV::Decoration::FuncParamAttr, {Attr});
323 if (Arg.hasAttribute(Attribute::ZExt)) {
325 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::Zext);
327 SPIRV::Decoration::FuncParamAttr, {Attr});
329 if (Arg.hasAttribute(Attribute::NoAlias)) {
331 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoAlias);
333 SPIRV::Decoration::FuncParamAttr, {Attr});
335 if (Arg.hasAttribute(Attribute::ByVal)) {
337 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::ByVal);
339 SPIRV::Decoration::FuncParamAttr, {Attr});
343 std::vector<SPIRV::Decoration::Decoration> ArgTypeQualDecs =
345 for (SPIRV::Decoration::Decoration Decoration : ArgTypeQualDecs)
349 MDNode *Node =
F.getMetadata(
"spirv.ParameterDecorations");
350 if (Node && i < Node->getNumOperands() &&
351 isa<MDNode>(Node->getOperand(i))) {
352 MDNode *MD = cast<MDNode>(Node->getOperand(i));
354 MDNode *MD2 = dyn_cast<MDNode>(MDOp);
355 assert(MD2 &&
"Metadata operand is expected");
357 assert(Const &&
"MDOperand should be ConstantInt");
359 static_cast<SPIRV::Decoration::Decoration
>(Const->getZExtValue());
360 std::vector<uint32_t> DecVec;
363 assert(Const &&
"MDOperand should be ConstantInt");
364 DecVec.push_back(
static_cast<uint32_t>(Const->getZExtValue()));
375 MRI->setRegClass(FuncVReg, &SPIRV::iIDRegClass);
376 if (
F.isDeclaration())
377 GR->
add(&
F, &MIRBuilder.
getMF(), FuncVReg);
391 FTy,
RetTy, ArgTypeVRegs, MIRBuilder);
404 for (
const auto &Arg :
F.args()) {
405 assert(VRegs[i].
size() == 1 &&
"Formal arg has multiple vregs");
406 MRI->setRegClass(VRegs[i][0], &SPIRV::iIDRegClass);
407 MIRBuilder.
buildInstr(SPIRV::OpFunctionParameter)
410 if (
F.isDeclaration())
411 GR->
add(&Arg, &MIRBuilder.
getMF(), VRegs[i][0]);
422 auto MIB = MIRBuilder.
buildInstr(SPIRV::OpEntryPoint)
428 SPIRV::LinkageType::LinkageType LnkTy =
430 ? SPIRV::LinkageType::Import
433 SPIRV::Extension::SPV_KHR_linkonce_odr)
434 ? SPIRV::LinkageType::LinkOnceODR
435 : SPIRV::LinkageType::Export);
436 buildOpDecorate(FuncVReg, MIRBuilder, SPIRV::Decoration::LinkageAttributes,
437 {
static_cast<uint32_t>(LnkTy)},
F.getGlobalIdentifier());
441 bool hasFunctionPointers =
442 ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
443 if (hasFunctionPointers) {
444 if (
F.hasFnAttribute(
"referenced-indirectly")) {
446 "Unexpected 'referenced-indirectly' attribute of the kernel "
449 SPIRV::Decoration::ReferencedIndirectlyINTEL, {});
462void SPIRVCallLowering::produceIndirectPtrTypes(
466 for (
auto const &IC : IndirectCalls) {
469 for (
size_t i = 0; i < IC.ArgTys.size(); ++i) {
479 FTy, SpirvRetTy, SpirvArgTypes, MIRBuilder);
482 SpirvFuncTy, MIRBuilder, SPIRV::StorageClass::Function);
492 if (
Info.OrigRet.Regs.size() > 1)
497 std::string DemangledName;
498 const Type *OrigRetTy =
Info.OrigRet.Ty;
503 if (
Info.Callee.isGlobal()) {
504 std::string FuncName =
Info.Callee.getGlobal()->getName().str();
506 CF = dyn_cast_or_null<const Function>(
Info.Callee.getGlobal());
511 OrigRetTy = FTy->getReturnType();
514 OrigRetTy = DerivedRetTy;
525 bool canUseOpenCL = ST->canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std);
526 bool canUseGLSL = ST->canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450);
527 assert(canUseGLSL != canUseOpenCL &&
528 "Scenario where both sets are enabled is not supported.");
530 if (isFunctionDecl && !DemangledName.empty() &&
531 (canUseGLSL || canUseOpenCL)) {
533 for (
auto Arg :
Info.OrigArgs) {
534 assert(Arg.Regs.size() == 1 &&
"Call arg has multiple VRegs");
540 auto instructionSet = canUseOpenCL ? SPIRV::InstructionSet::OpenCL_std
541 : SPIRV::InstructionSet::GLSL_std_450;
544 ResVReg, OrigRetTy, ArgVRegs, GR))
548 if (isFunctionDecl && !GR->
find(CF, &MF).
isValid()) {
552 FirstBlockBuilder.
setMF(MF);
561 MRI->setRegClass(Reg, &SPIRV::iIDRegClass);
571 if (
Info.CB->isIndirectCall()) {
572 if (!ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers))
574 "extensions does not support it",
577 CallOp = SPIRV::OpFunctionPointerCallINTEL;
585 for (
const auto &Arg :
Info.OrigArgs) {
586 assert(Arg.Regs.size() == 1 &&
"Call arg has multiple VRegs");
594 CallOp = SPIRV::OpFunctionCall;
608 for (
const auto &Arg :
Info.OrigArgs) {
610 if (Arg.Regs.size() > 1)
615 *ST->getRegBankInfo());
unsigned const MachineRegisterInfo * MRI
Analysis containing CSE Info
Given that RA is a live value
uint64_t IntrinsicInst * II
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...
@ PrivateLinkage
Like Internal, but omit from symbol table.
@ InternalLinkage
Rename collisions when linking (static functions).
@ 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.
The instances of the Type class are immutable: once they are created, they are never changed.
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)
Type * toTypedPointer(Type *Ty)
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)