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]; 88*06c3fb27SDimitry Andric auto *RC = MRI.getRegClassOrNull(MI->getOperand(0).getReg()); 89*06c3fb27SDimitry Andric if (!MRI.getRegClassOrNull(Reg) && RC) 90*06c3fb27SDimitry Andric MRI.setRegClass(Reg, RC); 91fcaf7f86SDimitry Andric MRI.replaceRegWith(MI->getOperand(0).getReg(), Reg); 92fcaf7f86SDimitry Andric MI->eraseFromParent(); 93fcaf7f86SDimitry Andric } 94fcaf7f86SDimitry Andric for (MachineInstr *MI : ToEraseComposites) 95fcaf7f86SDimitry Andric MI->eraseFromParent(); 9681ad6265SDimitry Andric } 9781ad6265SDimitry Andric 9881ad6265SDimitry Andric static void foldConstantsIntoIntrinsics(MachineFunction &MF) { 9981ad6265SDimitry Andric SmallVector<MachineInstr *, 10> ToErase; 10081ad6265SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 10181ad6265SDimitry Andric const unsigned AssignNameOperandShift = 2; 10281ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) { 10381ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 10481ad6265SDimitry Andric if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_name)) 10581ad6265SDimitry Andric continue; 10681ad6265SDimitry Andric unsigned NumOp = MI.getNumExplicitDefs() + AssignNameOperandShift; 10781ad6265SDimitry Andric while (MI.getOperand(NumOp).isReg()) { 10881ad6265SDimitry Andric MachineOperand &MOp = MI.getOperand(NumOp); 10981ad6265SDimitry Andric MachineInstr *ConstMI = MRI.getVRegDef(MOp.getReg()); 11081ad6265SDimitry Andric assert(ConstMI->getOpcode() == TargetOpcode::G_CONSTANT); 11181ad6265SDimitry Andric MI.removeOperand(NumOp); 11281ad6265SDimitry Andric MI.addOperand(MachineOperand::CreateImm( 11381ad6265SDimitry Andric ConstMI->getOperand(1).getCImm()->getZExtValue())); 11481ad6265SDimitry Andric if (MRI.use_empty(ConstMI->getOperand(0).getReg())) 11581ad6265SDimitry Andric ToErase.push_back(ConstMI); 11681ad6265SDimitry Andric } 11781ad6265SDimitry Andric } 11881ad6265SDimitry Andric } 11981ad6265SDimitry Andric for (MachineInstr *MI : ToErase) 12081ad6265SDimitry Andric MI->eraseFromParent(); 12181ad6265SDimitry Andric } 12281ad6265SDimitry Andric 12381ad6265SDimitry Andric static void insertBitcasts(MachineFunction &MF, SPIRVGlobalRegistry *GR, 12481ad6265SDimitry Andric MachineIRBuilder MIB) { 12581ad6265SDimitry Andric SmallVector<MachineInstr *, 10> ToErase; 12681ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) { 12781ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 12881ad6265SDimitry Andric if (!isSpvIntrinsic(MI, Intrinsic::spv_bitcast)) 12981ad6265SDimitry Andric continue; 13081ad6265SDimitry Andric assert(MI.getOperand(2).isReg()); 13181ad6265SDimitry Andric MIB.setInsertPt(*MI.getParent(), MI); 13281ad6265SDimitry Andric MIB.buildBitcast(MI.getOperand(0).getReg(), MI.getOperand(2).getReg()); 13381ad6265SDimitry Andric ToErase.push_back(&MI); 13481ad6265SDimitry Andric } 13581ad6265SDimitry Andric } 13681ad6265SDimitry Andric for (MachineInstr *MI : ToErase) 13781ad6265SDimitry Andric MI->eraseFromParent(); 13881ad6265SDimitry Andric } 13981ad6265SDimitry Andric 14081ad6265SDimitry Andric // Translating GV, IRTranslator sometimes generates following IR: 14181ad6265SDimitry Andric // %1 = G_GLOBAL_VALUE 14281ad6265SDimitry Andric // %2 = COPY %1 14381ad6265SDimitry Andric // %3 = G_ADDRSPACE_CAST %2 14481ad6265SDimitry Andric // New registers have no SPIRVType and no register class info. 14581ad6265SDimitry Andric // 14681ad6265SDimitry Andric // Set SPIRVType for GV, propagate it from GV to other instructions, 14781ad6265SDimitry Andric // also set register classes. 14881ad6265SDimitry Andric static SPIRVType *propagateSPIRVType(MachineInstr *MI, SPIRVGlobalRegistry *GR, 14981ad6265SDimitry Andric MachineRegisterInfo &MRI, 15081ad6265SDimitry Andric MachineIRBuilder &MIB) { 15181ad6265SDimitry Andric SPIRVType *SpirvTy = nullptr; 15281ad6265SDimitry Andric assert(MI && "Machine instr is expected"); 15381ad6265SDimitry Andric if (MI->getOperand(0).isReg()) { 15481ad6265SDimitry Andric Register Reg = MI->getOperand(0).getReg(); 15581ad6265SDimitry Andric SpirvTy = GR->getSPIRVTypeForVReg(Reg); 15681ad6265SDimitry Andric if (!SpirvTy) { 15781ad6265SDimitry Andric switch (MI->getOpcode()) { 15881ad6265SDimitry Andric case TargetOpcode::G_CONSTANT: { 15981ad6265SDimitry Andric MIB.setInsertPt(*MI->getParent(), MI); 16081ad6265SDimitry Andric Type *Ty = MI->getOperand(1).getCImm()->getType(); 16181ad6265SDimitry Andric SpirvTy = GR->getOrCreateSPIRVType(Ty, MIB); 16281ad6265SDimitry Andric break; 16381ad6265SDimitry Andric } 16481ad6265SDimitry Andric case TargetOpcode::G_GLOBAL_VALUE: { 16581ad6265SDimitry Andric MIB.setInsertPt(*MI->getParent(), MI); 16681ad6265SDimitry Andric Type *Ty = MI->getOperand(1).getGlobal()->getType(); 16781ad6265SDimitry Andric SpirvTy = GR->getOrCreateSPIRVType(Ty, MIB); 16881ad6265SDimitry Andric break; 16981ad6265SDimitry Andric } 17081ad6265SDimitry Andric case TargetOpcode::G_TRUNC: 17181ad6265SDimitry Andric case TargetOpcode::G_ADDRSPACE_CAST: 172fcaf7f86SDimitry Andric case TargetOpcode::G_PTR_ADD: 17381ad6265SDimitry Andric case TargetOpcode::COPY: { 17481ad6265SDimitry Andric MachineOperand &Op = MI->getOperand(1); 17581ad6265SDimitry Andric MachineInstr *Def = Op.isReg() ? MRI.getVRegDef(Op.getReg()) : nullptr; 17681ad6265SDimitry Andric if (Def) 17781ad6265SDimitry Andric SpirvTy = propagateSPIRVType(Def, GR, MRI, MIB); 17881ad6265SDimitry Andric break; 17981ad6265SDimitry Andric } 18081ad6265SDimitry Andric default: 18181ad6265SDimitry Andric break; 18281ad6265SDimitry Andric } 18381ad6265SDimitry Andric if (SpirvTy) 18481ad6265SDimitry Andric GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF()); 18581ad6265SDimitry Andric if (!MRI.getRegClassOrNull(Reg)) 18681ad6265SDimitry Andric MRI.setRegClass(Reg, &SPIRV::IDRegClass); 18781ad6265SDimitry Andric } 18881ad6265SDimitry Andric } 18981ad6265SDimitry Andric return SpirvTy; 19081ad6265SDimitry Andric } 19181ad6265SDimitry Andric 19281ad6265SDimitry Andric // Insert ASSIGN_TYPE instuction between Reg and its definition, set NewReg as 19381ad6265SDimitry Andric // a dst of the definition, assign SPIRVType to both registers. If SpirvTy is 19481ad6265SDimitry Andric // provided, use it as SPIRVType in ASSIGN_TYPE, otherwise create it from Ty. 195bdd1243dSDimitry Andric // It's used also in SPIRVBuiltins.cpp. 19681ad6265SDimitry Andric // TODO: maybe move to SPIRVUtils. 197bdd1243dSDimitry Andric namespace llvm { 198bdd1243dSDimitry Andric Register insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy, 199bdd1243dSDimitry Andric SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, 20081ad6265SDimitry Andric MachineRegisterInfo &MRI) { 20181ad6265SDimitry Andric MachineInstr *Def = MRI.getVRegDef(Reg); 20281ad6265SDimitry Andric assert((Ty || SpirvTy) && "Either LLVM or SPIRV type is expected."); 20381ad6265SDimitry Andric MIB.setInsertPt(*Def->getParent(), 20481ad6265SDimitry Andric (Def->getNextNode() ? Def->getNextNode()->getIterator() 20581ad6265SDimitry Andric : Def->getParent()->end())); 20681ad6265SDimitry Andric Register NewReg = MRI.createGenericVirtualRegister(MRI.getType(Reg)); 207*06c3fb27SDimitry Andric if (auto *RC = MRI.getRegClassOrNull(Reg)) { 20881ad6265SDimitry Andric MRI.setRegClass(NewReg, RC); 209*06c3fb27SDimitry Andric } else { 210*06c3fb27SDimitry Andric MRI.setRegClass(NewReg, &SPIRV::IDRegClass); 211*06c3fb27SDimitry Andric MRI.setRegClass(Reg, &SPIRV::IDRegClass); 212*06c3fb27SDimitry Andric } 21381ad6265SDimitry Andric SpirvTy = SpirvTy ? SpirvTy : GR->getOrCreateSPIRVType(Ty, MIB); 21481ad6265SDimitry Andric GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF()); 21581ad6265SDimitry Andric // This is to make it convenient for Legalizer to get the SPIRVType 21681ad6265SDimitry Andric // when processing the actual MI (i.e. not pseudo one). 21781ad6265SDimitry Andric GR->assignSPIRVTypeToVReg(SpirvTy, NewReg, MIB.getMF()); 218bdd1243dSDimitry Andric // Copy MIFlags from Def to ASSIGN_TYPE instruction. It's required to keep 219bdd1243dSDimitry Andric // the flags after instruction selection. 220*06c3fb27SDimitry Andric const uint32_t Flags = Def->getFlags(); 22181ad6265SDimitry Andric MIB.buildInstr(SPIRV::ASSIGN_TYPE) 22281ad6265SDimitry Andric .addDef(Reg) 22381ad6265SDimitry Andric .addUse(NewReg) 224bdd1243dSDimitry Andric .addUse(GR->getSPIRVTypeID(SpirvTy)) 225bdd1243dSDimitry Andric .setMIFlags(Flags); 22681ad6265SDimitry Andric Def->getOperand(0).setReg(NewReg); 22781ad6265SDimitry Andric return NewReg; 22881ad6265SDimitry Andric } 229bdd1243dSDimitry Andric } // namespace llvm 23081ad6265SDimitry Andric 23181ad6265SDimitry Andric static void generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR, 23281ad6265SDimitry Andric MachineIRBuilder MIB) { 23381ad6265SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 23481ad6265SDimitry Andric SmallVector<MachineInstr *, 10> ToErase; 23581ad6265SDimitry Andric 23681ad6265SDimitry Andric for (MachineBasicBlock *MBB : post_order(&MF)) { 23781ad6265SDimitry Andric if (MBB->empty()) 23881ad6265SDimitry Andric continue; 23981ad6265SDimitry Andric 24081ad6265SDimitry Andric bool ReachedBegin = false; 24181ad6265SDimitry Andric for (auto MII = std::prev(MBB->end()), Begin = MBB->begin(); 24281ad6265SDimitry Andric !ReachedBegin;) { 24381ad6265SDimitry Andric MachineInstr &MI = *MII; 24481ad6265SDimitry Andric 24581ad6265SDimitry Andric if (isSpvIntrinsic(MI, Intrinsic::spv_assign_type)) { 24681ad6265SDimitry Andric Register Reg = MI.getOperand(1).getReg(); 24781ad6265SDimitry Andric Type *Ty = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0); 24881ad6265SDimitry Andric MachineInstr *Def = MRI.getVRegDef(Reg); 24981ad6265SDimitry Andric assert(Def && "Expecting an instruction that defines the register"); 25081ad6265SDimitry Andric // G_GLOBAL_VALUE already has type info. 25181ad6265SDimitry Andric if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE) 25281ad6265SDimitry Andric insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MF.getRegInfo()); 25381ad6265SDimitry Andric ToErase.push_back(&MI); 25481ad6265SDimitry Andric } else if (MI.getOpcode() == TargetOpcode::G_CONSTANT || 25581ad6265SDimitry Andric MI.getOpcode() == TargetOpcode::G_FCONSTANT || 25681ad6265SDimitry Andric MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR) { 25781ad6265SDimitry Andric // %rc = G_CONSTANT ty Val 25881ad6265SDimitry Andric // ===> 25981ad6265SDimitry Andric // %cty = OpType* ty 26081ad6265SDimitry Andric // %rctmp = G_CONSTANT ty Val 26181ad6265SDimitry Andric // %rc = ASSIGN_TYPE %rctmp, %cty 26281ad6265SDimitry Andric Register Reg = MI.getOperand(0).getReg(); 26381ad6265SDimitry Andric if (MRI.hasOneUse(Reg)) { 26481ad6265SDimitry Andric MachineInstr &UseMI = *MRI.use_instr_begin(Reg); 26581ad6265SDimitry Andric if (isSpvIntrinsic(UseMI, Intrinsic::spv_assign_type) || 26681ad6265SDimitry Andric isSpvIntrinsic(UseMI, Intrinsic::spv_assign_name)) 26781ad6265SDimitry Andric continue; 26881ad6265SDimitry Andric } 26981ad6265SDimitry Andric Type *Ty = nullptr; 27081ad6265SDimitry Andric if (MI.getOpcode() == TargetOpcode::G_CONSTANT) 27181ad6265SDimitry Andric Ty = MI.getOperand(1).getCImm()->getType(); 27281ad6265SDimitry Andric else if (MI.getOpcode() == TargetOpcode::G_FCONSTANT) 27381ad6265SDimitry Andric Ty = MI.getOperand(1).getFPImm()->getType(); 27481ad6265SDimitry Andric else { 27581ad6265SDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR); 27681ad6265SDimitry Andric Type *ElemTy = nullptr; 27781ad6265SDimitry Andric MachineInstr *ElemMI = MRI.getVRegDef(MI.getOperand(1).getReg()); 27881ad6265SDimitry Andric assert(ElemMI); 27981ad6265SDimitry Andric 28081ad6265SDimitry Andric if (ElemMI->getOpcode() == TargetOpcode::G_CONSTANT) 28181ad6265SDimitry Andric ElemTy = ElemMI->getOperand(1).getCImm()->getType(); 28281ad6265SDimitry Andric else if (ElemMI->getOpcode() == TargetOpcode::G_FCONSTANT) 28381ad6265SDimitry Andric ElemTy = ElemMI->getOperand(1).getFPImm()->getType(); 28481ad6265SDimitry Andric else 28581ad6265SDimitry Andric llvm_unreachable("Unexpected opcode"); 28681ad6265SDimitry Andric unsigned NumElts = 28781ad6265SDimitry Andric MI.getNumExplicitOperands() - MI.getNumExplicitDefs(); 28881ad6265SDimitry Andric Ty = VectorType::get(ElemTy, NumElts, false); 28981ad6265SDimitry Andric } 29081ad6265SDimitry Andric insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MRI); 29181ad6265SDimitry Andric } else if (MI.getOpcode() == TargetOpcode::G_TRUNC || 29281ad6265SDimitry Andric MI.getOpcode() == TargetOpcode::G_GLOBAL_VALUE || 29381ad6265SDimitry Andric MI.getOpcode() == TargetOpcode::COPY || 29481ad6265SDimitry Andric MI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST) { 29581ad6265SDimitry Andric propagateSPIRVType(&MI, GR, MRI, MIB); 29681ad6265SDimitry Andric } 29781ad6265SDimitry Andric 29881ad6265SDimitry Andric if (MII == Begin) 29981ad6265SDimitry Andric ReachedBegin = true; 30081ad6265SDimitry Andric else 30181ad6265SDimitry Andric --MII; 30281ad6265SDimitry Andric } 30381ad6265SDimitry Andric } 30481ad6265SDimitry Andric for (MachineInstr *MI : ToErase) 30581ad6265SDimitry Andric MI->eraseFromParent(); 30681ad6265SDimitry Andric } 30781ad6265SDimitry Andric 30881ad6265SDimitry Andric static std::pair<Register, unsigned> 30981ad6265SDimitry Andric createNewIdReg(Register ValReg, unsigned Opcode, MachineRegisterInfo &MRI, 31081ad6265SDimitry Andric const SPIRVGlobalRegistry &GR) { 31181ad6265SDimitry Andric LLT NewT = LLT::scalar(32); 31281ad6265SDimitry Andric SPIRVType *SpvType = GR.getSPIRVTypeForVReg(ValReg); 31381ad6265SDimitry Andric assert(SpvType && "VReg is expected to have SPIRV type"); 31481ad6265SDimitry Andric bool IsFloat = SpvType->getOpcode() == SPIRV::OpTypeFloat; 31581ad6265SDimitry Andric bool IsVectorFloat = 31681ad6265SDimitry Andric SpvType->getOpcode() == SPIRV::OpTypeVector && 31781ad6265SDimitry Andric GR.getSPIRVTypeForVReg(SpvType->getOperand(1).getReg())->getOpcode() == 31881ad6265SDimitry Andric SPIRV::OpTypeFloat; 31981ad6265SDimitry Andric IsFloat |= IsVectorFloat; 32081ad6265SDimitry Andric auto GetIdOp = IsFloat ? SPIRV::GET_fID : SPIRV::GET_ID; 32181ad6265SDimitry Andric auto DstClass = IsFloat ? &SPIRV::fIDRegClass : &SPIRV::IDRegClass; 32281ad6265SDimitry Andric if (MRI.getType(ValReg).isPointer()) { 32381ad6265SDimitry Andric NewT = LLT::pointer(0, 32); 32481ad6265SDimitry Andric GetIdOp = SPIRV::GET_pID; 32581ad6265SDimitry Andric DstClass = &SPIRV::pIDRegClass; 32681ad6265SDimitry Andric } else if (MRI.getType(ValReg).isVector()) { 32781ad6265SDimitry Andric NewT = LLT::fixed_vector(2, NewT); 32881ad6265SDimitry Andric GetIdOp = IsFloat ? SPIRV::GET_vfID : SPIRV::GET_vID; 32981ad6265SDimitry Andric DstClass = IsFloat ? &SPIRV::vfIDRegClass : &SPIRV::vIDRegClass; 33081ad6265SDimitry Andric } 33181ad6265SDimitry Andric Register IdReg = MRI.createGenericVirtualRegister(NewT); 33281ad6265SDimitry Andric MRI.setRegClass(IdReg, DstClass); 33381ad6265SDimitry Andric return {IdReg, GetIdOp}; 33481ad6265SDimitry Andric } 33581ad6265SDimitry Andric 33681ad6265SDimitry Andric static void processInstr(MachineInstr &MI, MachineIRBuilder &MIB, 33781ad6265SDimitry Andric MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR) { 33881ad6265SDimitry Andric unsigned Opc = MI.getOpcode(); 33981ad6265SDimitry Andric assert(MI.getNumDefs() > 0 && MRI.hasOneUse(MI.getOperand(0).getReg())); 34081ad6265SDimitry Andric MachineInstr &AssignTypeInst = 34181ad6265SDimitry Andric *(MRI.use_instr_begin(MI.getOperand(0).getReg())); 34281ad6265SDimitry Andric auto NewReg = createNewIdReg(MI.getOperand(0).getReg(), Opc, MRI, *GR).first; 34381ad6265SDimitry Andric AssignTypeInst.getOperand(1).setReg(NewReg); 34481ad6265SDimitry Andric MI.getOperand(0).setReg(NewReg); 34581ad6265SDimitry Andric MIB.setInsertPt(*MI.getParent(), 34681ad6265SDimitry Andric (MI.getNextNode() ? MI.getNextNode()->getIterator() 34781ad6265SDimitry Andric : MI.getParent()->end())); 34881ad6265SDimitry Andric for (auto &Op : MI.operands()) { 34981ad6265SDimitry Andric if (!Op.isReg() || Op.isDef()) 35081ad6265SDimitry Andric continue; 35181ad6265SDimitry Andric auto IdOpInfo = createNewIdReg(Op.getReg(), Opc, MRI, *GR); 35281ad6265SDimitry Andric MIB.buildInstr(IdOpInfo.second).addDef(IdOpInfo.first).addUse(Op.getReg()); 35381ad6265SDimitry Andric Op.setReg(IdOpInfo.first); 35481ad6265SDimitry Andric } 35581ad6265SDimitry Andric } 35681ad6265SDimitry Andric 35781ad6265SDimitry Andric // Defined in SPIRVLegalizerInfo.cpp. 35881ad6265SDimitry Andric extern bool isTypeFoldingSupported(unsigned Opcode); 35981ad6265SDimitry Andric 36081ad6265SDimitry Andric static void processInstrsWithTypeFolding(MachineFunction &MF, 36181ad6265SDimitry Andric SPIRVGlobalRegistry *GR, 36281ad6265SDimitry Andric MachineIRBuilder MIB) { 36381ad6265SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 36481ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) { 36581ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 36681ad6265SDimitry Andric if (isTypeFoldingSupported(MI.getOpcode())) 36781ad6265SDimitry Andric processInstr(MI, MIB, MRI, GR); 36881ad6265SDimitry Andric } 36981ad6265SDimitry Andric } 370fcaf7f86SDimitry Andric for (MachineBasicBlock &MBB : MF) { 371fcaf7f86SDimitry Andric for (MachineInstr &MI : MBB) { 372fcaf7f86SDimitry Andric // We need to rewrite dst types for ASSIGN_TYPE instrs to be able 373fcaf7f86SDimitry Andric // to perform tblgen'erated selection and we can't do that on Legalizer 374fcaf7f86SDimitry Andric // as it operates on gMIR only. 375fcaf7f86SDimitry Andric if (MI.getOpcode() != SPIRV::ASSIGN_TYPE) 376fcaf7f86SDimitry Andric continue; 377fcaf7f86SDimitry Andric Register SrcReg = MI.getOperand(1).getReg(); 378bdd1243dSDimitry Andric unsigned Opcode = MRI.getVRegDef(SrcReg)->getOpcode(); 379bdd1243dSDimitry Andric if (!isTypeFoldingSupported(Opcode)) 380fcaf7f86SDimitry Andric continue; 381fcaf7f86SDimitry Andric Register DstReg = MI.getOperand(0).getReg(); 382fcaf7f86SDimitry Andric if (MRI.getType(DstReg).isVector()) 383fcaf7f86SDimitry Andric MRI.setRegClass(DstReg, &SPIRV::IDRegClass); 384bdd1243dSDimitry Andric // Don't need to reset type of register holding constant and used in 385bdd1243dSDimitry Andric // G_ADDRSPACE_CAST, since it braaks legalizer. 386bdd1243dSDimitry Andric if (Opcode == TargetOpcode::G_CONSTANT && MRI.hasOneUse(DstReg)) { 387bdd1243dSDimitry Andric MachineInstr &UseMI = *MRI.use_instr_begin(DstReg); 388bdd1243dSDimitry Andric if (UseMI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST) 389bdd1243dSDimitry Andric continue; 390bdd1243dSDimitry Andric } 391fcaf7f86SDimitry Andric MRI.setType(DstReg, LLT::scalar(32)); 392fcaf7f86SDimitry Andric } 393fcaf7f86SDimitry Andric } 39481ad6265SDimitry Andric } 39581ad6265SDimitry Andric 39681ad6265SDimitry Andric static void processSwitches(MachineFunction &MF, SPIRVGlobalRegistry *GR, 39781ad6265SDimitry Andric MachineIRBuilder MIB) { 398bdd1243dSDimitry Andric // Before IRTranslator pass, calls to spv_switch intrinsic are inserted before 399bdd1243dSDimitry Andric // each switch instruction. IRTranslator lowers switches to G_ICMP + G_BRCOND 400bdd1243dSDimitry Andric // + G_BR triples. A switch with two cases may be transformed to this MIR 401bdd1243dSDimitry Andric // sequence: 402bdd1243dSDimitry Andric // 40381ad6265SDimitry Andric // intrinsic(@llvm.spv.switch), %CmpReg, %Const0, %Const1 40481ad6265SDimitry Andric // %Dst0 = G_ICMP intpred(eq), %CmpReg, %Const0 40581ad6265SDimitry Andric // G_BRCOND %Dst0, %bb.2 40681ad6265SDimitry Andric // G_BR %bb.5 40781ad6265SDimitry Andric // bb.5.entry: 40881ad6265SDimitry Andric // %Dst1 = G_ICMP intpred(eq), %CmpReg, %Const1 40981ad6265SDimitry Andric // G_BRCOND %Dst1, %bb.3 41081ad6265SDimitry Andric // G_BR %bb.4 41181ad6265SDimitry Andric // bb.2.sw.bb: 41281ad6265SDimitry Andric // ... 41381ad6265SDimitry Andric // bb.3.sw.bb1: 41481ad6265SDimitry Andric // ... 41581ad6265SDimitry Andric // bb.4.sw.epilog: 41681ad6265SDimitry Andric // ... 417bdd1243dSDimitry Andric // 418bdd1243dSDimitry Andric // Sometimes (in case of range-compare switches), additional G_SUBs 419bdd1243dSDimitry Andric // instructions are inserted before G_ICMPs. Those need to be additionally 420*06c3fb27SDimitry Andric // processed. 421bdd1243dSDimitry Andric // 422bdd1243dSDimitry Andric // This function modifies spv_switch call's operands to include destination 423bdd1243dSDimitry Andric // MBBs (default and for each constant value). 424*06c3fb27SDimitry Andric // 425*06c3fb27SDimitry Andric // At the end, the function removes redundant [G_SUB] + G_ICMP + G_BRCOND + 426*06c3fb27SDimitry Andric // G_BR sequences. 427bdd1243dSDimitry Andric 428bdd1243dSDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 429bdd1243dSDimitry Andric 430*06c3fb27SDimitry Andric // Collect spv_switches and G_ICMPs across all MBBs in MF. 431bdd1243dSDimitry Andric std::vector<MachineInstr *> RelevantInsts; 432bdd1243dSDimitry Andric 433*06c3fb27SDimitry Andric // Collect redundant MIs from [G_SUB] + G_ICMP + G_BRCOND + G_BR sequences. 434*06c3fb27SDimitry Andric // After updating spv_switches, the instructions can be removed. 435*06c3fb27SDimitry Andric std::vector<MachineInstr *> PostUpdateArtifacts; 436*06c3fb27SDimitry Andric 437bdd1243dSDimitry Andric // Temporary set of compare registers. G_SUBs and G_ICMPs relating to 438bdd1243dSDimitry Andric // spv_switch use these registers. 439bdd1243dSDimitry Andric DenseSet<Register> CompareRegs; 44081ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) { 44181ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 442bdd1243dSDimitry Andric // Calls to spv_switch intrinsics representing IR switches. 44381ad6265SDimitry Andric if (isSpvIntrinsic(MI, Intrinsic::spv_switch)) { 44481ad6265SDimitry Andric assert(MI.getOperand(1).isReg()); 445bdd1243dSDimitry Andric CompareRegs.insert(MI.getOperand(1).getReg()); 446bdd1243dSDimitry Andric RelevantInsts.push_back(&MI); 44781ad6265SDimitry Andric } 448bdd1243dSDimitry Andric 449bdd1243dSDimitry Andric // G_SUBs coming from range-compare switch lowering. G_SUBs are found 450bdd1243dSDimitry Andric // after spv_switch but before G_ICMP. 451bdd1243dSDimitry Andric if (MI.getOpcode() == TargetOpcode::G_SUB && MI.getOperand(1).isReg() && 452bdd1243dSDimitry Andric CompareRegs.contains(MI.getOperand(1).getReg())) { 453bdd1243dSDimitry Andric assert(MI.getOperand(0).isReg() && MI.getOperand(1).isReg()); 454bdd1243dSDimitry Andric Register Dst = MI.getOperand(0).getReg(); 455bdd1243dSDimitry Andric CompareRegs.insert(Dst); 456*06c3fb27SDimitry Andric PostUpdateArtifacts.push_back(&MI); 457bdd1243dSDimitry Andric } 458bdd1243dSDimitry Andric 459bdd1243dSDimitry Andric // G_ICMPs relating to switches. 46081ad6265SDimitry Andric if (MI.getOpcode() == TargetOpcode::G_ICMP && MI.getOperand(2).isReg() && 461bdd1243dSDimitry Andric CompareRegs.contains(MI.getOperand(2).getReg())) { 46281ad6265SDimitry Andric Register Dst = MI.getOperand(0).getReg(); 463bdd1243dSDimitry Andric RelevantInsts.push_back(&MI); 464*06c3fb27SDimitry Andric PostUpdateArtifacts.push_back(&MI); 465*06c3fb27SDimitry Andric MachineInstr *CBr = MRI.use_begin(Dst)->getParent(); 466*06c3fb27SDimitry Andric assert(CBr->getOpcode() == SPIRV::G_BRCOND); 467*06c3fb27SDimitry Andric PostUpdateArtifacts.push_back(CBr); 468*06c3fb27SDimitry Andric MachineInstr *Br = CBr->getNextNode(); 469*06c3fb27SDimitry Andric assert(Br->getOpcode() == SPIRV::G_BR); 470*06c3fb27SDimitry Andric PostUpdateArtifacts.push_back(Br); 471bdd1243dSDimitry Andric } 472bdd1243dSDimitry Andric } 473bdd1243dSDimitry Andric } 474bdd1243dSDimitry Andric 475bdd1243dSDimitry Andric // Update each spv_switch with destination MBBs. 476bdd1243dSDimitry Andric for (auto i = RelevantInsts.begin(); i != RelevantInsts.end(); i++) { 477bdd1243dSDimitry Andric if (!isSpvIntrinsic(**i, Intrinsic::spv_switch)) 478bdd1243dSDimitry Andric continue; 479bdd1243dSDimitry Andric 480bdd1243dSDimitry Andric // Currently considered spv_switch. 481bdd1243dSDimitry Andric MachineInstr *Switch = *i; 482bdd1243dSDimitry Andric // Set the first successor as default MBB to support empty switches. 483bdd1243dSDimitry Andric MachineBasicBlock *DefaultMBB = *Switch->getParent()->succ_begin(); 484bdd1243dSDimitry Andric // Container for mapping values to MMBs. 485bdd1243dSDimitry Andric SmallDenseMap<uint64_t, MachineBasicBlock *> ValuesToMBBs; 486bdd1243dSDimitry Andric 487bdd1243dSDimitry Andric // Walk all G_ICMPs to collect ValuesToMBBs. Start at currently considered 488bdd1243dSDimitry Andric // spv_switch (i) and break at any spv_switch with the same compare 489bdd1243dSDimitry Andric // register (indicating we are back at the same scope). 490bdd1243dSDimitry Andric Register CompareReg = Switch->getOperand(1).getReg(); 491bdd1243dSDimitry Andric for (auto j = i + 1; j != RelevantInsts.end(); j++) { 492bdd1243dSDimitry Andric if (isSpvIntrinsic(**j, Intrinsic::spv_switch) && 493bdd1243dSDimitry Andric (*j)->getOperand(1).getReg() == CompareReg) 494bdd1243dSDimitry Andric break; 495bdd1243dSDimitry Andric 496bdd1243dSDimitry Andric if (!((*j)->getOpcode() == TargetOpcode::G_ICMP && 497bdd1243dSDimitry Andric (*j)->getOperand(2).getReg() == CompareReg)) 498bdd1243dSDimitry Andric continue; 499bdd1243dSDimitry Andric 500bdd1243dSDimitry Andric MachineInstr *ICMP = *j; 501bdd1243dSDimitry Andric Register Dst = ICMP->getOperand(0).getReg(); 502bdd1243dSDimitry Andric MachineOperand &PredOp = ICMP->getOperand(1); 50381ad6265SDimitry Andric const auto CC = static_cast<CmpInst::Predicate>(PredOp.getPredicate()); 504bdd1243dSDimitry Andric assert((CC == CmpInst::ICMP_EQ || CC == CmpInst::ICMP_ULE) && 505bdd1243dSDimitry Andric MRI.hasOneUse(Dst) && MRI.hasOneDef(CompareReg)); 506bdd1243dSDimitry Andric uint64_t Value = getIConstVal(ICMP->getOperand(3).getReg(), &MRI); 50781ad6265SDimitry Andric MachineInstr *CBr = MRI.use_begin(Dst)->getParent(); 508bdd1243dSDimitry Andric assert(CBr->getOpcode() == SPIRV::G_BRCOND && CBr->getOperand(1).isMBB()); 509bdd1243dSDimitry Andric MachineBasicBlock *MBB = CBr->getOperand(1).getMBB(); 510bdd1243dSDimitry Andric 511bdd1243dSDimitry Andric // Map switch case Value to target MBB. 512bdd1243dSDimitry Andric ValuesToMBBs[Value] = MBB; 513bdd1243dSDimitry Andric 514*06c3fb27SDimitry Andric // Add target MBB as successor to the switch's MBB. 515*06c3fb27SDimitry Andric Switch->getParent()->addSuccessor(MBB); 516*06c3fb27SDimitry Andric 517bdd1243dSDimitry Andric // The next MI is always G_BR to either the next case or the default. 51881ad6265SDimitry Andric MachineInstr *NextMI = CBr->getNextNode(); 51981ad6265SDimitry Andric assert(NextMI->getOpcode() == SPIRV::G_BR && 52081ad6265SDimitry Andric NextMI->getOperand(0).isMBB()); 52181ad6265SDimitry Andric MachineBasicBlock *NextMBB = NextMI->getOperand(0).getMBB(); 522bdd1243dSDimitry Andric // Default MBB does not begin with G_ICMP using spv_switch compare 523bdd1243dSDimitry Andric // register. 52481ad6265SDimitry Andric if (NextMBB->front().getOpcode() != SPIRV::G_ICMP || 52581ad6265SDimitry Andric (NextMBB->front().getOperand(2).isReg() && 526*06c3fb27SDimitry Andric NextMBB->front().getOperand(2).getReg() != CompareReg)) { 527*06c3fb27SDimitry Andric // Set default MBB and add it as successor to the switch's MBB. 528bdd1243dSDimitry Andric DefaultMBB = NextMBB; 529*06c3fb27SDimitry Andric Switch->getParent()->addSuccessor(DefaultMBB); 530*06c3fb27SDimitry Andric } 53181ad6265SDimitry Andric } 532bdd1243dSDimitry Andric 533bdd1243dSDimitry Andric // Modify considered spv_switch operands using collected Values and 534bdd1243dSDimitry Andric // MBBs. 535bdd1243dSDimitry Andric SmallVector<const ConstantInt *, 3> Values; 53681ad6265SDimitry Andric SmallVector<MachineBasicBlock *, 3> MBBs; 537bdd1243dSDimitry Andric for (unsigned k = 2; k < Switch->getNumExplicitOperands(); k++) { 538bdd1243dSDimitry Andric Register CReg = Switch->getOperand(k).getReg(); 53981ad6265SDimitry Andric uint64_t Val = getIConstVal(CReg, &MRI); 54081ad6265SDimitry Andric MachineInstr *ConstInstr = getDefInstrMaybeConstant(CReg, &MRI); 541bdd1243dSDimitry Andric if (!ValuesToMBBs[Val]) 542bdd1243dSDimitry Andric continue; 543bdd1243dSDimitry Andric 544bdd1243dSDimitry Andric Values.push_back(ConstInstr->getOperand(1).getCImm()); 545bdd1243dSDimitry Andric MBBs.push_back(ValuesToMBBs[Val]); 54681ad6265SDimitry Andric } 547bdd1243dSDimitry Andric 548bdd1243dSDimitry Andric for (unsigned k = Switch->getNumExplicitOperands() - 1; k > 1; k--) 549bdd1243dSDimitry Andric Switch->removeOperand(k); 550bdd1243dSDimitry Andric 551bdd1243dSDimitry Andric Switch->addOperand(MachineOperand::CreateMBB(DefaultMBB)); 552bdd1243dSDimitry Andric for (unsigned k = 0; k < Values.size(); k++) { 553bdd1243dSDimitry Andric Switch->addOperand(MachineOperand::CreateCImm(Values[k])); 554bdd1243dSDimitry Andric Switch->addOperand(MachineOperand::CreateMBB(MBBs[k])); 55581ad6265SDimitry Andric } 55681ad6265SDimitry Andric } 557*06c3fb27SDimitry Andric 558*06c3fb27SDimitry Andric for (MachineInstr *MI : PostUpdateArtifacts) { 559*06c3fb27SDimitry Andric MachineBasicBlock *ParentMBB = MI->getParent(); 560*06c3fb27SDimitry Andric MI->eraseFromParent(); 561*06c3fb27SDimitry Andric // If G_ICMP + G_BRCOND + G_BR were the only MIs in MBB, erase this MBB. It 562*06c3fb27SDimitry Andric // can be safely assumed, there are no breaks or phis directing into this 563*06c3fb27SDimitry Andric // MBB. However, we need to remove this MBB from the CFG graph. MBBs must be 564*06c3fb27SDimitry Andric // erased top-down. 565*06c3fb27SDimitry Andric if (ParentMBB->empty()) { 566*06c3fb27SDimitry Andric while (!ParentMBB->pred_empty()) 567*06c3fb27SDimitry Andric (*ParentMBB->pred_begin())->removeSuccessor(ParentMBB); 568*06c3fb27SDimitry Andric 569*06c3fb27SDimitry Andric while (!ParentMBB->succ_empty()) 570*06c3fb27SDimitry Andric ParentMBB->removeSuccessor(ParentMBB->succ_begin()); 571*06c3fb27SDimitry Andric 572*06c3fb27SDimitry Andric ParentMBB->eraseFromParent(); 573*06c3fb27SDimitry Andric } 574*06c3fb27SDimitry Andric } 57581ad6265SDimitry Andric } 57681ad6265SDimitry Andric 57781ad6265SDimitry Andric bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) { 57881ad6265SDimitry Andric // Initialize the type registry. 57981ad6265SDimitry Andric const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>(); 58081ad6265SDimitry Andric SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry(); 58181ad6265SDimitry Andric GR->setCurrentFunc(MF); 58281ad6265SDimitry Andric MachineIRBuilder MIB(MF); 583fcaf7f86SDimitry Andric addConstantsToTrack(MF, GR); 58481ad6265SDimitry Andric foldConstantsIntoIntrinsics(MF); 58581ad6265SDimitry Andric insertBitcasts(MF, GR, MIB); 58681ad6265SDimitry Andric generateAssignInstrs(MF, GR, MIB); 58781ad6265SDimitry Andric processSwitches(MF, GR, MIB); 588bdd1243dSDimitry Andric processInstrsWithTypeFolding(MF, GR, MIB); 58981ad6265SDimitry Andric 59081ad6265SDimitry Andric return true; 59181ad6265SDimitry Andric } 59281ad6265SDimitry Andric 59381ad6265SDimitry Andric INITIALIZE_PASS(SPIRVPreLegalizer, DEBUG_TYPE, "SPIRV pre legalizer", false, 59481ad6265SDimitry Andric false) 59581ad6265SDimitry Andric 59681ad6265SDimitry Andric char SPIRVPreLegalizer::ID = 0; 59781ad6265SDimitry Andric 59881ad6265SDimitry Andric FunctionPass *llvm::createSPIRVPreLegalizerPass() { 59981ad6265SDimitry Andric return new SPIRVPreLegalizer(); 60081ad6265SDimitry Andric } 601