23#include "llvm/IR/IntrinsicsSPIRV.h"
25#define DEBUG_TYPE "spirv-lower"
51 if (Ty1->
getOpcode() == SPIRV::OpTypeArray) {
60 return ElemType1 == ElemType2 ||
64 if (Ty1->
getOpcode() == SPIRV::OpTypeStruct) {
70 if (ElemType1 != ElemType2 &&
106 STI.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector)) {
121 unsigned AlignIdx = 0;
122 unsigned OrderingIdx = 0;
126 case Intrinsic::spv_load:
130 case Intrinsic::spv_store:
134 case Intrinsic::spv_atomic_load:
138 case Intrinsic::spv_atomic_store:
148 Info.memVT = MVT::i64;
154 Info.align =
Align(AlignOp->getZExtValue());
172 if (Constraint ==
"m")
177std::pair<unsigned, const TargetRegisterClass *>
183 return std::make_pair(0u, RC);
186 RC = VT.
isVector() ? &SPIRV::vfIDRegClass : &SPIRV::fIDRegClass;
188 RC = VT.
isVector() ? &SPIRV::viIDRegClass : &SPIRV::iIDRegClass;
190 RC = &SPIRV::iIDRegClass;
192 return std::make_pair(0u, RC);
197 return Inst && Inst->
getOpcode() == SPIRV::OpFunctionParameter
214 I.getOperand(OpIdx).setReg(NewReg);
221 SPIRV::StorageClass::StorageClass SC =
222 static_cast<SPIRV::StorageClass::StorageClass
>(
223 OpType->getOperand(1).
getImm());
228 ResTy, MIB, SPIRV::AccessQualifier::ReadWrite,
false);
238 const Type *ResTy =
nullptr) {
241 Register OpReg =
I.getOperand(OpIdx).getReg();
244 if (!ResType || !OpType || OpType->
getOpcode() != SPIRV::OpTypePointer)
247 Register ElemTypeReg = OpType->getOperand(2).getReg();
253 bool IsEqualTypes = IsSameMF ? ElemType == ResType
263 "insert validation bitcast: incompatible result and operand types");
273 constexpr unsigned OpIdx = 2;
275 Register OpReg =
I.getOperand(OpIdx).getReg();
278 if (!OpType || OpType->getOpcode() != SPIRV::OpTypePointer)
282 if (!ElemType || ElemType->
getOpcode() == SPIRV::OpTypeEvent)
295 Register PtrReg =
I.getOperand(0).getReg();
300 if (!PonteeElemType || PonteeElemType->
getOpcode() == SPIRV::OpTypeVoid ||
301 (PonteeElemType->
getOpcode() == SPIRV::OpTypeInt &&
305 SPIRV::StorageClass::StorageClass SC =
306 static_cast<SPIRV::StorageClass::StorageClass
>(
320 Register OpReg =
I.getOperand(OpIdx).getReg();
323 if (!OpType || OpType->getOpcode() != SPIRV::OpTypePointer)
327 if (!ElemType || ElemType->
getOpcode() != SPIRV::OpTypeStruct ||
335 unsigned MemberTypeOp = MemberType->
getOpcode();
336 if (!
isVectorType(MemberType) && MemberTypeOp != SPIRV::OpTypeInt &&
337 MemberTypeOp != SPIRV::OpTypeFloat && MemberTypeOp != SPIRV::OpTypeBool)
341 SPIRV::StorageClass::StorageClass SC =
342 static_cast<SPIRV::StorageClass::StorageClass
>(
343 OpType->getOperand(1).
getImm());
363 if (FunDef->
getOpcode() != SPIRV::OpFunction)
367 FunDef && FunDef->
getOpcode() == SPIRV::OpFunctionParameter &&
373 DefPtrType && DefPtrType->
getOpcode() == SPIRV::OpTypePointer
419 &FunCall->getParent()->getParent()->getRegInfo();
428 if (BaseTypeInst && BaseTypeInst->
getOpcode() == SPIRV::OpTypePointer) {
441 switch (
MI.getOpcode()) {
442 case SPIRV::OpBitwiseAndS:
443 case SPIRV::OpBitwiseOrS:
444 case SPIRV::OpBitwiseXorS:
448 case SPIRV::OpFNegate:
451 case SPIRV::OpIAddCarryS:
454 case SPIRV::OpISubBorrowS:
458 case SPIRV::OpShiftLeftLogicalS:
459 case SPIRV::OpShiftRightArithmeticS:
460 case SPIRV::OpShiftRightLogicalS:
461 case SPIRV::OpStrictFAddS:
462 case SPIRV::OpStrictFDivS:
463 case SPIRV::OpStrictFMulS:
464 case SPIRV::OpStrictFRemS:
465 case SPIRV::OpStrictFSubS:
467 case SPIRV::OpUModS: {
481 for (
unsigned I = 2;
I !=
MI.getNumOperands(); ++
I) {
493 "Expected to find Result Type (Vec1)!");
499 case TargetOpcode::COPY: {
540 switch (
MI.getOpcode()) {
541 case SPIRV::OpAtomicLoad:
542 case SPIRV::OpAtomicExchange:
543 case SPIRV::OpAtomicCompareExchange:
544 case SPIRV::OpAtomicCompareExchangeWeak:
545 case SPIRV::OpAtomicIIncrement:
546 case SPIRV::OpAtomicIDecrement:
547 case SPIRV::OpAtomicIAdd:
548 case SPIRV::OpAtomicISub:
549 case SPIRV::OpAtomicSMin:
550 case SPIRV::OpAtomicUMin:
551 case SPIRV::OpAtomicSMax:
552 case SPIRV::OpAtomicUMax:
553 case SPIRV::OpAtomicAnd:
554 case SPIRV::OpAtomicOr:
555 case SPIRV::OpAtomicXor:
567 case SPIRV::OpAtomicStore:
578 case SPIRV::OpPtrCastToGeneric:
579 case SPIRV::OpGenericCastToPtr:
580 case SPIRV::OpGenericCastToPtrExplicit:
583 case SPIRV::OpPtrAccessChain:
584 case SPIRV::OpInBoundsPtrAccessChain:
585 if (
MI.getNumOperands() == 4)
589 case SPIRV::OpFunctionCall:
592 if (
MI.getNumOperands() > 3)
596 case SPIRV::OpFunction:
610 MI.setDesc(STI.getInstrInfo()->get(SPIRV::OpLogicalNotEqual));
617 MI.setDesc(STI.getInstrInfo()->get(SPIRV::OpLogicalAnd));
622 case SPIRV::OpBitwiseOrS:
623 case SPIRV::OpBitwiseOrV:
626 MI.setDesc(STI.getInstrInfo()->get(SPIRV::OpLogicalOr));
628 case SPIRV::OpBitwiseAndS:
629 case SPIRV::OpBitwiseAndV:
632 MI.setDesc(STI.getInstrInfo()->get(SPIRV::OpLogicalAnd));
634 case SPIRV::OpBitwiseXorS:
635 case SPIRV::OpBitwiseXorV:
638 MI.setDesc(STI.getInstrInfo()->get(SPIRV::OpLogicalNotEqual));
640 case SPIRV::OpLifetimeStart:
641 case SPIRV::OpLifetimeStop:
642 if (
MI.getOperand(1).getImm() > 0)
645 case SPIRV::OpGroupAsyncCopy:
649 case SPIRV::OpGroupWaitEvents:
653 case SPIRV::OpConstantI: {
655 if (
Type->getOpcode() != SPIRV::OpTypeInt &&
MI.getOperand(2).isImm() &&
656 MI.getOperand(2).getImm() == 0) {
658 MI.setDesc(STI.getInstrInfo()->get(SPIRV::OpConstantNull));
659 for (
unsigned i =
MI.getNumOperands() - 1; i > 1; --i)
663 case SPIRV::OpExtInst: {
665 if (!
MI.getOperand(2).isImm() || !
MI.getOperand(3).isImm() ||
666 MI.getOperand(2).getImm() != SPIRV::InstructionSet::OpenCL_std)
668 switch (
MI.getOperand(3).getImm()) {
669 case SPIRV::OpenCLExtInst::frexp:
670 case SPIRV::OpenCLExtInst::lgamma_r:
671 case SPIRV::OpenCLExtInst::remquo: {
677 assert(RetType &&
"Expected return type");
679 STI, MRI, GR,
MI,
MI.getNumOperands() - 1,
686 case SPIRV::OpenCLExtInst::fract:
687 case SPIRV::OpenCLExtInst::modf:
688 case SPIRV::OpenCLExtInst::sincos:
691 assert(
MI.getOperand(
MI.getNumOperands() - 2).isReg() &&
694 STI, MRI, GR,
MI,
MI.getNumOperands() - 1,
696 MI.getOperand(
MI.getNumOperands() - 2).getReg()));
698 case SPIRV::OpenCLExtInst::prefetch:
701 assert(
MI.getOperand(
MI.getNumOperands() - 2).isReg() &&
704 MI.getNumOperands() - 2);
718 MachineInstr &
I,
unsigned int PtrOpIdx,
unsigned int OpIdx)
const {
722 if (PtrType && PtrType->
getOpcode() == SPIRV::OpTypeUntypedPointerKHR)
728 if (PointeeType == OpType)
738 if (
I.getOperand(OpIdx).isDef() &&
765 OldResult.
setReg(NewResultReg);
766 OldType.
setReg(NewTypeReg);
774 *STI.getRegBankInfo());
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator MBBI
Register const TargetRegisterInfo * TRI
static bool typesLogicallyMatch(const SPIRVTypeInst Ty1, const SPIRVTypeInst Ty2, SPIRVGlobalRegistry &GR)
static void validateVec1Ops(const SPIRVSubtarget &STI, MachineRegisterInfo *MRI, SPIRVGlobalRegistry &GR, MachineInstr &MI)
static void validateLifetimeStart(const SPIRVSubtarget &STI, MachineRegisterInfo *MRI, SPIRVGlobalRegistry &GR, MachineInstr &I)
static void validatePtrTypes(const SPIRVSubtarget &STI, MachineRegisterInfo *MRI, SPIRVGlobalRegistry &GR, MachineInstr &I, unsigned OpIdx, SPIRVTypeInst ResType, const Type *ResTy=nullptr)
static void validateGroupWaitEventsPtr(const SPIRVSubtarget &STI, MachineRegisterInfo *MRI, SPIRVGlobalRegistry &GR, MachineInstr &I)
static void validatePtrUnwrapStructField(const SPIRVSubtarget &STI, MachineRegisterInfo *MRI, SPIRVGlobalRegistry &GR, MachineInstr &I, unsigned OpIdx)
Register getTypeReg(MachineRegisterInfo *MRI, Register OpReg)
void validateAccessChain(const SPIRVSubtarget &STI, MachineRegisterInfo *MRI, SPIRVGlobalRegistry &GR, MachineInstr &I)
void validateFunCallMachineDef(const SPIRVSubtarget &STI, MachineRegisterInfo *DefMRI, MachineRegisterInfo *CallMRI, SPIRVGlobalRegistry &GR, MachineInstr &FunCall, MachineInstr *FunDef)
void validateForwardCalls(const SPIRVSubtarget &STI, MachineRegisterInfo *DefMRI, SPIRVGlobalRegistry &GR, MachineInstr &FunDef)
const Function * validateFunCall(const SPIRVSubtarget &STI, MachineRegisterInfo *CallMRI, SPIRVGlobalRegistry &GR, MachineInstr &FunCall)
static void doInsertBitcast(const SPIRVSubtarget &STI, MachineRegisterInfo *MRI, SPIRVGlobalRegistry &GR, MachineInstr &I, Register OpReg, unsigned OpIdx, SPIRVTypeInst NewPtrType)
static SPIRVTypeInst createNewPtrType(SPIRVGlobalRegistry &GR, MachineInstr &I, SPIRVTypeInst OpType, bool ReuseType, SPIRVTypeInst ResType, const Type *ResTy)
This file describes how to lower LLVM code to machine code.
an instruction that atomically reads a memory location, combines it with another value,...
@ UIncWrap
Increment one up to a maximum value.
@ FMin
*p = minnum(old, v) minnum matches the behavior of llvm.minnum.
@ FMax
*p = maxnum(old, v) maxnum matches the behavior of llvm.maxnum.
@ UDecWrap
Decrement one until a minimum value or zero.
BinOp getOperation() const
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
static constexpr ElementCount getFixed(ScalarTy MinVal)
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
This is an important class for using LLVM in a threaded context.
An instruction for reading from memory.
bool isVector() const
Return true if this is a vector value type.
bool isInteger() const
Return true if this is an integer or a vector integer type.
static MVT getVectorVT(MVT VT, unsigned NumElements)
bool isFloatingPoint() const
Return true if this is a FP or a vector FP type.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
BasicBlockListType::iterator iterator
Helper class to build MachineInstr.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
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 & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
unsigned getNumOperands() const
Retuns the total number of operands.
const MachineOperand & getOperand(unsigned i) const
Flags
Flags values. These may be or'd together.
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
bool reservedRegsFrozen() const
reservedRegsFrozen - Returns true after freezeReservedRegs() was called to ensure the set of reserved...
iterator_range< use_instr_iterator > use_instructions(Register Reg) const
LLVM_ABI void replaceRegWith(Register FromReg, Register ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
Wrapper class representing virtual and physical registers.
void addForwardCall(const Function *F, MachineInstr *MI)
SPIRVTypeInst getOrCreateSPIRVPointerType(const Type *BaseType, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SC, bool ForceTyped=false)
SPIRVTypeInst getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineIRBuilder &MIRBuilder)
SPIRVTypeInst getOrCreateSPIRVVectorType(SPIRVTypeInst BaseType, unsigned NumElements, MachineIRBuilder &MIRBuilder, bool EmitIR)
SPIRVTypeInst getResultType(Register VReg, MachineFunction *MF=nullptr)
unsigned getScalarOrVectorComponentCount(Register VReg) const
const Type * getTypeForSPIRVType(SPIRVTypeInst Ty) const
bool isBitcastCompatible(SPIRVTypeInst Type1, SPIRVTypeInst Type2) const
const MachineInstr * getFunctionDefinition(const Function *F)
Register getSPIRVTypeID(SPIRVTypeInst SpirvType) const
SPIRVTypeInst getPointeeType(SPIRVTypeInst PtrType)
SmallPtrSet< MachineInstr *, 8 > * getForwardCalls(const Function *F)
SPIRVTypeInst getOrCreateSPIRVType(const Type *Type, MachineInstr &I, SPIRV::AccessQualifier::AccessQualifier AQ, bool EmitIR)
bool isScalarOrVectorOfType(Register VReg, unsigned TypeOpcode) const
MachineFunction * setCurrentFunc(MachineFunction &MF)
SPIRVTypeInst getSPIRVTypeForVReg(Register VReg, const MachineFunction *MF=nullptr) const
const Function * getFunctionByDefinition(const MachineInstr *MI)
const SPIRVInstrInfo * getInstrInfo() const override
const SPIRVRegisterInfo * getRegisterInfo() const override
const RegisterBankInfo * getRegBankInfo() const override
AtomicExpansionKind shouldCastAtomicRMWIInIR(AtomicRMWInst *RMWI) const override
Returns how the given atomic atomicrmw should be cast by the IR-level AtomicExpand pass.
AtomicExpansionKind shouldCastAtomicLoadInIR(LoadInst *LI) const override
Returns how the given (atomic) load should be cast by the IR-level AtomicExpand pass.
bool enforcePtrTypeCompatibility(MachineInstr &I, unsigned PtrOpIdx, unsigned OpIdx) const
unsigned getNumRegisters(LLVMContext &Context, EVT VT, std::optional< MVT > RegisterVT=std::nullopt) const override
Return the number of registers that this ValueType will eventually require.
unsigned getNumRegistersForCallingConv(LLVMContext &Context, CallingConv::ID CC, EVT VT) const override
Certain targets require unusual breakdowns of certain types.
MVT getRegisterTypeForCallingConv(LLVMContext &Context, CallingConv::ID CC, EVT VT) const override
Certain combinations of ABIs, Targets and features require that types are legal for some operations a...
AtomicExpansionKind shouldExpandAtomicRMWInIR(const AtomicRMWInst *RMW) const override
Returns how the IR-level AtomicExpand pass should expand the given AtomicRMW, if at all.
void finalizeLowering(MachineFunction &MF) const override
Execute target specific actions to finalize target lowering.
void getTgtMemIntrinsic(SmallVectorImpl< IntrinsicInfo > &Infos, const CallBase &I, MachineFunction &MF, unsigned Intrinsic) const override
Given an intrinsic, checks if on the target the intrinsic will need to map to a MemIntrinsicNode (tou...
bool insertLogicalCopyOnResult(MachineInstr &I, SPIRVTypeInst NewResultType) const
AtomicExpansionKind shouldCastAtomicStoreInIR(StoreInst *SI) const override
Returns how the given (atomic) store should be cast by the IR-level AtomicExpand pass into.
SPIRVTargetLowering(const TargetMachine &TM, const SPIRVSubtarget &ST)
std::pair< unsigned, const TargetRegisterClass * > getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const override
Given a physical register constraint (e.g.
ConstraintType getConstraintType(StringRef Constraint) const override
Given a constraint, return the type of constraint it is for this target.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
An instruction for storing to memory.
Represent a constant reference to a string, i.e.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
static LLVM_ABI TargetExtType * get(LLVMContext &Context, StringRef Name, ArrayRef< Type * > Types={}, ArrayRef< unsigned > Ints={})
Return a target extension type having the specified name and optional type and integer parameters.
virtual void finalizeLowering(MachineFunction &MF) const
Execute target specific actions to finalize target lowering.
virtual AtomicExpansionKind shouldExpandAtomicRMWInIR(const AtomicRMWInst *RMW) const
Returns how the IR-level AtomicExpand pass should expand the given AtomicRMW, if at all.
MVT getRegisterType(LLVMContext &Context, EVT VT) const
Return the type of registers that this ValueType will eventually require.
void setMaxAtomicSizeInBitsSupported(unsigned SizeInBits)
Set the maximum atomic operation size supported by the backend.
void setMinCmpXchgSizeInBits(unsigned SizeInBits)
Sets the minimum cmpxchg or ll/sc size supported by the backend.
AtomicExpansionKind
Enum that specifies what an atomic load/AtomicRMWInst is expanded to, if at all.
TargetLowering(const TargetLowering &)=delete
Primary interface to the complete machine description for the target machine.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
The instances of the Type class are immutable: once they are created, they are never changed.
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
This namespace contains an enum with a value for every intrinsic/builtin function known by LLVM.
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.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
MachineInstr * getDef(const MachineOperand &MO, const MachineRegisterInfo *MRI)
Register createVirtualRegister(SPIRVTypeInst SpvType, SPIRVGlobalRegistry *GR, MachineRegisterInfo *MRI, const MachineFunction &MF)
bool isVectorType(SPIRVTypeInst SPVTy)
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
AtomicOrdering
Atomic ordering for LLVM's memory model.
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
MCRegisterClass TargetRegisterClass
This struct is a compact representation of a valid (non-zero power of two) alignment.
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
bool isVector() const
Return true if this is a vector value type.
EVT getVectorElementType() const
Given a vector type, return the type of each element.
unsigned getVectorNumElements() const
Given a vector type, return the number of elements it contains.
bool isInteger() const
Return true if this is an integer or a vector integer type.
MachineMemOperand::Flags flags