26#include "llvm/IR/IntrinsicsSPIRV.h"
40 if (MIRBuilder.
getMF()
52 return MIRBuilder.
buildInstr(SPIRV::OpReturnValue)
55 *STI.getRegBankInfo());
68 if (
F.hasFnAttribute(Attribute::AttrKind::NoInline))
69 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::DontInline);
70 else if (
F.hasFnAttribute(Attribute::AttrKind::AlwaysInline))
71 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::Inline);
74 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::Pure);
76 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::Const);
78 if (ST->canUseExtension(SPIRV::Extension::SPV_INTEL_optnone) ||
79 ST->canUseExtension(SPIRV::Extension::SPV_EXT_optnone))
80 if (
F.hasFnAttribute(Attribute::OptimizeNone))
81 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::OptNoneEXT);
104 bool hasArgPtrs =
false;
105 for (
auto &Arg :
F.args()) {
107 if (Arg.getType()->isPointerTy()) {
113 Type *RetTy = FTy->getReturnType();
123 for (
auto SArgTy : SArgTys)
128static SPIRV::AccessQualifier::AccessQualifier
131 return SPIRV::AccessQualifier::ReadWrite;
135 return SPIRV::AccessQualifier::ReadWrite;
137 if (ArgAttribute->
getString() ==
"read_only")
138 return SPIRV::AccessQualifier::ReadOnly;
139 if (ArgAttribute->
getString() ==
"write_only")
140 return SPIRV::AccessQualifier::WriteOnly;
141 return SPIRV::AccessQualifier::ReadWrite;
144static std::vector<SPIRV::Decoration::Decoration>
147 if (ArgAttribute && ArgAttribute->
getString() ==
"volatile")
148 return {SPIRV::Decoration::Volatile};
157 SPIRV::AccessQualifier::AccessQualifier ArgAccessQual =
160 Type *OriginalArgType =
194 if (
II &&
II->getIntrinsicID() == Intrinsic::spv_assign_type) {
198 assert(BuiltinType->isTargetExtTy() &&
"Expected TargetExtType");
204 if (!
II ||
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type)
211 ElementTy, MIRBuilder,
219 ArgAccessQual,
true);
222static SPIRV::ExecutionModel::ExecutionModel
225 return SPIRV::ExecutionModel::Kernel;
228 auto attribute =
F.getFnAttribute(
"hlsl.shader");
229 if (!attribute.isValid()) {
231 "This entry point lacks mandatory hlsl.shader attribute.");
234 const auto value = attribute.getValueAsString();
235 if (value ==
"compute")
236 return SPIRV::ExecutionModel::GLCompute;
237 if (value ==
"vertex")
238 return SPIRV::ExecutionModel::Vertex;
239 if (value ==
"pixel")
240 return SPIRV::ExecutionModel::Fragment;
243 "This HLSL entry point is not supported by this backend.");
253 auto attribute =
F.getFnAttribute(
"hlsl.shader");
254 if (!attribute.isValid()) {
256 return SPIRV::ExecutionModel::Kernel;
260 const auto value = attribute.getValueAsString();
261 if (value ==
"compute")
262 return SPIRV::ExecutionModel::GLCompute;
263 if (value ==
"vertex")
264 return SPIRV::ExecutionModel::Vertex;
265 if (value ==
"pixel")
266 return SPIRV::ExecutionModel::Fragment;
279 assert(GR &&
"Must initialize the SPIRV type registry before lowering args.");
280 GR->setCurrentFunc(MIRBuilder.
getMF());
288 if (VRegs.size() > 0) {
290 for (
const auto &Arg :
F.args()) {
293 if (VRegs[i].
size() > 1)
296 GR->assignSPIRVTypeToVReg(SpirvTy, VRegs[i][0], MIRBuilder.
getMF());
300 buildOpName(VRegs[i][0], Arg.getName(), MIRBuilder);
302 auto DerefBytes =
static_cast<unsigned>(Arg.getDereferenceableBytes());
305 SPIRV::Decoration::MaxByteOffset, {DerefBytes});
307 if (Arg.hasAttribute(Attribute::Alignment) && !ST->isShader()) {
308 auto Alignment =
static_cast<unsigned>(
309 Arg.getAttribute(Attribute::Alignment).getValueAsInt());
313 if (Arg.hasAttribute(Attribute::ReadOnly)) {
315 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoWrite);
317 SPIRV::Decoration::FuncParamAttr, {Attr});
319 if (Arg.hasAttribute(Attribute::ZExt)) {
321 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::Zext);
323 SPIRV::Decoration::FuncParamAttr, {Attr});
325 if (Arg.hasAttribute(Attribute::NoAlias)) {
327 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoAlias);
329 SPIRV::Decoration::FuncParamAttr, {Attr});
336 if (Arg.hasAttribute(Attribute::ByVal) ||
337 (Arg.hasAttribute(Attribute::ByRef) &&
338 F.getParent()->getTargetTriple().getVendor() ==
341 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::ByVal);
343 SPIRV::Decoration::FuncParamAttr, {Attr});
345 if (Arg.hasAttribute(Attribute::StructRet)) {
347 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::Sret);
349 SPIRV::Decoration::FuncParamAttr, {Attr});
353 std::vector<SPIRV::Decoration::Decoration> ArgTypeQualDecs =
355 for (SPIRV::Decoration::Decoration Decoration : ArgTypeQualDecs)
359 MDNode *
Node =
F.getMetadata(
"spirv.ParameterDecorations");
360 if (
Node && i < Node->getNumOperands() &&
365 assert(MD2 &&
"Metadata operand is expected");
367 assert(Const &&
"MDOperand should be ConstantInt");
369 static_cast<SPIRV::Decoration::Decoration
>(Const->getZExtValue());
370 std::vector<uint32_t> DecVec;
373 assert(Const &&
"MDOperand should be ConstantInt");
374 DecVec.push_back(
static_cast<uint32_t>(Const->getZExtValue()));
385 MRI->setRegClass(FuncVReg, &SPIRV::iIDRegClass);
389 if (
Type *FRetElemTy = GR->findDeducedElementType(&
F)) {
392 GR->addReturnType(&
F, DerivedTy);
396 SPIRVType *RetTy = GR->getOrCreateSPIRVType(
397 FRetTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
true);
399 SPIRVType *FuncTy = GR->getOrCreateOpTypeFunctionWithArgs(
400 FTy, RetTy, ArgTypeVRegs, MIRBuilder);
406 .
addUse(GR->getSPIRVTypeID(RetTy))
408 .
addUse(GR->getSPIRVTypeID(FuncTy));
410 GR->addGlobalObject(&
F, &MIRBuilder.
getMF(), FuncVReg);
411 if (
F.isDeclaration())
416 for (
const auto &Arg :
F.args()) {
417 assert(VRegs[i].
size() == 1 &&
"Formal arg has multiple vregs");
419 MRI->setRegClass(ArgReg, GR->getRegClass(ArgTypeVRegs[i]));
420 MRI->setType(ArgReg, GR->getRegType(ArgTypeVRegs[i]));
421 auto MIB = MIRBuilder.
buildInstr(SPIRV::OpFunctionParameter)
423 .
addUse(GR->getSPIRVTypeID(ArgTypeVRegs[i]));
424 if (
F.isDeclaration())
426 GR->addGlobalObject(&Arg, &MIRBuilder.
getMF(), ArgReg);
440 auto MIB = MIRBuilder.
buildInstr(SPIRV::OpEntryPoint)
445 buildOpDecorate(FuncVReg, MIRBuilder, SPIRV::Decoration::LinkageAttributes,
446 {
static_cast<uint32_t>(*LnkTy)},
F.getName());
450 bool hasFunctionPointers =
451 ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
452 if (hasFunctionPointers) {
453 if (
F.hasFnAttribute(
"referenced-indirectly")) {
455 "Unexpected 'referenced-indirectly' attribute of the kernel "
458 SPIRV::Decoration::ReferencedIndirectlyINTEL, {});
473void SPIRVCallLowering::produceIndirectPtrType(
475 const SPIRVCallLowering::SPIRVIndirectCall &IC)
const {
480 IC.RetTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
true);
482 for (
size_t i = 0; i < IC.ArgTys.size(); ++i) {
484 IC.ArgTys[i], MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
true);
493 FTy, SpirvRetTy, SpirvArgTypes, MIRBuilder);
495 auto SC = ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)
496 ? SPIRV::StorageClass::CodeSectionINTEL
497 : SPIRV::StorageClass::Function;
508 if (Info.OrigRet.Regs.size() > 1)
511 GR->setCurrentFunc(MF);
513 std::string DemangledName;
514 const Type *OrigRetTy = Info.OrigRet.Ty;
519 if (Info.Callee.isGlobal()) {
520 std::string FuncName = Info.Callee.getGlobal()->getName().str();
530 if (
auto *DerivedRetTy = GR->findReturnType(CF))
531 OrigRetTy = DerivedRetTy;
537 Info.OrigRet.Regs.empty() ?
Register(0) : Info.OrigRet.Regs[0];
541 if (isFunctionDecl && !DemangledName.empty()) {
543 if (!GR->getSPIRVTypeForVReg(ResVReg)) {
544 const Type *RetTy = OrigRetTy;
546 const Value *OrigValue = Info.OrigRet.OrigValue;
550 if (
Type *ElemTy = GR->findDeducedElementType(OrigValue))
555 SPIRV::AccessQualifier::ReadWrite,
true);
559 SPIRV::AccessQualifier::ReadWrite,
true);
562 for (
auto Arg : Info.OrigArgs) {
563 assert(Arg.Regs.size() == 1 &&
"Call arg has multiple VRegs");
566 SPIRVType *SpvType = GR->getSPIRVTypeForVReg(ArgReg);
568 Type *ArgTy =
nullptr;
576 if (
Type *ElemTy = GR->findDeducedElementType(Arg.OrigValue))
583 SpvType = GR->getOrCreateSPIRVType(
584 ArgTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
true);
585 GR->assignSPIRVTypeToVReg(SpvType, ArgReg, MF);
588 if (!
MRI->getRegClassOrNull(ArgReg)) {
592 MRI->setRegClass(ArgReg, SpvType ? GR->getRegClass(SpvType)
593 : &SPIRV::pIDRegClass);
596 SpvType ? GR->getRegType(SpvType)
598 GR->getPointerSize()));
602 DemangledName, ST->getPreferredInstructionSet(), MIRBuilder,
603 ResVReg, OrigRetTy, ArgVRegs, GR, *Info.CB))
607 if (isFunctionDecl && !GR->find(CF, &MF).isValid()) {
611 FirstBlockBuilder.
setMF(MF);
620 MRI->setRegClass(Reg, &SPIRV::iIDRegClass);
630 if (MIRBuilder.
getMF()
640 if (Info.CB->isIndirectCall()) {
641 if (!ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers))
643 "extensions does not support it",
646 CallOp = SPIRV::OpFunctionPointerCallINTEL;
648 Register CalleeReg = Info.Callee.getReg();
655 "Function types mismatch");
656 for (
unsigned I = 0;
I != Info.OrigArgs.size(); ++
I) {
657 assert(Info.OrigArgs[
I].Regs.size() == 1 &&
658 "Call arg has multiple VRegs");
666 CallOp = SPIRV::OpFunctionCall;
672 SPIRVType *RetType = GR->assignTypeToVReg(
673 OrigRetTy, ResVReg, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
true);
678 .
addUse(GR->getSPIRVTypeID(RetType))
681 for (
const auto &Arg : Info.OrigArgs) {
683 if (Arg.Regs.size() > 1)
685 MIB.addUse(Arg.Regs[0]);
688 if (ST->canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing)) {
693 GR->buildMemAliasingOpDecorate(ResVReg, MIRBuilder,
694 SPIRV::Decoration::AliasScopeINTEL, MD);
696 GR->buildMemAliasingOpDecorate(ResVReg, MIRBuilder,
697 SPIRV::Decoration::NoAliasINTEL, MD);
702 *ST->getRegBankInfo());
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Promote Memory to Register
uint64_t IntrinsicInst * II
static ConstantInt * getConstInt(MDNode *MD, unsigned NumOp)
static SPIRV::ExecutionModel::ExecutionModel getExecutionModel(const SPIRVSubtarget &STI, 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.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
CallLowering(const TargetLowering *TLI)
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.
unsigned getNumParams() const
Return the number of fixed parameters this function type requires.
Type * getParamType(unsigned i) const
Parameter type accessors.
Type * getReturnType() const
static LLVM_ABI 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.
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
bool hasMetadata() const
Return true if this instruction has any metadata attached to it.
MDNode * getMetadata(unsigned KindID) const
Get the metadata of given kind attached to this Instruction.
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.
LLVM_ABI 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 & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
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 & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
const MachineOperand & getOperand(unsigned i) const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI 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,...
SPIRVType * getSPIRVTypeForVReg(Register VReg, const MachineFunction *MF=nullptr) const
void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg, const MachineFunction &MF)
const Type * getTypeForSPIRVType(const SPIRVType *Ty) const
SPIRVType * getOrCreateSPIRVType(const Type *Type, MachineInstr &I, SPIRV::AccessQualifier::AccessQualifier AQ, bool EmitIR)
SPIRVType * getOrCreateSPIRVPointerType(const Type *BaseType, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SC)
SPIRVType * getOrCreateOpTypeFunctionWithArgs(const Type *Ty, SPIRVType *RetType, const SmallVectorImpl< SPIRVType * > &ArgTypes, MachineIRBuilder &MIRBuilder)
SPIRVEnvType getEnv() const
void setEnv(SPIRVEnvType E)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
const TargetRegisterInfo & getRegisterInfo() const
The instances of the Type class are immutable: once they are created, they are never changed.
bool isPointerTy() const
True if this is an instance of PointerType.
A few GPU targets, such as DXIL and SPIR-V, have typed pointers.
static LLVM_ABI 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, const CallBase &CB)
FunctionType * getOriginalFunctionType(const Function &F)
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)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
MemoryEffectsBase< IRMemLocation > MemoryEffects
Summary of how a function affects memory in the program.
MDString * getOCLKernelArgAccessQual(const Function &F, unsigned ArgIdx)
std::string getOclOrSpirvBuiltinDemangledName(StringRef Name)
bool isTypedPointerTy(const Type *T)
auto dyn_cast_or_null(const Y &Val)
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)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
const MachineInstr SPIRVType
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...
std::optional< SPIRV::LinkageType::LinkageType > getSpirvLinkageTypeFor(const SPIRVSubtarget &ST, const GlobalValue &GV)
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)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
bool isPointerTyOrWrapper(const Type *Ty)
void addStringImm(const StringRef &Str, MCInst &Inst)
bool isUntypedPointerTy(const Type *T)