21#include "llvm/IR/IntrinsicsSPIRV.h"
25#define DEBUG_TYPE "spirv-postlegalizer"
62 Register ResVReg =
I->getOperand(0).getReg();
79 for (
unsigned i = StartOp; i < EndOp; ++i) {
81#ifdef EXPENSIVE_CHECKS
82 assert(!ResType ||
Type == ResType &&
"Conflicting type from operands.");
116 assert(
Use->getOpcode() == TargetOpcode::G_LOAD ||
117 Use->getOpcode() == TargetOpcode::G_STORE);
125 SPIRV::StorageClass::Function);
132 assert(
Use->getOpcode() == TargetOpcode::G_LOAD ||
133 Use->getOpcode() == TargetOpcode::G_STORE);
150 switch (
Use.getOpcode()) {
151 case TargetOpcode::G_BUILD_VECTOR:
152 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
153 case TargetOpcode::G_UNMERGE_VALUES:
154 case TargetOpcode::G_ADD:
155 case TargetOpcode::G_SUB:
156 case TargetOpcode::G_MUL:
157 case TargetOpcode::G_SDIV:
158 case TargetOpcode::G_UDIV:
159 case TargetOpcode::G_SREM:
160 case TargetOpcode::G_UREM:
161 case TargetOpcode::G_FADD:
162 case TargetOpcode::G_FSUB:
163 case TargetOpcode::G_FMUL:
164 case TargetOpcode::G_FDIV:
165 case TargetOpcode::G_FREM:
166 case TargetOpcode::G_FMA:
167 case TargetOpcode::COPY:
168 case TargetOpcode::G_STRICT_FMA:
171 case TargetOpcode::G_LOAD:
172 case TargetOpcode::G_STORE:
173 if (
Reg ==
Use.getOperand(1).getReg())
178 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
179 case TargetOpcode::G_INTRINSIC: {
181 if (IntrinsicID == Intrinsic::spv_insertelt) {
182 if (
Reg ==
Use.getOperand(2).getReg())
184 }
else if (IntrinsicID == Intrinsic::spv_extractelt) {
185 if (
Reg ==
Use.getOperand(2).getReg())
202 Register PtrReg =
I->getOperand(3).getReg();
205 LLVM_DEBUG(
dbgs() <<
" Could not get type for pointer operand.\n");
211 LLVM_DEBUG(
dbgs() <<
" Could not get pointee type from pointer type.\n");
219 for (
unsigned i = 5; i <
I->getNumOperands(); ++i) {
221 <<
", current type: " << *PointeeType);
223 case SPIRV::OpTypeArray:
224 case SPIRV::OpTypeRuntimeArray:
225 case SPIRV::OpTypeVector: {
230 case SPIRV::OpTypeStruct: {
232 if (!IdxOp.
isReg()) {
239 dbgs() <<
" Could not find definition for index register.\n");
254 LLVM_DEBUG(
dbgs() <<
" Unknown type opcode for GEP traversal.\n");
274 Register ResVReg =
I->getOperand(0).getReg();
275 switch (
I->getOpcode()) {
276 case TargetOpcode::G_CONSTANT:
277 case TargetOpcode::G_ANYEXT:
278 case TargetOpcode::G_SEXT:
279 case TargetOpcode::G_ZEXT:
281 case TargetOpcode::G_BUILD_VECTOR:
283 case TargetOpcode::G_SHUFFLE_VECTOR:
285 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
286 case TargetOpcode::G_INTRINSIC: {
288 if (IntrinsicID == Intrinsic::spv_gep)
292 case TargetOpcode::G_LOAD: {
297 if (
I->getNumDefs() == 1 &&
I->getNumOperands() > 1 &&
298 I->getOperand(1).isReg())
308 Register SrcReg =
I->getOperand(
I->getNumOperands() - 1).getReg();
311 assert(DefType->getOpcode() == SPIRV::OpTypeVector);
318 for (
unsigned i = 0; i <
I->getNumDefs(); ++i) {
319 Register DefReg =
I->getOperand(i).getReg();
331 for (
unsigned i = 0; i <
I->getNumOperands(); ++i) {
332 Register DefReg =
I->getOperand(i).getReg();
336 LLT DefLLT =
MRI.getType(DefReg);
353 Register ResVReg =
I->getOperand(0).getReg();
358 if (
I->getOpcode() == TargetOpcode::G_UNMERGE_VALUES)
374 if (!
MRI.getRegClassOrNull(ResVReg)) {
383 LLVM_DEBUG(
dbgs() <<
"Checking if instruction requires a SPIR-V type: "
385 if (
I.getNumDefs() == 0) {
386 LLVM_DEBUG(
dbgs() <<
"Instruction does not have a definition.\n");
390 if (!
I.isPreISelOpcode()) {
391 LLVM_DEBUG(
dbgs() <<
"Instruction is not a generic instruction.\n");
395 Register ResultRegister =
I.defs().begin()->getReg();
398 if (!
MRI.getRegClassOrNull(ResultRegister)) {
421 if (Worklist.
empty()) {
427 for (
auto *
I : Worklist) {
I->dump(); });
442 Worklist = std::move(NextWorklist);
443 LLVM_DEBUG(
dbgs() <<
"Worklist size: " << Worklist.size() <<
"\n");
446 if (Worklist.
empty())
449 for (
auto *
I : Worklist) {
452 for (
unsigned Idx = 0; Idx <
I->getNumDefs(); ++Idx) {
453 Register ResVReg =
I->getOperand(Idx).getReg();
456 const LLT &ResLLT =
MRI.getType(ResVReg);
473 if (UseInstr.getOpcode() == SPIRV::ASSIGN_TYPE) {
485 <<
printReg(ResultRegister,
MRI.getTargetRegisterInfo())
486 <<
" with type: " << *ResultType);
494 MRI.createGenericVirtualRegister(
MRI.getType(ResultRegister));
495 const auto *RegClass = GR->
getRegClass(ResultType);
496 MRI.setRegClass(NewReg, RegClass);
497 MRI.setRegClass(ResultRegister, RegClass);
511 for (
unsigned I = 0,
E =
MI.getNumDefs();
I !=
E; ++
I) {
513 if (MO.
getReg() == ResultRegister) {
522 LLVM_DEBUG(
dbgs() <<
"Entering ensureAssignTypeForTypeFolding for function "
532 Register ResultRegister =
MI.defs().begin()->getReg();
547 SPIRVGlobalRegistry *GR =
ST.getSPIRVGlobalRegistry();
548 GR->setCurrentFunc(MF);
557char SPIRVPostLegalizer::
ID = 0;
560 return new SPIRVPostLegalizer();
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
MachineInstr unsigned OpIdx
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
static bool deduceAndAssignSpirvType(MachineInstr *I, MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB)
static SPIRVTypeInst deduceTypeFromPointerOperand(MachineInstr *Use, Register UseRegister, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB)
static void registerSpirvTypeForNewInstructions(MachineFunction &MF, SPIRVGlobalRegistry *GR)
static bool hasAssignType(Register Reg, MachineRegisterInfo &MRI)
static SPIRVTypeInst deduceTypeFromOperandRange(MachineInstr *I, MachineIRBuilder &MIB, SPIRVGlobalRegistry *GR, unsigned StartOp, unsigned EndOp)
static SPIRVTypeInst deduceTypeFromResultRegister(MachineInstr *Use, Register UseRegister, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB)
static SPIRVTypeInst deduceTypeFromSingleOperand(MachineInstr *I, MachineIRBuilder &MIB, SPIRVGlobalRegistry *GR, unsigned OpIdx)
static SPIRVTypeInst deducePointerTypeFromResultRegister(MachineInstr *Use, Register UseRegister, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB)
static SPIRVTypeInst deduceIntTypeFromResult(Register ResVReg, MachineIRBuilder &MIB, SPIRVGlobalRegistry *GR)
static SPIRVTypeInst deduceGEPType(MachineInstr *I, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB)
static void ensureAssignTypeForTypeFolding(MachineFunction &MF, SPIRVGlobalRegistry *GR)
static SPIRVTypeInst deduceTypeFromUses(Register Reg, MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB)
static bool deduceAndAssignTypeForGUnmerge(MachineInstr *I, MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB)
static SPIRVTypeInst deduceResultTypeFromOperands(MachineInstr *I, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB)
static void generateAssignType(MachineInstr &MI, Register ResultRegister, SPIRVTypeInst ResultType, SPIRVGlobalRegistry *GR, MachineRegisterInfo &MRI)
static bool requiresSpirvType(MachineInstr &I, SPIRVGlobalRegistry *GR, MachineRegisterInfo &MRI)
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Helper class to build MachineInstr.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
unsigned getNumOperands() const
Retuns the total number of operands.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
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,...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
Wrapper class representing virtual and physical registers.
void assignSPIRVTypeToVReg(SPIRVTypeInst Type, Register VReg, const MachineFunction &MF)
const TargetRegisterClass * getRegClass(SPIRVTypeInst SpvType) const
SPIRVTypeInst getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineIRBuilder &MIRBuilder)
SPIRVTypeInst getOrCreateSPIRVVectorType(SPIRVTypeInst BaseType, unsigned NumElements, MachineIRBuilder &MIRBuilder, bool EmitIR)
SPIRVTypeInst getOrCreateSPIRVPointerType(const Type *BaseType, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SC)
Register getSPIRVTypeID(SPIRVTypeInst SpirvType) const
SPIRVTypeInst getScalarOrVectorComponentType(SPIRVTypeInst Type) const
SPIRVTypeInst getPointeeType(SPIRVTypeInst PtrType)
SPIRVTypeInst getSPIRVTypeForVReg(Register VReg, const MachineFunction *MF=nullptr) const
SPIRV::StorageClass::StorageClass getPointerStorageClass(Register VReg) const
const SPIRVInstrInfo * getInstrInfo() const override
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 Use represents the edge between a Value definition and its users.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
This is an optimization pass for GlobalISel generic memory operations.
bool isTypeFoldingSupported(unsigned Opcode)
void updateRegType(Register Reg, Type *Ty, SPIRVTypeInst SpirvTy, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, MachineRegisterInfo &MRI)
Helper external function for assigning a SPIRV type to a register, ensuring the register class and ty...
FunctionPass * createSPIRVPostLegalizerPass()
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void setRegClassType(Register Reg, SPIRVTypeInst SpvType, SPIRVGlobalRegistry *GR, MachineRegisterInfo *MRI, const MachineFunction &MF, bool Force)
void processInstr(MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR, SPIRVTypeInst KnownResType)
int64_t foldImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
PointerUnion< const Value *, const PseudoSourceValue * > ValueType
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.