26#include "llvm/IR/IntrinsicsSPIRV.h"
40 if (MIRBuilder.
getMF()
47 if (IndirectCalls.
size() > 0) {
48 produceIndirectPtrTypes(MIRBuilder);
49 IndirectCalls.
clear();
58 return MIRBuilder.
buildInstr(SPIRV::OpReturnValue)
61 *STI.getRegBankInfo());
74 if (
F.hasFnAttribute(Attribute::AttrKind::NoInline))
75 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::DontInline);
76 else if (
F.hasFnAttribute(Attribute::AttrKind::AlwaysInline))
77 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::Inline);
80 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::Pure);
82 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::Const);
84 if (ST->canUseExtension(SPIRV::Extension::SPV_INTEL_optnone) ||
85 ST->canUseExtension(SPIRV::Extension::SPV_EXT_optnone))
86 if (
F.hasFnAttribute(Attribute::OptimizeNone))
87 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::OptNoneEXT);
94 auto *CMeta = dyn_cast<ConstantAsMetadata>(MD->
getOperand(NumOp));
96 return dyn_cast<ConstantInt>(CMeta->getValue());
110 bool hasArgPtrs =
false;
111 for (
auto &Arg :
F.args()) {
113 if (Arg.getType()->isPointerTy()) {
121 if (!
RetTy->isPointerTy())
129 for (
auto SArgTy : SArgTys)
138 auto *NamedMD =
F.getParent()->getNamedMetadata(
"spv.cloned_funcs");
139 if (NamedMD ==
nullptr)
140 return F.getFunctionType();
142 Type *
RetTy =
F.getFunctionType()->getReturnType();
144 for (
auto &Arg :
F.args())
148 std::find_if(NamedMD->op_begin(), NamedMD->op_end(), [&
F](
MDNode *
N) {
149 return isa<MDString>(N->getOperand(0)) &&
150 cast<MDString>(N->getOperand(0))->getString() == F.getName();
154 if (ThisFuncMDIt != NamedMD->op_end()) {
155 auto *ThisFuncMD = *ThisFuncMDIt;
156 MDNode *MD = dyn_cast<MDNode>(ThisFuncMD->getOperand(1));
157 assert(MD &&
"MDNode operand is expected");
160 auto *CMeta = dyn_cast<ConstantAsMetadata>(MD->
getOperand(1));
161 assert(CMeta &&
"ConstantAsMetadata operand is expected");
162 assert(Const->getSExtValue() >= -1);
165 if (Const->getSExtValue() == -1)
166 RetTy = CMeta->getType();
168 ArgTypes[Const->getSExtValue()] = CMeta->getType();
175static SPIRV::AccessQualifier::AccessQualifier
178 return SPIRV::AccessQualifier::ReadWrite;
182 return SPIRV::AccessQualifier::ReadWrite;
184 if (ArgAttribute->
getString() ==
"read_only")
185 return SPIRV::AccessQualifier::ReadOnly;
186 if (ArgAttribute->
getString() ==
"write_only")
187 return SPIRV::AccessQualifier::WriteOnly;
188 return SPIRV::AccessQualifier::ReadWrite;
191static std::vector<SPIRV::Decoration::Decoration>
194 if (ArgAttribute && ArgAttribute->
getString() ==
"volatile")
195 return {SPIRV::Decoration::Volatile};
204 SPIRV::AccessQualifier::AccessQualifier ArgAccessQual =
218 cast<TypedPointerType>(ArgType)->getElementType(), MIRBuilder);
220 ElementType, MIRBuilder,
236 ElementType, MIRBuilder,
241 auto *
II = dyn_cast<IntrinsicInst>(
User);
243 if (
II &&
II->getIntrinsicID() == Intrinsic::spv_assign_type) {
246 cast<ConstantAsMetadata>(VMD->
getMetadata())->getType();
247 assert(BuiltinType->isTargetExtTy() &&
"Expected TargetExtType");
252 if (!
II ||
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type)
260 ElementType, MIRBuilder,
262 cast<ConstantInt>(
II->getOperand(2))->getZExtValue(), ST));
271static SPIRV::ExecutionModel::ExecutionModel
274 return SPIRV::ExecutionModel::Kernel;
276 auto attribute =
F.getFnAttribute(
"hlsl.shader");
277 if (!attribute.isValid()) {
279 "This entry point lacks mandatory hlsl.shader attribute.");
282 const auto value = attribute.getValueAsString();
283 if (
value ==
"compute")
284 return SPIRV::ExecutionModel::GLCompute;
297 assert(GR &&
"Must initialize the SPIRV type registry before lowering args.");
306 if (VRegs.size() > 0) {
308 for (
const auto &Arg :
F.args()) {
311 if (VRegs[i].
size() > 1)
318 buildOpName(VRegs[i][0], Arg.getName(), MIRBuilder);
320 auto DerefBytes =
static_cast<unsigned>(Arg.getDereferenceableBytes());
323 SPIRV::Decoration::MaxByteOffset, {DerefBytes});
325 if (Arg.hasAttribute(Attribute::Alignment)) {
326 auto Alignment =
static_cast<unsigned>(
327 Arg.getAttribute(Attribute::Alignment).getValueAsInt());
331 if (Arg.hasAttribute(Attribute::ReadOnly)) {
333 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoWrite);
335 SPIRV::Decoration::FuncParamAttr, {Attr});
337 if (Arg.hasAttribute(Attribute::ZExt)) {
339 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::Zext);
341 SPIRV::Decoration::FuncParamAttr, {Attr});
343 if (Arg.hasAttribute(Attribute::NoAlias)) {
345 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoAlias);
347 SPIRV::Decoration::FuncParamAttr, {Attr});
349 if (Arg.hasAttribute(Attribute::ByVal)) {
351 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::ByVal);
353 SPIRV::Decoration::FuncParamAttr, {Attr});
355 if (Arg.hasAttribute(Attribute::StructRet)) {
357 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::Sret);
359 SPIRV::Decoration::FuncParamAttr, {Attr});
363 std::vector<SPIRV::Decoration::Decoration> ArgTypeQualDecs =
365 for (SPIRV::Decoration::Decoration Decoration : ArgTypeQualDecs)
369 MDNode *Node =
F.getMetadata(
"spirv.ParameterDecorations");
370 if (Node && i < Node->getNumOperands() &&
371 isa<MDNode>(Node->getOperand(i))) {
372 MDNode *MD = cast<MDNode>(Node->getOperand(i));
374 MDNode *MD2 = dyn_cast<MDNode>(MDOp);
375 assert(MD2 &&
"Metadata operand is expected");
377 assert(Const &&
"MDOperand should be ConstantInt");
379 static_cast<SPIRV::Decoration::Decoration
>(Const->getZExtValue());
380 std::vector<uint32_t> DecVec;
383 assert(Const &&
"MDOperand should be ConstantInt");
384 DecVec.push_back(
static_cast<uint32_t>(Const->getZExtValue()));
395 MRI->setRegClass(FuncVReg, &SPIRV::iIDRegClass);
396 if (
F.isDeclaration())
397 GR->
add(&
F, &MIRBuilder.
getMF(), FuncVReg);
411 FTy,
RetTy, ArgTypeVRegs, MIRBuilder);
425 for (
const auto &Arg :
F.args()) {
426 assert(VRegs[i].
size() == 1 &&
"Formal arg has multiple vregs");
430 MIRBuilder.
buildInstr(SPIRV::OpFunctionParameter)
433 if (
F.isDeclaration())
434 GR->
add(&Arg, &MIRBuilder.
getMF(), ArgReg);
444 auto MIB = MIRBuilder.
buildInstr(SPIRV::OpEntryPoint)
450 SPIRV::LinkageType::LinkageType LnkTy =
452 ? SPIRV::LinkageType::Import
455 SPIRV::Extension::SPV_KHR_linkonce_odr)
456 ? SPIRV::LinkageType::LinkOnceODR
457 : SPIRV::LinkageType::Export);
458 buildOpDecorate(FuncVReg, MIRBuilder, SPIRV::Decoration::LinkageAttributes,
459 {
static_cast<uint32_t>(LnkTy)},
F.getGlobalIdentifier());
463 bool hasFunctionPointers =
464 ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
465 if (hasFunctionPointers) {
466 if (
F.hasFnAttribute(
"referenced-indirectly")) {
468 "Unexpected 'referenced-indirectly' attribute of the kernel "
471 SPIRV::Decoration::ReferencedIndirectlyINTEL, {});
484void SPIRVCallLowering::produceIndirectPtrTypes(
488 for (
auto const &IC : IndirectCalls) {
491 for (
size_t i = 0; i < IC.ArgTys.size(); ++i) {
501 FTy, SpirvRetTy, SpirvArgTypes, MIRBuilder);
504 SpirvFuncTy, MIRBuilder, SPIRV::StorageClass::Function);
514 if (
Info.OrigRet.Regs.size() > 1)
519 std::string DemangledName;
520 const Type *OrigRetTy =
Info.OrigRet.Ty;
525 if (
Info.Callee.isGlobal()) {
526 std::string FuncName =
Info.Callee.getGlobal()->getName().str();
528 CF = dyn_cast_or_null<const Function>(
Info.Callee.getGlobal());
533 OrigRetTy = FTy->getReturnType();
536 OrigRetTy = DerivedRetTy;
547 bool canUseOpenCL = ST->canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std);
548 bool canUseGLSL = ST->canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450);
549 assert(canUseGLSL != canUseOpenCL &&
550 "Scenario where both sets are enabled is not supported.");
552 if (isFunctionDecl && !DemangledName.empty() &&
553 (canUseGLSL || canUseOpenCL)) {
557 if (
auto *PtrRetTy = dyn_cast<PointerType>(OrigRetTy)) {
558 const Value *OrigValue =
Info.OrigRet.OrigValue;
572 for (
auto Arg :
Info.OrigArgs) {
573 assert(Arg.Regs.size() == 1 &&
"Call arg has multiple VRegs");
578 Type *ArgTy =
nullptr;
579 if (
auto *PtrArgTy = dyn_cast<PointerType>(Arg.Ty)) {
597 if (!
MRI->getRegClassOrNull(ArgReg)) {
602 : &SPIRV::pIDRegClass);
606 :
LLT::pointer(cast<PointerType>(Arg.Ty)->getAddressSpace(),
610 auto instructionSet = canUseOpenCL ? SPIRV::InstructionSet::OpenCL_std
611 : SPIRV::InstructionSet::GLSL_std_450;
614 ResVReg, OrigRetTy, ArgVRegs, GR))
618 if (isFunctionDecl && !GR->
find(CF, &MF).
isValid()) {
622 FirstBlockBuilder.
setMF(MF);
631 MRI->setRegClass(Reg, &SPIRV::iIDRegClass);
641 if (MIRBuilder.
getMF()
651 if (
Info.CB->isIndirectCall()) {
652 if (!ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers))
654 "extensions does not support it",
657 CallOp = SPIRV::OpFunctionPointerCallINTEL;
665 for (
const auto &Arg :
Info.OrigArgs) {
666 assert(Arg.Regs.size() == 1 &&
"Call arg has multiple VRegs");
674 CallOp = SPIRV::OpFunctionCall;
688 for (
const auto &Arg :
Info.OrigArgs) {
690 if (Arg.Regs.size() > 1)
695 *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 SPIRV::ExecutionModel::ExecutionModel getExecutionModel(const SPIRVSubtarget &STI, const Function &F)
static FunctionType * getOriginalFunctionType(const Function &F)
static uint32_t getFunctionControl(const Function &F, const SPIRVSubtarget *ST)
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)
#define SPIRV_BACKEND_SERVICE_FUN_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),...
size_t size() const
size - Get the array size.
bool isValid() const
Return true if the attribute is any kind of attribute.
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()
Attribute getFnAttribute(Attribute::AttrKind Kind) const
Return the attribute for the given attribute kind.
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".
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
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...
Function & getFunction()
Return the LLVM function that this machine code represents.
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.
MachineInstrBuilder buildTrap(bool Debug=false)
Build and insert G_TRAP or G_DEBUGTRAP.
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 assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg, const MachineFunction &MF)
void add(const Constant *C, MachineFunction *MF, Register R)
const Type * getTypeForSPIRVType(const SPIRVType *Ty) const
unsigned getPointerSize() 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 addGlobalObject(const Value *V, const MachineFunction *MF, Register R)
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)
const TargetRegisterClass * getRegClass(SPIRVType *SpvType) const
MachineFunction * setCurrentFunc(MachineFunction &MF)
Register find(const MachineInstr *MI, MachineFunction *MF)
SPIRVType * getOrCreateSPIRVPointerType(SPIRVType *BaseType, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SClass=SPIRV::StorageClass::Function)
LLT getRegType(SPIRVType *SpvType) const
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)
Register createVirtualRegister(SPIRVType *SpvType, SPIRVGlobalRegistry *GR, MachineRegisterInfo *MRI, const MachineFunction &MF)
Type * toTypedPointer(Type *Ty)
void setRegClassType(Register Reg, SPIRVType *SpvType, SPIRVGlobalRegistry *GR, MachineRegisterInfo *MRI, const MachineFunction &MF, bool Force)
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)
bool isPointerTyOrWrapper(const Type *Ty)
void addStringImm(const StringRef &Str, MCInst &Inst)
bool isUntypedPointerTy(const Type *T)