xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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