21#include "llvm/IR/IntrinsicsSPIRV.h"
25#define DEBUG_TYPE "spirv-postlegalizer"
62 Register ResVReg =
I->getOperand(0).getReg();
76 unsigned StartOp,
unsigned EndOp) {
78 for (
unsigned i = StartOp; i < EndOp; ++i) {
80#ifdef EXPENSIVE_CHECKS
81 assert(!ResType ||
Type == ResType &&
"Conflicting type from operands.");
115 assert(
Use->getOpcode() == TargetOpcode::G_LOAD ||
116 Use->getOpcode() == TargetOpcode::G_STORE);
124 SPIRV::StorageClass::Function);
131 assert(
Use->getOpcode() == TargetOpcode::G_LOAD ||
132 Use->getOpcode() == TargetOpcode::G_STORE);
149 switch (
Use.getOpcode()) {
150 case TargetOpcode::G_BUILD_VECTOR:
151 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
152 case TargetOpcode::G_UNMERGE_VALUES:
153 case TargetOpcode::G_ADD:
154 case TargetOpcode::G_SUB:
155 case TargetOpcode::G_MUL:
156 case TargetOpcode::G_SDIV:
157 case TargetOpcode::G_UDIV:
158 case TargetOpcode::G_SREM:
159 case TargetOpcode::G_UREM:
160 case TargetOpcode::G_FADD:
161 case TargetOpcode::G_FSUB:
162 case TargetOpcode::G_FMUL:
163 case TargetOpcode::G_FDIV:
164 case TargetOpcode::G_FREM:
165 case TargetOpcode::G_FMA:
166 case TargetOpcode::COPY:
167 case TargetOpcode::G_STRICT_FMA:
170 case TargetOpcode::G_LOAD:
171 case TargetOpcode::G_STORE:
172 if (
Reg ==
Use.getOperand(1).getReg())
177 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
178 case TargetOpcode::G_INTRINSIC: {
180 if (IntrinsicID == Intrinsic::spv_insertelt) {
181 if (
Reg ==
Use.getOperand(2).getReg())
183 }
else if (IntrinsicID == Intrinsic::spv_extractelt) {
184 if (
Reg ==
Use.getOperand(2).getReg())
201 Register PtrReg =
I->getOperand(3).getReg();
204 LLVM_DEBUG(
dbgs() <<
" Could not get type for pointer operand.\n");
210 LLVM_DEBUG(
dbgs() <<
" Could not get pointee type from pointer type.\n");
218 for (
unsigned i = 5; i <
I->getNumOperands(); ++i) {
220 <<
", current type: " << *PointeeType);
222 case SPIRV::OpTypeArray:
223 case SPIRV::OpTypeRuntimeArray:
224 case SPIRV::OpTypeVector: {
229 case SPIRV::OpTypeStruct: {
231 if (!IdxOp.
isReg()) {
238 dbgs() <<
" Could not find definition for index register.\n");
253 LLVM_DEBUG(
dbgs() <<
" Unknown type opcode for GEP traversal.\n");
273 Register ResVReg =
I->getOperand(0).getReg();
274 switch (
I->getOpcode()) {
275 case TargetOpcode::G_CONSTANT:
276 case TargetOpcode::G_ANYEXT:
277 case TargetOpcode::G_SEXT:
278 case TargetOpcode::G_ZEXT:
280 case TargetOpcode::G_BUILD_VECTOR:
282 case TargetOpcode::G_SHUFFLE_VECTOR:
284 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
285 case TargetOpcode::G_INTRINSIC: {
287 if (IntrinsicID == Intrinsic::spv_gep)
291 case TargetOpcode::G_LOAD: {
296 if (
I->getNumDefs() == 1 &&
I->getNumOperands() > 1 &&
297 I->getOperand(1).isReg())
307 Register SrcReg =
I->getOperand(
I->getNumOperands() - 1).getReg();
310 assert(DefType->getOpcode() == SPIRV::OpTypeVector);
317 for (
unsigned i = 0; i <
I->getNumDefs(); ++i) {
318 Register DefReg =
I->getOperand(i).getReg();
330 for (
unsigned i = 0; i <
I->getNumOperands(); ++i) {
331 Register DefReg =
I->getOperand(i).getReg();
335 LLT DefLLT =
MRI.getType(DefReg);
352 Register ResVReg =
I->getOperand(0).getReg();
357 if (
I->getOpcode() == TargetOpcode::G_UNMERGE_VALUES)
373 if (!
MRI.getRegClassOrNull(ResVReg)) {
382 LLVM_DEBUG(
dbgs() <<
"Checking if instruction requires a SPIR-V type: "
384 if (
I.getNumDefs() == 0) {
385 LLVM_DEBUG(
dbgs() <<
"Instruction does not have a definition.\n");
389 if (!
I.isPreISelOpcode()) {
390 LLVM_DEBUG(
dbgs() <<
"Instruction is not a generic instruction.\n");
394 Register ResultRegister =
I.defs().begin()->getReg();
397 if (!
MRI.getRegClassOrNull(ResultRegister)) {
420 if (Worklist.
empty()) {
426 for (
auto *
I : Worklist) {
I->dump(); });
441 Worklist = std::move(NextWorklist);
442 LLVM_DEBUG(
dbgs() <<
"Worklist size: " << Worklist.size() <<
"\n");
445 if (Worklist.
empty())
448 for (
auto *
I : Worklist) {
451 for (
unsigned Idx = 0; Idx <
I->getNumDefs(); ++Idx) {
452 Register ResVReg =
I->getOperand(Idx).getReg();
455 const LLT &ResLLT =
MRI.getType(ResVReg);
472 if (UseInstr.getOpcode() == SPIRV::ASSIGN_TYPE) {
483 <<
printReg(ResultRegister,
MRI.getTargetRegisterInfo())
484 <<
" with type: " << *ResultType);
492 MRI.createGenericVirtualRegister(
MRI.getType(ResultRegister));
493 const auto *RegClass = GR->
getRegClass(ResultType);
494 MRI.setRegClass(NewReg, RegClass);
495 MRI.setRegClass(ResultRegister, RegClass);
509 for (
unsigned I = 0,
E =
MI.getNumDefs();
I !=
E; ++
I) {
511 if (MO.
getReg() == ResultRegister) {
520 LLVM_DEBUG(
dbgs() <<
"Entering ensureAssignTypeForTypeFolding for function "
530 Register ResultRegister =
MI.defs().begin()->getReg();
547 std::stack<MachineBasicBlock *> ToVisit;
550 ToVisit.push(&Start);
551 Seen.
insert(ToVisit.top());
552 while (ToVisit.size() != 0) {
558 for (
auto Succ :
MBB->successors()) {
576 SPIRVGlobalRegistry *GR =
ST.getSPIRVGlobalRegistry();
577 GR->setCurrentFunc(MF);
586char SPIRVPostLegalizer::
ID = 0;
589 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 SPIRVType * deduceIntTypeFromResult(Register ResVReg, MachineIRBuilder &MIB, SPIRVGlobalRegistry *GR)
void visit(MachineFunction &MF, MachineBasicBlock &Start, std::function< void(MachineBasicBlock *)> op)
static SPIRVType * deduceTypeFromPointerOperand(MachineInstr *Use, Register UseRegister, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB)
static void registerSpirvTypeForNewInstructions(MachineFunction &MF, SPIRVGlobalRegistry *GR)
static bool hasAssignType(Register Reg, MachineRegisterInfo &MRI)
static SPIRVType * deduceResultTypeFromOperands(MachineInstr *I, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB)
static SPIRVType * deducePointerTypeFromResultRegister(MachineInstr *Use, Register UseRegister, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB)
static SPIRVType * deduceTypeFromOperandRange(MachineInstr *I, MachineIRBuilder &MIB, SPIRVGlobalRegistry *GR, unsigned StartOp, unsigned EndOp)
static SPIRVType * deduceTypeFromUses(Register Reg, MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB)
static SPIRVType * deduceTypeFromResultRegister(MachineInstr *Use, Register UseRegister, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB)
static void generateAssignType(MachineInstr &MI, Register ResultRegister, SPIRVType *ResultType, SPIRVGlobalRegistry *GR, MachineRegisterInfo &MRI)
static void ensureAssignTypeForTypeFolding(MachineFunction &MF, SPIRVGlobalRegistry *GR)
static SPIRVType * deduceGEPType(MachineInstr *I, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB)
static bool deduceAndAssignTypeForGUnmerge(MachineInstr *I, MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB)
static bool requiresSpirvType(MachineInstr &I, SPIRVGlobalRegistry *GR, MachineRegisterInfo &MRI)
static SPIRVType * deduceTypeFromSingleOperand(MachineInstr *I, MachineIRBuilder &MIB, SPIRVGlobalRegistry *GR, unsigned OpIdx)
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, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & setMIFlags(unsigned Flags) const
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
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.
SPIRVType * getSPIRVTypeForVReg(Register VReg, const MachineFunction *MF=nullptr) const
void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg, const MachineFunction &MF)
SPIRVType * getOrCreateSPIRVPointerType(const Type *BaseType, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SC)
SPIRVType * getPointeeType(SPIRVType *PtrType)
Register getSPIRVTypeID(const SPIRVType *SpirvType) const
SPIRVType * getScalarOrVectorComponentType(Register VReg) const
const TargetRegisterClass * getRegClass(SPIRVType *SpvType) const
SPIRVType * getOrCreateSPIRVVectorType(SPIRVType *BaseType, unsigned NumElements, MachineIRBuilder &MIRBuilder, bool EmitIR)
SPIRVType * getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineIRBuilder &MIRBuilder)
SPIRV::StorageClass::StorageClass getPointerStorageClass(Register VReg) const
const SPIRVInstrInfo * getInstrInfo() const override
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
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, SPIRVType *SpirvTy, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, MachineRegisterInfo &MRI)
Helper external function for assigning SPIRVType to a register, ensuring the register class and type ...
void processInstr(MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR, SPIRVType *KnownResType)
FunctionPass * createSPIRVPostLegalizerPass()
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void setRegClassType(Register Reg, SPIRVType *SpvType, SPIRVGlobalRegistry *GR, MachineRegisterInfo *MRI, const MachineFunction &MF, bool Force)
const MachineInstr SPIRVType
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.