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 41*0fca6ea1SDimitry Andric static void 42*0fca6ea1SDimitry Andric addConstantsToTrack(MachineFunction &MF, SPIRVGlobalRegistry *GR, 43*0fca6ea1SDimitry Andric const SPIRVSubtarget &STI, 44*0fca6ea1SDimitry Andric DenseMap<MachineInstr *, Type *> &TargetExtConstTypes, 45*0fca6ea1SDimitry Andric SmallSet<Register, 4> &TrackedConstRegs) { 46fcaf7f86SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 47fcaf7f86SDimitry Andric DenseMap<MachineInstr *, Register> RegsAlreadyAddedToDT; 48fcaf7f86SDimitry Andric SmallVector<MachineInstr *, 10> ToErase, ToEraseComposites; 49fcaf7f86SDimitry Andric for (MachineBasicBlock &MBB : MF) { 50fcaf7f86SDimitry Andric for (MachineInstr &MI : MBB) { 51fcaf7f86SDimitry Andric if (!isSpvIntrinsic(MI, Intrinsic::spv_track_constant)) 52fcaf7f86SDimitry Andric continue; 53fcaf7f86SDimitry Andric ToErase.push_back(&MI); 54*0fca6ea1SDimitry Andric Register SrcReg = MI.getOperand(2).getReg(); 55fcaf7f86SDimitry Andric auto *Const = 56fcaf7f86SDimitry Andric cast<Constant>(cast<ConstantAsMetadata>( 57fcaf7f86SDimitry Andric MI.getOperand(3).getMetadata()->getOperand(0)) 58fcaf7f86SDimitry Andric ->getValue()); 59fcaf7f86SDimitry Andric if (auto *GV = dyn_cast<GlobalValue>(Const)) { 60fcaf7f86SDimitry Andric Register Reg = GR->find(GV, &MF); 61fcaf7f86SDimitry Andric if (!Reg.isValid()) 62*0fca6ea1SDimitry Andric GR->add(GV, &MF, SrcReg); 63fcaf7f86SDimitry Andric else 64fcaf7f86SDimitry Andric RegsAlreadyAddedToDT[&MI] = Reg; 65fcaf7f86SDimitry Andric } else { 66fcaf7f86SDimitry Andric Register Reg = GR->find(Const, &MF); 67fcaf7f86SDimitry Andric if (!Reg.isValid()) { 68fcaf7f86SDimitry Andric if (auto *ConstVec = dyn_cast<ConstantDataVector>(Const)) { 69*0fca6ea1SDimitry Andric auto *BuildVec = MRI.getVRegDef(SrcReg); 70fcaf7f86SDimitry Andric assert(BuildVec && 71fcaf7f86SDimitry Andric BuildVec->getOpcode() == TargetOpcode::G_BUILD_VECTOR); 72*0fca6ea1SDimitry Andric for (unsigned i = 0; i < ConstVec->getNumElements(); ++i) { 73*0fca6ea1SDimitry Andric // Ensure that OpConstantComposite reuses a constant when it's 74*0fca6ea1SDimitry Andric // already created and available in the same machine function. 75*0fca6ea1SDimitry Andric Constant *ElemConst = ConstVec->getElementAsConstant(i); 76*0fca6ea1SDimitry Andric Register ElemReg = GR->find(ElemConst, &MF); 77*0fca6ea1SDimitry Andric if (!ElemReg.isValid()) 78*0fca6ea1SDimitry Andric GR->add(ElemConst, &MF, BuildVec->getOperand(1 + i).getReg()); 79*0fca6ea1SDimitry Andric else 80*0fca6ea1SDimitry Andric BuildVec->getOperand(1 + i).setReg(ElemReg); 81fcaf7f86SDimitry Andric } 82*0fca6ea1SDimitry Andric } 83*0fca6ea1SDimitry Andric GR->add(Const, &MF, SrcReg); 84*0fca6ea1SDimitry Andric TrackedConstRegs.insert(SrcReg); 85*0fca6ea1SDimitry Andric if (Const->getType()->isTargetExtTy()) { 86*0fca6ea1SDimitry Andric // remember association so that we can restore it when assign types 87*0fca6ea1SDimitry Andric MachineInstr *SrcMI = MRI.getVRegDef(SrcReg); 88*0fca6ea1SDimitry Andric if (SrcMI && (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT || 89*0fca6ea1SDimitry Andric SrcMI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF)) 90*0fca6ea1SDimitry Andric TargetExtConstTypes[SrcMI] = Const->getType(); 91*0fca6ea1SDimitry Andric if (Const->isNullValue()) { 92*0fca6ea1SDimitry Andric MachineIRBuilder MIB(MF); 93*0fca6ea1SDimitry Andric SPIRVType *ExtType = 94*0fca6ea1SDimitry Andric GR->getOrCreateSPIRVType(Const->getType(), MIB); 95*0fca6ea1SDimitry Andric SrcMI->setDesc(STI.getInstrInfo()->get(SPIRV::OpConstantNull)); 96*0fca6ea1SDimitry Andric SrcMI->addOperand(MachineOperand::CreateReg( 97*0fca6ea1SDimitry Andric GR->getSPIRVTypeID(ExtType), false)); 98*0fca6ea1SDimitry Andric } 99*0fca6ea1SDimitry Andric } 100fcaf7f86SDimitry Andric } else { 101fcaf7f86SDimitry Andric RegsAlreadyAddedToDT[&MI] = Reg; 102fcaf7f86SDimitry Andric // This MI is unused and will be removed. If the MI uses 103fcaf7f86SDimitry Andric // const_composite, it will be unused and should be removed too. 104fcaf7f86SDimitry Andric assert(MI.getOperand(2).isReg() && "Reg operand is expected"); 105fcaf7f86SDimitry Andric MachineInstr *SrcMI = MRI.getVRegDef(MI.getOperand(2).getReg()); 106fcaf7f86SDimitry Andric if (SrcMI && isSpvIntrinsic(*SrcMI, Intrinsic::spv_const_composite)) 107fcaf7f86SDimitry Andric ToEraseComposites.push_back(SrcMI); 108fcaf7f86SDimitry Andric } 109fcaf7f86SDimitry Andric } 110fcaf7f86SDimitry Andric } 111fcaf7f86SDimitry Andric } 112fcaf7f86SDimitry Andric for (MachineInstr *MI : ToErase) { 113fcaf7f86SDimitry Andric Register Reg = MI->getOperand(2).getReg(); 114cb14a3feSDimitry Andric if (RegsAlreadyAddedToDT.contains(MI)) 115fcaf7f86SDimitry Andric Reg = RegsAlreadyAddedToDT[MI]; 11606c3fb27SDimitry Andric auto *RC = MRI.getRegClassOrNull(MI->getOperand(0).getReg()); 11706c3fb27SDimitry Andric if (!MRI.getRegClassOrNull(Reg) && RC) 11806c3fb27SDimitry Andric MRI.setRegClass(Reg, RC); 119fcaf7f86SDimitry Andric MRI.replaceRegWith(MI->getOperand(0).getReg(), Reg); 120fcaf7f86SDimitry Andric MI->eraseFromParent(); 121fcaf7f86SDimitry Andric } 122fcaf7f86SDimitry Andric for (MachineInstr *MI : ToEraseComposites) 123fcaf7f86SDimitry Andric MI->eraseFromParent(); 12481ad6265SDimitry Andric } 12581ad6265SDimitry Andric 126*0fca6ea1SDimitry Andric static void 127*0fca6ea1SDimitry Andric foldConstantsIntoIntrinsics(MachineFunction &MF, 128*0fca6ea1SDimitry Andric const SmallSet<Register, 4> &TrackedConstRegs) { 12981ad6265SDimitry Andric SmallVector<MachineInstr *, 10> ToErase; 13081ad6265SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 13181ad6265SDimitry Andric const unsigned AssignNameOperandShift = 2; 13281ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) { 13381ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 13481ad6265SDimitry Andric if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_name)) 13581ad6265SDimitry Andric continue; 13681ad6265SDimitry Andric unsigned NumOp = MI.getNumExplicitDefs() + AssignNameOperandShift; 13781ad6265SDimitry Andric while (MI.getOperand(NumOp).isReg()) { 13881ad6265SDimitry Andric MachineOperand &MOp = MI.getOperand(NumOp); 13981ad6265SDimitry Andric MachineInstr *ConstMI = MRI.getVRegDef(MOp.getReg()); 14081ad6265SDimitry Andric assert(ConstMI->getOpcode() == TargetOpcode::G_CONSTANT); 14181ad6265SDimitry Andric MI.removeOperand(NumOp); 14281ad6265SDimitry Andric MI.addOperand(MachineOperand::CreateImm( 14381ad6265SDimitry Andric ConstMI->getOperand(1).getCImm()->getZExtValue())); 144*0fca6ea1SDimitry Andric Register DefReg = ConstMI->getOperand(0).getReg(); 145*0fca6ea1SDimitry Andric if (MRI.use_empty(DefReg) && !TrackedConstRegs.contains(DefReg)) 14681ad6265SDimitry Andric ToErase.push_back(ConstMI); 14781ad6265SDimitry Andric } 14881ad6265SDimitry Andric } 14981ad6265SDimitry Andric } 15081ad6265SDimitry Andric for (MachineInstr *MI : ToErase) 15181ad6265SDimitry Andric MI->eraseFromParent(); 15281ad6265SDimitry Andric } 15381ad6265SDimitry Andric 154*0fca6ea1SDimitry Andric static MachineInstr *findAssignTypeInstr(Register Reg, 155*0fca6ea1SDimitry Andric MachineRegisterInfo *MRI) { 156*0fca6ea1SDimitry Andric for (MachineRegisterInfo::use_instr_iterator I = MRI->use_instr_begin(Reg), 157*0fca6ea1SDimitry Andric IE = MRI->use_instr_end(); 158*0fca6ea1SDimitry Andric I != IE; ++I) { 159*0fca6ea1SDimitry Andric MachineInstr *UseMI = &*I; 160*0fca6ea1SDimitry Andric if ((isSpvIntrinsic(*UseMI, Intrinsic::spv_assign_ptr_type) || 161*0fca6ea1SDimitry Andric isSpvIntrinsic(*UseMI, Intrinsic::spv_assign_type)) && 162*0fca6ea1SDimitry Andric UseMI->getOperand(1).getReg() == Reg) 163*0fca6ea1SDimitry Andric return UseMI; 164*0fca6ea1SDimitry Andric } 165*0fca6ea1SDimitry Andric return nullptr; 166*0fca6ea1SDimitry Andric } 167*0fca6ea1SDimitry Andric 16881ad6265SDimitry Andric static void insertBitcasts(MachineFunction &MF, SPIRVGlobalRegistry *GR, 16981ad6265SDimitry Andric MachineIRBuilder MIB) { 170*0fca6ea1SDimitry Andric // Get access to information about available extensions 171*0fca6ea1SDimitry Andric const SPIRVSubtarget *ST = 172*0fca6ea1SDimitry Andric static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget()); 17381ad6265SDimitry Andric SmallVector<MachineInstr *, 10> ToErase; 17481ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) { 17581ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 1761db9f3b2SDimitry Andric if (!isSpvIntrinsic(MI, Intrinsic::spv_bitcast) && 1771db9f3b2SDimitry Andric !isSpvIntrinsic(MI, Intrinsic::spv_ptrcast)) 17881ad6265SDimitry Andric continue; 17981ad6265SDimitry Andric assert(MI.getOperand(2).isReg()); 18081ad6265SDimitry Andric MIB.setInsertPt(*MI.getParent(), MI); 18181ad6265SDimitry Andric ToErase.push_back(&MI); 1821db9f3b2SDimitry Andric if (isSpvIntrinsic(MI, Intrinsic::spv_bitcast)) { 1831db9f3b2SDimitry Andric MIB.buildBitcast(MI.getOperand(0).getReg(), MI.getOperand(2).getReg()); 1841db9f3b2SDimitry Andric continue; 1851db9f3b2SDimitry Andric } 1861db9f3b2SDimitry Andric Register Def = MI.getOperand(0).getReg(); 1871db9f3b2SDimitry Andric Register Source = MI.getOperand(2).getReg(); 188*0fca6ea1SDimitry Andric Type *ElemTy = getMDOperandAsType(MI.getOperand(3).getMetadata(), 0); 189*0fca6ea1SDimitry Andric SPIRVType *BaseTy = GR->getOrCreateSPIRVType(ElemTy, MIB); 1901db9f3b2SDimitry Andric SPIRVType *AssignedPtrType = GR->getOrCreateSPIRVPointerType( 1911db9f3b2SDimitry Andric BaseTy, MI, *MF.getSubtarget<SPIRVSubtarget>().getInstrInfo(), 192*0fca6ea1SDimitry Andric addressSpaceToStorageClass(MI.getOperand(4).getImm(), *ST)); 1931db9f3b2SDimitry Andric 194*0fca6ea1SDimitry Andric // If the ptrcast would be redundant, replace all uses with the source 1951db9f3b2SDimitry Andric // register. 1961db9f3b2SDimitry Andric if (GR->getSPIRVTypeForVReg(Source) == AssignedPtrType) { 197*0fca6ea1SDimitry Andric // Erase Def's assign type instruction if we are going to replace Def. 198*0fca6ea1SDimitry Andric if (MachineInstr *AssignMI = findAssignTypeInstr(Def, MIB.getMRI())) 199*0fca6ea1SDimitry Andric ToErase.push_back(AssignMI); 2001db9f3b2SDimitry Andric MIB.getMRI()->replaceRegWith(Def, Source); 2011db9f3b2SDimitry Andric } else { 2021db9f3b2SDimitry Andric GR->assignSPIRVTypeToVReg(AssignedPtrType, Def, MF); 2031db9f3b2SDimitry Andric MIB.buildBitcast(Def, Source); 2041db9f3b2SDimitry Andric } 20581ad6265SDimitry Andric } 20681ad6265SDimitry Andric } 20781ad6265SDimitry Andric for (MachineInstr *MI : ToErase) 20881ad6265SDimitry Andric MI->eraseFromParent(); 20981ad6265SDimitry Andric } 21081ad6265SDimitry Andric 21181ad6265SDimitry Andric // Translating GV, IRTranslator sometimes generates following IR: 21281ad6265SDimitry Andric // %1 = G_GLOBAL_VALUE 21381ad6265SDimitry Andric // %2 = COPY %1 21481ad6265SDimitry Andric // %3 = G_ADDRSPACE_CAST %2 215*0fca6ea1SDimitry Andric // 216*0fca6ea1SDimitry Andric // or 217*0fca6ea1SDimitry Andric // 218*0fca6ea1SDimitry Andric // %1 = G_ZEXT %2 219*0fca6ea1SDimitry Andric // G_MEMCPY ... %2 ... 220*0fca6ea1SDimitry Andric // 22181ad6265SDimitry Andric // New registers have no SPIRVType and no register class info. 22281ad6265SDimitry Andric // 22381ad6265SDimitry Andric // Set SPIRVType for GV, propagate it from GV to other instructions, 22481ad6265SDimitry Andric // also set register classes. 22581ad6265SDimitry Andric static SPIRVType *propagateSPIRVType(MachineInstr *MI, SPIRVGlobalRegistry *GR, 22681ad6265SDimitry Andric MachineRegisterInfo &MRI, 22781ad6265SDimitry Andric MachineIRBuilder &MIB) { 22881ad6265SDimitry Andric SPIRVType *SpirvTy = nullptr; 22981ad6265SDimitry Andric assert(MI && "Machine instr is expected"); 23081ad6265SDimitry Andric if (MI->getOperand(0).isReg()) { 23181ad6265SDimitry Andric Register Reg = MI->getOperand(0).getReg(); 23281ad6265SDimitry Andric SpirvTy = GR->getSPIRVTypeForVReg(Reg); 23381ad6265SDimitry Andric if (!SpirvTy) { 23481ad6265SDimitry Andric switch (MI->getOpcode()) { 23581ad6265SDimitry Andric case TargetOpcode::G_CONSTANT: { 23681ad6265SDimitry Andric MIB.setInsertPt(*MI->getParent(), MI); 23781ad6265SDimitry Andric Type *Ty = MI->getOperand(1).getCImm()->getType(); 23881ad6265SDimitry Andric SpirvTy = GR->getOrCreateSPIRVType(Ty, MIB); 23981ad6265SDimitry Andric break; 24081ad6265SDimitry Andric } 24181ad6265SDimitry Andric case TargetOpcode::G_GLOBAL_VALUE: { 24281ad6265SDimitry Andric MIB.setInsertPt(*MI->getParent(), MI); 243*0fca6ea1SDimitry Andric const GlobalValue *Global = MI->getOperand(1).getGlobal(); 244*0fca6ea1SDimitry Andric Type *ElementTy = toTypedPointer(GR->getDeducedGlobalValueType(Global)); 245*0fca6ea1SDimitry Andric auto *Ty = TypedPointerType::get(ElementTy, 246*0fca6ea1SDimitry Andric Global->getType()->getAddressSpace()); 24781ad6265SDimitry Andric SpirvTy = GR->getOrCreateSPIRVType(Ty, MIB); 24881ad6265SDimitry Andric break; 24981ad6265SDimitry Andric } 250*0fca6ea1SDimitry Andric case TargetOpcode::G_ANYEXT: 251*0fca6ea1SDimitry Andric case TargetOpcode::G_SEXT: 252*0fca6ea1SDimitry Andric case TargetOpcode::G_ZEXT: { 253*0fca6ea1SDimitry Andric if (MI->getOperand(1).isReg()) { 254*0fca6ea1SDimitry Andric if (MachineInstr *DefInstr = 255*0fca6ea1SDimitry Andric MRI.getVRegDef(MI->getOperand(1).getReg())) { 256*0fca6ea1SDimitry Andric if (SPIRVType *Def = propagateSPIRVType(DefInstr, GR, MRI, MIB)) { 257*0fca6ea1SDimitry Andric unsigned CurrentBW = GR->getScalarOrVectorBitWidth(Def); 258*0fca6ea1SDimitry Andric unsigned ExpectedBW = 259*0fca6ea1SDimitry Andric std::max(MRI.getType(Reg).getScalarSizeInBits(), CurrentBW); 260*0fca6ea1SDimitry Andric unsigned NumElements = GR->getScalarOrVectorComponentCount(Def); 261*0fca6ea1SDimitry Andric SpirvTy = GR->getOrCreateSPIRVIntegerType(ExpectedBW, MIB); 262*0fca6ea1SDimitry Andric if (NumElements > 1) 263*0fca6ea1SDimitry Andric SpirvTy = 264*0fca6ea1SDimitry Andric GR->getOrCreateSPIRVVectorType(SpirvTy, NumElements, MIB); 265*0fca6ea1SDimitry Andric } 266*0fca6ea1SDimitry Andric } 267*0fca6ea1SDimitry Andric } 268*0fca6ea1SDimitry Andric break; 269*0fca6ea1SDimitry Andric } 270*0fca6ea1SDimitry Andric case TargetOpcode::G_PTRTOINT: 271*0fca6ea1SDimitry Andric SpirvTy = GR->getOrCreateSPIRVIntegerType( 272*0fca6ea1SDimitry Andric MRI.getType(Reg).getScalarSizeInBits(), MIB); 273*0fca6ea1SDimitry Andric break; 27481ad6265SDimitry Andric case TargetOpcode::G_TRUNC: 27581ad6265SDimitry Andric case TargetOpcode::G_ADDRSPACE_CAST: 276fcaf7f86SDimitry Andric case TargetOpcode::G_PTR_ADD: 27781ad6265SDimitry Andric case TargetOpcode::COPY: { 27881ad6265SDimitry Andric MachineOperand &Op = MI->getOperand(1); 27981ad6265SDimitry Andric MachineInstr *Def = Op.isReg() ? MRI.getVRegDef(Op.getReg()) : nullptr; 28081ad6265SDimitry Andric if (Def) 28181ad6265SDimitry Andric SpirvTy = propagateSPIRVType(Def, GR, MRI, MIB); 28281ad6265SDimitry Andric break; 28381ad6265SDimitry Andric } 28481ad6265SDimitry Andric default: 28581ad6265SDimitry Andric break; 28681ad6265SDimitry Andric } 28781ad6265SDimitry Andric if (SpirvTy) 28881ad6265SDimitry Andric GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF()); 28981ad6265SDimitry Andric if (!MRI.getRegClassOrNull(Reg)) 29081ad6265SDimitry Andric MRI.setRegClass(Reg, &SPIRV::IDRegClass); 29181ad6265SDimitry Andric } 29281ad6265SDimitry Andric } 29381ad6265SDimitry Andric return SpirvTy; 29481ad6265SDimitry Andric } 29581ad6265SDimitry Andric 296*0fca6ea1SDimitry Andric // To support current approach and limitations wrt. bit width here we widen a 297*0fca6ea1SDimitry Andric // scalar register with a bit width greater than 1 to valid sizes and cap it to 298*0fca6ea1SDimitry Andric // 64 width. 299*0fca6ea1SDimitry Andric static void widenScalarLLTNextPow2(Register Reg, MachineRegisterInfo &MRI) { 300*0fca6ea1SDimitry Andric LLT RegType = MRI.getType(Reg); 301*0fca6ea1SDimitry Andric if (!RegType.isScalar()) 302*0fca6ea1SDimitry Andric return; 303*0fca6ea1SDimitry Andric unsigned Sz = RegType.getScalarSizeInBits(); 304*0fca6ea1SDimitry Andric if (Sz == 1) 305*0fca6ea1SDimitry Andric return; 306*0fca6ea1SDimitry Andric unsigned NewSz = std::min(std::max(1u << Log2_32_Ceil(Sz), 8u), 64u); 307*0fca6ea1SDimitry Andric if (NewSz != Sz) 308*0fca6ea1SDimitry Andric MRI.setType(Reg, LLT::scalar(NewSz)); 309*0fca6ea1SDimitry Andric } 310*0fca6ea1SDimitry Andric 311*0fca6ea1SDimitry Andric static std::pair<Register, unsigned> 312*0fca6ea1SDimitry Andric createNewIdReg(SPIRVType *SpvType, Register SrcReg, MachineRegisterInfo &MRI, 313*0fca6ea1SDimitry Andric const SPIRVGlobalRegistry &GR) { 314*0fca6ea1SDimitry Andric if (!SpvType) 315*0fca6ea1SDimitry Andric SpvType = GR.getSPIRVTypeForVReg(SrcReg); 316*0fca6ea1SDimitry Andric assert(SpvType && "VReg is expected to have SPIRV type"); 317*0fca6ea1SDimitry Andric LLT SrcLLT = MRI.getType(SrcReg); 318*0fca6ea1SDimitry Andric LLT NewT = LLT::scalar(32); 319*0fca6ea1SDimitry Andric bool IsFloat = SpvType->getOpcode() == SPIRV::OpTypeFloat; 320*0fca6ea1SDimitry Andric bool IsVectorFloat = 321*0fca6ea1SDimitry Andric SpvType->getOpcode() == SPIRV::OpTypeVector && 322*0fca6ea1SDimitry Andric GR.getSPIRVTypeForVReg(SpvType->getOperand(1).getReg())->getOpcode() == 323*0fca6ea1SDimitry Andric SPIRV::OpTypeFloat; 324*0fca6ea1SDimitry Andric IsFloat |= IsVectorFloat; 325*0fca6ea1SDimitry Andric auto GetIdOp = IsFloat ? SPIRV::GET_fID : SPIRV::GET_ID; 326*0fca6ea1SDimitry Andric auto DstClass = IsFloat ? &SPIRV::fIDRegClass : &SPIRV::IDRegClass; 327*0fca6ea1SDimitry Andric if (SrcLLT.isPointer()) { 328*0fca6ea1SDimitry Andric unsigned PtrSz = GR.getPointerSize(); 329*0fca6ea1SDimitry Andric NewT = LLT::pointer(0, PtrSz); 330*0fca6ea1SDimitry Andric bool IsVec = SrcLLT.isVector(); 331*0fca6ea1SDimitry Andric if (IsVec) 332*0fca6ea1SDimitry Andric NewT = LLT::fixed_vector(2, NewT); 333*0fca6ea1SDimitry Andric if (PtrSz == 64) { 334*0fca6ea1SDimitry Andric if (IsVec) { 335*0fca6ea1SDimitry Andric GetIdOp = SPIRV::GET_vpID64; 336*0fca6ea1SDimitry Andric DstClass = &SPIRV::vpID64RegClass; 337*0fca6ea1SDimitry Andric } else { 338*0fca6ea1SDimitry Andric GetIdOp = SPIRV::GET_pID64; 339*0fca6ea1SDimitry Andric DstClass = &SPIRV::pID64RegClass; 340*0fca6ea1SDimitry Andric } 341*0fca6ea1SDimitry Andric } else { 342*0fca6ea1SDimitry Andric if (IsVec) { 343*0fca6ea1SDimitry Andric GetIdOp = SPIRV::GET_vpID32; 344*0fca6ea1SDimitry Andric DstClass = &SPIRV::vpID32RegClass; 345*0fca6ea1SDimitry Andric } else { 346*0fca6ea1SDimitry Andric GetIdOp = SPIRV::GET_pID32; 347*0fca6ea1SDimitry Andric DstClass = &SPIRV::pID32RegClass; 348*0fca6ea1SDimitry Andric } 349*0fca6ea1SDimitry Andric } 350*0fca6ea1SDimitry Andric } else if (SrcLLT.isVector()) { 351*0fca6ea1SDimitry Andric NewT = LLT::fixed_vector(2, NewT); 352*0fca6ea1SDimitry Andric if (IsFloat) { 353*0fca6ea1SDimitry Andric GetIdOp = SPIRV::GET_vfID; 354*0fca6ea1SDimitry Andric DstClass = &SPIRV::vfIDRegClass; 355*0fca6ea1SDimitry Andric } else { 356*0fca6ea1SDimitry Andric GetIdOp = SPIRV::GET_vID; 357*0fca6ea1SDimitry Andric DstClass = &SPIRV::vIDRegClass; 358*0fca6ea1SDimitry Andric } 359*0fca6ea1SDimitry Andric } 360*0fca6ea1SDimitry Andric Register IdReg = MRI.createGenericVirtualRegister(NewT); 361*0fca6ea1SDimitry Andric MRI.setRegClass(IdReg, DstClass); 362*0fca6ea1SDimitry Andric return {IdReg, GetIdOp}; 363*0fca6ea1SDimitry Andric } 364*0fca6ea1SDimitry Andric 36581ad6265SDimitry Andric // Insert ASSIGN_TYPE instuction between Reg and its definition, set NewReg as 36681ad6265SDimitry Andric // a dst of the definition, assign SPIRVType to both registers. If SpirvTy is 36781ad6265SDimitry Andric // provided, use it as SPIRVType in ASSIGN_TYPE, otherwise create it from Ty. 368bdd1243dSDimitry Andric // It's used also in SPIRVBuiltins.cpp. 36981ad6265SDimitry Andric // TODO: maybe move to SPIRVUtils. 370bdd1243dSDimitry Andric namespace llvm { 371bdd1243dSDimitry Andric Register insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy, 372bdd1243dSDimitry Andric SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, 37381ad6265SDimitry Andric MachineRegisterInfo &MRI) { 37481ad6265SDimitry Andric MachineInstr *Def = MRI.getVRegDef(Reg); 37581ad6265SDimitry Andric assert((Ty || SpirvTy) && "Either LLVM or SPIRV type is expected."); 37681ad6265SDimitry Andric MIB.setInsertPt(*Def->getParent(), 37781ad6265SDimitry Andric (Def->getNextNode() ? Def->getNextNode()->getIterator() 37881ad6265SDimitry Andric : Def->getParent()->end())); 379*0fca6ea1SDimitry Andric SpirvTy = SpirvTy ? SpirvTy : GR->getOrCreateSPIRVType(Ty, MIB); 38081ad6265SDimitry Andric Register NewReg = MRI.createGenericVirtualRegister(MRI.getType(Reg)); 38106c3fb27SDimitry Andric if (auto *RC = MRI.getRegClassOrNull(Reg)) { 38281ad6265SDimitry Andric MRI.setRegClass(NewReg, RC); 38306c3fb27SDimitry Andric } else { 38406c3fb27SDimitry Andric MRI.setRegClass(NewReg, &SPIRV::IDRegClass); 38506c3fb27SDimitry Andric MRI.setRegClass(Reg, &SPIRV::IDRegClass); 38606c3fb27SDimitry Andric } 38781ad6265SDimitry Andric GR->assignSPIRVTypeToVReg(SpirvTy, Reg, MIB.getMF()); 38881ad6265SDimitry Andric // This is to make it convenient for Legalizer to get the SPIRVType 38981ad6265SDimitry Andric // when processing the actual MI (i.e. not pseudo one). 39081ad6265SDimitry Andric GR->assignSPIRVTypeToVReg(SpirvTy, NewReg, MIB.getMF()); 391bdd1243dSDimitry Andric // Copy MIFlags from Def to ASSIGN_TYPE instruction. It's required to keep 392bdd1243dSDimitry Andric // the flags after instruction selection. 39306c3fb27SDimitry Andric const uint32_t Flags = Def->getFlags(); 39481ad6265SDimitry Andric MIB.buildInstr(SPIRV::ASSIGN_TYPE) 39581ad6265SDimitry Andric .addDef(Reg) 39681ad6265SDimitry Andric .addUse(NewReg) 397bdd1243dSDimitry Andric .addUse(GR->getSPIRVTypeID(SpirvTy)) 398bdd1243dSDimitry Andric .setMIFlags(Flags); 39981ad6265SDimitry Andric Def->getOperand(0).setReg(NewReg); 40081ad6265SDimitry Andric return NewReg; 40181ad6265SDimitry Andric } 402*0fca6ea1SDimitry Andric 403*0fca6ea1SDimitry Andric void processInstr(MachineInstr &MI, MachineIRBuilder &MIB, 404*0fca6ea1SDimitry Andric MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR) { 405*0fca6ea1SDimitry Andric assert(MI.getNumDefs() > 0 && MRI.hasOneUse(MI.getOperand(0).getReg())); 406*0fca6ea1SDimitry Andric MachineInstr &AssignTypeInst = 407*0fca6ea1SDimitry Andric *(MRI.use_instr_begin(MI.getOperand(0).getReg())); 408*0fca6ea1SDimitry Andric auto NewReg = 409*0fca6ea1SDimitry Andric createNewIdReg(nullptr, MI.getOperand(0).getReg(), MRI, *GR).first; 410*0fca6ea1SDimitry Andric AssignTypeInst.getOperand(1).setReg(NewReg); 411*0fca6ea1SDimitry Andric MI.getOperand(0).setReg(NewReg); 412*0fca6ea1SDimitry Andric MIB.setInsertPt(*MI.getParent(), 413*0fca6ea1SDimitry Andric (MI.getNextNode() ? MI.getNextNode()->getIterator() 414*0fca6ea1SDimitry Andric : MI.getParent()->end())); 415*0fca6ea1SDimitry Andric for (auto &Op : MI.operands()) { 416*0fca6ea1SDimitry Andric if (!Op.isReg() || Op.isDef()) 417*0fca6ea1SDimitry Andric continue; 418*0fca6ea1SDimitry Andric auto IdOpInfo = createNewIdReg(nullptr, Op.getReg(), MRI, *GR); 419*0fca6ea1SDimitry Andric MIB.buildInstr(IdOpInfo.second).addDef(IdOpInfo.first).addUse(Op.getReg()); 420*0fca6ea1SDimitry Andric Op.setReg(IdOpInfo.first); 421*0fca6ea1SDimitry Andric } 422*0fca6ea1SDimitry Andric } 423bdd1243dSDimitry Andric } // namespace llvm 42481ad6265SDimitry Andric 425*0fca6ea1SDimitry Andric static void 426*0fca6ea1SDimitry Andric generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR, 427*0fca6ea1SDimitry Andric MachineIRBuilder MIB, 428*0fca6ea1SDimitry Andric DenseMap<MachineInstr *, Type *> &TargetExtConstTypes) { 429*0fca6ea1SDimitry Andric // Get access to information about available extensions 430*0fca6ea1SDimitry Andric const SPIRVSubtarget *ST = 431*0fca6ea1SDimitry Andric static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget()); 432*0fca6ea1SDimitry Andric 43381ad6265SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 43481ad6265SDimitry Andric SmallVector<MachineInstr *, 10> ToErase; 435*0fca6ea1SDimitry Andric DenseMap<MachineInstr *, Register> RegsAlreadyAddedToDT; 43681ad6265SDimitry Andric 43781ad6265SDimitry Andric for (MachineBasicBlock *MBB : post_order(&MF)) { 43881ad6265SDimitry Andric if (MBB->empty()) 43981ad6265SDimitry Andric continue; 44081ad6265SDimitry Andric 44181ad6265SDimitry Andric bool ReachedBegin = false; 44281ad6265SDimitry Andric for (auto MII = std::prev(MBB->end()), Begin = MBB->begin(); 44381ad6265SDimitry Andric !ReachedBegin;) { 44481ad6265SDimitry Andric MachineInstr &MI = *MII; 445*0fca6ea1SDimitry Andric unsigned MIOp = MI.getOpcode(); 446*0fca6ea1SDimitry Andric 447*0fca6ea1SDimitry Andric // validate bit width of scalar registers 448*0fca6ea1SDimitry Andric for (const auto &MOP : MI.operands()) 449*0fca6ea1SDimitry Andric if (MOP.isReg()) 450*0fca6ea1SDimitry Andric widenScalarLLTNextPow2(MOP.getReg(), MRI); 45181ad6265SDimitry Andric 4525f757f3fSDimitry Andric if (isSpvIntrinsic(MI, Intrinsic::spv_assign_ptr_type)) { 4535f757f3fSDimitry Andric Register Reg = MI.getOperand(1).getReg(); 4545f757f3fSDimitry Andric MIB.setInsertPt(*MI.getParent(), MI.getIterator()); 455*0fca6ea1SDimitry Andric Type *ElementTy = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0); 456*0fca6ea1SDimitry Andric SPIRVType *BaseTy = GR->getOrCreateSPIRVType(ElementTy, MIB); 4575f757f3fSDimitry Andric SPIRVType *AssignedPtrType = GR->getOrCreateSPIRVPointerType( 4585f757f3fSDimitry Andric BaseTy, MI, *MF.getSubtarget<SPIRVSubtarget>().getInstrInfo(), 459*0fca6ea1SDimitry Andric addressSpaceToStorageClass(MI.getOperand(3).getImm(), *ST)); 4605f757f3fSDimitry Andric MachineInstr *Def = MRI.getVRegDef(Reg); 4615f757f3fSDimitry Andric assert(Def && "Expecting an instruction that defines the register"); 462*0fca6ea1SDimitry Andric // G_GLOBAL_VALUE already has type info. 463*0fca6ea1SDimitry Andric if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE && 464*0fca6ea1SDimitry Andric Def->getOpcode() != SPIRV::ASSIGN_TYPE) 4655f757f3fSDimitry Andric insertAssignInstr(Reg, nullptr, AssignedPtrType, GR, MIB, 4665f757f3fSDimitry Andric MF.getRegInfo()); 4675f757f3fSDimitry Andric ToErase.push_back(&MI); 4685f757f3fSDimitry Andric } else if (isSpvIntrinsic(MI, Intrinsic::spv_assign_type)) { 46981ad6265SDimitry Andric Register Reg = MI.getOperand(1).getReg(); 47081ad6265SDimitry Andric Type *Ty = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0); 47181ad6265SDimitry Andric MachineInstr *Def = MRI.getVRegDef(Reg); 47281ad6265SDimitry Andric assert(Def && "Expecting an instruction that defines the register"); 47381ad6265SDimitry Andric // G_GLOBAL_VALUE already has type info. 474*0fca6ea1SDimitry Andric if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE && 475*0fca6ea1SDimitry Andric Def->getOpcode() != SPIRV::ASSIGN_TYPE) 47681ad6265SDimitry Andric insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MF.getRegInfo()); 47781ad6265SDimitry Andric ToErase.push_back(&MI); 478*0fca6ea1SDimitry Andric } else if (MIOp == TargetOpcode::G_CONSTANT || 479*0fca6ea1SDimitry Andric MIOp == TargetOpcode::G_FCONSTANT || 480*0fca6ea1SDimitry Andric MIOp == TargetOpcode::G_BUILD_VECTOR) { 48181ad6265SDimitry Andric // %rc = G_CONSTANT ty Val 48281ad6265SDimitry Andric // ===> 48381ad6265SDimitry Andric // %cty = OpType* ty 48481ad6265SDimitry Andric // %rctmp = G_CONSTANT ty Val 48581ad6265SDimitry Andric // %rc = ASSIGN_TYPE %rctmp, %cty 48681ad6265SDimitry Andric Register Reg = MI.getOperand(0).getReg(); 487*0fca6ea1SDimitry Andric bool NeedAssignType = true; 48881ad6265SDimitry Andric if (MRI.hasOneUse(Reg)) { 48981ad6265SDimitry Andric MachineInstr &UseMI = *MRI.use_instr_begin(Reg); 49081ad6265SDimitry Andric if (isSpvIntrinsic(UseMI, Intrinsic::spv_assign_type) || 49181ad6265SDimitry Andric isSpvIntrinsic(UseMI, Intrinsic::spv_assign_name)) 49281ad6265SDimitry Andric continue; 49381ad6265SDimitry Andric } 49481ad6265SDimitry Andric Type *Ty = nullptr; 495*0fca6ea1SDimitry Andric if (MIOp == TargetOpcode::G_CONSTANT) { 496*0fca6ea1SDimitry Andric auto TargetExtIt = TargetExtConstTypes.find(&MI); 497*0fca6ea1SDimitry Andric Ty = TargetExtIt == TargetExtConstTypes.end() 498*0fca6ea1SDimitry Andric ? MI.getOperand(1).getCImm()->getType() 499*0fca6ea1SDimitry Andric : TargetExtIt->second; 500*0fca6ea1SDimitry Andric const ConstantInt *OpCI = MI.getOperand(1).getCImm(); 501*0fca6ea1SDimitry Andric Register PrimaryReg = GR->find(OpCI, &MF); 502*0fca6ea1SDimitry Andric if (!PrimaryReg.isValid()) { 503*0fca6ea1SDimitry Andric GR->add(OpCI, &MF, Reg); 504*0fca6ea1SDimitry Andric } else if (PrimaryReg != Reg && 505*0fca6ea1SDimitry Andric MRI.getType(Reg) == MRI.getType(PrimaryReg)) { 506*0fca6ea1SDimitry Andric auto *RCReg = MRI.getRegClassOrNull(Reg); 507*0fca6ea1SDimitry Andric auto *RCPrimary = MRI.getRegClassOrNull(PrimaryReg); 508*0fca6ea1SDimitry Andric if (!RCReg || RCPrimary == RCReg) { 509*0fca6ea1SDimitry Andric RegsAlreadyAddedToDT[&MI] = PrimaryReg; 510*0fca6ea1SDimitry Andric ToErase.push_back(&MI); 511*0fca6ea1SDimitry Andric NeedAssignType = false; 512*0fca6ea1SDimitry Andric } 513*0fca6ea1SDimitry Andric } 514*0fca6ea1SDimitry Andric } else if (MIOp == TargetOpcode::G_FCONSTANT) { 51581ad6265SDimitry Andric Ty = MI.getOperand(1).getFPImm()->getType(); 516*0fca6ea1SDimitry Andric } else { 517*0fca6ea1SDimitry Andric assert(MIOp == TargetOpcode::G_BUILD_VECTOR); 51881ad6265SDimitry Andric Type *ElemTy = nullptr; 51981ad6265SDimitry Andric MachineInstr *ElemMI = MRI.getVRegDef(MI.getOperand(1).getReg()); 52081ad6265SDimitry Andric assert(ElemMI); 52181ad6265SDimitry Andric 52281ad6265SDimitry Andric if (ElemMI->getOpcode() == TargetOpcode::G_CONSTANT) 52381ad6265SDimitry Andric ElemTy = ElemMI->getOperand(1).getCImm()->getType(); 52481ad6265SDimitry Andric else if (ElemMI->getOpcode() == TargetOpcode::G_FCONSTANT) 52581ad6265SDimitry Andric ElemTy = ElemMI->getOperand(1).getFPImm()->getType(); 52681ad6265SDimitry Andric else 52781ad6265SDimitry Andric llvm_unreachable("Unexpected opcode"); 52881ad6265SDimitry Andric unsigned NumElts = 52981ad6265SDimitry Andric MI.getNumExplicitOperands() - MI.getNumExplicitDefs(); 53081ad6265SDimitry Andric Ty = VectorType::get(ElemTy, NumElts, false); 53181ad6265SDimitry Andric } 532*0fca6ea1SDimitry Andric if (NeedAssignType) 53381ad6265SDimitry Andric insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MRI); 534*0fca6ea1SDimitry Andric } else if (MIOp == TargetOpcode::G_GLOBAL_VALUE) { 53581ad6265SDimitry Andric propagateSPIRVType(&MI, GR, MRI, MIB); 53681ad6265SDimitry Andric } 53781ad6265SDimitry Andric 53881ad6265SDimitry Andric if (MII == Begin) 53981ad6265SDimitry Andric ReachedBegin = true; 54081ad6265SDimitry Andric else 54181ad6265SDimitry Andric --MII; 54281ad6265SDimitry Andric } 54381ad6265SDimitry Andric } 544*0fca6ea1SDimitry Andric for (MachineInstr *MI : ToErase) { 545*0fca6ea1SDimitry Andric auto It = RegsAlreadyAddedToDT.find(MI); 546*0fca6ea1SDimitry Andric if (RegsAlreadyAddedToDT.contains(MI)) 547*0fca6ea1SDimitry Andric MRI.replaceRegWith(MI->getOperand(0).getReg(), It->second); 54881ad6265SDimitry Andric MI->eraseFromParent(); 54981ad6265SDimitry Andric } 55081ad6265SDimitry Andric 551*0fca6ea1SDimitry Andric // Address the case when IRTranslator introduces instructions with new 552*0fca6ea1SDimitry Andric // registers without SPIRVType associated. 553*0fca6ea1SDimitry Andric for (MachineBasicBlock &MBB : MF) { 554*0fca6ea1SDimitry Andric for (MachineInstr &MI : MBB) { 555*0fca6ea1SDimitry Andric switch (MI.getOpcode()) { 556*0fca6ea1SDimitry Andric case TargetOpcode::G_TRUNC: 557*0fca6ea1SDimitry Andric case TargetOpcode::G_ANYEXT: 558*0fca6ea1SDimitry Andric case TargetOpcode::G_SEXT: 559*0fca6ea1SDimitry Andric case TargetOpcode::G_ZEXT: 560*0fca6ea1SDimitry Andric case TargetOpcode::G_PTRTOINT: 561*0fca6ea1SDimitry Andric case TargetOpcode::COPY: 562*0fca6ea1SDimitry Andric case TargetOpcode::G_ADDRSPACE_CAST: 563*0fca6ea1SDimitry Andric propagateSPIRVType(&MI, GR, MRI, MIB); 564*0fca6ea1SDimitry Andric break; 56581ad6265SDimitry Andric } 56681ad6265SDimitry Andric } 56781ad6265SDimitry Andric } 56881ad6265SDimitry Andric } 56981ad6265SDimitry Andric 57081ad6265SDimitry Andric // Defined in SPIRVLegalizerInfo.cpp. 57181ad6265SDimitry Andric extern bool isTypeFoldingSupported(unsigned Opcode); 57281ad6265SDimitry Andric 57381ad6265SDimitry Andric static void processInstrsWithTypeFolding(MachineFunction &MF, 57481ad6265SDimitry Andric SPIRVGlobalRegistry *GR, 57581ad6265SDimitry Andric MachineIRBuilder MIB) { 57681ad6265SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 57781ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) { 57881ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 57981ad6265SDimitry Andric if (isTypeFoldingSupported(MI.getOpcode())) 58081ad6265SDimitry Andric processInstr(MI, MIB, MRI, GR); 58181ad6265SDimitry Andric } 58281ad6265SDimitry Andric } 583*0fca6ea1SDimitry Andric 584fcaf7f86SDimitry Andric for (MachineBasicBlock &MBB : MF) { 585fcaf7f86SDimitry Andric for (MachineInstr &MI : MBB) { 586fcaf7f86SDimitry Andric // We need to rewrite dst types for ASSIGN_TYPE instrs to be able 587fcaf7f86SDimitry Andric // to perform tblgen'erated selection and we can't do that on Legalizer 588fcaf7f86SDimitry Andric // as it operates on gMIR only. 589fcaf7f86SDimitry Andric if (MI.getOpcode() != SPIRV::ASSIGN_TYPE) 590fcaf7f86SDimitry Andric continue; 591fcaf7f86SDimitry Andric Register SrcReg = MI.getOperand(1).getReg(); 592bdd1243dSDimitry Andric unsigned Opcode = MRI.getVRegDef(SrcReg)->getOpcode(); 593bdd1243dSDimitry Andric if (!isTypeFoldingSupported(Opcode)) 594fcaf7f86SDimitry Andric continue; 595fcaf7f86SDimitry Andric Register DstReg = MI.getOperand(0).getReg(); 596*0fca6ea1SDimitry Andric bool IsDstPtr = MRI.getType(DstReg).isPointer(); 597*0fca6ea1SDimitry Andric bool isDstVec = MRI.getType(DstReg).isVector(); 598*0fca6ea1SDimitry Andric if (IsDstPtr || isDstVec) 599fcaf7f86SDimitry Andric MRI.setRegClass(DstReg, &SPIRV::IDRegClass); 600bdd1243dSDimitry Andric // Don't need to reset type of register holding constant and used in 601*0fca6ea1SDimitry Andric // G_ADDRSPACE_CAST, since it breaks legalizer. 602bdd1243dSDimitry Andric if (Opcode == TargetOpcode::G_CONSTANT && MRI.hasOneUse(DstReg)) { 603bdd1243dSDimitry Andric MachineInstr &UseMI = *MRI.use_instr_begin(DstReg); 604bdd1243dSDimitry Andric if (UseMI.getOpcode() == TargetOpcode::G_ADDRSPACE_CAST) 605bdd1243dSDimitry Andric continue; 606bdd1243dSDimitry Andric } 607*0fca6ea1SDimitry Andric MRI.setType(DstReg, IsDstPtr ? LLT::pointer(0, GR->getPointerSize()) 608*0fca6ea1SDimitry Andric : LLT::scalar(32)); 609fcaf7f86SDimitry Andric } 610fcaf7f86SDimitry Andric } 61181ad6265SDimitry Andric } 61281ad6265SDimitry Andric 613*0fca6ea1SDimitry Andric static void 614*0fca6ea1SDimitry Andric insertInlineAsmProcess(MachineFunction &MF, SPIRVGlobalRegistry *GR, 615*0fca6ea1SDimitry Andric const SPIRVSubtarget &ST, MachineIRBuilder MIRBuilder, 616*0fca6ea1SDimitry Andric const SmallVector<MachineInstr *> &ToProcess) { 617bdd1243dSDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 618*0fca6ea1SDimitry Andric Register AsmTargetReg; 619*0fca6ea1SDimitry Andric for (unsigned i = 0, Sz = ToProcess.size(); i + 1 < Sz; i += 2) { 620*0fca6ea1SDimitry Andric MachineInstr *I1 = ToProcess[i], *I2 = ToProcess[i + 1]; 621*0fca6ea1SDimitry Andric assert(isSpvIntrinsic(*I1, Intrinsic::spv_inline_asm) && I2->isInlineAsm()); 622*0fca6ea1SDimitry Andric MIRBuilder.setInsertPt(*I1->getParent(), *I1); 623bdd1243dSDimitry Andric 624*0fca6ea1SDimitry Andric if (!AsmTargetReg.isValid()) { 625*0fca6ea1SDimitry Andric // define vendor specific assembly target or dialect 626*0fca6ea1SDimitry Andric AsmTargetReg = MRI.createGenericVirtualRegister(LLT::scalar(32)); 627*0fca6ea1SDimitry Andric MRI.setRegClass(AsmTargetReg, &SPIRV::IDRegClass); 628*0fca6ea1SDimitry Andric auto AsmTargetMIB = 629*0fca6ea1SDimitry Andric MIRBuilder.buildInstr(SPIRV::OpAsmTargetINTEL).addDef(AsmTargetReg); 630*0fca6ea1SDimitry Andric addStringImm(ST.getTargetTripleAsStr(), AsmTargetMIB); 631*0fca6ea1SDimitry Andric GR->add(AsmTargetMIB.getInstr(), &MF, AsmTargetReg); 632*0fca6ea1SDimitry Andric } 633bdd1243dSDimitry Andric 634*0fca6ea1SDimitry Andric // create types 635*0fca6ea1SDimitry Andric const MDNode *IAMD = I1->getOperand(1).getMetadata(); 636*0fca6ea1SDimitry Andric FunctionType *FTy = cast<FunctionType>(getMDOperandAsType(IAMD, 0)); 637*0fca6ea1SDimitry Andric SmallVector<SPIRVType *, 4> ArgTypes; 638*0fca6ea1SDimitry Andric for (const auto &ArgTy : FTy->params()) 639*0fca6ea1SDimitry Andric ArgTypes.push_back(GR->getOrCreateSPIRVType(ArgTy, MIRBuilder)); 640*0fca6ea1SDimitry Andric SPIRVType *RetType = 641*0fca6ea1SDimitry Andric GR->getOrCreateSPIRVType(FTy->getReturnType(), MIRBuilder); 642*0fca6ea1SDimitry Andric SPIRVType *FuncType = GR->getOrCreateOpTypeFunctionWithArgs( 643*0fca6ea1SDimitry Andric FTy, RetType, ArgTypes, MIRBuilder); 64406c3fb27SDimitry Andric 645*0fca6ea1SDimitry Andric // define vendor specific assembly instructions string 646*0fca6ea1SDimitry Andric Register AsmReg = MRI.createGenericVirtualRegister(LLT::scalar(32)); 647*0fca6ea1SDimitry Andric MRI.setRegClass(AsmReg, &SPIRV::IDRegClass); 648*0fca6ea1SDimitry Andric auto AsmMIB = MIRBuilder.buildInstr(SPIRV::OpAsmINTEL) 649*0fca6ea1SDimitry Andric .addDef(AsmReg) 650*0fca6ea1SDimitry Andric .addUse(GR->getSPIRVTypeID(RetType)) 651*0fca6ea1SDimitry Andric .addUse(GR->getSPIRVTypeID(FuncType)) 652*0fca6ea1SDimitry Andric .addUse(AsmTargetReg); 653*0fca6ea1SDimitry Andric // inline asm string: 654*0fca6ea1SDimitry Andric addStringImm(I2->getOperand(InlineAsm::MIOp_AsmString).getSymbolName(), 655*0fca6ea1SDimitry Andric AsmMIB); 656*0fca6ea1SDimitry Andric // inline asm constraint string: 657*0fca6ea1SDimitry Andric addStringImm(cast<MDString>(I1->getOperand(2).getMetadata()->getOperand(0)) 658*0fca6ea1SDimitry Andric ->getString(), 659*0fca6ea1SDimitry Andric AsmMIB); 660*0fca6ea1SDimitry Andric GR->add(AsmMIB.getInstr(), &MF, AsmReg); 661*0fca6ea1SDimitry Andric 662*0fca6ea1SDimitry Andric // calls the inline assembly instruction 663*0fca6ea1SDimitry Andric unsigned ExtraInfo = I2->getOperand(InlineAsm::MIOp_ExtraInfo).getImm(); 664*0fca6ea1SDimitry Andric if (ExtraInfo & InlineAsm::Extra_HasSideEffects) 665*0fca6ea1SDimitry Andric MIRBuilder.buildInstr(SPIRV::OpDecorate) 666*0fca6ea1SDimitry Andric .addUse(AsmReg) 667*0fca6ea1SDimitry Andric .addImm(static_cast<uint32_t>(SPIRV::Decoration::SideEffectsINTEL)); 668*0fca6ea1SDimitry Andric Register DefReg; 669*0fca6ea1SDimitry Andric SmallVector<unsigned, 4> Ops; 670*0fca6ea1SDimitry Andric unsigned StartOp = InlineAsm::MIOp_FirstOperand, 671*0fca6ea1SDimitry Andric AsmDescOp = InlineAsm::MIOp_FirstOperand; 672*0fca6ea1SDimitry Andric unsigned I2Sz = I2->getNumOperands(); 673*0fca6ea1SDimitry Andric for (unsigned Idx = StartOp; Idx != I2Sz; ++Idx) { 674*0fca6ea1SDimitry Andric const MachineOperand &MO = I2->getOperand(Idx); 675*0fca6ea1SDimitry Andric if (MO.isMetadata()) 676*0fca6ea1SDimitry Andric continue; 677*0fca6ea1SDimitry Andric if (Idx == AsmDescOp && MO.isImm()) { 678*0fca6ea1SDimitry Andric // compute the index of the next operand descriptor 679*0fca6ea1SDimitry Andric const InlineAsm::Flag F(MO.getImm()); 680*0fca6ea1SDimitry Andric AsmDescOp += 1 + F.getNumOperandRegisters(); 681*0fca6ea1SDimitry Andric } else { 682*0fca6ea1SDimitry Andric if (MO.isReg() && MO.isDef()) 683*0fca6ea1SDimitry Andric DefReg = MO.getReg(); 684*0fca6ea1SDimitry Andric else 685*0fca6ea1SDimitry Andric Ops.push_back(Idx); 686*0fca6ea1SDimitry Andric } 687*0fca6ea1SDimitry Andric } 688*0fca6ea1SDimitry Andric if (!DefReg.isValid()) { 689*0fca6ea1SDimitry Andric DefReg = MRI.createGenericVirtualRegister(LLT::scalar(32)); 690*0fca6ea1SDimitry Andric MRI.setRegClass(DefReg, &SPIRV::IDRegClass); 691*0fca6ea1SDimitry Andric SPIRVType *VoidType = GR->getOrCreateSPIRVType( 692*0fca6ea1SDimitry Andric Type::getVoidTy(MF.getFunction().getContext()), MIRBuilder); 693*0fca6ea1SDimitry Andric GR->assignSPIRVTypeToVReg(VoidType, DefReg, MF); 694*0fca6ea1SDimitry Andric } 695*0fca6ea1SDimitry Andric auto AsmCall = MIRBuilder.buildInstr(SPIRV::OpAsmCallINTEL) 696*0fca6ea1SDimitry Andric .addDef(DefReg) 697*0fca6ea1SDimitry Andric .addUse(GR->getSPIRVTypeID(RetType)) 698*0fca6ea1SDimitry Andric .addUse(AsmReg); 699*0fca6ea1SDimitry Andric unsigned IntrIdx = 2; 700*0fca6ea1SDimitry Andric for (unsigned Idx : Ops) { 701*0fca6ea1SDimitry Andric ++IntrIdx; 702*0fca6ea1SDimitry Andric const MachineOperand &MO = I2->getOperand(Idx); 703*0fca6ea1SDimitry Andric if (MO.isReg()) 704*0fca6ea1SDimitry Andric AsmCall.addUse(MO.getReg()); 705*0fca6ea1SDimitry Andric else 706*0fca6ea1SDimitry Andric AsmCall.addUse(I1->getOperand(IntrIdx).getReg()); 707*0fca6ea1SDimitry Andric } 708*0fca6ea1SDimitry Andric } 709*0fca6ea1SDimitry Andric for (MachineInstr *MI : ToProcess) 710*0fca6ea1SDimitry Andric MI->eraseFromParent(); 711*0fca6ea1SDimitry Andric } 712*0fca6ea1SDimitry Andric 713*0fca6ea1SDimitry Andric static void insertInlineAsm(MachineFunction &MF, SPIRVGlobalRegistry *GR, 714*0fca6ea1SDimitry Andric const SPIRVSubtarget &ST, 715*0fca6ea1SDimitry Andric MachineIRBuilder MIRBuilder) { 716*0fca6ea1SDimitry Andric SmallVector<MachineInstr *> ToProcess; 71781ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) { 71881ad6265SDimitry Andric for (MachineInstr &MI : MBB) { 719*0fca6ea1SDimitry Andric if (isSpvIntrinsic(MI, Intrinsic::spv_inline_asm) || 720*0fca6ea1SDimitry Andric MI.getOpcode() == TargetOpcode::INLINEASM) 721*0fca6ea1SDimitry Andric ToProcess.push_back(&MI); 722*0fca6ea1SDimitry Andric } 723*0fca6ea1SDimitry Andric } 724*0fca6ea1SDimitry Andric if (ToProcess.size() == 0) 725*0fca6ea1SDimitry Andric return; 726*0fca6ea1SDimitry Andric 727*0fca6ea1SDimitry Andric if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_inline_assembly)) 728*0fca6ea1SDimitry Andric report_fatal_error("Inline assembly instructions require the " 729*0fca6ea1SDimitry Andric "following SPIR-V extension: SPV_INTEL_inline_assembly", 730*0fca6ea1SDimitry Andric false); 731*0fca6ea1SDimitry Andric 732*0fca6ea1SDimitry Andric insertInlineAsmProcess(MF, GR, ST, MIRBuilder, ToProcess); 73381ad6265SDimitry Andric } 734bdd1243dSDimitry Andric 735*0fca6ea1SDimitry Andric static void insertSpirvDecorations(MachineFunction &MF, MachineIRBuilder MIB) { 736*0fca6ea1SDimitry Andric SmallVector<MachineInstr *, 10> ToErase; 737*0fca6ea1SDimitry Andric for (MachineBasicBlock &MBB : MF) { 738*0fca6ea1SDimitry Andric for (MachineInstr &MI : MBB) { 739*0fca6ea1SDimitry Andric if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration)) 740bdd1243dSDimitry Andric continue; 741*0fca6ea1SDimitry Andric MIB.setInsertPt(*MI.getParent(), MI); 742*0fca6ea1SDimitry Andric buildOpSpirvDecorations(MI.getOperand(1).getReg(), MIB, 743*0fca6ea1SDimitry Andric MI.getOperand(2).getMetadata()); 744*0fca6ea1SDimitry Andric ToErase.push_back(&MI); 74506c3fb27SDimitry Andric } 74681ad6265SDimitry Andric } 747*0fca6ea1SDimitry Andric for (MachineInstr *MI : ToErase) 74806c3fb27SDimitry Andric MI->eraseFromParent(); 74906c3fb27SDimitry Andric } 750*0fca6ea1SDimitry Andric 751*0fca6ea1SDimitry Andric // Find basic blocks of the switch and replace registers in spv_switch() by its 752*0fca6ea1SDimitry Andric // MBB equivalent. 753*0fca6ea1SDimitry Andric static void processSwitches(MachineFunction &MF, SPIRVGlobalRegistry *GR, 754*0fca6ea1SDimitry Andric MachineIRBuilder MIB) { 755*0fca6ea1SDimitry Andric DenseMap<const BasicBlock *, MachineBasicBlock *> BB2MBB; 756*0fca6ea1SDimitry Andric SmallVector<std::pair<MachineInstr *, SmallVector<MachineInstr *, 8>>> 757*0fca6ea1SDimitry Andric Switches; 758*0fca6ea1SDimitry Andric for (MachineBasicBlock &MBB : MF) { 759*0fca6ea1SDimitry Andric MachineRegisterInfo &MRI = MF.getRegInfo(); 760*0fca6ea1SDimitry Andric BB2MBB[MBB.getBasicBlock()] = &MBB; 761*0fca6ea1SDimitry Andric for (MachineInstr &MI : MBB) { 762*0fca6ea1SDimitry Andric if (!isSpvIntrinsic(MI, Intrinsic::spv_switch)) 763*0fca6ea1SDimitry Andric continue; 764*0fca6ea1SDimitry Andric // Calls to spv_switch intrinsics representing IR switches. 765*0fca6ea1SDimitry Andric SmallVector<MachineInstr *, 8> NewOps; 766*0fca6ea1SDimitry Andric for (unsigned i = 2; i < MI.getNumOperands(); ++i) { 767*0fca6ea1SDimitry Andric Register Reg = MI.getOperand(i).getReg(); 768*0fca6ea1SDimitry Andric if (i % 2 == 1) { 769*0fca6ea1SDimitry Andric MachineInstr *ConstInstr = getDefInstrMaybeConstant(Reg, &MRI); 770*0fca6ea1SDimitry Andric NewOps.push_back(ConstInstr); 771*0fca6ea1SDimitry Andric } else { 772*0fca6ea1SDimitry Andric MachineInstr *BuildMBB = MRI.getVRegDef(Reg); 773*0fca6ea1SDimitry Andric assert(BuildMBB && 774*0fca6ea1SDimitry Andric BuildMBB->getOpcode() == TargetOpcode::G_BLOCK_ADDR && 775*0fca6ea1SDimitry Andric BuildMBB->getOperand(1).isBlockAddress() && 776*0fca6ea1SDimitry Andric BuildMBB->getOperand(1).getBlockAddress()); 777*0fca6ea1SDimitry Andric NewOps.push_back(BuildMBB); 778*0fca6ea1SDimitry Andric } 779*0fca6ea1SDimitry Andric } 780*0fca6ea1SDimitry Andric Switches.push_back(std::make_pair(&MI, NewOps)); 781*0fca6ea1SDimitry Andric } 782*0fca6ea1SDimitry Andric } 783*0fca6ea1SDimitry Andric 784*0fca6ea1SDimitry Andric SmallPtrSet<MachineInstr *, 8> ToEraseMI; 785*0fca6ea1SDimitry Andric for (auto &SwIt : Switches) { 786*0fca6ea1SDimitry Andric MachineInstr &MI = *SwIt.first; 787*0fca6ea1SDimitry Andric SmallVector<MachineInstr *, 8> &Ins = SwIt.second; 788*0fca6ea1SDimitry Andric SmallVector<MachineOperand, 8> NewOps; 789*0fca6ea1SDimitry Andric for (unsigned i = 0; i < Ins.size(); ++i) { 790*0fca6ea1SDimitry Andric if (Ins[i]->getOpcode() == TargetOpcode::G_BLOCK_ADDR) { 791*0fca6ea1SDimitry Andric BasicBlock *CaseBB = 792*0fca6ea1SDimitry Andric Ins[i]->getOperand(1).getBlockAddress()->getBasicBlock(); 793*0fca6ea1SDimitry Andric auto It = BB2MBB.find(CaseBB); 794*0fca6ea1SDimitry Andric if (It == BB2MBB.end()) 795*0fca6ea1SDimitry Andric report_fatal_error("cannot find a machine basic block by a basic " 796*0fca6ea1SDimitry Andric "block in a switch statement"); 797*0fca6ea1SDimitry Andric NewOps.push_back(MachineOperand::CreateMBB(It->second)); 798*0fca6ea1SDimitry Andric MI.getParent()->addSuccessor(It->second); 799*0fca6ea1SDimitry Andric ToEraseMI.insert(Ins[i]); 800*0fca6ea1SDimitry Andric } else { 801*0fca6ea1SDimitry Andric NewOps.push_back( 802*0fca6ea1SDimitry Andric MachineOperand::CreateCImm(Ins[i]->getOperand(1).getCImm())); 803*0fca6ea1SDimitry Andric } 804*0fca6ea1SDimitry Andric } 805*0fca6ea1SDimitry Andric for (unsigned i = MI.getNumOperands() - 1; i > 1; --i) 806*0fca6ea1SDimitry Andric MI.removeOperand(i); 807*0fca6ea1SDimitry Andric for (auto &MO : NewOps) 808*0fca6ea1SDimitry Andric MI.addOperand(MO); 809*0fca6ea1SDimitry Andric if (MachineInstr *Next = MI.getNextNode()) { 810*0fca6ea1SDimitry Andric if (isSpvIntrinsic(*Next, Intrinsic::spv_track_constant)) { 811*0fca6ea1SDimitry Andric ToEraseMI.insert(Next); 812*0fca6ea1SDimitry Andric Next = MI.getNextNode(); 813*0fca6ea1SDimitry Andric } 814*0fca6ea1SDimitry Andric if (Next && Next->getOpcode() == TargetOpcode::G_BRINDIRECT) 815*0fca6ea1SDimitry Andric ToEraseMI.insert(Next); 816*0fca6ea1SDimitry Andric } 817*0fca6ea1SDimitry Andric } 818*0fca6ea1SDimitry Andric 819*0fca6ea1SDimitry Andric // If we just delete G_BLOCK_ADDR instructions with BlockAddress operands, 820*0fca6ea1SDimitry Andric // this leaves their BasicBlock counterparts in a "address taken" status. This 821*0fca6ea1SDimitry Andric // would make AsmPrinter to generate a series of unneeded labels of a "Address 822*0fca6ea1SDimitry Andric // of block that was removed by CodeGen" kind. Let's first ensure that we 823*0fca6ea1SDimitry Andric // don't have a dangling BlockAddress constants by zapping the BlockAddress 824*0fca6ea1SDimitry Andric // nodes, and only after that proceed with erasing G_BLOCK_ADDR instructions. 825*0fca6ea1SDimitry Andric Constant *Replacement = 826*0fca6ea1SDimitry Andric ConstantInt::get(Type::getInt32Ty(MF.getFunction().getContext()), 1); 827*0fca6ea1SDimitry Andric for (MachineInstr *BlockAddrI : ToEraseMI) { 828*0fca6ea1SDimitry Andric if (BlockAddrI->getOpcode() == TargetOpcode::G_BLOCK_ADDR) { 829*0fca6ea1SDimitry Andric BlockAddress *BA = const_cast<BlockAddress *>( 830*0fca6ea1SDimitry Andric BlockAddrI->getOperand(1).getBlockAddress()); 831*0fca6ea1SDimitry Andric BA->replaceAllUsesWith( 832*0fca6ea1SDimitry Andric ConstantExpr::getIntToPtr(Replacement, BA->getType())); 833*0fca6ea1SDimitry Andric BA->destroyConstant(); 834*0fca6ea1SDimitry Andric } 835*0fca6ea1SDimitry Andric BlockAddrI->eraseFromParent(); 83606c3fb27SDimitry Andric } 83781ad6265SDimitry Andric } 83881ad6265SDimitry Andric 8391db9f3b2SDimitry Andric static bool isImplicitFallthrough(MachineBasicBlock &MBB) { 8401db9f3b2SDimitry Andric if (MBB.empty()) 8411db9f3b2SDimitry Andric return true; 8421db9f3b2SDimitry Andric 8431db9f3b2SDimitry Andric // Branching SPIR-V intrinsics are not detected by this generic method. 8441db9f3b2SDimitry Andric // Thus, we can only trust negative result. 8451db9f3b2SDimitry Andric if (!MBB.canFallThrough()) 8461db9f3b2SDimitry Andric return false; 8471db9f3b2SDimitry Andric 8481db9f3b2SDimitry Andric // Otherwise, we must manually check if we have a SPIR-V intrinsic which 8491db9f3b2SDimitry Andric // prevent an implicit fallthrough. 8501db9f3b2SDimitry Andric for (MachineBasicBlock::reverse_iterator It = MBB.rbegin(), E = MBB.rend(); 8511db9f3b2SDimitry Andric It != E; ++It) { 8521db9f3b2SDimitry Andric if (isSpvIntrinsic(*It, Intrinsic::spv_switch)) 8531db9f3b2SDimitry Andric return false; 8541db9f3b2SDimitry Andric } 8551db9f3b2SDimitry Andric return true; 8561db9f3b2SDimitry Andric } 8571db9f3b2SDimitry Andric 8581db9f3b2SDimitry Andric static void removeImplicitFallthroughs(MachineFunction &MF, 8591db9f3b2SDimitry Andric MachineIRBuilder MIB) { 8601db9f3b2SDimitry Andric // It is valid for MachineBasicBlocks to not finish with a branch instruction. 8611db9f3b2SDimitry Andric // In such cases, they will simply fallthrough their immediate successor. 8621db9f3b2SDimitry Andric for (MachineBasicBlock &MBB : MF) { 8631db9f3b2SDimitry Andric if (!isImplicitFallthrough(MBB)) 8641db9f3b2SDimitry Andric continue; 8651db9f3b2SDimitry Andric 8661db9f3b2SDimitry Andric assert(std::distance(MBB.successors().begin(), MBB.successors().end()) == 8671db9f3b2SDimitry Andric 1); 8681db9f3b2SDimitry Andric MIB.setInsertPt(MBB, MBB.end()); 8691db9f3b2SDimitry Andric MIB.buildBr(**MBB.successors().begin()); 8701db9f3b2SDimitry Andric } 8711db9f3b2SDimitry Andric } 8721db9f3b2SDimitry Andric 87381ad6265SDimitry Andric bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) { 87481ad6265SDimitry Andric // Initialize the type registry. 87581ad6265SDimitry Andric const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>(); 87681ad6265SDimitry Andric SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry(); 87781ad6265SDimitry Andric GR->setCurrentFunc(MF); 87881ad6265SDimitry Andric MachineIRBuilder MIB(MF); 879*0fca6ea1SDimitry Andric // a registry of target extension constants 880*0fca6ea1SDimitry Andric DenseMap<MachineInstr *, Type *> TargetExtConstTypes; 881*0fca6ea1SDimitry Andric // to keep record of tracked constants 882*0fca6ea1SDimitry Andric SmallSet<Register, 4> TrackedConstRegs; 883*0fca6ea1SDimitry Andric addConstantsToTrack(MF, GR, ST, TargetExtConstTypes, TrackedConstRegs); 884*0fca6ea1SDimitry Andric foldConstantsIntoIntrinsics(MF, TrackedConstRegs); 88581ad6265SDimitry Andric insertBitcasts(MF, GR, MIB); 886*0fca6ea1SDimitry Andric generateAssignInstrs(MF, GR, MIB, TargetExtConstTypes); 88781ad6265SDimitry Andric processSwitches(MF, GR, MIB); 888bdd1243dSDimitry Andric processInstrsWithTypeFolding(MF, GR, MIB); 8891db9f3b2SDimitry Andric removeImplicitFallthroughs(MF, MIB); 890*0fca6ea1SDimitry Andric insertSpirvDecorations(MF, MIB); 891*0fca6ea1SDimitry Andric insertInlineAsm(MF, GR, ST, MIB); 89281ad6265SDimitry Andric 89381ad6265SDimitry Andric return true; 89481ad6265SDimitry Andric } 89581ad6265SDimitry Andric 89681ad6265SDimitry Andric INITIALIZE_PASS(SPIRVPreLegalizer, DEBUG_TYPE, "SPIRV pre legalizer", false, 89781ad6265SDimitry Andric false) 89881ad6265SDimitry Andric 89981ad6265SDimitry Andric char SPIRVPreLegalizer::ID = 0; 90081ad6265SDimitry Andric 90181ad6265SDimitry Andric FunctionPass *llvm::createSPIRVPreLegalizerPass() { 90281ad6265SDimitry Andric return new SPIRVPreLegalizer(); 90381ad6265SDimitry Andric } 904