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(); 86cb14a3feSDimitry Andric if (RegsAlreadyAddedToDT.contains(MI)) 87fcaf7f86SDimitry Andric Reg = RegsAlreadyAddedToDT[MI]; 8806c3fb27SDimitry Andric auto *RC = MRI.getRegClassOrNull(MI->getOperand(0).getReg()); 8906c3fb27SDimitry Andric if (!MRI.getRegClassOrNull(Reg) && RC) 9006c3fb27SDimitry 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) { 128*1db9f3b2SDimitry Andric if (!isSpvIntrinsic(MI, Intrinsic::spv_bitcast) && 129*1db9f3b2SDimitry Andric !isSpvIntrinsic(MI, Intrinsic::spv_ptrcast)) 13081ad6265SDimitry Andric continue; 13181ad6265SDimitry Andric assert(MI.getOperand(2).isReg()); 13281ad6265SDimitry Andric MIB.setInsertPt(*MI.getParent(), MI); 13381ad6265SDimitry Andric ToErase.push_back(&MI); 134*1db9f3b2SDimitry Andric if (isSpvIntrinsic(MI, Intrinsic::spv_bitcast)) { 135*1db9f3b2SDimitry Andric MIB.buildBitcast(MI.getOperand(0).getReg(), MI.getOperand(2).getReg()); 136*1db9f3b2SDimitry Andric continue; 137*1db9f3b2SDimitry Andric } 138*1db9f3b2SDimitry Andric Register Def = MI.getOperand(0).getReg(); 139*1db9f3b2SDimitry Andric Register Source = MI.getOperand(2).getReg(); 140*1db9f3b2SDimitry Andric SPIRVType *BaseTy = GR->getOrCreateSPIRVType( 141*1db9f3b2SDimitry Andric getMDOperandAsType(MI.getOperand(3).getMetadata(), 0), MIB); 142*1db9f3b2SDimitry Andric SPIRVType *AssignedPtrType = GR->getOrCreateSPIRVPointerType( 143*1db9f3b2SDimitry Andric BaseTy, MI, *MF.getSubtarget<SPIRVSubtarget>().getInstrInfo(), 144*1db9f3b2SDimitry Andric addressSpaceToStorageClass(MI.getOperand(4).getImm())); 145*1db9f3b2SDimitry Andric 146*1db9f3b2SDimitry Andric // If the bitcast would be redundant, replace all uses with the source 147*1db9f3b2SDimitry Andric // register. 148*1db9f3b2SDimitry Andric if (GR->getSPIRVTypeForVReg(Source) == AssignedPtrType) { 149*1db9f3b2SDimitry Andric MIB.getMRI()->replaceRegWith(Def, Source); 150*1db9f3b2SDimitry Andric } else { 151*1db9f3b2SDimitry Andric GR->assignSPIRVTypeToVReg(AssignedPtrType, Def, MF); 152*1db9f3b2SDimitry Andric MIB.buildBitcast(Def, Source); 153*1db9f3b2SDimitry Andric } 15481ad6265SDimitry Andric } 15581ad6265SDimitry Andric } 15681ad6265SDimitry Andric for (MachineInstr *MI : ToErase) 15781ad6265SDimitry Andric MI->eraseFromParent(); 15881ad6265SDimitry Andric } 15981ad6265SDimitry Andric 16081ad6265SDimitry Andric // Translating GV, IRTranslator sometimes generates following IR: 16181ad6265SDimitry Andric // %1 = G_GLOBAL_VALUE 16281ad6265SDimitry Andric // %2 = COPY %1 16381ad6265SDimitry Andric // %3 = G_ADDRSPACE_CAST %2 16481ad6265SDimitry Andric // New registers have no SPIRVType and no register class info. 16581ad6265SDimitry Andric // 16681ad6265SDimitry Andric // Set SPIRVType for GV, propagate it from GV to other instructions, 16781ad6265SDimitry Andric // also set register classes. 16881ad6265SDimitry Andric static SPIRVType *propagateSPIRVType(MachineInstr *MI, SPIRVGlobalRegistry *GR, 16981ad6265SDimitry Andric MachineRegisterInfo &MRI, 17081ad6265SDimitry Andric MachineIRBuilder &MIB) { 17181ad6265SDimitry Andric SPIRVType *SpirvTy = nullptr; 17281ad6265SDimitry Andric assert(MI && "Machine instr is expected"); 17381ad6265SDimitry Andric if (MI->getOperand(0).isReg()) { 17481ad6265SDimitry Andric Register Reg = MI->getOperand(0).getReg(); 17581ad6265SDimitry Andric SpirvTy = GR->getSPIRVTypeForVReg(Reg); 17681ad6265SDimitry Andric if (!SpirvTy) { 17781ad6265SDimitry Andric switch (MI->getOpcode()) { 17881ad6265SDimitry Andric case TargetOpcode::G_CONSTANT: { 17981ad6265SDimitry Andric MIB.setInsertPt(*MI->getParent(), MI); 18081ad6265SDimitry Andric Type *Ty = MI->getOperand(1).getCImm()->getType(); 18181ad6265SDimitry Andric SpirvTy = GR->getOrCreateSPIRVType(Ty, MIB); 18281ad6265SDimitry Andric break; 18381ad6265SDimitry Andric } 18481ad6265SDimitry Andric case TargetOpcode::G_GLOBAL_VALUE: { 18581ad6265SDimitry Andric MIB.setInsertPt(*MI->getParent(), MI); 18681ad6265SDimitry Andric Type *Ty = MI->getOperand(1).getGlobal()->getType(); 18781ad6265SDimitry Andric SpirvTy = GR->getOrCreateSPIRVType(Ty, MIB); 18881ad6265SDimitry Andric break; 18981ad6265SDimitry Andric } 19081ad6265SDimitry Andric case TargetOpcode::G_TRUNC: 19181ad6265SDimitry Andric case TargetOpcode::G_ADDRSPACE_CAST: 192fcaf7f86SDimitry Andric case TargetOpcode::G_PTR_ADD: 19381ad6265SDimitry Andric case TargetOpcode::COPY: { 19481ad6265SDimitry Andric MachineOperand &Op = MI->getOperand(1); 19581ad6265SDimitry Andric MachineInstr *Def = Op.isReg() ? MRI.getVRegDef(Op.getReg()) : nullptr; 19681ad6265SDimitry Andric if (Def) 19781ad6265SDimitry Andric SpirvTy = propagateSPIRVType(Def, GR, MRI, MIB); 19881ad6265SDimitry Andric break; 19981ad6265SDimitry Andric } 20081ad6265SDimitry Andric default: 20181ad6265SDimitry Andric break; 20281ad6265SDimitry Andric } 20381ad6265SDimitry Andric if (SpirvTy) 20481ad6265SDimitry Andric GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF()); 20581ad6265SDimitry Andric if (!MRI.getRegClassOrNull(Reg)) 20681ad6265SDimitry Andric MRI.setRegClass(Reg, &SPIRV::IDRegClass); 20781ad6265SDimitry Andric } 20881ad6265SDimitry Andric } 20981ad6265SDimitry Andric return SpirvTy; 21081ad6265SDimitry Andric } 21181ad6265SDimitry Andric 21281ad6265SDimitry Andric // Insert ASSIGN_TYPE instuction between Reg and its definition, set NewReg as 21381ad6265SDimitry Andric // a dst of the definition, assign SPIRVType to both registers. If SpirvTy is 21481ad6265SDimitry Andric // provided, use it as SPIRVType in ASSIGN_TYPE, otherwise create it from Ty. 215bdd1243dSDimitry Andric // It's used also in SPIRVBuiltins.cpp. 21681ad6265SDimitry Andric // TODO: maybe move to SPIRVUtils. 217bdd1243dSDimitry Andric namespace llvm { 218bdd1243dSDimitry Andric Register insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy, 219bdd1243dSDimitry Andric SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, 22081ad6265SDimitry Andric MachineRegisterInfo &MRI) { 22181ad6265SDimitry Andric MachineInstr *Def = MRI.getVRegDef(Reg); 22281ad6265SDimitry Andric assert((Ty || SpirvTy) && "Either LLVM or SPIRV type is expected."); 22381ad6265SDimitry Andric MIB.setInsertPt(*Def->getParent(), 22481ad6265SDimitry Andric (Def->getNextNode() ? Def->getNextNode()->getIterator() 22581ad6265SDimitry Andric : Def->getParent()->end())); 22681ad6265SDimitry Andric Register NewReg = MRI.createGenericVirtualRegister(MRI.getType(Reg)); 22706c3fb27SDimitry Andric if (auto *RC = MRI.getRegClassOrNull(Reg)) { 22881ad6265SDimitry Andric MRI.setRegClass(NewReg, RC); 22906c3fb27SDimitry Andric } else { 23006c3fb27SDimitry Andric MRI.setRegClass(NewReg, &SPIRV::IDRegClass); 23106c3fb27SDimitry Andric MRI.setRegClass(Reg, &SPIRV::IDRegClass); 23206c3fb27SDimitry Andric } 23381ad6265SDimitry Andric SpirvTy = SpirvTy ? SpirvTy : GR->getOrCreateSPIRVType(Ty, MIB); 23481ad6265SDimitry Andric GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF()); 23581ad6265SDimitry Andric // This is to make it convenient for Legalizer to get the SPIRVType 23681ad6265SDimitry Andric // when processing the actual MI (i.e. not pseudo one). 23781ad6265SDimitry Andric GR->assignSPIRVTypeToVReg(SpirvTy, NewReg, MIB.getMF()); 238bdd1243dSDimitry Andric // Copy MIFlags from Def to ASSIGN_TYPE instruction. It's required to keep 239bdd1243dSDimitry Andric // the flags after instruction selection. 24006c3fb27SDimitry Andric const uint32_t Flags = Def->getFlags(); 24181ad6265SDimitry Andric MIB.buildInstr(SPIRV::ASSIGN_TYPE) 24281ad6265SDimitry Andric .addDef(Reg) 24381ad6265SDimitry Andric .addUse(NewReg) 244bdd1243dSDimitry Andric .addUse(GR->getSPIRVTypeID(SpirvTy)) 245bdd1243dSDimitry Andric .setMIFlags(Flags); 24681ad6265SDimitry Andric Def->getOperand(0).setReg(NewReg); 24781ad6265SDimitry Andric return NewReg; 24881ad6265SDimitry Andric } 249bdd1243dSDimitry Andric } // namespace llvm 25081ad6265SDimitry Andric 25181ad6265SDimitry Andric static void generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR, 25281ad6265SDimitry Andric MachineIRBuilder MIB) { 25381ad6265SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 25481ad6265SDimitry Andric SmallVector<MachineInstr *, 10> ToErase; 25581ad6265SDimitry Andric 25681ad6265SDimitry Andric for (MachineBasicBlock *MBB : post_order(&MF)) { 25781ad6265SDimitry Andric if (MBB->empty()) 25881ad6265SDimitry Andric continue; 25981ad6265SDimitry Andric 26081ad6265SDimitry Andric bool ReachedBegin = false; 26181ad6265SDimitry Andric for (auto MII = std::prev(MBB->end()), Begin = MBB->begin(); 26281ad6265SDimitry Andric !ReachedBegin;) { 26381ad6265SDimitry Andric MachineInstr &MI = *MII; 26481ad6265SDimitry Andric 2655f757f3fSDimitry Andric if (isSpvIntrinsic(MI, Intrinsic::spv_assign_ptr_type)) { 2665f757f3fSDimitry Andric Register Reg = MI.getOperand(1).getReg(); 2675f757f3fSDimitry Andric MIB.setInsertPt(*MI.getParent(), MI.getIterator()); 2685f757f3fSDimitry Andric SPIRVType *BaseTy = GR->getOrCreateSPIRVType( 2695f757f3fSDimitry Andric getMDOperandAsType(MI.getOperand(2).getMetadata(), 0), MIB); 2705f757f3fSDimitry Andric SPIRVType *AssignedPtrType = GR->getOrCreateSPIRVPointerType( 2715f757f3fSDimitry Andric BaseTy, MI, *MF.getSubtarget<SPIRVSubtarget>().getInstrInfo(), 2725f757f3fSDimitry Andric addressSpaceToStorageClass(MI.getOperand(3).getImm())); 2735f757f3fSDimitry Andric MachineInstr *Def = MRI.getVRegDef(Reg); 2745f757f3fSDimitry Andric assert(Def && "Expecting an instruction that defines the register"); 2755f757f3fSDimitry Andric insertAssignInstr(Reg, nullptr, AssignedPtrType, GR, MIB, 2765f757f3fSDimitry Andric MF.getRegInfo()); 2775f757f3fSDimitry Andric ToErase.push_back(&MI); 2785f757f3fSDimitry Andric } else if (isSpvIntrinsic(MI, Intrinsic::spv_assign_type)) { 27981ad6265SDimitry Andric Register Reg = MI.getOperand(1).getReg(); 28081ad6265SDimitry Andric Type *Ty = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0); 28181ad6265SDimitry Andric MachineInstr *Def = MRI.getVRegDef(Reg); 28281ad6265SDimitry Andric assert(Def && "Expecting an instruction that defines the register"); 28381ad6265SDimitry Andric // G_GLOBAL_VALUE already has type info. 28481ad6265SDimitry Andric if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE) 28581ad6265SDimitry Andric insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MF.getRegInfo()); 28681ad6265SDimitry Andric ToErase.push_back(&MI); 28781ad6265SDimitry Andric } else if (MI.getOpcode() == TargetOpcode::G_CONSTANT || 28881ad6265SDimitry Andric MI.getOpcode() == TargetOpcode::G_FCONSTANT || 28981ad6265SDimitry Andric MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR) { 29081ad6265SDimitry Andric // %rc = G_CONSTANT ty Val 29181ad6265SDimitry Andric // ===> 29281ad6265SDimitry Andric // %cty = OpType* ty 29381ad6265SDimitry Andric // %rctmp = G_CONSTANT ty Val 29481ad6265SDimitry Andric // %rc = ASSIGN_TYPE %rctmp, %cty 29581ad6265SDimitry Andric Register Reg = MI.getOperand(0).getReg(); 29681ad6265SDimitry Andric if (MRI.hasOneUse(Reg)) { 29781ad6265SDimitry Andric MachineInstr &UseMI = *MRI.use_instr_begin(Reg); 29881ad6265SDimitry Andric if (isSpvIntrinsic(UseMI, Intrinsic::spv_assign_type) || 29981ad6265SDimitry Andric isSpvIntrinsic(UseMI, Intrinsic::spv_assign_name)) 30081ad6265SDimitry Andric continue; 30181ad6265SDimitry Andric } 30281ad6265SDimitry Andric Type *Ty = nullptr; 30381ad6265SDimitry Andric if (MI.getOpcode() == TargetOpcode::G_CONSTANT) 30481ad6265SDimitry Andric Ty = MI.getOperand(1).getCImm()->getType(); 30581ad6265SDimitry Andric else if (MI.getOpcode() == TargetOpcode::G_FCONSTANT) 30681ad6265SDimitry Andric Ty = MI.getOperand(1).getFPImm()->getType(); 30781ad6265SDimitry Andric else { 30881ad6265SDimitry Andric assert(MI.getOpcode() == TargetOpcode::G_BUILD_VECTOR); 30981ad6265SDimitry Andric Type *ElemTy = nullptr; 31081ad6265SDimitry Andric MachineInstr *ElemMI = MRI.getVRegDef(MI.getOperand(1).getReg()); 31181ad6265SDimitry Andric assert(ElemMI); 31281ad6265SDimitry Andric 31381ad6265SDimitry Andric if (ElemMI->getOpcode() == TargetOpcode::G_CONSTANT) 31481ad6265SDimitry Andric ElemTy = ElemMI->getOperand(1).getCImm()->getType(); 31581ad6265SDimitry Andric else if (ElemMI->getOpcode() == TargetOpcode::G_FCONSTANT) 31681ad6265SDimitry Andric ElemTy = ElemMI->getOperand(1).getFPImm()->getType(); 31781ad6265SDimitry Andric else 31881ad6265SDimitry Andric llvm_unreachable("Unexpected opcode"); 31981ad6265SDimitry Andric unsigned NumElts = 32081ad6265SDimitry Andric MI.getNumExplicitOperands() - MI.getNumExplicitDefs(); 32181ad6265SDimitry Andric Ty = VectorType::get(ElemTy, NumElts, false); 32281ad6265SDimitry Andric } 32381ad6265SDimitry Andric insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MRI); 32481ad6265SDimitry Andric } else if (MI.getOpcode() == TargetOpcode::G_TRUNC || 32581ad6265SDimitry Andric MI.getOpcode() == TargetOpcode::G_GLOBAL_VALUE || 32681ad6265SDimitry Andric MI.getOpcode() == TargetOpcode::COPY || 32781ad6265SDimitry Andric MI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST) { 32881ad6265SDimitry Andric propagateSPIRVType(&MI, GR, MRI, MIB); 32981ad6265SDimitry Andric } 33081ad6265SDimitry Andric 33181ad6265SDimitry Andric if (MII == Begin) 33281ad6265SDimitry Andric ReachedBegin = true; 33381ad6265SDimitry Andric else 33481ad6265SDimitry Andric --MII; 33581ad6265SDimitry Andric } 33681ad6265SDimitry Andric } 33781ad6265SDimitry Andric for (MachineInstr *MI : ToErase) 33881ad6265SDimitry Andric MI->eraseFromParent(); 33981ad6265SDimitry Andric } 34081ad6265SDimitry Andric 34181ad6265SDimitry Andric static std::pair<Register, unsigned> 34281ad6265SDimitry Andric createNewIdReg(Register ValReg, unsigned Opcode, MachineRegisterInfo &MRI, 34381ad6265SDimitry Andric const SPIRVGlobalRegistry &GR) { 34481ad6265SDimitry Andric LLT NewT = LLT::scalar(32); 34581ad6265SDimitry Andric SPIRVType *SpvType = GR.getSPIRVTypeForVReg(ValReg); 34681ad6265SDimitry Andric assert(SpvType && "VReg is expected to have SPIRV type"); 34781ad6265SDimitry Andric bool IsFloat = SpvType->getOpcode() == SPIRV::OpTypeFloat; 34881ad6265SDimitry Andric bool IsVectorFloat = 34981ad6265SDimitry Andric SpvType->getOpcode() == SPIRV::OpTypeVector && 35081ad6265SDimitry Andric GR.getSPIRVTypeForVReg(SpvType->getOperand(1).getReg())->getOpcode() == 35181ad6265SDimitry Andric SPIRV::OpTypeFloat; 35281ad6265SDimitry Andric IsFloat |= IsVectorFloat; 35381ad6265SDimitry Andric auto GetIdOp = IsFloat ? SPIRV::GET_fID : SPIRV::GET_ID; 35481ad6265SDimitry Andric auto DstClass = IsFloat ? &SPIRV::fIDRegClass : &SPIRV::IDRegClass; 35581ad6265SDimitry Andric if (MRI.getType(ValReg).isPointer()) { 35681ad6265SDimitry Andric NewT = LLT::pointer(0, 32); 35781ad6265SDimitry Andric GetIdOp = SPIRV::GET_pID; 35881ad6265SDimitry Andric DstClass = &SPIRV::pIDRegClass; 35981ad6265SDimitry Andric } else if (MRI.getType(ValReg).isVector()) { 36081ad6265SDimitry Andric NewT = LLT::fixed_vector(2, NewT); 36181ad6265SDimitry Andric GetIdOp = IsFloat ? SPIRV::GET_vfID : SPIRV::GET_vID; 36281ad6265SDimitry Andric DstClass = IsFloat ? &SPIRV::vfIDRegClass : &SPIRV::vIDRegClass; 36381ad6265SDimitry Andric } 36481ad6265SDimitry Andric Register IdReg = MRI.createGenericVirtualRegister(NewT); 36581ad6265SDimitry Andric MRI.setRegClass(IdReg, DstClass); 36681ad6265SDimitry Andric return {IdReg, GetIdOp}; 36781ad6265SDimitry Andric } 36881ad6265SDimitry Andric 36981ad6265SDimitry Andric static void processInstr(MachineInstr &MI, MachineIRBuilder &MIB, 37081ad6265SDimitry Andric MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR) { 37181ad6265SDimitry Andric unsigned Opc = MI.getOpcode(); 37281ad6265SDimitry Andric assert(MI.getNumDefs() > 0 && MRI.hasOneUse(MI.getOperand(0).getReg())); 37381ad6265SDimitry Andric MachineInstr &AssignTypeInst = 37481ad6265SDimitry Andric *(MRI.use_instr_begin(MI.getOperand(0).getReg())); 37581ad6265SDimitry Andric auto NewReg = createNewIdReg(MI.getOperand(0).getReg(), Opc, MRI, *GR).first; 37681ad6265SDimitry Andric AssignTypeInst.getOperand(1).setReg(NewReg); 37781ad6265SDimitry Andric MI.getOperand(0).setReg(NewReg); 37881ad6265SDimitry Andric MIB.setInsertPt(*MI.getParent(), 37981ad6265SDimitry Andric (MI.getNextNode() ? MI.getNextNode()->getIterator() 38081ad6265SDimitry Andric : MI.getParent()->end())); 38181ad6265SDimitry Andric for (auto &Op : MI.operands()) { 38281ad6265SDimitry Andric if (!Op.isReg() || Op.isDef()) 38381ad6265SDimitry Andric continue; 38481ad6265SDimitry Andric auto IdOpInfo = createNewIdReg(Op.getReg(), Opc, MRI, *GR); 38581ad6265SDimitry Andric MIB.buildInstr(IdOpInfo.second).addDef(IdOpInfo.first).addUse(Op.getReg()); 38681ad6265SDimitry Andric Op.setReg(IdOpInfo.first); 38781ad6265SDimitry Andric } 38881ad6265SDimitry Andric } 38981ad6265SDimitry Andric 39081ad6265SDimitry Andric // Defined in SPIRVLegalizerInfo.cpp. 39181ad6265SDimitry Andric extern bool isTypeFoldingSupported(unsigned Opcode); 39281ad6265SDimitry Andric 39381ad6265SDimitry Andric static void processInstrsWithTypeFolding(MachineFunction &MF, 39481ad6265SDimitry Andric SPIRVGlobalRegistry *GR, 39581ad6265SDimitry Andric MachineIRBuilder MIB) { 39681ad6265SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 39781ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) { 39881ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 39981ad6265SDimitry Andric if (isTypeFoldingSupported(MI.getOpcode())) 40081ad6265SDimitry Andric processInstr(MI, MIB, MRI, GR); 40181ad6265SDimitry Andric } 40281ad6265SDimitry Andric } 403fcaf7f86SDimitry Andric for (MachineBasicBlock &MBB : MF) { 404fcaf7f86SDimitry Andric for (MachineInstr &MI : MBB) { 405fcaf7f86SDimitry Andric // We need to rewrite dst types for ASSIGN_TYPE instrs to be able 406fcaf7f86SDimitry Andric // to perform tblgen'erated selection and we can't do that on Legalizer 407fcaf7f86SDimitry Andric // as it operates on gMIR only. 408fcaf7f86SDimitry Andric if (MI.getOpcode() != SPIRV::ASSIGN_TYPE) 409fcaf7f86SDimitry Andric continue; 410fcaf7f86SDimitry Andric Register SrcReg = MI.getOperand(1).getReg(); 411bdd1243dSDimitry Andric unsigned Opcode = MRI.getVRegDef(SrcReg)->getOpcode(); 412bdd1243dSDimitry Andric if (!isTypeFoldingSupported(Opcode)) 413fcaf7f86SDimitry Andric continue; 414fcaf7f86SDimitry Andric Register DstReg = MI.getOperand(0).getReg(); 415fcaf7f86SDimitry Andric if (MRI.getType(DstReg).isVector()) 416fcaf7f86SDimitry Andric MRI.setRegClass(DstReg, &SPIRV::IDRegClass); 417bdd1243dSDimitry Andric // Don't need to reset type of register holding constant and used in 418bdd1243dSDimitry Andric // G_ADDRSPACE_CAST, since it braaks legalizer. 419bdd1243dSDimitry Andric if (Opcode == TargetOpcode::G_CONSTANT && MRI.hasOneUse(DstReg)) { 420bdd1243dSDimitry Andric MachineInstr &UseMI = *MRI.use_instr_begin(DstReg); 421bdd1243dSDimitry Andric if (UseMI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST) 422bdd1243dSDimitry Andric continue; 423bdd1243dSDimitry Andric } 424fcaf7f86SDimitry Andric MRI.setType(DstReg, LLT::scalar(32)); 425fcaf7f86SDimitry Andric } 426fcaf7f86SDimitry Andric } 42781ad6265SDimitry Andric } 42881ad6265SDimitry Andric 42981ad6265SDimitry Andric static void processSwitches(MachineFunction &MF, SPIRVGlobalRegistry *GR, 43081ad6265SDimitry Andric MachineIRBuilder MIB) { 431bdd1243dSDimitry Andric // Before IRTranslator pass, calls to spv_switch intrinsic are inserted before 432bdd1243dSDimitry Andric // each switch instruction. IRTranslator lowers switches to G_ICMP + G_BRCOND 433bdd1243dSDimitry Andric // + G_BR triples. A switch with two cases may be transformed to this MIR 434bdd1243dSDimitry Andric // sequence: 435bdd1243dSDimitry Andric // 43681ad6265SDimitry Andric // intrinsic(@llvm.spv.switch), %CmpReg, %Const0, %Const1 43781ad6265SDimitry Andric // %Dst0 = G_ICMP intpred(eq), %CmpReg, %Const0 43881ad6265SDimitry Andric // G_BRCOND %Dst0, %bb.2 43981ad6265SDimitry Andric // G_BR %bb.5 44081ad6265SDimitry Andric // bb.5.entry: 44181ad6265SDimitry Andric // %Dst1 = G_ICMP intpred(eq), %CmpReg, %Const1 44281ad6265SDimitry Andric // G_BRCOND %Dst1, %bb.3 44381ad6265SDimitry Andric // G_BR %bb.4 44481ad6265SDimitry Andric // bb.2.sw.bb: 44581ad6265SDimitry Andric // ... 44681ad6265SDimitry Andric // bb.3.sw.bb1: 44781ad6265SDimitry Andric // ... 44881ad6265SDimitry Andric // bb.4.sw.epilog: 44981ad6265SDimitry Andric // ... 450bdd1243dSDimitry Andric // 451bdd1243dSDimitry Andric // Sometimes (in case of range-compare switches), additional G_SUBs 452bdd1243dSDimitry Andric // instructions are inserted before G_ICMPs. Those need to be additionally 45306c3fb27SDimitry Andric // processed. 454bdd1243dSDimitry Andric // 455bdd1243dSDimitry Andric // This function modifies spv_switch call's operands to include destination 456bdd1243dSDimitry Andric // MBBs (default and for each constant value). 45706c3fb27SDimitry Andric // 45806c3fb27SDimitry Andric // At the end, the function removes redundant [G_SUB] + G_ICMP + G_BRCOND + 45906c3fb27SDimitry Andric // G_BR sequences. 460bdd1243dSDimitry Andric 461bdd1243dSDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 462bdd1243dSDimitry Andric 46306c3fb27SDimitry Andric // Collect spv_switches and G_ICMPs across all MBBs in MF. 464bdd1243dSDimitry Andric std::vector<MachineInstr *> RelevantInsts; 465bdd1243dSDimitry Andric 46606c3fb27SDimitry Andric // Collect redundant MIs from [G_SUB] + G_ICMP + G_BRCOND + G_BR sequences. 46706c3fb27SDimitry Andric // After updating spv_switches, the instructions can be removed. 46806c3fb27SDimitry Andric std::vector<MachineInstr *> PostUpdateArtifacts; 46906c3fb27SDimitry Andric 470bdd1243dSDimitry Andric // Temporary set of compare registers. G_SUBs and G_ICMPs relating to 471bdd1243dSDimitry Andric // spv_switch use these registers. 472bdd1243dSDimitry Andric DenseSet<Register> CompareRegs; 47381ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) { 47481ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 475bdd1243dSDimitry Andric // Calls to spv_switch intrinsics representing IR switches. 47681ad6265SDimitry Andric if (isSpvIntrinsic(MI, Intrinsic::spv_switch)) { 47781ad6265SDimitry Andric assert(MI.getOperand(1).isReg()); 478bdd1243dSDimitry Andric CompareRegs.insert(MI.getOperand(1).getReg()); 479bdd1243dSDimitry Andric RelevantInsts.push_back(&MI); 48081ad6265SDimitry Andric } 481bdd1243dSDimitry Andric 482bdd1243dSDimitry Andric // G_SUBs coming from range-compare switch lowering. G_SUBs are found 483bdd1243dSDimitry Andric // after spv_switch but before G_ICMP. 484bdd1243dSDimitry Andric if (MI.getOpcode() == TargetOpcode::G_SUB && MI.getOperand(1).isReg() && 485bdd1243dSDimitry Andric CompareRegs.contains(MI.getOperand(1).getReg())) { 486bdd1243dSDimitry Andric assert(MI.getOperand(0).isReg() && MI.getOperand(1).isReg()); 487bdd1243dSDimitry Andric Register Dst = MI.getOperand(0).getReg(); 488bdd1243dSDimitry Andric CompareRegs.insert(Dst); 48906c3fb27SDimitry Andric PostUpdateArtifacts.push_back(&MI); 490bdd1243dSDimitry Andric } 491bdd1243dSDimitry Andric 492bdd1243dSDimitry Andric // G_ICMPs relating to switches. 49381ad6265SDimitry Andric if (MI.getOpcode() == TargetOpcode::G_ICMP && MI.getOperand(2).isReg() && 494bdd1243dSDimitry Andric CompareRegs.contains(MI.getOperand(2).getReg())) { 49581ad6265SDimitry Andric Register Dst = MI.getOperand(0).getReg(); 496bdd1243dSDimitry Andric RelevantInsts.push_back(&MI); 49706c3fb27SDimitry Andric PostUpdateArtifacts.push_back(&MI); 49806c3fb27SDimitry Andric MachineInstr *CBr = MRI.use_begin(Dst)->getParent(); 49906c3fb27SDimitry Andric assert(CBr->getOpcode() == SPIRV::G_BRCOND); 50006c3fb27SDimitry Andric PostUpdateArtifacts.push_back(CBr); 50106c3fb27SDimitry Andric MachineInstr *Br = CBr->getNextNode(); 50206c3fb27SDimitry Andric assert(Br->getOpcode() == SPIRV::G_BR); 50306c3fb27SDimitry Andric PostUpdateArtifacts.push_back(Br); 504bdd1243dSDimitry Andric } 505bdd1243dSDimitry Andric } 506bdd1243dSDimitry Andric } 507bdd1243dSDimitry Andric 508bdd1243dSDimitry Andric // Update each spv_switch with destination MBBs. 509bdd1243dSDimitry Andric for (auto i = RelevantInsts.begin(); i != RelevantInsts.end(); i++) { 510bdd1243dSDimitry Andric if (!isSpvIntrinsic(**i, Intrinsic::spv_switch)) 511bdd1243dSDimitry Andric continue; 512bdd1243dSDimitry Andric 513bdd1243dSDimitry Andric // Currently considered spv_switch. 514bdd1243dSDimitry Andric MachineInstr *Switch = *i; 515bdd1243dSDimitry Andric // Set the first successor as default MBB to support empty switches. 516bdd1243dSDimitry Andric MachineBasicBlock *DefaultMBB = *Switch->getParent()->succ_begin(); 517bdd1243dSDimitry Andric // Container for mapping values to MMBs. 518bdd1243dSDimitry Andric SmallDenseMap<uint64_t, MachineBasicBlock *> ValuesToMBBs; 519bdd1243dSDimitry Andric 520bdd1243dSDimitry Andric // Walk all G_ICMPs to collect ValuesToMBBs. Start at currently considered 521bdd1243dSDimitry Andric // spv_switch (i) and break at any spv_switch with the same compare 522bdd1243dSDimitry Andric // register (indicating we are back at the same scope). 523bdd1243dSDimitry Andric Register CompareReg = Switch->getOperand(1).getReg(); 524bdd1243dSDimitry Andric for (auto j = i + 1; j != RelevantInsts.end(); j++) { 525bdd1243dSDimitry Andric if (isSpvIntrinsic(**j, Intrinsic::spv_switch) && 526bdd1243dSDimitry Andric (*j)->getOperand(1).getReg() == CompareReg) 527bdd1243dSDimitry Andric break; 528bdd1243dSDimitry Andric 529bdd1243dSDimitry Andric if (!((*j)->getOpcode() == TargetOpcode::G_ICMP && 530bdd1243dSDimitry Andric (*j)->getOperand(2).getReg() == CompareReg)) 531bdd1243dSDimitry Andric continue; 532bdd1243dSDimitry Andric 533bdd1243dSDimitry Andric MachineInstr *ICMP = *j; 534bdd1243dSDimitry Andric Register Dst = ICMP->getOperand(0).getReg(); 535bdd1243dSDimitry Andric MachineOperand &PredOp = ICMP->getOperand(1); 53681ad6265SDimitry Andric const auto CC = static_cast<CmpInst::Predicate>(PredOp.getPredicate()); 537bdd1243dSDimitry Andric assert((CC == CmpInst::ICMP_EQ || CC == CmpInst::ICMP_ULE) && 538bdd1243dSDimitry Andric MRI.hasOneUse(Dst) && MRI.hasOneDef(CompareReg)); 539bdd1243dSDimitry Andric uint64_t Value = getIConstVal(ICMP->getOperand(3).getReg(), &MRI); 54081ad6265SDimitry Andric MachineInstr *CBr = MRI.use_begin(Dst)->getParent(); 541bdd1243dSDimitry Andric assert(CBr->getOpcode() == SPIRV::G_BRCOND && CBr->getOperand(1).isMBB()); 542bdd1243dSDimitry Andric MachineBasicBlock *MBB = CBr->getOperand(1).getMBB(); 543bdd1243dSDimitry Andric 544bdd1243dSDimitry Andric // Map switch case Value to target MBB. 545bdd1243dSDimitry Andric ValuesToMBBs[Value] = MBB; 546bdd1243dSDimitry Andric 54706c3fb27SDimitry Andric // Add target MBB as successor to the switch's MBB. 54806c3fb27SDimitry Andric Switch->getParent()->addSuccessor(MBB); 54906c3fb27SDimitry Andric 550bdd1243dSDimitry Andric // The next MI is always G_BR to either the next case or the default. 55181ad6265SDimitry Andric MachineInstr *NextMI = CBr->getNextNode(); 55281ad6265SDimitry Andric assert(NextMI->getOpcode() == SPIRV::G_BR && 55381ad6265SDimitry Andric NextMI->getOperand(0).isMBB()); 55481ad6265SDimitry Andric MachineBasicBlock *NextMBB = NextMI->getOperand(0).getMBB(); 555bdd1243dSDimitry Andric // Default MBB does not begin with G_ICMP using spv_switch compare 556bdd1243dSDimitry Andric // register. 55781ad6265SDimitry Andric if (NextMBB->front().getOpcode() != SPIRV::G_ICMP || 55881ad6265SDimitry Andric (NextMBB->front().getOperand(2).isReg() && 55906c3fb27SDimitry Andric NextMBB->front().getOperand(2).getReg() != CompareReg)) { 56006c3fb27SDimitry Andric // Set default MBB and add it as successor to the switch's MBB. 561bdd1243dSDimitry Andric DefaultMBB = NextMBB; 56206c3fb27SDimitry Andric Switch->getParent()->addSuccessor(DefaultMBB); 56306c3fb27SDimitry Andric } 56481ad6265SDimitry Andric } 565bdd1243dSDimitry Andric 566bdd1243dSDimitry Andric // Modify considered spv_switch operands using collected Values and 567bdd1243dSDimitry Andric // MBBs. 568bdd1243dSDimitry Andric SmallVector<const ConstantInt *, 3> Values; 56981ad6265SDimitry Andric SmallVector<MachineBasicBlock *, 3> MBBs; 570bdd1243dSDimitry Andric for (unsigned k = 2; k < Switch->getNumExplicitOperands(); k++) { 571bdd1243dSDimitry Andric Register CReg = Switch->getOperand(k).getReg(); 57281ad6265SDimitry Andric uint64_t Val = getIConstVal(CReg, &MRI); 57381ad6265SDimitry Andric MachineInstr *ConstInstr = getDefInstrMaybeConstant(CReg, &MRI); 574bdd1243dSDimitry Andric if (!ValuesToMBBs[Val]) 575bdd1243dSDimitry Andric continue; 576bdd1243dSDimitry Andric 577bdd1243dSDimitry Andric Values.push_back(ConstInstr->getOperand(1).getCImm()); 578bdd1243dSDimitry Andric MBBs.push_back(ValuesToMBBs[Val]); 57981ad6265SDimitry Andric } 580bdd1243dSDimitry Andric 581bdd1243dSDimitry Andric for (unsigned k = Switch->getNumExplicitOperands() - 1; k > 1; k--) 582bdd1243dSDimitry Andric Switch->removeOperand(k); 583bdd1243dSDimitry Andric 584bdd1243dSDimitry Andric Switch->addOperand(MachineOperand::CreateMBB(DefaultMBB)); 585bdd1243dSDimitry Andric for (unsigned k = 0; k < Values.size(); k++) { 586bdd1243dSDimitry Andric Switch->addOperand(MachineOperand::CreateCImm(Values[k])); 587bdd1243dSDimitry Andric Switch->addOperand(MachineOperand::CreateMBB(MBBs[k])); 58881ad6265SDimitry Andric } 58981ad6265SDimitry Andric } 59006c3fb27SDimitry Andric 59106c3fb27SDimitry Andric for (MachineInstr *MI : PostUpdateArtifacts) { 59206c3fb27SDimitry Andric MachineBasicBlock *ParentMBB = MI->getParent(); 59306c3fb27SDimitry Andric MI->eraseFromParent(); 59406c3fb27SDimitry Andric // If G_ICMP + G_BRCOND + G_BR were the only MIs in MBB, erase this MBB. It 59506c3fb27SDimitry Andric // can be safely assumed, there are no breaks or phis directing into this 59606c3fb27SDimitry Andric // MBB. However, we need to remove this MBB from the CFG graph. MBBs must be 59706c3fb27SDimitry Andric // erased top-down. 59806c3fb27SDimitry Andric if (ParentMBB->empty()) { 59906c3fb27SDimitry Andric while (!ParentMBB->pred_empty()) 60006c3fb27SDimitry Andric (*ParentMBB->pred_begin())->removeSuccessor(ParentMBB); 60106c3fb27SDimitry Andric 60206c3fb27SDimitry Andric while (!ParentMBB->succ_empty()) 60306c3fb27SDimitry Andric ParentMBB->removeSuccessor(ParentMBB->succ_begin()); 60406c3fb27SDimitry Andric 60506c3fb27SDimitry Andric ParentMBB->eraseFromParent(); 60606c3fb27SDimitry Andric } 60706c3fb27SDimitry Andric } 60881ad6265SDimitry Andric } 60981ad6265SDimitry Andric 610*1db9f3b2SDimitry Andric static bool isImplicitFallthrough(MachineBasicBlock &MBB) { 611*1db9f3b2SDimitry Andric if (MBB.empty()) 612*1db9f3b2SDimitry Andric return true; 613*1db9f3b2SDimitry Andric 614*1db9f3b2SDimitry Andric // Branching SPIR-V intrinsics are not detected by this generic method. 615*1db9f3b2SDimitry Andric // Thus, we can only trust negative result. 616*1db9f3b2SDimitry Andric if (!MBB.canFallThrough()) 617*1db9f3b2SDimitry Andric return false; 618*1db9f3b2SDimitry Andric 619*1db9f3b2SDimitry Andric // Otherwise, we must manually check if we have a SPIR-V intrinsic which 620*1db9f3b2SDimitry Andric // prevent an implicit fallthrough. 621*1db9f3b2SDimitry Andric for (MachineBasicBlock::reverse_iterator It = MBB.rbegin(), E = MBB.rend(); 622*1db9f3b2SDimitry Andric It != E; ++It) { 623*1db9f3b2SDimitry Andric if (isSpvIntrinsic(*It, Intrinsic::spv_switch)) 624*1db9f3b2SDimitry Andric return false; 625*1db9f3b2SDimitry Andric } 626*1db9f3b2SDimitry Andric return true; 627*1db9f3b2SDimitry Andric } 628*1db9f3b2SDimitry Andric 629*1db9f3b2SDimitry Andric static void removeImplicitFallthroughs(MachineFunction &MF, 630*1db9f3b2SDimitry Andric MachineIRBuilder MIB) { 631*1db9f3b2SDimitry Andric // It is valid for MachineBasicBlocks to not finish with a branch instruction. 632*1db9f3b2SDimitry Andric // In such cases, they will simply fallthrough their immediate successor. 633*1db9f3b2SDimitry Andric for (MachineBasicBlock &MBB : MF) { 634*1db9f3b2SDimitry Andric if (!isImplicitFallthrough(MBB)) 635*1db9f3b2SDimitry Andric continue; 636*1db9f3b2SDimitry Andric 637*1db9f3b2SDimitry Andric assert(std::distance(MBB.successors().begin(), MBB.successors().end()) == 638*1db9f3b2SDimitry Andric 1); 639*1db9f3b2SDimitry Andric MIB.setInsertPt(MBB, MBB.end()); 640*1db9f3b2SDimitry Andric MIB.buildBr(**MBB.successors().begin()); 641*1db9f3b2SDimitry Andric } 642*1db9f3b2SDimitry Andric } 643*1db9f3b2SDimitry Andric 64481ad6265SDimitry Andric bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) { 64581ad6265SDimitry Andric // Initialize the type registry. 64681ad6265SDimitry Andric const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>(); 64781ad6265SDimitry Andric SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry(); 64881ad6265SDimitry Andric GR->setCurrentFunc(MF); 64981ad6265SDimitry Andric MachineIRBuilder MIB(MF); 650fcaf7f86SDimitry Andric addConstantsToTrack(MF, GR); 65181ad6265SDimitry Andric foldConstantsIntoIntrinsics(MF); 65281ad6265SDimitry Andric insertBitcasts(MF, GR, MIB); 65381ad6265SDimitry Andric generateAssignInstrs(MF, GR, MIB); 65481ad6265SDimitry Andric processSwitches(MF, GR, MIB); 655bdd1243dSDimitry Andric processInstrsWithTypeFolding(MF, GR, MIB); 656*1db9f3b2SDimitry Andric removeImplicitFallthroughs(MF, MIB); 65781ad6265SDimitry Andric 65881ad6265SDimitry Andric return true; 65981ad6265SDimitry Andric } 66081ad6265SDimitry Andric 66181ad6265SDimitry Andric INITIALIZE_PASS(SPIRVPreLegalizer, DEBUG_TYPE, "SPIRV pre legalizer", false, 66281ad6265SDimitry Andric false) 66381ad6265SDimitry Andric 66481ad6265SDimitry Andric char SPIRVPreLegalizer::ID = 0; 66581ad6265SDimitry Andric 66681ad6265SDimitry Andric FunctionPass *llvm::createSPIRVPreLegalizerPass() { 66781ad6265SDimitry Andric return new SPIRVPreLegalizer(); 66881ad6265SDimitry Andric } 669