181ad6265SDimitry Andric //===-- SPIRVPreLegalizer.cpp - prepare IR for legalization -----*- C++ -*-===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // The pass prepares IR for legalization: it assigns SPIR-V types to registers 1081ad6265SDimitry Andric // and removes intrinsics which holded these types during IR translation. 1181ad6265SDimitry Andric // Also it processes constants and registers them in GR to avoid duplication. 1281ad6265SDimitry Andric // 1381ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1481ad6265SDimitry Andric 1581ad6265SDimitry Andric #include "SPIRV.h" 1681ad6265SDimitry Andric #include "SPIRVSubtarget.h" 1781ad6265SDimitry Andric #include "SPIRVUtils.h" 1881ad6265SDimitry Andric #include "llvm/ADT/PostOrderIterator.h" 1981ad6265SDimitry Andric #include "llvm/Analysis/OptimizationRemarkEmitter.h" 2081ad6265SDimitry Andric #include "llvm/IR/Attributes.h" 2181ad6265SDimitry Andric #include "llvm/IR/Constants.h" 2281ad6265SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h" 2381ad6265SDimitry Andric #include "llvm/IR/IntrinsicsSPIRV.h" 2481ad6265SDimitry Andric #include "llvm/Target/TargetIntrinsicInfo.h" 2581ad6265SDimitry Andric 2681ad6265SDimitry Andric #define DEBUG_TYPE "spirv-prelegalizer" 2781ad6265SDimitry Andric 2881ad6265SDimitry Andric using namespace llvm; 2981ad6265SDimitry Andric 3081ad6265SDimitry Andric namespace { 3181ad6265SDimitry Andric class SPIRVPreLegalizer : public MachineFunctionPass { 3281ad6265SDimitry Andric public: 3381ad6265SDimitry Andric static char ID; 3481ad6265SDimitry Andric SPIRVPreLegalizer() : MachineFunctionPass(ID) { 3581ad6265SDimitry Andric initializeSPIRVPreLegalizerPass(*PassRegistry::getPassRegistry()); 3681ad6265SDimitry Andric } 3781ad6265SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 3881ad6265SDimitry Andric }; 3981ad6265SDimitry Andric } // namespace 4081ad6265SDimitry Andric 41fcaf7f86SDimitry Andric static void addConstantsToTrack(MachineFunction &MF, SPIRVGlobalRegistry *GR) { 42fcaf7f86SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 43fcaf7f86SDimitry Andric DenseMap<MachineInstr *, Register> RegsAlreadyAddedToDT; 44fcaf7f86SDimitry Andric SmallVector<MachineInstr *, 10> ToErase, ToEraseComposites; 45fcaf7f86SDimitry Andric for (MachineBasicBlock &MBB : MF) { 46fcaf7f86SDimitry Andric for (MachineInstr &MI : MBB) { 47fcaf7f86SDimitry Andric if (!isSpvIntrinsic(MI, Intrinsic::spv_track_constant)) 48fcaf7f86SDimitry Andric continue; 49fcaf7f86SDimitry Andric ToErase.push_back(&MI); 50fcaf7f86SDimitry Andric auto *Const = 51fcaf7f86SDimitry Andric cast<Constant>(cast<ConstantAsMetadata>( 52fcaf7f86SDimitry Andric MI.getOperand(3).getMetadata()->getOperand(0)) 53fcaf7f86SDimitry Andric ->getValue()); 54fcaf7f86SDimitry Andric if (auto *GV = dyn_cast<GlobalValue>(Const)) { 55fcaf7f86SDimitry Andric Register Reg = GR->find(GV, &MF); 56fcaf7f86SDimitry Andric if (!Reg.isValid()) 57fcaf7f86SDimitry Andric GR->add(GV, &MF, MI.getOperand(2).getReg()); 58fcaf7f86SDimitry Andric else 59fcaf7f86SDimitry Andric RegsAlreadyAddedToDT[&MI] = Reg; 60fcaf7f86SDimitry Andric } else { 61fcaf7f86SDimitry Andric Register Reg = GR->find(Const, &MF); 62fcaf7f86SDimitry Andric if (!Reg.isValid()) { 63fcaf7f86SDimitry Andric if (auto *ConstVec = dyn_cast<ConstantDataVector>(Const)) { 64fcaf7f86SDimitry Andric auto *BuildVec = MRI.getVRegDef(MI.getOperand(2).getReg()); 65fcaf7f86SDimitry Andric assert(BuildVec && 66fcaf7f86SDimitry Andric BuildVec->getOpcode() == TargetOpcode::G_BUILD_VECTOR); 67fcaf7f86SDimitry Andric for (unsigned i = 0; i < ConstVec->getNumElements(); ++i) 68fcaf7f86SDimitry Andric GR->add(ConstVec->getElementAsConstant(i), &MF, 69fcaf7f86SDimitry Andric BuildVec->getOperand(1 + i).getReg()); 70fcaf7f86SDimitry Andric } 71fcaf7f86SDimitry Andric GR->add(Const, &MF, MI.getOperand(2).getReg()); 72fcaf7f86SDimitry Andric } else { 73fcaf7f86SDimitry Andric RegsAlreadyAddedToDT[&MI] = Reg; 74fcaf7f86SDimitry Andric // This MI is unused and will be removed. If the MI uses 75fcaf7f86SDimitry Andric // const_composite, it will be unused and should be removed too. 76fcaf7f86SDimitry Andric assert(MI.getOperand(2).isReg() && "Reg operand is expected"); 77fcaf7f86SDimitry Andric MachineInstr *SrcMI = MRI.getVRegDef(MI.getOperand(2).getReg()); 78fcaf7f86SDimitry Andric if (SrcMI && isSpvIntrinsic(*SrcMI, Intrinsic::spv_const_composite)) 79fcaf7f86SDimitry Andric ToEraseComposites.push_back(SrcMI); 80fcaf7f86SDimitry Andric } 81fcaf7f86SDimitry Andric } 82fcaf7f86SDimitry Andric } 83fcaf7f86SDimitry Andric } 84fcaf7f86SDimitry Andric for (MachineInstr *MI : ToErase) { 85fcaf7f86SDimitry Andric Register Reg = MI->getOperand(2).getReg(); 86fcaf7f86SDimitry Andric if (RegsAlreadyAddedToDT.find(MI) != RegsAlreadyAddedToDT.end()) 87fcaf7f86SDimitry Andric Reg = RegsAlreadyAddedToDT[MI]; 88fcaf7f86SDimitry Andric MRI.replaceRegWith(MI->getOperand(0).getReg(), Reg); 89fcaf7f86SDimitry Andric MI->eraseFromParent(); 90fcaf7f86SDimitry Andric } 91fcaf7f86SDimitry Andric for (MachineInstr *MI : ToEraseComposites) 92fcaf7f86SDimitry Andric MI->eraseFromParent(); 9381ad6265SDimitry Andric } 9481ad6265SDimitry Andric 9581ad6265SDimitry Andric static void foldConstantsIntoIntrinsics(MachineFunction &MF) { 9681ad6265SDimitry Andric SmallVector<MachineInstr *, 10> ToErase; 9781ad6265SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 9881ad6265SDimitry Andric const unsigned AssignNameOperandShift = 2; 9981ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) { 10081ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 10181ad6265SDimitry Andric if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_name)) 10281ad6265SDimitry Andric continue; 10381ad6265SDimitry Andric unsigned NumOp = MI.getNumExplicitDefs() + AssignNameOperandShift; 10481ad6265SDimitry Andric while (MI.getOperand(NumOp).isReg()) { 10581ad6265SDimitry Andric MachineOperand &MOp = MI.getOperand(NumOp); 10681ad6265SDimitry Andric MachineInstr *ConstMI = MRI.getVRegDef(MOp.getReg()); 10781ad6265SDimitry Andric assert(ConstMI->getOpcode() == TargetOpcode::G_CONSTANT); 10881ad6265SDimitry Andric MI.removeOperand(NumOp); 10981ad6265SDimitry Andric MI.addOperand(MachineOperand::CreateImm( 11081ad6265SDimitry Andric ConstMI->getOperand(1).getCImm()->getZExtValue())); 11181ad6265SDimitry Andric if (MRI.use_empty(ConstMI->getOperand(0).getReg())) 11281ad6265SDimitry Andric ToErase.push_back(ConstMI); 11381ad6265SDimitry Andric } 11481ad6265SDimitry Andric } 11581ad6265SDimitry Andric } 11681ad6265SDimitry Andric for (MachineInstr *MI : ToErase) 11781ad6265SDimitry Andric MI->eraseFromParent(); 11881ad6265SDimitry Andric } 11981ad6265SDimitry Andric 12081ad6265SDimitry Andric static void insertBitcasts(MachineFunction &MF, SPIRVGlobalRegistry *GR, 12181ad6265SDimitry Andric MachineIRBuilder MIB) { 12281ad6265SDimitry Andric SmallVector<MachineInstr *, 10> ToErase; 12381ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) { 12481ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 12581ad6265SDimitry Andric if (!isSpvIntrinsic(MI, Intrinsic::spv_bitcast)) 12681ad6265SDimitry Andric continue; 12781ad6265SDimitry Andric assert(MI.getOperand(2).isReg()); 12881ad6265SDimitry Andric MIB.setInsertPt(*MI.getParent(), MI); 12981ad6265SDimitry Andric MIB.buildBitcast(MI.getOperand(0).getReg(), MI.getOperand(2).getReg()); 13081ad6265SDimitry Andric ToErase.push_back(&MI); 13181ad6265SDimitry Andric } 13281ad6265SDimitry Andric } 13381ad6265SDimitry Andric for (MachineInstr *MI : ToErase) 13481ad6265SDimitry Andric MI->eraseFromParent(); 13581ad6265SDimitry Andric } 13681ad6265SDimitry Andric 13781ad6265SDimitry Andric // Translating GV, IRTranslator sometimes generates following IR: 13881ad6265SDimitry Andric // %1 = G_GLOBAL_VALUE 13981ad6265SDimitry Andric // %2 = COPY %1 14081ad6265SDimitry Andric // %3 = G_ADDRSPACE_CAST %2 14181ad6265SDimitry Andric // New registers have no SPIRVType and no register class info. 14281ad6265SDimitry Andric // 14381ad6265SDimitry Andric // Set SPIRVType for GV, propagate it from GV to other instructions, 14481ad6265SDimitry Andric // also set register classes. 14581ad6265SDimitry Andric static SPIRVType *propagateSPIRVType(MachineInstr *MI, SPIRVGlobalRegistry *GR, 14681ad6265SDimitry Andric MachineRegisterInfo &MRI, 14781ad6265SDimitry Andric MachineIRBuilder &MIB) { 14881ad6265SDimitry Andric SPIRVType *SpirvTy = nullptr; 14981ad6265SDimitry Andric assert(MI && "Machine instr is expected"); 15081ad6265SDimitry Andric if (MI->getOperand(0).isReg()) { 15181ad6265SDimitry Andric Register Reg = MI->getOperand(0).getReg(); 15281ad6265SDimitry Andric SpirvTy = GR->getSPIRVTypeForVReg(Reg); 15381ad6265SDimitry Andric if (!SpirvTy) { 15481ad6265SDimitry Andric switch (MI->getOpcode()) { 15581ad6265SDimitry Andric case TargetOpcode::G_CONSTANT: { 15681ad6265SDimitry Andric MIB.setInsertPt(*MI->getParent(), MI); 15781ad6265SDimitry Andric Type *Ty = MI->getOperand(1).getCImm()->getType(); 15881ad6265SDimitry Andric SpirvTy = GR->getOrCreateSPIRVType(Ty, MIB); 15981ad6265SDimitry Andric break; 16081ad6265SDimitry Andric } 16181ad6265SDimitry Andric case TargetOpcode::G_GLOBAL_VALUE: { 16281ad6265SDimitry Andric MIB.setInsertPt(*MI->getParent(), MI); 16381ad6265SDimitry Andric Type *Ty = MI->getOperand(1).getGlobal()->getType(); 16481ad6265SDimitry Andric SpirvTy = GR->getOrCreateSPIRVType(Ty, MIB); 16581ad6265SDimitry Andric break; 16681ad6265SDimitry Andric } 16781ad6265SDimitry Andric case TargetOpcode::G_TRUNC: 16881ad6265SDimitry Andric case TargetOpcode::G_ADDRSPACE_CAST: 169fcaf7f86SDimitry Andric case TargetOpcode::G_PTR_ADD: 17081ad6265SDimitry Andric case TargetOpcode::COPY: { 17181ad6265SDimitry Andric MachineOperand &Op = MI->getOperand(1); 17281ad6265SDimitry Andric MachineInstr *Def = Op.isReg() ? MRI.getVRegDef(Op.getReg()) : nullptr; 17381ad6265SDimitry Andric if (Def) 17481ad6265SDimitry Andric SpirvTy = propagateSPIRVType(Def, GR, MRI, MIB); 17581ad6265SDimitry Andric break; 17681ad6265SDimitry Andric } 17781ad6265SDimitry Andric default: 17881ad6265SDimitry Andric break; 17981ad6265SDimitry Andric } 18081ad6265SDimitry Andric if (SpirvTy) 18181ad6265SDimitry Andric GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF()); 18281ad6265SDimitry Andric if (!MRI.getRegClassOrNull(Reg)) 18381ad6265SDimitry Andric MRI.setRegClass(Reg, &SPIRV::IDRegClass); 18481ad6265SDimitry Andric } 18581ad6265SDimitry Andric } 18681ad6265SDimitry Andric return SpirvTy; 18781ad6265SDimitry Andric } 18881ad6265SDimitry Andric 18981ad6265SDimitry Andric // Insert ASSIGN_TYPE instuction between Reg and its definition, set NewReg as 19081ad6265SDimitry Andric // a dst of the definition, assign SPIRVType to both registers. If SpirvTy is 19181ad6265SDimitry Andric // provided, use it as SPIRVType in ASSIGN_TYPE, otherwise create it from Ty. 192*bdd1243dSDimitry Andric // It's used also in SPIRVBuiltins.cpp. 19381ad6265SDimitry Andric // TODO: maybe move to SPIRVUtils. 194*bdd1243dSDimitry Andric namespace llvm { 195*bdd1243dSDimitry Andric Register insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy, 196*bdd1243dSDimitry Andric SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, 19781ad6265SDimitry Andric MachineRegisterInfo &MRI) { 19881ad6265SDimitry Andric MachineInstr *Def = MRI.getVRegDef(Reg); 19981ad6265SDimitry Andric assert((Ty || SpirvTy) && "Either LLVM or SPIRV type is expected."); 20081ad6265SDimitry Andric MIB.setInsertPt(*Def->getParent(), 20181ad6265SDimitry Andric (Def->getNextNode() ? Def->getNextNode()->getIterator() 20281ad6265SDimitry Andric : Def->getParent()->end())); 20381ad6265SDimitry Andric Register NewReg = MRI.createGenericVirtualRegister(MRI.getType(Reg)); 20481ad6265SDimitry Andric if (auto *RC = MRI.getRegClassOrNull(Reg)) 20581ad6265SDimitry Andric MRI.setRegClass(NewReg, RC); 20681ad6265SDimitry Andric SpirvTy = SpirvTy ? SpirvTy : GR->getOrCreateSPIRVType(Ty, MIB); 20781ad6265SDimitry Andric GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF()); 20881ad6265SDimitry Andric // This is to make it convenient for Legalizer to get the SPIRVType 20981ad6265SDimitry Andric // when processing the actual MI (i.e. not pseudo one). 21081ad6265SDimitry Andric GR->assignSPIRVTypeToVReg(SpirvTy, NewReg, MIB.getMF()); 211*bdd1243dSDimitry Andric // Copy MIFlags from Def to ASSIGN_TYPE instruction. It's required to keep 212*bdd1243dSDimitry Andric // the flags after instruction selection. 213*bdd1243dSDimitry Andric const uint16_t Flags = Def->getFlags(); 21481ad6265SDimitry Andric MIB.buildInstr(SPIRV::ASSIGN_TYPE) 21581ad6265SDimitry Andric .addDef(Reg) 21681ad6265SDimitry Andric .addUse(NewReg) 217*bdd1243dSDimitry Andric .addUse(GR->getSPIRVTypeID(SpirvTy)) 218*bdd1243dSDimitry Andric .setMIFlags(Flags); 21981ad6265SDimitry Andric Def->getOperand(0).setReg(NewReg); 22081ad6265SDimitry Andric MRI.setRegClass(Reg, &SPIRV::ANYIDRegClass); 22181ad6265SDimitry Andric return NewReg; 22281ad6265SDimitry Andric } 223*bdd1243dSDimitry Andric } // namespace llvm 22481ad6265SDimitry Andric 22581ad6265SDimitry Andric static void generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR, 22681ad6265SDimitry Andric MachineIRBuilder MIB) { 22781ad6265SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 22881ad6265SDimitry Andric SmallVector<MachineInstr *, 10> ToErase; 22981ad6265SDimitry Andric 23081ad6265SDimitry Andric for (MachineBasicBlock *MBB : post_order(&MF)) { 23181ad6265SDimitry Andric if (MBB->empty()) 23281ad6265SDimitry Andric continue; 23381ad6265SDimitry Andric 23481ad6265SDimitry Andric bool ReachedBegin = false; 23581ad6265SDimitry Andric for (auto MII = std::prev(MBB->end()), Begin = MBB->begin(); 23681ad6265SDimitry Andric !ReachedBegin;) { 23781ad6265SDimitry Andric MachineInstr &MI = *MII; 23881ad6265SDimitry Andric 23981ad6265SDimitry Andric if (isSpvIntrinsic(MI, Intrinsic::spv_assign_type)) { 24081ad6265SDimitry Andric Register Reg = MI.getOperand(1).getReg(); 24181ad6265SDimitry Andric Type *Ty = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0); 24281ad6265SDimitry Andric MachineInstr *Def = MRI.getVRegDef(Reg); 24381ad6265SDimitry Andric assert(Def && "Expecting an instruction that defines the register"); 24481ad6265SDimitry Andric // G_GLOBAL_VALUE already has type info. 24581ad6265SDimitry Andric if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE) 24681ad6265SDimitry Andric insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MF.getRegInfo()); 24781ad6265SDimitry Andric ToErase.push_back(&MI); 24881ad6265SDimitry Andric } else if (MI.getOpcode() == TargetOpcode::G_CONSTANT || 24981ad6265SDimitry Andric MI.getOpcode() == TargetOpcode::G_FCONSTANT || 25081ad6265SDimitry Andric MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR) { 25181ad6265SDimitry Andric // %rc = G_CONSTANT ty Val 25281ad6265SDimitry Andric // ===> 25381ad6265SDimitry Andric // %cty = OpType* ty 25481ad6265SDimitry Andric // %rctmp = G_CONSTANT ty Val 25581ad6265SDimitry Andric // %rc = ASSIGN_TYPE %rctmp, %cty 25681ad6265SDimitry Andric Register Reg = MI.getOperand(0).getReg(); 25781ad6265SDimitry Andric if (MRI.hasOneUse(Reg)) { 25881ad6265SDimitry Andric MachineInstr &UseMI = *MRI.use_instr_begin(Reg); 25981ad6265SDimitry Andric if (isSpvIntrinsic(UseMI, Intrinsic::spv_assign_type) || 26081ad6265SDimitry Andric isSpvIntrinsic(UseMI, Intrinsic::spv_assign_name)) 26181ad6265SDimitry Andric continue; 26281ad6265SDimitry Andric } 26381ad6265SDimitry Andric Type *Ty = nullptr; 26481ad6265SDimitry Andric if (MI.getOpcode() == TargetOpcode::G_CONSTANT) 26581ad6265SDimitry Andric Ty = MI.getOperand(1).getCImm()->getType(); 26681ad6265SDimitry Andric else if (MI.getOpcode() == TargetOpcode::G_FCONSTANT) 26781ad6265SDimitry Andric Ty = MI.getOperand(1).getFPImm()->getType(); 26881ad6265SDimitry Andric else { 26981ad6265SDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR); 27081ad6265SDimitry Andric Type *ElemTy = nullptr; 27181ad6265SDimitry Andric MachineInstr *ElemMI = MRI.getVRegDef(MI.getOperand(1).getReg()); 27281ad6265SDimitry Andric assert(ElemMI); 27381ad6265SDimitry Andric 27481ad6265SDimitry Andric if (ElemMI->getOpcode() == TargetOpcode::G_CONSTANT) 27581ad6265SDimitry Andric ElemTy = ElemMI->getOperand(1).getCImm()->getType(); 27681ad6265SDimitry Andric else if (ElemMI->getOpcode() == TargetOpcode::G_FCONSTANT) 27781ad6265SDimitry Andric ElemTy = ElemMI->getOperand(1).getFPImm()->getType(); 27881ad6265SDimitry Andric else 27981ad6265SDimitry Andric llvm_unreachable("Unexpected opcode"); 28081ad6265SDimitry Andric unsigned NumElts = 28181ad6265SDimitry Andric MI.getNumExplicitOperands() - MI.getNumExplicitDefs(); 28281ad6265SDimitry Andric Ty = VectorType::get(ElemTy, NumElts, false); 28381ad6265SDimitry Andric } 28481ad6265SDimitry Andric insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MRI); 28581ad6265SDimitry Andric } else if (MI.getOpcode() == TargetOpcode::G_TRUNC || 28681ad6265SDimitry Andric MI.getOpcode() == TargetOpcode::G_GLOBAL_VALUE || 28781ad6265SDimitry Andric MI.getOpcode() == TargetOpcode::COPY || 28881ad6265SDimitry Andric MI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST) { 28981ad6265SDimitry Andric propagateSPIRVType(&MI, GR, MRI, MIB); 29081ad6265SDimitry Andric } 29181ad6265SDimitry Andric 29281ad6265SDimitry Andric if (MII == Begin) 29381ad6265SDimitry Andric ReachedBegin = true; 29481ad6265SDimitry Andric else 29581ad6265SDimitry Andric --MII; 29681ad6265SDimitry Andric } 29781ad6265SDimitry Andric } 29881ad6265SDimitry Andric for (MachineInstr *MI : ToErase) 29981ad6265SDimitry Andric MI->eraseFromParent(); 30081ad6265SDimitry Andric } 30181ad6265SDimitry Andric 30281ad6265SDimitry Andric static std::pair<Register, unsigned> 30381ad6265SDimitry Andric createNewIdReg(Register ValReg, unsigned Opcode, MachineRegisterInfo &MRI, 30481ad6265SDimitry Andric const SPIRVGlobalRegistry &GR) { 30581ad6265SDimitry Andric LLT NewT = LLT::scalar(32); 30681ad6265SDimitry Andric SPIRVType *SpvType = GR.getSPIRVTypeForVReg(ValReg); 30781ad6265SDimitry Andric assert(SpvType && "VReg is expected to have SPIRV type"); 30881ad6265SDimitry Andric bool IsFloat = SpvType->getOpcode() == SPIRV::OpTypeFloat; 30981ad6265SDimitry Andric bool IsVectorFloat = 31081ad6265SDimitry Andric SpvType->getOpcode() == SPIRV::OpTypeVector && 31181ad6265SDimitry Andric GR.getSPIRVTypeForVReg(SpvType->getOperand(1).getReg())->getOpcode() == 31281ad6265SDimitry Andric SPIRV::OpTypeFloat; 31381ad6265SDimitry Andric IsFloat |= IsVectorFloat; 31481ad6265SDimitry Andric auto GetIdOp = IsFloat ? SPIRV::GET_fID : SPIRV::GET_ID; 31581ad6265SDimitry Andric auto DstClass = IsFloat ? &SPIRV::fIDRegClass : &SPIRV::IDRegClass; 31681ad6265SDimitry Andric if (MRI.getType(ValReg).isPointer()) { 31781ad6265SDimitry Andric NewT = LLT::pointer(0, 32); 31881ad6265SDimitry Andric GetIdOp = SPIRV::GET_pID; 31981ad6265SDimitry Andric DstClass = &SPIRV::pIDRegClass; 32081ad6265SDimitry Andric } else if (MRI.getType(ValReg).isVector()) { 32181ad6265SDimitry Andric NewT = LLT::fixed_vector(2, NewT); 32281ad6265SDimitry Andric GetIdOp = IsFloat ? SPIRV::GET_vfID : SPIRV::GET_vID; 32381ad6265SDimitry Andric DstClass = IsFloat ? &SPIRV::vfIDRegClass : &SPIRV::vIDRegClass; 32481ad6265SDimitry Andric } 32581ad6265SDimitry Andric Register IdReg = MRI.createGenericVirtualRegister(NewT); 32681ad6265SDimitry Andric MRI.setRegClass(IdReg, DstClass); 32781ad6265SDimitry Andric return {IdReg, GetIdOp}; 32881ad6265SDimitry Andric } 32981ad6265SDimitry Andric 33081ad6265SDimitry Andric static void processInstr(MachineInstr &MI, MachineIRBuilder &MIB, 33181ad6265SDimitry Andric MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR) { 33281ad6265SDimitry Andric unsigned Opc = MI.getOpcode(); 33381ad6265SDimitry Andric assert(MI.getNumDefs() > 0 && MRI.hasOneUse(MI.getOperand(0).getReg())); 33481ad6265SDimitry Andric MachineInstr &AssignTypeInst = 33581ad6265SDimitry Andric *(MRI.use_instr_begin(MI.getOperand(0).getReg())); 33681ad6265SDimitry Andric auto NewReg = createNewIdReg(MI.getOperand(0).getReg(), Opc, MRI, *GR).first; 33781ad6265SDimitry Andric AssignTypeInst.getOperand(1).setReg(NewReg); 33881ad6265SDimitry Andric MI.getOperand(0).setReg(NewReg); 33981ad6265SDimitry Andric MIB.setInsertPt(*MI.getParent(), 34081ad6265SDimitry Andric (MI.getNextNode() ? MI.getNextNode()->getIterator() 34181ad6265SDimitry Andric : MI.getParent()->end())); 34281ad6265SDimitry Andric for (auto &Op : MI.operands()) { 34381ad6265SDimitry Andric if (!Op.isReg() || Op.isDef()) 34481ad6265SDimitry Andric continue; 34581ad6265SDimitry Andric auto IdOpInfo = createNewIdReg(Op.getReg(), Opc, MRI, *GR); 34681ad6265SDimitry Andric MIB.buildInstr(IdOpInfo.second).addDef(IdOpInfo.first).addUse(Op.getReg()); 34781ad6265SDimitry Andric Op.setReg(IdOpInfo.first); 34881ad6265SDimitry Andric } 34981ad6265SDimitry Andric } 35081ad6265SDimitry Andric 35181ad6265SDimitry Andric // Defined in SPIRVLegalizerInfo.cpp. 35281ad6265SDimitry Andric extern bool isTypeFoldingSupported(unsigned Opcode); 35381ad6265SDimitry Andric 35481ad6265SDimitry Andric static void processInstrsWithTypeFolding(MachineFunction &MF, 35581ad6265SDimitry Andric SPIRVGlobalRegistry *GR, 35681ad6265SDimitry Andric MachineIRBuilder MIB) { 35781ad6265SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 35881ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) { 35981ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 36081ad6265SDimitry Andric if (isTypeFoldingSupported(MI.getOpcode())) 36181ad6265SDimitry Andric processInstr(MI, MIB, MRI, GR); 36281ad6265SDimitry Andric } 36381ad6265SDimitry Andric } 364fcaf7f86SDimitry Andric for (MachineBasicBlock &MBB : MF) { 365fcaf7f86SDimitry Andric for (MachineInstr &MI : MBB) { 366fcaf7f86SDimitry Andric // We need to rewrite dst types for ASSIGN_TYPE instrs to be able 367fcaf7f86SDimitry Andric // to perform tblgen'erated selection and we can't do that on Legalizer 368fcaf7f86SDimitry Andric // as it operates on gMIR only. 369fcaf7f86SDimitry Andric if (MI.getOpcode() != SPIRV::ASSIGN_TYPE) 370fcaf7f86SDimitry Andric continue; 371fcaf7f86SDimitry Andric Register SrcReg = MI.getOperand(1).getReg(); 372*bdd1243dSDimitry Andric unsigned Opcode = MRI.getVRegDef(SrcReg)->getOpcode(); 373*bdd1243dSDimitry Andric if (!isTypeFoldingSupported(Opcode)) 374fcaf7f86SDimitry Andric continue; 375fcaf7f86SDimitry Andric Register DstReg = MI.getOperand(0).getReg(); 376fcaf7f86SDimitry Andric if (MRI.getType(DstReg).isVector()) 377fcaf7f86SDimitry Andric MRI.setRegClass(DstReg, &SPIRV::IDRegClass); 378*bdd1243dSDimitry Andric // Don't need to reset type of register holding constant and used in 379*bdd1243dSDimitry Andric // G_ADDRSPACE_CAST, since it braaks legalizer. 380*bdd1243dSDimitry Andric if (Opcode == TargetOpcode::G_CONSTANT && MRI.hasOneUse(DstReg)) { 381*bdd1243dSDimitry Andric MachineInstr &UseMI = *MRI.use_instr_begin(DstReg); 382*bdd1243dSDimitry Andric if (UseMI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST) 383*bdd1243dSDimitry Andric continue; 384*bdd1243dSDimitry Andric } 385fcaf7f86SDimitry Andric MRI.setType(DstReg, LLT::scalar(32)); 386fcaf7f86SDimitry Andric } 387fcaf7f86SDimitry Andric } 38881ad6265SDimitry Andric } 38981ad6265SDimitry Andric 39081ad6265SDimitry Andric static void processSwitches(MachineFunction &MF, SPIRVGlobalRegistry *GR, 39181ad6265SDimitry Andric MachineIRBuilder MIB) { 392*bdd1243dSDimitry Andric // Before IRTranslator pass, calls to spv_switch intrinsic are inserted before 393*bdd1243dSDimitry Andric // each switch instruction. IRTranslator lowers switches to G_ICMP + G_BRCOND 394*bdd1243dSDimitry Andric // + G_BR triples. A switch with two cases may be transformed to this MIR 395*bdd1243dSDimitry Andric // sequence: 396*bdd1243dSDimitry Andric // 39781ad6265SDimitry Andric // intrinsic(@llvm.spv.switch), %CmpReg, %Const0, %Const1 39881ad6265SDimitry Andric // %Dst0 = G_ICMP intpred(eq), %CmpReg, %Const0 39981ad6265SDimitry Andric // G_BRCOND %Dst0, %bb.2 40081ad6265SDimitry Andric // G_BR %bb.5 40181ad6265SDimitry Andric // bb.5.entry: 40281ad6265SDimitry Andric // %Dst1 = G_ICMP intpred(eq), %CmpReg, %Const1 40381ad6265SDimitry Andric // G_BRCOND %Dst1, %bb.3 40481ad6265SDimitry Andric // G_BR %bb.4 40581ad6265SDimitry Andric // bb.2.sw.bb: 40681ad6265SDimitry Andric // ... 40781ad6265SDimitry Andric // bb.3.sw.bb1: 40881ad6265SDimitry Andric // ... 40981ad6265SDimitry Andric // bb.4.sw.epilog: 41081ad6265SDimitry Andric // ... 411*bdd1243dSDimitry Andric // 412*bdd1243dSDimitry Andric // Sometimes (in case of range-compare switches), additional G_SUBs 413*bdd1243dSDimitry Andric // instructions are inserted before G_ICMPs. Those need to be additionally 414*bdd1243dSDimitry Andric // processed and require type assignment. 415*bdd1243dSDimitry Andric // 416*bdd1243dSDimitry Andric // This function modifies spv_switch call's operands to include destination 417*bdd1243dSDimitry Andric // MBBs (default and for each constant value). 418*bdd1243dSDimitry Andric // Note that this function does not remove G_ICMP + G_BRCOND + G_BR sequences, 419*bdd1243dSDimitry Andric // but they are marked by ModuleAnalysis as skipped and as a result AsmPrinter 420*bdd1243dSDimitry Andric // does not output them. 421*bdd1243dSDimitry Andric 422*bdd1243dSDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 423*bdd1243dSDimitry Andric 424*bdd1243dSDimitry Andric // Collect all MIs relevant to switches across all MBBs in MF. 425*bdd1243dSDimitry Andric std::vector<MachineInstr *> RelevantInsts; 426*bdd1243dSDimitry Andric 427*bdd1243dSDimitry Andric // Temporary set of compare registers. G_SUBs and G_ICMPs relating to 428*bdd1243dSDimitry Andric // spv_switch use these registers. 429*bdd1243dSDimitry Andric DenseSet<Register> CompareRegs; 43081ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) { 43181ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 432*bdd1243dSDimitry Andric // Calls to spv_switch intrinsics representing IR switches. 43381ad6265SDimitry Andric if (isSpvIntrinsic(MI, Intrinsic::spv_switch)) { 43481ad6265SDimitry Andric assert(MI.getOperand(1).isReg()); 435*bdd1243dSDimitry Andric CompareRegs.insert(MI.getOperand(1).getReg()); 436*bdd1243dSDimitry Andric RelevantInsts.push_back(&MI); 43781ad6265SDimitry Andric } 438*bdd1243dSDimitry Andric 439*bdd1243dSDimitry Andric // G_SUBs coming from range-compare switch lowering. G_SUBs are found 440*bdd1243dSDimitry Andric // after spv_switch but before G_ICMP. 441*bdd1243dSDimitry Andric if (MI.getOpcode() == TargetOpcode::G_SUB && MI.getOperand(1).isReg() && 442*bdd1243dSDimitry Andric CompareRegs.contains(MI.getOperand(1).getReg())) { 443*bdd1243dSDimitry Andric assert(MI.getOperand(0).isReg() && MI.getOperand(1).isReg()); 444*bdd1243dSDimitry Andric Register Dst = MI.getOperand(0).getReg(); 445*bdd1243dSDimitry Andric CompareRegs.insert(Dst); 446*bdd1243dSDimitry Andric SPIRVType *Ty = GR->getSPIRVTypeForVReg(MI.getOperand(1).getReg()); 447*bdd1243dSDimitry Andric insertAssignInstr(Dst, nullptr, Ty, GR, MIB, MRI); 448*bdd1243dSDimitry Andric } 449*bdd1243dSDimitry Andric 450*bdd1243dSDimitry Andric // G_ICMPs relating to switches. 45181ad6265SDimitry Andric if (MI.getOpcode() == TargetOpcode::G_ICMP && MI.getOperand(2).isReg() && 452*bdd1243dSDimitry Andric CompareRegs.contains(MI.getOperand(2).getReg())) { 45381ad6265SDimitry Andric Register Dst = MI.getOperand(0).getReg(); 45481ad6265SDimitry Andric // Set type info for destination register of switch's ICMP instruction. 45581ad6265SDimitry Andric if (GR->getSPIRVTypeForVReg(Dst) == nullptr) { 45681ad6265SDimitry Andric MIB.setInsertPt(*MI.getParent(), MI); 45781ad6265SDimitry Andric Type *LLVMTy = IntegerType::get(MF.getFunction().getContext(), 1); 45881ad6265SDimitry Andric SPIRVType *SpirvTy = GR->getOrCreateSPIRVType(LLVMTy, MIB); 45981ad6265SDimitry Andric MRI.setRegClass(Dst, &SPIRV::IDRegClass); 46081ad6265SDimitry Andric GR->assignSPIRVTypeToVReg(SpirvTy, Dst, MIB.getMF()); 46181ad6265SDimitry Andric } 462*bdd1243dSDimitry Andric RelevantInsts.push_back(&MI); 463*bdd1243dSDimitry Andric } 464*bdd1243dSDimitry Andric } 465*bdd1243dSDimitry Andric } 466*bdd1243dSDimitry Andric 467*bdd1243dSDimitry Andric // Update each spv_switch with destination MBBs. 468*bdd1243dSDimitry Andric for (auto i = RelevantInsts.begin(); i != RelevantInsts.end(); i++) { 469*bdd1243dSDimitry Andric if (!isSpvIntrinsic(**i, Intrinsic::spv_switch)) 470*bdd1243dSDimitry Andric continue; 471*bdd1243dSDimitry Andric 472*bdd1243dSDimitry Andric // Currently considered spv_switch. 473*bdd1243dSDimitry Andric MachineInstr *Switch = *i; 474*bdd1243dSDimitry Andric // Set the first successor as default MBB to support empty switches. 475*bdd1243dSDimitry Andric MachineBasicBlock *DefaultMBB = *Switch->getParent()->succ_begin(); 476*bdd1243dSDimitry Andric // Container for mapping values to MMBs. 477*bdd1243dSDimitry Andric SmallDenseMap<uint64_t, MachineBasicBlock *> ValuesToMBBs; 478*bdd1243dSDimitry Andric 479*bdd1243dSDimitry Andric // Walk all G_ICMPs to collect ValuesToMBBs. Start at currently considered 480*bdd1243dSDimitry Andric // spv_switch (i) and break at any spv_switch with the same compare 481*bdd1243dSDimitry Andric // register (indicating we are back at the same scope). 482*bdd1243dSDimitry Andric Register CompareReg = Switch->getOperand(1).getReg(); 483*bdd1243dSDimitry Andric for (auto j = i + 1; j != RelevantInsts.end(); j++) { 484*bdd1243dSDimitry Andric if (isSpvIntrinsic(**j, Intrinsic::spv_switch) && 485*bdd1243dSDimitry Andric (*j)->getOperand(1).getReg() == CompareReg) 486*bdd1243dSDimitry Andric break; 487*bdd1243dSDimitry Andric 488*bdd1243dSDimitry Andric if (!((*j)->getOpcode() == TargetOpcode::G_ICMP && 489*bdd1243dSDimitry Andric (*j)->getOperand(2).getReg() == CompareReg)) 490*bdd1243dSDimitry Andric continue; 491*bdd1243dSDimitry Andric 492*bdd1243dSDimitry Andric MachineInstr *ICMP = *j; 493*bdd1243dSDimitry Andric Register Dst = ICMP->getOperand(0).getReg(); 494*bdd1243dSDimitry Andric MachineOperand &PredOp = ICMP->getOperand(1); 49581ad6265SDimitry Andric const auto CC = static_cast<CmpInst::Predicate>(PredOp.getPredicate()); 496*bdd1243dSDimitry Andric assert((CC == CmpInst::ICMP_EQ || CC == CmpInst::ICMP_ULE) && 497*bdd1243dSDimitry Andric MRI.hasOneUse(Dst) && MRI.hasOneDef(CompareReg)); 498*bdd1243dSDimitry Andric uint64_t Value = getIConstVal(ICMP->getOperand(3).getReg(), &MRI); 49981ad6265SDimitry Andric MachineInstr *CBr = MRI.use_begin(Dst)->getParent(); 500*bdd1243dSDimitry Andric assert(CBr->getOpcode() == SPIRV::G_BRCOND && CBr->getOperand(1).isMBB()); 501*bdd1243dSDimitry Andric MachineBasicBlock *MBB = CBr->getOperand(1).getMBB(); 502*bdd1243dSDimitry Andric 503*bdd1243dSDimitry Andric // Map switch case Value to target MBB. 504*bdd1243dSDimitry Andric ValuesToMBBs[Value] = MBB; 505*bdd1243dSDimitry Andric 506*bdd1243dSDimitry Andric // The next MI is always G_BR to either the next case or the default. 50781ad6265SDimitry Andric MachineInstr *NextMI = CBr->getNextNode(); 50881ad6265SDimitry Andric assert(NextMI->getOpcode() == SPIRV::G_BR && 50981ad6265SDimitry Andric NextMI->getOperand(0).isMBB()); 51081ad6265SDimitry Andric MachineBasicBlock *NextMBB = NextMI->getOperand(0).getMBB(); 511*bdd1243dSDimitry Andric // Default MBB does not begin with G_ICMP using spv_switch compare 512*bdd1243dSDimitry Andric // register. 51381ad6265SDimitry Andric if (NextMBB->front().getOpcode() != SPIRV::G_ICMP || 51481ad6265SDimitry Andric (NextMBB->front().getOperand(2).isReg() && 515*bdd1243dSDimitry Andric NextMBB->front().getOperand(2).getReg() != CompareReg)) 516*bdd1243dSDimitry Andric DefaultMBB = NextMBB; 51781ad6265SDimitry Andric } 518*bdd1243dSDimitry Andric 519*bdd1243dSDimitry Andric // Modify considered spv_switch operands using collected Values and 520*bdd1243dSDimitry Andric // MBBs. 521*bdd1243dSDimitry Andric SmallVector<const ConstantInt *, 3> Values; 52281ad6265SDimitry Andric SmallVector<MachineBasicBlock *, 3> MBBs; 523*bdd1243dSDimitry Andric for (unsigned k = 2; k < Switch->getNumExplicitOperands(); k++) { 524*bdd1243dSDimitry Andric Register CReg = Switch->getOperand(k).getReg(); 52581ad6265SDimitry Andric uint64_t Val = getIConstVal(CReg, &MRI); 52681ad6265SDimitry Andric MachineInstr *ConstInstr = getDefInstrMaybeConstant(CReg, &MRI); 527*bdd1243dSDimitry Andric if (!ValuesToMBBs[Val]) 528*bdd1243dSDimitry Andric continue; 529*bdd1243dSDimitry Andric 530*bdd1243dSDimitry Andric Values.push_back(ConstInstr->getOperand(1).getCImm()); 531*bdd1243dSDimitry Andric MBBs.push_back(ValuesToMBBs[Val]); 53281ad6265SDimitry Andric } 533*bdd1243dSDimitry Andric 534*bdd1243dSDimitry Andric for (unsigned k = Switch->getNumExplicitOperands() - 1; k > 1; k--) 535*bdd1243dSDimitry Andric Switch->removeOperand(k); 536*bdd1243dSDimitry Andric 537*bdd1243dSDimitry Andric Switch->addOperand(MachineOperand::CreateMBB(DefaultMBB)); 538*bdd1243dSDimitry Andric for (unsigned k = 0; k < Values.size(); k++) { 539*bdd1243dSDimitry Andric Switch->addOperand(MachineOperand::CreateCImm(Values[k])); 540*bdd1243dSDimitry Andric Switch->addOperand(MachineOperand::CreateMBB(MBBs[k])); 54181ad6265SDimitry Andric } 54281ad6265SDimitry Andric } 54381ad6265SDimitry Andric } 54481ad6265SDimitry Andric 54581ad6265SDimitry Andric bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) { 54681ad6265SDimitry Andric // Initialize the type registry. 54781ad6265SDimitry Andric const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>(); 54881ad6265SDimitry Andric SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry(); 54981ad6265SDimitry Andric GR->setCurrentFunc(MF); 55081ad6265SDimitry Andric MachineIRBuilder MIB(MF); 551fcaf7f86SDimitry Andric addConstantsToTrack(MF, GR); 55281ad6265SDimitry Andric foldConstantsIntoIntrinsics(MF); 55381ad6265SDimitry Andric insertBitcasts(MF, GR, MIB); 55481ad6265SDimitry Andric generateAssignInstrs(MF, GR, MIB); 55581ad6265SDimitry Andric processSwitches(MF, GR, MIB); 556*bdd1243dSDimitry Andric processInstrsWithTypeFolding(MF, GR, MIB); 55781ad6265SDimitry Andric 55881ad6265SDimitry Andric return true; 55981ad6265SDimitry Andric } 56081ad6265SDimitry Andric 56181ad6265SDimitry Andric INITIALIZE_PASS(SPIRVPreLegalizer, DEBUG_TYPE, "SPIRV pre legalizer", false, 56281ad6265SDimitry Andric false) 56381ad6265SDimitry Andric 56481ad6265SDimitry Andric char SPIRVPreLegalizer::ID = 0; 56581ad6265SDimitry Andric 56681ad6265SDimitry Andric FunctionPass *llvm::createSPIRVPreLegalizerPass() { 56781ad6265SDimitry Andric return new SPIRVPreLegalizer(); 56881ad6265SDimitry Andric } 569