27#include "llvm/IR/IntrinsicsSPIRV.h"
41 if (MIRBuilder.
getMF()
57 *STI.getRegBankInfo());
71 if (
F.hasFnAttribute(Attribute::AttrKind::NoInline))
72 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::DontInline);
73 else if (
F.hasFnAttribute(Attribute::AttrKind::AlwaysInline))
74 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::Inline);
77 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::Pure);
79 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::Const);
81 if (ST->canUseExtension(SPIRV::Extension::SPV_INTEL_optnone) ||
82 ST->canUseExtension(SPIRV::Extension::SPV_EXT_optnone))
83 if (
F.hasFnAttribute(Attribute::OptimizeNone))
84 FuncControl |=
static_cast<uint32_t>(SPIRV::FunctionControl::OptNoneEXT);
100 return Arg.getType()->isPointerTy();
103 Type *RetTy = FTy->getReturnType();
113 for (
auto SArgTy : SArgTys)
118static SPIRV::AccessQualifier::AccessQualifier
121 return SPIRV::AccessQualifier::ReadWrite;
125 return SPIRV::AccessQualifier::ReadWrite;
127 if (ArgAttribute->
getString() ==
"read_only")
128 return SPIRV::AccessQualifier::ReadOnly;
129 if (ArgAttribute->
getString() ==
"write_only")
130 return SPIRV::AccessQualifier::WriteOnly;
131 return SPIRV::AccessQualifier::ReadWrite;
139 SPIRV::AccessQualifier::AccessQualifier ArgAccessQual =
142 Type *OriginalArgType =
156 VTy->getNumElements(), MIRBuilder,
true);
186 if (
II &&
II->getIntrinsicID() == Intrinsic::spv_assign_type) {
190 assert(BuiltinType->isTargetExtTy() &&
"Expected TargetExtType");
196 if (!
II ||
II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type)
203 ElementTy, MIRBuilder,
209 if (
F.isDeclaration())
218 ArgAccessQual,
true);
221static SPIRV::ExecutionModel::ExecutionModel
224 "Environment must be resolved before lowering entry points.");
227 return SPIRV::ExecutionModel::Kernel;
229 auto attribute =
F.getFnAttribute(
"hlsl.shader");
230 if (!attribute.isValid()) {
232 "This entry point lacks mandatory hlsl.shader attribute.");
235 const auto value = attribute.getValueAsString();
236 if (value ==
"compute")
237 return SPIRV::ExecutionModel::GLCompute;
238 if (value ==
"vertex")
239 return SPIRV::ExecutionModel::Vertex;
240 if (value ==
"pixel")
241 return SPIRV::ExecutionModel::Fragment;
254 assert(GR &&
"Must initialize the SPIRV type registry before lowering args.");
255 GR->setCurrentFunc(MIRBuilder.
getMF());
263 if (VRegs.size() > 0) {
265 for (
const auto &Arg :
F.args()) {
268 if (VRegs[i].
size() > 1)
271 GR->assignSPIRVTypeToVReg(SpirvTy, VRegs[i][0], MIRBuilder.
getMF());
275 buildOpName(VRegs[i][0], Arg.getName(), MIRBuilder);
277 auto DerefBytes =
static_cast<unsigned>(Arg.getDereferenceableBytes());
278 if (DerefBytes != 0 && ST->isAtLeastSPIRVVer(
VersionTuple(1, 1)))
280 SPIRV::Decoration::MaxByteOffset, {DerefBytes});
282 if (Arg.hasAttribute(Attribute::Alignment) && !ST->isShader()) {
283 auto Alignment =
static_cast<unsigned>(
284 Arg.getAttribute(Attribute::Alignment).getValueAsInt());
288 if (ST->isKernel()) {
289 if (Arg.hasAttribute(Attribute::ReadOnly)) {
291 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoWrite);
293 SPIRV::Decoration::FuncParamAttr, {Attr});
295 if (Arg.hasAttribute(Attribute::ReadNone)) {
296 auto Attr =
static_cast<unsigned>(
297 SPIRV::FunctionParameterAttribute::NoReadWrite);
299 SPIRV::Decoration::FuncParamAttr, {Attr});
301 if (Arg.hasAttribute(Attribute::ZExt)) {
303 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::Zext);
305 SPIRV::Decoration::FuncParamAttr, {Attr});
307 if (Arg.hasAttribute(Attribute::SExt)) {
309 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::Sext);
311 SPIRV::Decoration::FuncParamAttr, {Attr});
313 if (Arg.hasAttribute(Attribute::NoAlias)) {
315 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoAlias);
317 SPIRV::Decoration::FuncParamAttr, {Attr});
319 if (Arg.hasNoCaptureAttr()) {
320 auto Attr =
static_cast<unsigned>(
321 SPIRV::FunctionParameterAttribute::NoCapture);
323 SPIRV::Decoration::FuncParamAttr, {Attr});
330 if (Arg.hasAttribute(Attribute::ByVal) ||
331 (Arg.hasAttribute(Attribute::ByRef) &&
332 F.getParent()->getTargetTriple().getVendor() ==
335 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::ByVal);
337 SPIRV::Decoration::FuncParamAttr, {Attr});
339 if (Arg.hasAttribute(Attribute::StructRet)) {
341 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::Sret);
343 SPIRV::Decoration::FuncParamAttr, {Attr});
347 MDNode *
Node =
F.getMetadata(
"spirv.ParameterDecorations");
348 if (
Node && i < Node->getNumOperands() &&
358 MRI->setRegClass(FuncVReg, &SPIRV::iIDRegClass);
362 if (
Type *FRetElemTy = GR->findDeducedElementType(&
F)) {
365 GR->addReturnType(&
F, DerivedTy);
370 FRetTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
true);
372 SPIRVTypeInst FuncTy = GR->getOrCreateOpTypeFunctionWithArgs(
373 FTy, RetTy, ArgTypeVRegs, MIRBuilder);
379 .
addUse(GR->getSPIRVTypeID(RetTy))
381 .
addUse(GR->getSPIRVTypeID(FuncTy));
383 GR->addGlobalObject(&
F, &MIRBuilder.
getMF(), FuncVReg);
384 if (
F.isDeclaration())
389 for (
const auto &Arg :
F.args()) {
390 assert(VRegs[i].
size() == 1 &&
"Formal arg has multiple vregs");
392 MRI->setRegClass(ArgReg, GR->getRegClass(ArgTypeVRegs[i]));
393 auto MIB = MIRBuilder.
buildInstr(SPIRV::OpFunctionParameter)
395 .
addUse(GR->getSPIRVTypeID(ArgTypeVRegs[i]));
396 if (
F.isDeclaration())
398 GR->addGlobalObject(&Arg, &MIRBuilder.
getMF(), ArgReg);
401 if (!ST->isShader()) {
402 if (
F.hasRetAttribute(Attribute::ZExt)) {
404 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::Zext);
405 buildOpDecorate(FuncVReg, MIRBuilder, SPIRV::Decoration::FuncParamAttr,
408 if (
F.hasRetAttribute(Attribute::SExt)) {
410 static_cast<unsigned>(SPIRV::FunctionParameterAttribute::Sext);
411 buildOpDecorate(FuncVReg, MIRBuilder, SPIRV::Decoration::FuncParamAttr,
422 if (
F.getName().empty())
424 auto MIB = MIRBuilder.
buildInstr(SPIRV::OpEntryPoint)
429 LnkTy && !
F.getName().empty()) {
430 buildOpDecorate(FuncVReg, MIRBuilder, SPIRV::Decoration::LinkageAttributes,
431 {
static_cast<uint32_t>(*LnkTy)},
F.getName());
435 bool hasFunctionPointers =
436 ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers);
437 if (hasFunctionPointers) {
438 if (
F.hasFnAttribute(
"referenced-indirectly")) {
440 "Unexpected 'referenced-indirectly' attribute of the kernel "
443 SPIRV::Decoration::ReferencedIndirectlyINTEL, {});
447 if (
MDNode *FuncMD =
F.getMetadata(
"spirv.Decorations"))
461void SPIRVCallLowering::produceIndirectPtrType(
463 const SPIRVCallLowering::SPIRVIndirectCall &IC)
const {
468 IC.RetTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
true);
470 for (
size_t i = 0; i < IC.ArgTys.size(); ++i) {
472 IC.ArgTys[i], MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
true);
481 FTy, SpirvRetTy, SpirvArgTypes, MIRBuilder);
483 auto SC = ST.canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)
484 ? SPIRV::StorageClass::CodeSectionINTEL
485 : SPIRV::StorageClass::Function;
496 if (Info.OrigRet.Regs.size() > 1)
499 GR->setCurrentFunc(MF);
501 std::string DemangledName;
502 const Type *OrigRetTy = Info.OrigRet.Ty;
507 if (Info.Callee.isGlobal()) {
508 std::string FuncName = Info.Callee.getGlobal()->getName().str();
518 if (
auto *DerivedRetTy = GR->findReturnType(CF))
519 OrigRetTy = DerivedRetTy;
525 Info.OrigRet.Regs.empty() ?
Register(0) : Info.OrigRet.Regs[0];
529 if (isFunctionDecl && !DemangledName.empty()) {
531 if (!GR->getSPIRVTypeForVReg(ResVReg)) {
532 const Type *RetTy = OrigRetTy;
534 const Value *OrigValue = Info.OrigRet.OrigValue;
538 if (
Type *
ElemTy = GR->findDeducedElementType(OrigValue))
543 SPIRV::AccessQualifier::ReadWrite,
true);
547 SPIRV::AccessQualifier::ReadWrite,
true);
550 for (
auto Arg : Info.OrigArgs) {
551 assert(Arg.Regs.size() == 1 &&
"Call arg has multiple VRegs");
556 Type *ArgTy =
nullptr;
564 if (
Type *
ElemTy = GR->findDeducedElementType(Arg.OrigValue))
571 SpvType = GR->getOrCreateSPIRVType(
572 ArgTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
true);
573 GR->assignSPIRVTypeToVReg(SpvType, ArgReg, MF);
576 if (!
MRI->getRegClassOrNull(ArgReg)) {
580 MRI->setRegClass(ArgReg, SpvType ? GR->getRegClass(SpvType)
581 : &SPIRV::pIDRegClass);
584 SpvType ? GR->getRegType(SpvType)
586 GR->getPointerSize()));
590 DemangledName, ST->getPreferredInstructionSet(), MIRBuilder,
591 ResVReg, OrigRetTy, ArgVRegs, GR, *Info.CB))
595 if (isFunctionDecl && !GR->find(CF, &MF).isValid()) {
599 FirstBlockBuilder.
setMF(MF);
608 MRI->setRegClass(Reg, &SPIRV::iIDRegClass);
618 if (MIRBuilder.
getMF()
628 if (Info.CB && Info.CB->isIndirectCall()) {
629 if (!ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers))
631 "extensions does not support it",
634 CallOp = SPIRV::OpFunctionPointerCallINTEL;
636 Register CalleeReg = Info.Callee.getReg();
643 "Function types mismatch");
644 for (
unsigned I = 0;
I != Info.OrigArgs.size(); ++
I) {
645 assert(Info.OrigArgs[
I].Regs.size() == 1 &&
646 "Call arg has multiple VRegs");
654 CallOp = SPIRV::OpFunctionCall;
661 OrigRetTy, ResVReg, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
true);
666 .
addUse(GR->getSPIRVTypeID(RetType))
671 for (
const auto &Arg : Info.OrigArgs) {
673 if (Arg.Regs.size() > 1)
675 MIB.addUse(Arg.Regs[0]);
681 if (ST->canUseExtension(SPIRV::Extension::SPV_INTEL_memory_access_aliasing)) {
686 GR->buildMemAliasingOpDecorate(ResVReg, MIRBuilder,
687 SPIRV::Decoration::AliasScopeINTEL, MD);
689 GR->buildMemAliasingOpDecorate(ResVReg, MIRBuilder,
690 SPIRV::Decoration::NoAliasINTEL, MD);
694 MIB.constrainAllUses(MIRBuilder.
getTII(), *ST->getRegisterInfo(),
695 *ST->getRegBankInfo());
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Promote Memory to Register
uint64_t IntrinsicInst * II
MachineRegisterInfo & MRI
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)
#define SPIRV_BACKEND_SERVICE_FUN_NAME
This class represents an incoming formal argument to a Function.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
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)
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.
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 & setMIFlag(MachineInstr::MIFlag Flag) const
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.
LLVM_ABI void copyIRFlags(const Instruction &I)
Copy all flags to MachineInst MIFlags.
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)
SPIRVTypeInst getOrCreateSPIRVPointerType(const Type *BaseType, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SC, bool ForceTyped=false)
SPIRVTypeInst getOrCreateSPIRVTypedPointerType(const Type *BaseType, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SC)
SPIRVTypeInst getOrCreateSPIRVVectorType(SPIRVTypeInst BaseType, unsigned NumElements, MachineIRBuilder &MIRBuilder, bool EmitIR)
const Type * getTypeForSPIRVType(SPIRVTypeInst Ty) const
SPIRVTypeInst getOrCreateSPIRVType(const Type *Type, MachineInstr &I, SPIRV::AccessQualifier::AccessQualifier AQ, bool EmitIR)
SPIRVTypeInst getSPIRVTypeForVReg(Register VReg, const MachineFunction *MF=nullptr) const
Type * findDeducedElementType(const Value *Val)
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()
Represents a version number in the form major[.minor[.subminor[.build]]].
constexpr bool isZero() const
@ SPIR_KERNEL
Used for SPIR kernel functions.
std::optional< bool > lowerBuiltin(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.
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.
void addStringImm(StringRef Str, MCInst &Inst)
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.
void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, SPIRV::Decoration::Decoration Dec, ArrayRef< uint32_t > DecArgs, StringRef StrImm)
MDString * getOCLKernelArgAccessQual(const Function &F, unsigned ArgIdx)
std::string getOclOrSpirvBuiltinDemangledName(StringRef Name)
auto dyn_cast_or_null(const Y &Val)
void buildOpName(Register Target, StringRef Name, MachineIRBuilder &MIRBuilder)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
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)
void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder, const MDNode *GVarMD, const SPIRVSubtarget &ST)
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)
bool isUntypedPointerTy(const Type *T)