26#include "llvm/IR/IntrinsicsSPIRV.h"
40 if (MIRBuilder.
getMF()
56 *STI.getRegBankInfo());
70 if (
F.hasFnAttribute(Attribute::AttrKind::NoInline))
71 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::DontInline);
72 else if (
F.hasFnAttribute(Attribute::AttrKind::AlwaysInline))
73 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::Inline);
76 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::Pure);
78 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::Const);
80 if (ST->canUseExtension(SPIRV::Extension::SPV_INTEL_optnone) ||
81 ST->canUseExtension(SPIRV::Extension::SPV_EXT_optnone))
82 if (
F.hasFnAttribute(Attribute::OptimizeNone))
83 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::OptNoneEXT);
106 bool hasArgPtrs =
false;
107 for (
auto &Arg :
F.args()) {
109 if (Arg.getType()->isPointerTy()) {
115 Type *RetTy = FTy->getReturnType();
125 for (
auto SArgTy : SArgTys)
130static SPIRV::AccessQualifier::AccessQualifier
133 return SPIRV::AccessQualifier::ReadWrite;
137 return SPIRV::AccessQualifier::ReadWrite;
139 if (ArgAttribute->
getString() ==
"read_only")
140 return SPIRV::AccessQualifier::ReadOnly;
141 if (ArgAttribute->
getString() ==
"write_only")
142 return SPIRV::AccessQualifier::WriteOnly;
143 return SPIRV::AccessQualifier::ReadWrite;
146static std::vector<SPIRV::Decoration::Decoration>
149 if (ArgAttribute && ArgAttribute->
getString() ==
"volatile")
150 return {SPIRV::Decoration::Volatile};
159 SPIRV::AccessQualifier::AccessQualifier ArgAccessQual =
162 Type *OriginalArgType =
196 if (
II &&
II->getIntrinsicID() == Intrinsic::spv_assign_type) {
200 assert(BuiltinType->isTargetExtTy() &&
"Expected TargetExtType");
206 if (!
II ||
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type)
213 ElementTy, MIRBuilder,
221 ArgAccessQual,
true);
224static SPIRV::ExecutionModel::ExecutionModel
227 "Environment must be resolved before lowering entry points.");
230 return SPIRV::ExecutionModel::Kernel;
232 auto attribute =
F.getFnAttribute(
"hlsl.shader");
233 if (!attribute.isValid()) {
235 "This entry point lacks mandatory hlsl.shader attribute.");
238 const auto value = attribute.getValueAsString();
239 if (value ==
"compute")
240 return SPIRV::ExecutionModel::GLCompute;
241 if (value ==
"vertex")
242 return SPIRV::ExecutionModel::Vertex;
243 if (value ==
"pixel")
244 return SPIRV::ExecutionModel::Fragment;
257 assert(GR &&
"Must initialize the SPIRV type registry before lowering args.");
258 GR->setCurrentFunc(MIRBuilder.
getMF());
266 if (VRegs.size() > 0) {
268 for (
const auto &Arg :
F.args()) {
271 if (VRegs[i].
size() > 1)
274 GR->assignSPIRVTypeToVReg(SpirvTy, VRegs[i][0], MIRBuilder.
getMF());
278 buildOpName(VRegs[i][0], Arg.getName(), MIRBuilder);
280 auto DerefBytes =
static_cast<unsigned>(Arg.getDereferenceableBytes());
283 SPIRV::Decoration::MaxByteOffset, {DerefBytes});
285 if (Arg.hasAttribute(Attribute::Alignment) && !ST->isShader()) {
286 auto Alignment =
static_cast<unsigned>(
287 Arg.getAttribute(Attribute::Alignment).getValueAsInt());
291 if (Arg.hasAttribute(Attribute::ReadOnly)) {
293 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoWrite);
295 SPIRV::Decoration::FuncParamAttr, {Attr});
297 if (Arg.hasAttribute(Attribute::ZExt)) {
299 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::Zext);
301 SPIRV::Decoration::FuncParamAttr, {Attr});
303 if (Arg.hasAttribute(Attribute::NoAlias)) {
305 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoAlias);
307 SPIRV::Decoration::FuncParamAttr, {Attr});
314 if (Arg.hasAttribute(Attribute::ByVal) ||
315 (Arg.hasAttribute(Attribute::ByRef) &&
316 F.getParent()->getTargetTriple().getVendor() ==
319 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::ByVal);
321 SPIRV::Decoration::FuncParamAttr, {Attr});
323 if (Arg.hasAttribute(Attribute::StructRet)) {
325 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::Sret);
327 SPIRV::Decoration::FuncParamAttr, {Attr});
331 std::vector<SPIRV::Decoration::Decoration> ArgTypeQualDecs =
333 for (SPIRV::Decoration::Decoration Decoration : ArgTypeQualDecs)
337 MDNode *
Node =
F.getMetadata(
"spirv.ParameterDecorations");
338 if (
Node && i < Node->getNumOperands() &&
343 assert(MD2 &&
"Metadata operand is expected");
345 assert(Const &&
"MDOperand should be ConstantInt");
347 static_cast<SPIRV::Decoration::Decoration
>(Const->getZExtValue());
348 std::vector<uint32_t> DecVec;
351 assert(Const &&
"MDOperand should be ConstantInt");
352 DecVec.push_back(
static_cast<uint32_t>(Const->getZExtValue()));
363 MRI->setRegClass(FuncVReg, &SPIRV::iIDRegClass);
367 if (
Type *FRetElemTy = GR->findDeducedElementType(&
F)) {
370 GR->addReturnType(&
F, DerivedTy);
375 FRetTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
true);
377 SPIRVTypeInst FuncTy = GR->getOrCreateOpTypeFunctionWithArgs(
378 FTy, RetTy, ArgTypeVRegs, MIRBuilder);
384 .
addUse(GR->getSPIRVTypeID(RetTy))
386 .
addUse(GR->getSPIRVTypeID(FuncTy));
388 GR->addGlobalObject(&
F, &MIRBuilder.
getMF(), FuncVReg);
389 if (
F.isDeclaration())
394 for (
const auto &Arg :
F.args()) {
395 assert(VRegs[i].
size() == 1 &&
"Formal arg has multiple vregs");
397 MRI->setRegClass(ArgReg, GR->getRegClass(ArgTypeVRegs[i]));
398 MRI->setType(ArgReg, GR->getRegType(ArgTypeVRegs[i]));
399 auto MIB = MIRBuilder.
buildInstr(SPIRV::OpFunctionParameter)
401 .
addUse(GR->getSPIRVTypeID(ArgTypeVRegs[i]));
402 if (
F.isDeclaration())
404 GR->addGlobalObject(&Arg, &MIRBuilder.
getMF(), ArgReg);
413 auto MIB = MIRBuilder.
buildInstr(SPIRV::OpEntryPoint)
418 buildOpDecorate(FuncVReg, MIRBuilder, SPIRV::Decoration::LinkageAttributes,
419 {
static_cast<uint32_t>(*LnkTy)},
F.getName());
423 bool hasFunctionPointers =
424 ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
425 if (hasFunctionPointers) {
426 if (
F.hasFnAttribute(
"referenced-indirectly")) {
428 "Unexpected 'referenced-indirectly' attribute of the kernel "
431 SPIRV::Decoration::ReferencedIndirectlyINTEL, {});
446void SPIRVCallLowering::produceIndirectPtrType(
448 const SPIRVCallLowering::SPIRVIndirectCall &IC)
const {
453 IC.RetTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
true);
455 for (
size_t i = 0; i < IC.ArgTys.size(); ++i) {
457 IC.ArgTys[i], MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
true);
466 FTy, SpirvRetTy, SpirvArgTypes, MIRBuilder);
468 auto SC = ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)
469 ? SPIRV::StorageClass::CodeSectionINTEL
470 : SPIRV::StorageClass::Function;
481 if (Info.OrigRet.Regs.size() > 1)
484 GR->setCurrentFunc(MF);
486 std::string DemangledName;
487 const Type *OrigRetTy = Info.OrigRet.Ty;
492 if (Info.Callee.isGlobal()) {
493 std::string FuncName = Info.Callee.getGlobal()->getName().str();
503 if (
auto *DerivedRetTy = GR->findReturnType(CF))
504 OrigRetTy = DerivedRetTy;
510 Info.OrigRet.Regs.empty() ?
Register(0) : Info.OrigRet.Regs[0];
514 if (isFunctionDecl && !DemangledName.empty()) {
516 if (!GR->getSPIRVTypeForVReg(ResVReg)) {
517 const Type *RetTy = OrigRetTy;
519 const Value *OrigValue = Info.OrigRet.OrigValue;
523 if (
Type *ElemTy = GR->findDeducedElementType(OrigValue))
528 SPIRV::AccessQualifier::ReadWrite,
true);
532 SPIRV::AccessQualifier::ReadWrite,
true);
535 for (
auto Arg : Info.OrigArgs) {
536 assert(Arg.Regs.size() == 1 &&
"Call arg has multiple VRegs");
541 Type *ArgTy =
nullptr;
549 if (
Type *ElemTy = GR->findDeducedElementType(Arg.OrigValue))
556 SpvType = GR->getOrCreateSPIRVType(
557 ArgTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
true);
558 GR->assignSPIRVTypeToVReg(SpvType, ArgReg, MF);
561 if (!
MRI->getRegClassOrNull(ArgReg)) {
565 MRI->setRegClass(ArgReg, SpvType ? GR->getRegClass(SpvType)
566 : &SPIRV::pIDRegClass);
569 SpvType ? GR->getRegType(SpvType)
571 GR->getPointerSize()));
575 DemangledName, ST->getPreferredInstructionSet(), MIRBuilder,
576 ResVReg, OrigRetTy, ArgVRegs, GR, *Info.CB))
580 if (isFunctionDecl && !GR->find(CF, &MF).isValid()) {
584 FirstBlockBuilder.
setMF(MF);
593 MRI->setRegClass(Reg, &SPIRV::iIDRegClass);
603 if (MIRBuilder.
getMF()
613 if (Info.CB->isIndirectCall()) {
614 if (!ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers))
616 "extensions does not support it",
619 CallOp = SPIRV::OpFunctionPointerCallINTEL;
621 Register CalleeReg = Info.Callee.getReg();
628 "Function types mismatch");
629 for (
unsigned I = 0;
I != Info.OrigArgs.size(); ++
I) {
630 assert(Info.OrigArgs[
I].Regs.size() == 1 &&
631 "Call arg has multiple VRegs");
639 CallOp = SPIRV::OpFunctionCall;
646 OrigRetTy, ResVReg, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
true);
651 .
addUse(GR->getSPIRVTypeID(RetType))
654 for (
const auto &Arg : Info.OrigArgs) {
656 if (Arg.Regs.size() > 1)
658 MIB.addUse(Arg.Regs[0]);
661 if (ST->canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing)) {
666 GR->buildMemAliasingOpDecorate(ResVReg, MIRBuilder,
667 SPIRV::Decoration::AliasScopeINTEL, MD);
669 GR->buildMemAliasingOpDecorate(ResVReg, MIRBuilder,
670 SPIRV::Decoration::NoAliasINTEL, MD);
675 *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 SPIRVTypeInst getArgSPIRVType(const Function &F, unsigned ArgIdx, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIRBuilder, const SPIRVSubtarget &ST)
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 FunctionType * fixFunctionTypeIfPtrArgs(SPIRVGlobalRegistry *GR, const Function &F, FunctionType *FTy, SPIRVTypeInst SRetTy, const SmallVector< SPIRVTypeInst, 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)
void constrainAllUses(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const
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
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,...
void assignSPIRVTypeToVReg(SPIRVTypeInst Type, Register VReg, const MachineFunction &MF)
SPIRVTypeInst getOrCreateOpTypeFunctionWithArgs(const Type *Ty, SPIRVTypeInst RetType, const SmallVectorImpl< SPIRVTypeInst > &ArgTypes, MachineIRBuilder &MIRBuilder)
const Type * getTypeForSPIRVType(SPIRVTypeInst Ty) const
SPIRVTypeInst getOrCreateSPIRVPointerType(const Type *BaseType, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SC)
SPIRVTypeInst getOrCreateSPIRVType(const Type *Type, MachineInstr &I, SPIRV::AccessQualifier::AccessQualifier AQ, bool EmitIR)
SPIRVTypeInst getSPIRVTypeForVReg(Register VReg, const MachineFunction *MF=nullptr) const
SPIRVEnvType getEnv() const
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.
Register createVirtualRegister(SPIRVTypeInst SpvType, SPIRVGlobalRegistry *GR, MachineRegisterInfo *MRI, const MachineFunction &MF)
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)
Type * toTypedPointer(Type *Ty)
bool isPointerTy(const Type *T)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
void setRegClassType(Register Reg, SPIRVTypeInst SpvType, SPIRVGlobalRegistry *GR, MachineRegisterInfo *MRI, const MachineFunction &MF, bool Force)
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)