23#include "llvm/IR/IntrinsicsSPIRV.h"
26#define DEBUG_TYPE "spirv-prelegalizer"
51 cast<Constant>(cast<ConstantAsMetadata>(
52 MI.getOperand(3).getMetadata()->getOperand(0))
54 if (
auto *GV = dyn_cast<GlobalValue>(Const)) {
57 GR->
add(GV, &MF,
MI.getOperand(2).getReg());
59 RegsAlreadyAddedToDT[&
MI] = Reg;
63 if (
auto *ConstVec = dyn_cast<ConstantDataVector>(Const)) {
64 auto *BuildVec =
MRI.getVRegDef(
MI.getOperand(2).getReg());
66 BuildVec->getOpcode() == TargetOpcode::G_BUILD_VECTOR);
67 for (
unsigned i = 0; i < ConstVec->getNumElements(); ++i)
68 GR->
add(ConstVec->getElementAsConstant(i), &MF,
69 BuildVec->getOperand(1 + i).getReg());
71 GR->
add(Const, &MF,
MI.getOperand(2).getReg());
73 RegsAlreadyAddedToDT[&
MI] = Reg;
76 assert(
MI.getOperand(2).isReg() &&
"Reg operand is expected");
78 if (SrcMI &&
isSpvIntrinsic(*SrcMI, Intrinsic::spv_const_composite))
86 if (RegsAlreadyAddedToDT.
find(
MI) != RegsAlreadyAddedToDT.
end())
87 Reg = RegsAlreadyAddedToDT[
MI];
88 auto *RC =
MRI.getRegClassOrNull(
MI->getOperand(0).getReg());
89 if (!
MRI.getRegClassOrNull(Reg) && RC)
90 MRI.setRegClass(Reg, RC);
91 MRI.replaceRegWith(
MI->getOperand(0).getReg(), Reg);
92 MI->eraseFromParent();
95 MI->eraseFromParent();
101 const unsigned AssignNameOperandShift = 2;
106 unsigned NumOp =
MI.getNumExplicitDefs() + AssignNameOperandShift;
107 while (
MI.getOperand(NumOp).isReg()) {
111 MI.removeOperand(NumOp);
120 MI->eraseFromParent();
137 MI->eraseFromParent();
152 assert(
MI &&
"Machine instr is expected");
153 if (
MI->getOperand(0).isReg()) {
157 switch (
MI->getOpcode()) {
158 case TargetOpcode::G_CONSTANT: {
160 Type *Ty =
MI->getOperand(1).getCImm()->getType();
164 case TargetOpcode::G_GLOBAL_VALUE: {
166 Type *Ty =
MI->getOperand(1).getGlobal()->getType();
170 case TargetOpcode::G_TRUNC:
171 case TargetOpcode::G_ADDRSPACE_CAST:
172 case TargetOpcode::G_PTR_ADD:
173 case TargetOpcode::COPY: {
185 if (!
MRI.getRegClassOrNull(Reg))
186 MRI.setRegClass(Reg, &SPIRV::IDRegClass);
202 assert((Ty || SpirvTy) &&
"Either LLVM or SPIRV type is expected.");
204 (Def->getNextNode() ? Def->getNextNode()->getIterator()
205 : Def->getParent()->end()));
206 Register NewReg =
MRI.createGenericVirtualRegister(
MRI.getType(Reg));
207 if (
auto *RC =
MRI.getRegClassOrNull(Reg)) {
208 MRI.setRegClass(NewReg, RC);
210 MRI.setRegClass(NewReg, &SPIRV::IDRegClass);
211 MRI.setRegClass(Reg, &SPIRV::IDRegClass);
220 const uint32_t Flags = Def->getFlags();
226 Def->getOperand(0).setReg(NewReg);
240 bool ReachedBegin =
false;
254 assert(Def &&
"Expecting an instruction that defines the register");
262 assert(Def &&
"Expecting an instruction that defines the register");
264 if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE)
267 }
else if (
MI.getOpcode() == TargetOpcode::G_CONSTANT ||
268 MI.getOpcode() == TargetOpcode::G_FCONSTANT ||
269 MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR) {
276 if (
MRI.hasOneUse(Reg)) {
283 if (
MI.getOpcode() == TargetOpcode::G_CONSTANT)
284 Ty =
MI.getOperand(1).getCImm()->getType();
285 else if (
MI.getOpcode() == TargetOpcode::G_FCONSTANT)
286 Ty =
MI.getOperand(1).getFPImm()->getType();
288 assert(
MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR);
289 Type *ElemTy =
nullptr;
293 if (ElemMI->
getOpcode() == TargetOpcode::G_CONSTANT)
295 else if (ElemMI->
getOpcode() == TargetOpcode::G_FCONSTANT)
300 MI.getNumExplicitOperands() -
MI.getNumExplicitDefs();
301 Ty = VectorType::get(ElemTy, NumElts,
false);
304 }
else if (
MI.getOpcode() == TargetOpcode::G_TRUNC ||
305 MI.getOpcode() == TargetOpcode::G_GLOBAL_VALUE ||
306 MI.getOpcode() == TargetOpcode::COPY ||
307 MI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST) {
318 MI->eraseFromParent();
321static std::pair<Register, unsigned>
326 assert(SpvType &&
"VReg is expected to have SPIRV type");
327 bool IsFloat = SpvType->
getOpcode() == SPIRV::OpTypeFloat;
329 SpvType->
getOpcode() == SPIRV::OpTypeVector &&
332 IsFloat |= IsVectorFloat;
333 auto GetIdOp = IsFloat ? SPIRV::GET_fID : SPIRV::GET_ID;
334 auto DstClass = IsFloat ? &SPIRV::fIDRegClass : &SPIRV::IDRegClass;
335 if (
MRI.getType(ValReg).isPointer()) {
337 GetIdOp = SPIRV::GET_pID;
338 DstClass = &SPIRV::pIDRegClass;
339 }
else if (
MRI.getType(ValReg).isVector()) {
341 GetIdOp = IsFloat ? SPIRV::GET_vfID : SPIRV::GET_vID;
342 DstClass = IsFloat ? &SPIRV::vfIDRegClass : &SPIRV::vIDRegClass;
344 Register IdReg =
MRI.createGenericVirtualRegister(NewT);
345 MRI.setRegClass(IdReg, DstClass);
346 return {IdReg, GetIdOp};
351 unsigned Opc =
MI.getOpcode();
352 assert(
MI.getNumDefs() > 0 &&
MRI.hasOneUse(
MI.getOperand(0).getReg()));
354 *(
MRI.use_instr_begin(
MI.getOperand(0).getReg()));
357 MI.getOperand(0).setReg(NewReg);
359 (
MI.getNextNode() ?
MI.getNextNode()->getIterator()
360 :
MI.getParent()->end()));
361 for (
auto &
Op :
MI.operands()) {
362 if (!
Op.isReg() ||
Op.isDef())
366 Op.setReg(IdOpInfo.first);
388 if (
MI.getOpcode() != SPIRV::ASSIGN_TYPE)
391 unsigned Opcode =
MRI.getVRegDef(SrcReg)->getOpcode();
395 if (
MRI.getType(DstReg).isVector())
396 MRI.setRegClass(DstReg, &SPIRV::IDRegClass);
399 if (Opcode == TargetOpcode::G_CONSTANT &&
MRI.hasOneUse(DstReg)) {
401 if (
UseMI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST)
444 std::vector<MachineInstr *> RelevantInsts;
448 std::vector<MachineInstr *> PostUpdateArtifacts;
458 CompareRegs.
insert(
MI.getOperand(1).getReg());
459 RelevantInsts.push_back(&
MI);
464 if (
MI.getOpcode() == TargetOpcode::G_SUB &&
MI.getOperand(1).isReg() &&
465 CompareRegs.
contains(
MI.getOperand(1).getReg())) {
466 assert(
MI.getOperand(0).isReg() &&
MI.getOperand(1).isReg());
469 PostUpdateArtifacts.push_back(&
MI);
473 if (
MI.getOpcode() == TargetOpcode::G_ICMP &&
MI.getOperand(2).isReg() &&
474 CompareRegs.
contains(
MI.getOperand(2).getReg())) {
476 RelevantInsts.push_back(&
MI);
477 PostUpdateArtifacts.push_back(&
MI);
480 PostUpdateArtifacts.push_back(CBr);
483 PostUpdateArtifacts.push_back(Br);
489 for (
auto i = RelevantInsts.begin(); i != RelevantInsts.end(); i++) {
503 Register CompareReg = Switch->getOperand(1).getReg();
504 for (
auto j = i + 1; j != RelevantInsts.end(); j++) {
506 (*j)->getOperand(1).getReg() == CompareReg)
509 if (!((*j)->getOpcode() == TargetOpcode::G_ICMP &&
510 (*j)->getOperand(2).getReg() == CompareReg))
514 Register Dst = ICMP->getOperand(0).getReg();
518 MRI.hasOneUse(Dst) &&
MRI.hasOneDef(CompareReg));
528 Switch->getParent()->addSuccessor(
MBB);
541 DefaultMBB = NextMBB;
542 Switch->getParent()->addSuccessor(DefaultMBB);
550 for (
unsigned k = 2; k < Switch->getNumExplicitOperands(); k++) {
551 Register CReg = Switch->getOperand(k).getReg();
554 if (!ValuesToMBBs[Val])
561 for (
unsigned k = Switch->getNumExplicitOperands() - 1; k > 1; k--)
562 Switch->removeOperand(k);
565 for (
unsigned k = 0; k < Values.
size(); k++) {
573 MI->eraseFromParent();
578 if (ParentMBB->
empty()) {
580 (*ParentMBB->
pred_begin())->removeSuccessor(ParentMBB);
594 GR->setCurrentFunc(MF);
609char SPIRVPreLegalizer::
ID = 0;
612 return new SPIRVPreLegalizer();
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
This file contains the simple types necessary to represent the attributes associated with functions a...
This file contains the declarations for the subclasses of Constant, which represent the different fla...
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
bool isTypeFoldingSupported(unsigned Opcode)
static void insertBitcasts(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void processInstr(MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR)
static void processInstrsWithTypeFolding(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static SPIRVType * propagateSPIRVType(MachineInstr *MI, SPIRVGlobalRegistry *GR, MachineRegisterInfo &MRI, MachineIRBuilder &MIB)
static void processSwitches(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static std::pair< Register, unsigned > createNewIdReg(Register ValReg, unsigned Opcode, MachineRegisterInfo &MRI, const SPIRVGlobalRegistry &GR)
static void generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR, MachineIRBuilder MIB)
static void addConstantsToTrack(MachineFunction &MF, SPIRVGlobalRegistry *GR)
static void foldConstantsIntoIntrinsics(MachineFunction &MF)
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
@ ICMP_ULE
unsigned less or equal
IntegerType * getType() const
getType - Specialize the getType() method to always return an IntegerType, which reduces the amount o...
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
This class represents an Operation in the Expression.
iterator find(const_arg_type_t< KeyT > Val)
Implements a dense probed hash-table based set.
FunctionPass class - This class is used to implement most global optimizations.
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.
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
succ_iterator succ_begin()
void removeSuccessor(MachineBasicBlock *Succ, bool NormalizeSuccProbs=false)
Remove successor from the successors list of this MachineBasicBlock.
pred_iterator pred_begin()
void eraseFromParent()
This method unlinks 'this' from the containing function and deletes it.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
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.
MachineInstrBuilder buildBitcast(const DstOp &Dst, const SrcOp &Src)
Build and insert Dst = G_BITCAST Src.
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.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
const ConstantInt * getCImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
static MachineOperand CreateCImm(const ConstantInt *CI)
void setReg(Register Reg)
Change the register this operand corresponds to.
static MachineOperand CreateImm(int64_t Val)
Register getReg() const
getReg - Returns the register number.
const ConstantFP * getFPImm() const
unsigned getPredicate() const
static MachineOperand CreateMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0)
bool isMBB() const
isMBB - Tests if this is a MO_MachineBasicBlock operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
Wrapper class representing virtual and physical registers.
void add(const Constant *C, MachineFunction *MF, Register R)
SPIRVType * getSPIRVTypeForVReg(Register VReg) const
Register find(const Constant *C, MachineFunction *MF)
Register getSPIRVTypeID(const SPIRVType *SpirvType) const
SPIRVType * getOrCreateSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder, SPIRV::AccessQualifier::AccessQualifier AQ=SPIRV::AccessQualifier::ReadWrite, bool EmitIR=true)
void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg, MachineFunction &MF)
SPIRVType * getOrCreateSPIRVPointerType(SPIRVType *BaseType, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SClass=SPIRV::StorageClass::Function)
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.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
std::pair< iterator, bool > insert(const ValueT &V)
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
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 is an optimization pass for GlobalISel generic memory operations.
FunctionPass * createSPIRVPreLegalizerPass()
Register insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, MachineRegisterInfo &MRI)
Helper external function for inserting ASSIGN_TYPE instuction between Reg and its definition,...
iterator_range< po_iterator< T > > post_order(const T &G)
uint64_t getIConstVal(Register ConstReg, const MachineRegisterInfo *MRI)
SPIRV::StorageClass::StorageClass addressSpaceToStorageClass(unsigned AddrSpace)
bool isSpvIntrinsic(MachineInstr &MI, Intrinsic::ID IntrinsicID)
MachineInstr * getDefInstrMaybeConstant(Register &ConstReg, const MachineRegisterInfo *MRI)
Type * getMDOperandAsType(const MDNode *N, unsigned I)
void initializeSPIRVPreLegalizerPass(PassRegistry &)