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