25#include "llvm/IR/IntrinsicsSPIRV.h"
28#define DEBUG_TYPE "spirv-postlegalizer"
70 Register OpReg =
I->getOperand(OpIdx).getReg();
73 Register ResVReg =
I->getOperand(0).getReg();
90 for (
unsigned i = StartOp; i < EndOp; ++i) {
92#ifdef EXPENSIVE_CHECKS
93 assert(!ResType ||
Type == ResType &&
"Conflicting type from operands.");
127 assert(
Use->getOpcode() == TargetOpcode::G_LOAD ||
128 Use->getOpcode() == TargetOpcode::G_STORE);
136 SPIRV::StorageClass::Function);
143 assert(
Use->getOpcode() == TargetOpcode::G_LOAD ||
144 Use->getOpcode() == TargetOpcode::G_STORE);
161 switch (
Use.getOpcode()) {
162 case TargetOpcode::G_BUILD_VECTOR:
163 case TargetOpcode::G_CONCAT_VECTORS:
164 case TargetOpcode::G_SHUFFLE_VECTOR:
165 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
166 case TargetOpcode::G_UNMERGE_VALUES:
167 case TargetOpcode::G_ADD:
168 case TargetOpcode::G_SUB:
169 case TargetOpcode::G_MUL:
170 case TargetOpcode::G_SDIV:
171 case TargetOpcode::G_UDIV:
172 case TargetOpcode::G_SREM:
173 case TargetOpcode::G_UREM:
174 case TargetOpcode::G_FADD:
175 case TargetOpcode::G_FSUB:
176 case TargetOpcode::G_FMUL:
177 case TargetOpcode::G_FDIV:
178 case TargetOpcode::G_FEXP:
179 case TargetOpcode::G_FEXP2:
180 case TargetOpcode::G_FCEIL:
181 case TargetOpcode::G_FFLOOR:
182 case TargetOpcode::G_FREM:
183 case TargetOpcode::G_FMA:
184 case TargetOpcode::G_FACOS:
185 case TargetOpcode::G_FASIN:
186 case TargetOpcode::G_FATAN:
187 case TargetOpcode::G_FATAN2:
188 case TargetOpcode::G_FCOS:
189 case TargetOpcode::G_FSIN:
190 case TargetOpcode::G_FTAN:
191 case TargetOpcode::G_FCOSH:
192 case TargetOpcode::G_FSINH:
193 case TargetOpcode::G_FTANH:
194 case TargetOpcode::G_FLOG:
195 case TargetOpcode::G_FLOG2:
196 case TargetOpcode::G_FLOG10:
197 case TargetOpcode::G_FPOW:
198 case TargetOpcode::G_FMINNUM:
199 case TargetOpcode::G_FMAXNUM:
200 case TargetOpcode::G_FABS:
201 case TargetOpcode::G_FSQRT:
202 case TargetOpcode::COPY:
203 case TargetOpcode::G_STRICT_FMA:
204 case TargetOpcode::G_INTRINSIC_TRUNC:
205 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
208 case TargetOpcode::G_SELECT:
209 if (
Reg ==
Use.getOperand(2).getReg() ||
210 Reg ==
Use.getOperand(3).getReg())
213 case TargetOpcode::G_LOAD:
214 case TargetOpcode::G_STORE:
215 if (
Reg ==
Use.getOperand(1).getReg())
220 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
221 case TargetOpcode::G_INTRINSIC: {
223 if (IntrinsicID == Intrinsic::spv_insertelt) {
224 if (
Reg ==
Use.getOperand(2).getReg())
226 }
else if (IntrinsicID == Intrinsic::spv_extractelt) {
227 if (
Reg ==
Use.getOperand(2).getReg())
244 Register PtrReg =
I->getOperand(3).getReg();
247 LLVM_DEBUG(
dbgs() <<
" Could not get type for pointer operand.\n");
253 LLVM_DEBUG(
dbgs() <<
" Could not get pointee type from pointer type.\n");
261 for (
unsigned i = 5; i <
I->getNumOperands(); ++i) {
263 <<
", current type: " << *PointeeType);
265 case SPIRV::OpTypeArray:
266 case SPIRV::OpTypeRuntimeArray:
267 case SPIRV::OpTypeVector:
268 case SPIRV::OpTypeVectorIdEXT: {
273 case SPIRV::OpTypeStruct: {
275 if (!IdxOp.
isReg()) {
282 dbgs() <<
" Could not find definition for index register.\n");
297 LLVM_DEBUG(
dbgs() <<
" Unknown type opcode for GEP traversal.\n");
317 Register ResVReg =
I->getOperand(0).getReg();
318 switch (
I->getOpcode()) {
319 case TargetOpcode::G_CONSTANT:
320 case TargetOpcode::G_ANYEXT:
321 case TargetOpcode::G_SEXT:
322 case TargetOpcode::G_ZEXT:
323 case TargetOpcode::G_TRUNC:
324 case TargetOpcode::G_FPTOSI:
325 case TargetOpcode::G_FPTOUI:
327 case TargetOpcode::G_BUILD_VECTOR:
329 case TargetOpcode::G_SHUFFLE_VECTOR:
331 case TargetOpcode::G_SELECT:
333 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
334 case TargetOpcode::G_INTRINSIC: {
336 if (IntrinsicID == Intrinsic::spv_gep)
338 if (IntrinsicID == Intrinsic::spv_extractelt)
342 case TargetOpcode::G_LOAD: {
346 case TargetOpcode::G_PHI: {
347 for (
unsigned Idx = 1; Idx <
I->getNumOperands(); Idx += 2) {
348 Register OpReg =
I->getOperand(Idx).getReg();
355 if (
I->getNumDefs() == 1 &&
I->getNumOperands() > 1 &&
356 I->getOperand(1).isReg())
366 Register SrcReg =
I->getOperand(
I->getNumOperands() - 1).getReg();
376 for (
unsigned i = 0; i <
I->getNumDefs(); ++i) {
377 Register DefReg =
I->getOperand(i).getReg();
389 for (
unsigned i = 0; i <
I->getNumOperands(); ++i) {
390 Register DefReg =
I->getOperand(i).getReg();
394 LLT DefLLT =
MRI.getType(DefReg);
411 Register ResVReg =
I->getOperand(0).getReg();
416 if (
I->getOpcode() == TargetOpcode::G_UNMERGE_VALUES)
436 LLVM_DEBUG(
dbgs() <<
"Checking if instruction requires a SPIR-V type: "
438 if (
I.getNumDefs() == 0) {
439 LLVM_DEBUG(
dbgs() <<
"Instruction does not have a definition.\n");
443 if (!
I.isPreISelOpcode()) {
444 LLVM_DEBUG(
dbgs() <<
"Instruction is not a generic instruction.\n");
448 Register ResultRegister =
I.defs().begin()->getReg();
451 if (!
MRI.getRegClassOrNull(ResultRegister)) {
474 if (Worklist.
empty()) {
480 for (
auto *
I : Worklist) {
I->dump(); });
495 Worklist = std::move(NextWorklist);
496 LLVM_DEBUG(
dbgs() <<
"Worklist size: " << Worklist.size() <<
"\n");
499 if (Worklist.
empty())
502 for (
auto *
I : Worklist) {
505 for (
unsigned Idx = 0; Idx <
I->getNumDefs(); ++Idx) {
506 Register ResVReg =
I->getOperand(Idx).getReg();
509 const LLT &ResLLT =
MRI.getType(ResVReg);
526 if (UseInstr.getOpcode() == SPIRV::ASSIGN_TYPE) {
538 <<
printReg(ResultRegister,
MRI.getTargetRegisterInfo())
539 <<
" with type: " << *ResultType);
548 MRI.createGenericVirtualRegister(
MRI.getType(ResultRegister));
549 const auto *RegClass = GR->
getRegClass(ResultType);
550 MRI.setRegClass(NewReg, RegClass);
551 MRI.setRegClass(ResultRegister, RegClass);
565 for (
unsigned I = 0,
E =
MI.getNumDefs();
I !=
E; ++
I) {
567 if (MO.
getReg() == ResultRegister) {
576 LLVM_DEBUG(
dbgs() <<
"Entering ensureAssignTypeForTypeFolding for function "
586 Register ResultRegister =
MI.defs().begin()->getReg();
602 GR->setCurrentFunc(MF);
611char SPIRVPostLegalizerLegacy::ID = 0;
614 return new SPIRVPostLegalizerLegacy();
617bool SPIRVPostLegalizerLegacy::runOnMachineFunction(
MachineFunction &MF) {
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...
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
MachineRegisterInfo & MRI
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 bool runPostLegalizer(MachineFunction &MF)
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)
FunctionPass class - This class is used to implement most global optimizations.
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.
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
An RAII based helper class to modify MachineFunctionProperties when running pass.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
Properties which a MachineFunction may have at a given point in time.
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.
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
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.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Wrapper class representing virtual and physical registers.
void assignSPIRVTypeToVReg(SPIRVTypeInst Type, Register VReg, const MachineFunction &MF)
SPIRVTypeInst getOrCreateSPIRVPointerType(const Type *BaseType, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SC, bool ForceTyped=false)
const TargetRegisterClass * getRegClass(SPIRVTypeInst SpvType) const
SPIRVTypeInst getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineIRBuilder &MIRBuilder)
SPIRVTypeInst getOrCreateSPIRVVectorType(SPIRVTypeInst BaseType, unsigned NumElements, MachineIRBuilder &MIRBuilder, bool EmitIR)
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
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
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.
Pass manager infrastructure for declaring and invalidating analyses.
This is an optimization pass for GlobalISel generic memory operations.
bool isTypeFoldingSupported(unsigned Opcode)
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
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...
bool isVectorType(SPIRVTypeInst SPVTy)
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
FunctionPass * createSPIRVPostLegalizerLegacyPass()
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.