xref: /llvm-project/llvm/lib/Target/SPIRV/SPIRVPreLegalizer.cpp (revision eddeb36cf1ced0e14e17ac90f60922366e382100)
10098f2aeSIlia Diachkov //===-- SPIRVPreLegalizer.cpp - prepare IR for legalization -----*- C++ -*-===//
20098f2aeSIlia Diachkov //
30098f2aeSIlia Diachkov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40098f2aeSIlia Diachkov // See https://llvm.org/LICENSE.txt for license information.
50098f2aeSIlia Diachkov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60098f2aeSIlia Diachkov //
70098f2aeSIlia Diachkov //===----------------------------------------------------------------------===//
80098f2aeSIlia Diachkov //
90098f2aeSIlia Diachkov // The pass prepares IR for legalization: it assigns SPIR-V types to registers
100098f2aeSIlia Diachkov // and removes intrinsics which holded these types during IR translation.
110098f2aeSIlia Diachkov // Also it processes constants and registers them in GR to avoid duplication.
120098f2aeSIlia Diachkov //
130098f2aeSIlia Diachkov //===----------------------------------------------------------------------===//
140098f2aeSIlia Diachkov 
150098f2aeSIlia Diachkov #include "SPIRV.h"
160098f2aeSIlia Diachkov #include "SPIRVSubtarget.h"
170098f2aeSIlia Diachkov #include "SPIRVUtils.h"
180098f2aeSIlia Diachkov #include "llvm/ADT/PostOrderIterator.h"
190098f2aeSIlia Diachkov #include "llvm/Analysis/OptimizationRemarkEmitter.h"
20*eddeb36cSFarzon Lotfi #include "llvm/CodeGen/GlobalISel/CSEInfo.h"
21*eddeb36cSFarzon Lotfi #include "llvm/CodeGen/GlobalISel/GISelKnownBits.h"
220098f2aeSIlia Diachkov #include "llvm/IR/Attributes.h"
230098f2aeSIlia Diachkov #include "llvm/IR/Constants.h"
240098f2aeSIlia Diachkov #include "llvm/IR/DebugInfoMetadata.h"
250098f2aeSIlia Diachkov #include "llvm/IR/IntrinsicsSPIRV.h"
260098f2aeSIlia Diachkov #include "llvm/Target/TargetIntrinsicInfo.h"
270098f2aeSIlia Diachkov 
280098f2aeSIlia Diachkov #define DEBUG_TYPE "spirv-prelegalizer"
290098f2aeSIlia Diachkov 
300098f2aeSIlia Diachkov using namespace llvm;
310098f2aeSIlia Diachkov 
320098f2aeSIlia Diachkov namespace {
330098f2aeSIlia Diachkov class SPIRVPreLegalizer : public MachineFunctionPass {
340098f2aeSIlia Diachkov public:
350098f2aeSIlia Diachkov   static char ID;
360098f2aeSIlia Diachkov   SPIRVPreLegalizer() : MachineFunctionPass(ID) {
370098f2aeSIlia Diachkov     initializeSPIRVPreLegalizerPass(*PassRegistry::getPassRegistry());
380098f2aeSIlia Diachkov   }
390098f2aeSIlia Diachkov   bool runOnMachineFunction(MachineFunction &MF) override;
40*eddeb36cSFarzon Lotfi   void getAnalysisUsage(AnalysisUsage &AU) const override;
410098f2aeSIlia Diachkov };
420098f2aeSIlia Diachkov } // namespace
430098f2aeSIlia Diachkov 
44*eddeb36cSFarzon Lotfi void SPIRVPreLegalizer::getAnalysisUsage(AnalysisUsage &AU) const {
45*eddeb36cSFarzon Lotfi   AU.addPreserved<GISelKnownBitsAnalysis>();
46*eddeb36cSFarzon Lotfi   MachineFunctionPass::getAnalysisUsage(AU);
47*eddeb36cSFarzon Lotfi }
48*eddeb36cSFarzon Lotfi 
491ed1ec9aSVyacheslav Levytskyy static void
501ed1ec9aSVyacheslav Levytskyy addConstantsToTrack(MachineFunction &MF, SPIRVGlobalRegistry *GR,
517c917e82SVyacheslav Levytskyy                     const SPIRVSubtarget &STI,
529c29217aSVyacheslav Levytskyy                     DenseMap<MachineInstr *, Type *> &TargetExtConstTypes,
539c29217aSVyacheslav Levytskyy                     SmallSet<Register, 4> &TrackedConstRegs) {
54b8e1544bSIlia Diachkov   MachineRegisterInfo &MRI = MF.getRegInfo();
55b8e1544bSIlia Diachkov   DenseMap<MachineInstr *, Register> RegsAlreadyAddedToDT;
56b8e1544bSIlia Diachkov   SmallVector<MachineInstr *, 10> ToErase, ToEraseComposites;
57b8e1544bSIlia Diachkov   for (MachineBasicBlock &MBB : MF) {
58b8e1544bSIlia Diachkov     for (MachineInstr &MI : MBB) {
59b8e1544bSIlia Diachkov       if (!isSpvIntrinsic(MI, Intrinsic::spv_track_constant))
60b8e1544bSIlia Diachkov         continue;
61b8e1544bSIlia Diachkov       ToErase.push_back(&MI);
621ed1ec9aSVyacheslav Levytskyy       Register SrcReg = MI.getOperand(2).getReg();
63b8e1544bSIlia Diachkov       auto *Const =
64b8e1544bSIlia Diachkov           cast<Constant>(cast<ConstantAsMetadata>(
65b8e1544bSIlia Diachkov                              MI.getOperand(3).getMetadata()->getOperand(0))
66b8e1544bSIlia Diachkov                              ->getValue());
67b8e1544bSIlia Diachkov       if (auto *GV = dyn_cast<GlobalValue>(Const)) {
68b8e1544bSIlia Diachkov         Register Reg = GR->find(GV, &MF);
6983c1d003SVyacheslav Levytskyy         if (!Reg.isValid()) {
701ed1ec9aSVyacheslav Levytskyy           GR->add(GV, &MF, SrcReg);
7183c1d003SVyacheslav Levytskyy           GR->addGlobalObject(GV, &MF, SrcReg);
7283c1d003SVyacheslav Levytskyy         } else
73b8e1544bSIlia Diachkov           RegsAlreadyAddedToDT[&MI] = Reg;
74b8e1544bSIlia Diachkov       } else {
75b8e1544bSIlia Diachkov         Register Reg = GR->find(Const, &MF);
76b8e1544bSIlia Diachkov         if (!Reg.isValid()) {
77b8e1544bSIlia Diachkov           if (auto *ConstVec = dyn_cast<ConstantDataVector>(Const)) {
781ed1ec9aSVyacheslav Levytskyy             auto *BuildVec = MRI.getVRegDef(SrcReg);
79b8e1544bSIlia Diachkov             assert(BuildVec &&
80b8e1544bSIlia Diachkov                    BuildVec->getOpcode() == TargetOpcode::G_BUILD_VECTOR);
81f7680835SVyacheslav Levytskyy             for (unsigned i = 0; i < ConstVec->getNumElements(); ++i) {
82f7680835SVyacheslav Levytskyy               // Ensure that OpConstantComposite reuses a constant when it's
83f7680835SVyacheslav Levytskyy               // already created and available in the same machine function.
84f7680835SVyacheslav Levytskyy               Constant *ElemConst = ConstVec->getElementAsConstant(i);
85f7680835SVyacheslav Levytskyy               Register ElemReg = GR->find(ElemConst, &MF);
86f7680835SVyacheslav Levytskyy               if (!ElemReg.isValid())
87f7680835SVyacheslav Levytskyy                 GR->add(ElemConst, &MF, BuildVec->getOperand(1 + i).getReg());
88f7680835SVyacheslav Levytskyy               else
89f7680835SVyacheslav Levytskyy                 BuildVec->getOperand(1 + i).setReg(ElemReg);
90f7680835SVyacheslav Levytskyy             }
91b8e1544bSIlia Diachkov           }
921ed1ec9aSVyacheslav Levytskyy           GR->add(Const, &MF, SrcReg);
939c29217aSVyacheslav Levytskyy           TrackedConstRegs.insert(SrcReg);
941ed1ec9aSVyacheslav Levytskyy           if (Const->getType()->isTargetExtTy()) {
951ed1ec9aSVyacheslav Levytskyy             // remember association so that we can restore it when assign types
961ed1ec9aSVyacheslav Levytskyy             MachineInstr *SrcMI = MRI.getVRegDef(SrcReg);
977c917e82SVyacheslav Levytskyy             if (SrcMI && (SrcMI->getOpcode() == TargetOpcode::G_CONSTANT ||
987c917e82SVyacheslav Levytskyy                           SrcMI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF))
991ed1ec9aSVyacheslav Levytskyy               TargetExtConstTypes[SrcMI] = Const->getType();
1007c917e82SVyacheslav Levytskyy             if (Const->isNullValue()) {
1017c917e82SVyacheslav Levytskyy               MachineIRBuilder MIB(MF);
1027c917e82SVyacheslav Levytskyy               SPIRVType *ExtType =
1037c917e82SVyacheslav Levytskyy                   GR->getOrCreateSPIRVType(Const->getType(), MIB);
1047c917e82SVyacheslav Levytskyy               SrcMI->setDesc(STI.getInstrInfo()->get(SPIRV::OpConstantNull));
1057c917e82SVyacheslav Levytskyy               SrcMI->addOperand(MachineOperand::CreateReg(
1067c917e82SVyacheslav Levytskyy                   GR->getSPIRVTypeID(ExtType), false));
1077c917e82SVyacheslav Levytskyy             }
1081ed1ec9aSVyacheslav Levytskyy           }
109b8e1544bSIlia Diachkov         } else {
110b8e1544bSIlia Diachkov           RegsAlreadyAddedToDT[&MI] = Reg;
111b8e1544bSIlia Diachkov           // This MI is unused and will be removed. If the MI uses
112b8e1544bSIlia Diachkov           // const_composite, it will be unused and should be removed too.
113b8e1544bSIlia Diachkov           assert(MI.getOperand(2).isReg() && "Reg operand is expected");
114b8e1544bSIlia Diachkov           MachineInstr *SrcMI = MRI.getVRegDef(MI.getOperand(2).getReg());
115b8e1544bSIlia Diachkov           if (SrcMI && isSpvIntrinsic(*SrcMI, Intrinsic::spv_const_composite))
116b8e1544bSIlia Diachkov             ToEraseComposites.push_back(SrcMI);
117b8e1544bSIlia Diachkov         }
118b8e1544bSIlia Diachkov       }
119b8e1544bSIlia Diachkov     }
120b8e1544bSIlia Diachkov   }
121b8e1544bSIlia Diachkov   for (MachineInstr *MI : ToErase) {
122b8e1544bSIlia Diachkov     Register Reg = MI->getOperand(2).getReg();
123e01c0636SKazu Hirata     if (RegsAlreadyAddedToDT.contains(MI))
124b8e1544bSIlia Diachkov       Reg = RegsAlreadyAddedToDT[MI];
12574c66710SIlia Diachkov     auto *RC = MRI.getRegClassOrNull(MI->getOperand(0).getReg());
12674c66710SIlia Diachkov     if (!MRI.getRegClassOrNull(Reg) && RC)
12774c66710SIlia Diachkov       MRI.setRegClass(Reg, RC);
128b8e1544bSIlia Diachkov     MRI.replaceRegWith(MI->getOperand(0).getReg(), Reg);
129b8e1544bSIlia Diachkov     MI->eraseFromParent();
130b8e1544bSIlia Diachkov   }
131b8e1544bSIlia Diachkov   for (MachineInstr *MI : ToEraseComposites)
132b8e1544bSIlia Diachkov     MI->eraseFromParent();
1330098f2aeSIlia Diachkov }
1340098f2aeSIlia Diachkov 
1359c29217aSVyacheslav Levytskyy static void
1369c29217aSVyacheslav Levytskyy foldConstantsIntoIntrinsics(MachineFunction &MF,
1379c29217aSVyacheslav Levytskyy                             const SmallSet<Register, 4> &TrackedConstRegs) {
1380098f2aeSIlia Diachkov   SmallVector<MachineInstr *, 10> ToErase;
1390098f2aeSIlia Diachkov   MachineRegisterInfo &MRI = MF.getRegInfo();
1400098f2aeSIlia Diachkov   const unsigned AssignNameOperandShift = 2;
1410098f2aeSIlia Diachkov   for (MachineBasicBlock &MBB : MF) {
1420098f2aeSIlia Diachkov     for (MachineInstr &MI : MBB) {
1430098f2aeSIlia Diachkov       if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_name))
1440098f2aeSIlia Diachkov         continue;
1450098f2aeSIlia Diachkov       unsigned NumOp = MI.getNumExplicitDefs() + AssignNameOperandShift;
1460098f2aeSIlia Diachkov       while (MI.getOperand(NumOp).isReg()) {
1470098f2aeSIlia Diachkov         MachineOperand &MOp = MI.getOperand(NumOp);
1480098f2aeSIlia Diachkov         MachineInstr *ConstMI = MRI.getVRegDef(MOp.getReg());
1490098f2aeSIlia Diachkov         assert(ConstMI->getOpcode() == TargetOpcode::G_CONSTANT);
1500098f2aeSIlia Diachkov         MI.removeOperand(NumOp);
1510098f2aeSIlia Diachkov         MI.addOperand(MachineOperand::CreateImm(
1520098f2aeSIlia Diachkov             ConstMI->getOperand(1).getCImm()->getZExtValue()));
1539c29217aSVyacheslav Levytskyy         Register DefReg = ConstMI->getOperand(0).getReg();
1549c29217aSVyacheslav Levytskyy         if (MRI.use_empty(DefReg) && !TrackedConstRegs.contains(DefReg))
1550098f2aeSIlia Diachkov           ToErase.push_back(ConstMI);
1560098f2aeSIlia Diachkov       }
1570098f2aeSIlia Diachkov     }
1580098f2aeSIlia Diachkov   }
1590098f2aeSIlia Diachkov   for (MachineInstr *MI : ToErase)
1600098f2aeSIlia Diachkov     MI->eraseFromParent();
1610098f2aeSIlia Diachkov }
1620098f2aeSIlia Diachkov 
163dbd00a59SVyacheslav Levytskyy static MachineInstr *findAssignTypeInstr(Register Reg,
164dbd00a59SVyacheslav Levytskyy                                          MachineRegisterInfo *MRI) {
165dbd00a59SVyacheslav Levytskyy   for (MachineRegisterInfo::use_instr_iterator I = MRI->use_instr_begin(Reg),
166dbd00a59SVyacheslav Levytskyy                                                IE = MRI->use_instr_end();
167dbd00a59SVyacheslav Levytskyy        I != IE; ++I) {
168dbd00a59SVyacheslav Levytskyy     MachineInstr *UseMI = &*I;
169dbd00a59SVyacheslav Levytskyy     if ((isSpvIntrinsic(*UseMI, Intrinsic::spv_assign_ptr_type) ||
170dbd00a59SVyacheslav Levytskyy          isSpvIntrinsic(*UseMI, Intrinsic::spv_assign_type)) &&
171dbd00a59SVyacheslav Levytskyy         UseMI->getOperand(1).getReg() == Reg)
172dbd00a59SVyacheslav Levytskyy       return UseMI;
173dbd00a59SVyacheslav Levytskyy   }
174dbd00a59SVyacheslav Levytskyy   return nullptr;
175dbd00a59SVyacheslav Levytskyy }
176dbd00a59SVyacheslav Levytskyy 
177c616f24bSVyacheslav Levytskyy static void buildOpBitcast(SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB,
178c616f24bSVyacheslav Levytskyy                            Register ResVReg, Register OpReg) {
179c616f24bSVyacheslav Levytskyy   SPIRVType *ResType = GR->getSPIRVTypeForVReg(ResVReg);
180c616f24bSVyacheslav Levytskyy   SPIRVType *OpType = GR->getSPIRVTypeForVReg(OpReg);
181c616f24bSVyacheslav Levytskyy   assert(ResType && OpType && "Operand types are expected");
182c616f24bSVyacheslav Levytskyy   if (!GR->isBitcastCompatible(ResType, OpType))
183c616f24bSVyacheslav Levytskyy     report_fatal_error("incompatible result and operand types in a bitcast");
184c616f24bSVyacheslav Levytskyy   MachineRegisterInfo *MRI = MIB.getMRI();
185c616f24bSVyacheslav Levytskyy   if (!MRI->getRegClassOrNull(ResVReg))
186c616f24bSVyacheslav Levytskyy     MRI->setRegClass(ResVReg, GR->getRegClass(ResType));
18793cda6d6SVyacheslav Levytskyy   if (ResType == OpType)
18893cda6d6SVyacheslav Levytskyy     MIB.buildInstr(TargetOpcode::COPY).addDef(ResVReg).addUse(OpReg);
18993cda6d6SVyacheslav Levytskyy   else
190c616f24bSVyacheslav Levytskyy     MIB.buildInstr(SPIRV::OpBitcast)
191c616f24bSVyacheslav Levytskyy         .addDef(ResVReg)
192c616f24bSVyacheslav Levytskyy         .addUse(GR->getSPIRVTypeID(ResType))
193c616f24bSVyacheslav Levytskyy         .addUse(OpReg);
194c616f24bSVyacheslav Levytskyy }
195c616f24bSVyacheslav Levytskyy 
196c616f24bSVyacheslav Levytskyy // We do instruction selections early instead of calling MIB.buildBitcast()
197c616f24bSVyacheslav Levytskyy // generating the general op code G_BITCAST. When MachineVerifier validates
198c616f24bSVyacheslav Levytskyy // G_BITCAST we see a check of a kind: if Source Type is equal to Destination
199c616f24bSVyacheslav Levytskyy // Type then report error "bitcast must change the type". This doesn't take into
200c616f24bSVyacheslav Levytskyy // account the notion of a typed pointer that is important for SPIR-V where a
201c616f24bSVyacheslav Levytskyy // user may and should use bitcast between pointers with different pointee types
202c616f24bSVyacheslav Levytskyy // (https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpBitcast).
203c616f24bSVyacheslav Levytskyy // It's important for correct lowering in SPIR-V, because interpretation of the
204c616f24bSVyacheslav Levytskyy // data type is not left to instructions that utilize the pointer, but encoded
205c616f24bSVyacheslav Levytskyy // by the pointer declaration, and the SPIRV target can and must handle the
206c616f24bSVyacheslav Levytskyy // declaration and use of pointers that specify the type of data they point to.
207c616f24bSVyacheslav Levytskyy // It's not feasible to improve validation of G_BITCAST using just information
208c616f24bSVyacheslav Levytskyy // provided by low level types of source and destination. Therefore we don't
209c616f24bSVyacheslav Levytskyy // produce G_BITCAST as the general op code with semantics different from
210c616f24bSVyacheslav Levytskyy // OpBitcast, but rather lower to OpBitcast immediately. As for now, the only
211c616f24bSVyacheslav Levytskyy // difference would be that CombinerHelper couldn't transform known patterns
212c616f24bSVyacheslav Levytskyy // around G_BUILD_VECTOR. See discussion
213c616f24bSVyacheslav Levytskyy // in https://github.com/llvm/llvm-project/pull/110270 for even more context.
214c616f24bSVyacheslav Levytskyy static void selectOpBitcasts(MachineFunction &MF, SPIRVGlobalRegistry *GR,
215c616f24bSVyacheslav Levytskyy                              MachineIRBuilder MIB) {
216c616f24bSVyacheslav Levytskyy   SmallVector<MachineInstr *, 16> ToErase;
217c616f24bSVyacheslav Levytskyy   for (MachineBasicBlock &MBB : MF) {
218c616f24bSVyacheslav Levytskyy     for (MachineInstr &MI : MBB) {
219c616f24bSVyacheslav Levytskyy       if (MI.getOpcode() != TargetOpcode::G_BITCAST)
220c616f24bSVyacheslav Levytskyy         continue;
221c616f24bSVyacheslav Levytskyy       MIB.setInsertPt(*MI.getParent(), MI);
222c616f24bSVyacheslav Levytskyy       buildOpBitcast(GR, MIB, MI.getOperand(0).getReg(),
223c616f24bSVyacheslav Levytskyy                      MI.getOperand(1).getReg());
224c616f24bSVyacheslav Levytskyy       ToErase.push_back(&MI);
225c616f24bSVyacheslav Levytskyy     }
226c616f24bSVyacheslav Levytskyy   }
227c616f24bSVyacheslav Levytskyy   for (MachineInstr *MI : ToErase)
228c616f24bSVyacheslav Levytskyy     MI->eraseFromParent();
229c616f24bSVyacheslav Levytskyy }
230c616f24bSVyacheslav Levytskyy 
2310098f2aeSIlia Diachkov static void insertBitcasts(MachineFunction &MF, SPIRVGlobalRegistry *GR,
2320098f2aeSIlia Diachkov                            MachineIRBuilder MIB) {
2334a602d92SVyacheslav Levytskyy   // Get access to information about available extensions
2344a602d92SVyacheslav Levytskyy   const SPIRVSubtarget *ST =
2354a602d92SVyacheslav Levytskyy       static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());
2360098f2aeSIlia Diachkov   SmallVector<MachineInstr *, 10> ToErase;
2370098f2aeSIlia Diachkov   for (MachineBasicBlock &MBB : MF) {
2380098f2aeSIlia Diachkov     for (MachineInstr &MI : MBB) {
239b4cfb50cSMichal Paszkowski       if (!isSpvIntrinsic(MI, Intrinsic::spv_bitcast) &&
240b4cfb50cSMichal Paszkowski           !isSpvIntrinsic(MI, Intrinsic::spv_ptrcast))
2410098f2aeSIlia Diachkov         continue;
2420098f2aeSIlia Diachkov       assert(MI.getOperand(2).isReg());
2430098f2aeSIlia Diachkov       MIB.setInsertPt(*MI.getParent(), MI);
2440098f2aeSIlia Diachkov       ToErase.push_back(&MI);
245b4cfb50cSMichal Paszkowski       if (isSpvIntrinsic(MI, Intrinsic::spv_bitcast)) {
246b4cfb50cSMichal Paszkowski         MIB.buildBitcast(MI.getOperand(0).getReg(), MI.getOperand(2).getReg());
247b4cfb50cSMichal Paszkowski         continue;
248b4cfb50cSMichal Paszkowski       }
249b4cfb50cSMichal Paszkowski       Register Def = MI.getOperand(0).getReg();
250b4cfb50cSMichal Paszkowski       Register Source = MI.getOperand(2).getReg();
2519a737109SVyacheslav Levytskyy       Type *ElemTy = getMDOperandAsType(MI.getOperand(3).getMetadata(), 0);
2529a737109SVyacheslav Levytskyy       SPIRVType *BaseTy = GR->getOrCreateSPIRVType(ElemTy, MIB);
253b4cfb50cSMichal Paszkowski       SPIRVType *AssignedPtrType = GR->getOrCreateSPIRVPointerType(
254b4cfb50cSMichal Paszkowski           BaseTy, MI, *MF.getSubtarget<SPIRVSubtarget>().getInstrInfo(),
2554a602d92SVyacheslav Levytskyy           addressSpaceToStorageClass(MI.getOperand(4).getImm(), *ST));
256b4cfb50cSMichal Paszkowski 
257dbd00a59SVyacheslav Levytskyy       // If the ptrcast would be redundant, replace all uses with the source
258b4cfb50cSMichal Paszkowski       // register.
25967d3ef74SVyacheslav Levytskyy       MachineRegisterInfo *MRI = MIB.getMRI();
260b4cfb50cSMichal Paszkowski       if (GR->getSPIRVTypeForVReg(Source) == AssignedPtrType) {
261dbd00a59SVyacheslav Levytskyy         // Erase Def's assign type instruction if we are going to replace Def.
26267d3ef74SVyacheslav Levytskyy         if (MachineInstr *AssignMI = findAssignTypeInstr(Def, MRI))
263dbd00a59SVyacheslav Levytskyy           ToErase.push_back(AssignMI);
26467d3ef74SVyacheslav Levytskyy         MRI->replaceRegWith(Def, Source);
265b4cfb50cSMichal Paszkowski       } else {
266b4cfb50cSMichal Paszkowski         GR->assignSPIRVTypeToVReg(AssignedPtrType, Def, MF);
267b4cfb50cSMichal Paszkowski         MIB.buildBitcast(Def, Source);
268b4cfb50cSMichal Paszkowski       }
2690098f2aeSIlia Diachkov     }
2700098f2aeSIlia Diachkov   }
2710098f2aeSIlia Diachkov   for (MachineInstr *MI : ToErase)
2720098f2aeSIlia Diachkov     MI->eraseFromParent();
2730098f2aeSIlia Diachkov }
2740098f2aeSIlia Diachkov 
2750098f2aeSIlia Diachkov // Translating GV, IRTranslator sometimes generates following IR:
2760098f2aeSIlia Diachkov //   %1 = G_GLOBAL_VALUE
2770098f2aeSIlia Diachkov //   %2 = COPY %1
2780098f2aeSIlia Diachkov //   %3 = G_ADDRSPACE_CAST %2
27942d801d4SVyacheslav Levytskyy //
28042d801d4SVyacheslav Levytskyy // or
28142d801d4SVyacheslav Levytskyy //
28242d801d4SVyacheslav Levytskyy //  %1 = G_ZEXT %2
28342d801d4SVyacheslav Levytskyy //  G_MEMCPY ... %2 ...
28442d801d4SVyacheslav Levytskyy //
2850098f2aeSIlia Diachkov // New registers have no SPIRVType and no register class info.
2860098f2aeSIlia Diachkov //
2870098f2aeSIlia Diachkov // Set SPIRVType for GV, propagate it from GV to other instructions,
2880098f2aeSIlia Diachkov // also set register classes.
2890098f2aeSIlia Diachkov static SPIRVType *propagateSPIRVType(MachineInstr *MI, SPIRVGlobalRegistry *GR,
2900098f2aeSIlia Diachkov                                      MachineRegisterInfo &MRI,
2910098f2aeSIlia Diachkov                                      MachineIRBuilder &MIB) {
292f9c98068SVyacheslav Levytskyy   SPIRVType *SpvType = nullptr;
2930098f2aeSIlia Diachkov   assert(MI && "Machine instr is expected");
2940098f2aeSIlia Diachkov   if (MI->getOperand(0).isReg()) {
2950098f2aeSIlia Diachkov     Register Reg = MI->getOperand(0).getReg();
296f9c98068SVyacheslav Levytskyy     SpvType = GR->getSPIRVTypeForVReg(Reg);
297f9c98068SVyacheslav Levytskyy     if (!SpvType) {
2980098f2aeSIlia Diachkov       switch (MI->getOpcode()) {
299978de2d6SVyacheslav Levytskyy       case TargetOpcode::G_FCONSTANT:
3000098f2aeSIlia Diachkov       case TargetOpcode::G_CONSTANT: {
3010098f2aeSIlia Diachkov         MIB.setInsertPt(*MI->getParent(), MI);
3020098f2aeSIlia Diachkov         Type *Ty = MI->getOperand(1).getCImm()->getType();
303f9c98068SVyacheslav Levytskyy         SpvType = GR->getOrCreateSPIRVType(Ty, MIB);
3040098f2aeSIlia Diachkov         break;
3050098f2aeSIlia Diachkov       }
3060098f2aeSIlia Diachkov       case TargetOpcode::G_GLOBAL_VALUE: {
3070098f2aeSIlia Diachkov         MIB.setInsertPt(*MI->getParent(), MI);
308b7ac8fddSVyacheslav Levytskyy         const GlobalValue *Global = MI->getOperand(1).getGlobal();
309dbd00a59SVyacheslav Levytskyy         Type *ElementTy = toTypedPointer(GR->getDeducedGlobalValueType(Global));
310dbd00a59SVyacheslav Levytskyy         auto *Ty = TypedPointerType::get(ElementTy,
311f0eb9083SNathan Gauër                                          Global->getType()->getAddressSpace());
312f9c98068SVyacheslav Levytskyy         SpvType = GR->getOrCreateSPIRVType(Ty, MIB);
3130098f2aeSIlia Diachkov         break;
3140098f2aeSIlia Diachkov       }
315214e6b40SVyacheslav Levytskyy       case TargetOpcode::G_ANYEXT:
316214e6b40SVyacheslav Levytskyy       case TargetOpcode::G_SEXT:
31742d801d4SVyacheslav Levytskyy       case TargetOpcode::G_ZEXT: {
31842d801d4SVyacheslav Levytskyy         if (MI->getOperand(1).isReg()) {
31942d801d4SVyacheslav Levytskyy           if (MachineInstr *DefInstr =
32042d801d4SVyacheslav Levytskyy                   MRI.getVRegDef(MI->getOperand(1).getReg())) {
32142d801d4SVyacheslav Levytskyy             if (SPIRVType *Def = propagateSPIRVType(DefInstr, GR, MRI, MIB)) {
32242d801d4SVyacheslav Levytskyy               unsigned CurrentBW = GR->getScalarOrVectorBitWidth(Def);
32342d801d4SVyacheslav Levytskyy               unsigned ExpectedBW =
32442d801d4SVyacheslav Levytskyy                   std::max(MRI.getType(Reg).getScalarSizeInBits(), CurrentBW);
32542d801d4SVyacheslav Levytskyy               unsigned NumElements = GR->getScalarOrVectorComponentCount(Def);
326f9c98068SVyacheslav Levytskyy               SpvType = GR->getOrCreateSPIRVIntegerType(ExpectedBW, MIB);
32742d801d4SVyacheslav Levytskyy               if (NumElements > 1)
328f9c98068SVyacheslav Levytskyy                 SpvType =
329f9c98068SVyacheslav Levytskyy                     GR->getOrCreateSPIRVVectorType(SpvType, NumElements, MIB);
33042d801d4SVyacheslav Levytskyy             }
33142d801d4SVyacheslav Levytskyy           }
33242d801d4SVyacheslav Levytskyy         }
33342d801d4SVyacheslav Levytskyy         break;
33442d801d4SVyacheslav Levytskyy       }
335486ea1ecSVyacheslav Levytskyy       case TargetOpcode::G_PTRTOINT:
336f9c98068SVyacheslav Levytskyy         SpvType = GR->getOrCreateSPIRVIntegerType(
337486ea1ecSVyacheslav Levytskyy             MRI.getType(Reg).getScalarSizeInBits(), MIB);
338486ea1ecSVyacheslav Levytskyy         break;
3390098f2aeSIlia Diachkov       case TargetOpcode::G_TRUNC:
3400098f2aeSIlia Diachkov       case TargetOpcode::G_ADDRSPACE_CAST:
341b8e1544bSIlia Diachkov       case TargetOpcode::G_PTR_ADD:
3420098f2aeSIlia Diachkov       case TargetOpcode::COPY: {
3430098f2aeSIlia Diachkov         MachineOperand &Op = MI->getOperand(1);
3440098f2aeSIlia Diachkov         MachineInstr *Def = Op.isReg() ? MRI.getVRegDef(Op.getReg()) : nullptr;
3450098f2aeSIlia Diachkov         if (Def)
346f9c98068SVyacheslav Levytskyy           SpvType = propagateSPIRVType(Def, GR, MRI, MIB);
3470098f2aeSIlia Diachkov         break;
3480098f2aeSIlia Diachkov       }
3490098f2aeSIlia Diachkov       default:
3500098f2aeSIlia Diachkov         break;
3510098f2aeSIlia Diachkov       }
3523e79c7feSVyacheslav Levytskyy       if (SpvType) {
3533e79c7feSVyacheslav Levytskyy         // check if the address space needs correction
3543e79c7feSVyacheslav Levytskyy         LLT RegType = MRI.getType(Reg);
3553e79c7feSVyacheslav Levytskyy         if (SpvType->getOpcode() == SPIRV::OpTypePointer &&
3563e79c7feSVyacheslav Levytskyy             RegType.isPointer() &&
3573e79c7feSVyacheslav Levytskyy             storageClassToAddressSpace(GR->getPointerStorageClass(SpvType)) !=
3583e79c7feSVyacheslav Levytskyy                 RegType.getAddressSpace()) {
3593e79c7feSVyacheslav Levytskyy           const SPIRVSubtarget &ST =
3603e79c7feSVyacheslav Levytskyy               MI->getParent()->getParent()->getSubtarget<SPIRVSubtarget>();
3613e79c7feSVyacheslav Levytskyy           SpvType = GR->getOrCreateSPIRVPointerType(
3623e79c7feSVyacheslav Levytskyy               GR->getPointeeType(SpvType), *MI, *ST.getInstrInfo(),
3633e79c7feSVyacheslav Levytskyy               addressSpaceToStorageClass(RegType.getAddressSpace(), ST));
3643e79c7feSVyacheslav Levytskyy         }
365f9c98068SVyacheslav Levytskyy         GR->assignSPIRVTypeToVReg(SpvType, Reg, MIB.getMF());
3663e79c7feSVyacheslav Levytskyy       }
3670098f2aeSIlia Diachkov       if (!MRI.getRegClassOrNull(Reg))
36867d3ef74SVyacheslav Levytskyy         MRI.setRegClass(Reg, SpvType ? GR->getRegClass(SpvType)
36967d3ef74SVyacheslav Levytskyy                                      : &SPIRV::iIDRegClass);
3700098f2aeSIlia Diachkov     }
3710098f2aeSIlia Diachkov   }
372f9c98068SVyacheslav Levytskyy   return SpvType;
3730098f2aeSIlia Diachkov }
3740098f2aeSIlia Diachkov 
375163d036dSVyacheslav Levytskyy // To support current approach and limitations wrt. bit width here we widen a
376163d036dSVyacheslav Levytskyy // scalar register with a bit width greater than 1 to valid sizes and cap it to
377163d036dSVyacheslav Levytskyy // 64 width.
378163d036dSVyacheslav Levytskyy static void widenScalarLLTNextPow2(Register Reg, MachineRegisterInfo &MRI) {
379163d036dSVyacheslav Levytskyy   LLT RegType = MRI.getType(Reg);
380163d036dSVyacheslav Levytskyy   if (!RegType.isScalar())
381163d036dSVyacheslav Levytskyy     return;
382163d036dSVyacheslav Levytskyy   unsigned Sz = RegType.getScalarSizeInBits();
383163d036dSVyacheslav Levytskyy   if (Sz == 1)
384163d036dSVyacheslav Levytskyy     return;
385163d036dSVyacheslav Levytskyy   unsigned NewSz = std::min(std::max(1u << Log2_32_Ceil(Sz), 8u), 64u);
386163d036dSVyacheslav Levytskyy   if (NewSz != Sz)
387163d036dSVyacheslav Levytskyy     MRI.setType(Reg, LLT::scalar(NewSz));
388163d036dSVyacheslav Levytskyy }
389163d036dSVyacheslav Levytskyy 
390540d2551SVyacheslav Levytskyy static std::pair<Register, unsigned>
391b512df66SVyacheslav Levytskyy createNewIdReg(SPIRVType *SpvType, Register SrcReg, MachineRegisterInfo &MRI,
392540d2551SVyacheslav Levytskyy                const SPIRVGlobalRegistry &GR) {
393b512df66SVyacheslav Levytskyy   if (!SpvType)
394b512df66SVyacheslav Levytskyy     SpvType = GR.getSPIRVTypeForVReg(SrcReg);
39567d3ef74SVyacheslav Levytskyy   const TargetRegisterClass *RC = GR.getRegClass(SpvType);
39667d3ef74SVyacheslav Levytskyy   Register Reg = MRI.createGenericVirtualRegister(GR.getRegType(SpvType));
39767d3ef74SVyacheslav Levytskyy   MRI.setRegClass(Reg, RC);
39867d3ef74SVyacheslav Levytskyy   unsigned GetIdOp = SPIRV::GET_ID;
39967d3ef74SVyacheslav Levytskyy   if (RC == &SPIRV::fIDRegClass)
40067d3ef74SVyacheslav Levytskyy     GetIdOp = SPIRV::GET_fID;
40167d3ef74SVyacheslav Levytskyy   else if (RC == &SPIRV::pIDRegClass)
40267d3ef74SVyacheslav Levytskyy     GetIdOp = SPIRV::GET_pID;
40367d3ef74SVyacheslav Levytskyy   else if (RC == &SPIRV::vfIDRegClass)
40467d3ef74SVyacheslav Levytskyy     GetIdOp = SPIRV::GET_vfID;
40567d3ef74SVyacheslav Levytskyy   else if (RC == &SPIRV::vpIDRegClass)
40667d3ef74SVyacheslav Levytskyy     GetIdOp = SPIRV::GET_vpID;
40767d3ef74SVyacheslav Levytskyy   else if (RC == &SPIRV::vIDRegClass)
40867d3ef74SVyacheslav Levytskyy     GetIdOp = SPIRV::GET_vID;
40967d3ef74SVyacheslav Levytskyy   return {Reg, GetIdOp};
410540d2551SVyacheslav Levytskyy }
411540d2551SVyacheslav Levytskyy 
4128bc8b842SVyacheslav Levytskyy static void setInsertPtAfterDef(MachineIRBuilder &MIB, MachineInstr *Def) {
4138bc8b842SVyacheslav Levytskyy   MachineBasicBlock &MBB = *Def->getParent();
4148bc8b842SVyacheslav Levytskyy   MachineBasicBlock::iterator DefIt =
4158bc8b842SVyacheslav Levytskyy       Def->getNextNode() ? Def->getNextNode()->getIterator() : MBB.end();
4168bc8b842SVyacheslav Levytskyy   // Skip all the PHI and debug instructions.
4178bc8b842SVyacheslav Levytskyy   while (DefIt != MBB.end() &&
4188bc8b842SVyacheslav Levytskyy          (DefIt->isPHI() || DefIt->isDebugOrPseudoInstr()))
4198bc8b842SVyacheslav Levytskyy     DefIt = std::next(DefIt);
4208bc8b842SVyacheslav Levytskyy   MIB.setInsertPt(MBB, DefIt);
4218bc8b842SVyacheslav Levytskyy }
4228bc8b842SVyacheslav Levytskyy 
4230098f2aeSIlia Diachkov // Insert ASSIGN_TYPE instuction between Reg and its definition, set NewReg as
424f9c98068SVyacheslav Levytskyy // a dst of the definition, assign SPIRVType to both registers. If SpvType is
4250098f2aeSIlia Diachkov // provided, use it as SPIRVType in ASSIGN_TYPE, otherwise create it from Ty.
426f61eb416SIlia Diachkov // It's used also in SPIRVBuiltins.cpp.
4270098f2aeSIlia Diachkov // TODO: maybe move to SPIRVUtils.
428f61eb416SIlia Diachkov namespace llvm {
429f9c98068SVyacheslav Levytskyy Register insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpvType,
430f61eb416SIlia Diachkov                            SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB,
4310098f2aeSIlia Diachkov                            MachineRegisterInfo &MRI) {
432f9c98068SVyacheslav Levytskyy   assert((Ty || SpvType) && "Either LLVM or SPIRV type is expected.");
4338bc8b842SVyacheslav Levytskyy   MachineInstr *Def = MRI.getVRegDef(Reg);
4348bc8b842SVyacheslav Levytskyy   setInsertPtAfterDef(MIB, Def);
435f9c98068SVyacheslav Levytskyy   SpvType = SpvType ? SpvType : GR->getOrCreateSPIRVType(Ty, MIB);
4360098f2aeSIlia Diachkov   Register NewReg = MRI.createGenericVirtualRegister(MRI.getType(Reg));
43774c66710SIlia Diachkov   if (auto *RC = MRI.getRegClassOrNull(Reg)) {
4380098f2aeSIlia Diachkov     MRI.setRegClass(NewReg, RC);
43974c66710SIlia Diachkov   } else {
44067d3ef74SVyacheslav Levytskyy     auto RegClass = GR->getRegClass(SpvType);
441f9c98068SVyacheslav Levytskyy     MRI.setRegClass(NewReg, RegClass);
442f9c98068SVyacheslav Levytskyy     MRI.setRegClass(Reg, RegClass);
44374c66710SIlia Diachkov   }
444f9c98068SVyacheslav Levytskyy   GR->assignSPIRVTypeToVReg(SpvType, Reg, MIB.getMF());
4450098f2aeSIlia Diachkov   // This is to make it convenient for Legalizer to get the SPIRVType
4460098f2aeSIlia Diachkov   // when processing the actual MI (i.e. not pseudo one).
447f9c98068SVyacheslav Levytskyy   GR->assignSPIRVTypeToVReg(SpvType, NewReg, MIB.getMF());
448df871307SIlia Diachkov   // Copy MIFlags from Def to ASSIGN_TYPE instruction. It's required to keep
449df871307SIlia Diachkov   // the flags after instruction selection.
45009515f2cSDávid Bolvanský   const uint32_t Flags = Def->getFlags();
4510098f2aeSIlia Diachkov   MIB.buildInstr(SPIRV::ASSIGN_TYPE)
4520098f2aeSIlia Diachkov       .addDef(Reg)
4530098f2aeSIlia Diachkov       .addUse(NewReg)
454f9c98068SVyacheslav Levytskyy       .addUse(GR->getSPIRVTypeID(SpvType))
455df871307SIlia Diachkov       .setMIFlags(Flags);
456a059b299SVyacheslav Levytskyy   for (unsigned I = 0, E = Def->getNumDefs(); I != E; ++I) {
457a059b299SVyacheslav Levytskyy     MachineOperand &MO = Def->getOperand(I);
458a059b299SVyacheslav Levytskyy     if (MO.getReg() == Reg) {
459a059b299SVyacheslav Levytskyy       MO.setReg(NewReg);
460a059b299SVyacheslav Levytskyy       break;
461a059b299SVyacheslav Levytskyy     }
462a059b299SVyacheslav Levytskyy   }
4630098f2aeSIlia Diachkov   return NewReg;
4640098f2aeSIlia Diachkov }
465540d2551SVyacheslav Levytskyy 
466540d2551SVyacheslav Levytskyy void processInstr(MachineInstr &MI, MachineIRBuilder &MIB,
467540d2551SVyacheslav Levytskyy                   MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR) {
46802a334deSNathan Gauër   MIB.setInsertPt(*MI.getParent(), MI.getIterator());
469540d2551SVyacheslav Levytskyy   for (auto &Op : MI.operands()) {
470540d2551SVyacheslav Levytskyy     if (!Op.isReg() || Op.isDef())
471540d2551SVyacheslav Levytskyy       continue;
47242633cf2SVyacheslav Levytskyy     Register OpReg = Op.getReg();
47342633cf2SVyacheslav Levytskyy     SPIRVType *SpvType = GR->getSPIRVTypeForVReg(OpReg);
47442633cf2SVyacheslav Levytskyy     auto IdOpInfo = createNewIdReg(SpvType, OpReg, MRI, *GR);
47542633cf2SVyacheslav Levytskyy     MIB.buildInstr(IdOpInfo.second).addDef(IdOpInfo.first).addUse(OpReg);
47642633cf2SVyacheslav Levytskyy     const TargetRegisterClass *RC = GR->getRegClass(SpvType);
47742633cf2SVyacheslav Levytskyy     if (RC != MRI.getRegClassOrNull(OpReg))
47842633cf2SVyacheslav Levytskyy       MRI.setRegClass(OpReg, RC);
479540d2551SVyacheslav Levytskyy     Op.setReg(IdOpInfo.first);
480540d2551SVyacheslav Levytskyy   }
481540d2551SVyacheslav Levytskyy }
482f61eb416SIlia Diachkov } // namespace llvm
4830098f2aeSIlia Diachkov 
4841ed1ec9aSVyacheslav Levytskyy static void
4851ed1ec9aSVyacheslav Levytskyy generateAssignInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR,
4861ed1ec9aSVyacheslav Levytskyy                      MachineIRBuilder MIB,
4871ed1ec9aSVyacheslav Levytskyy                      DenseMap<MachineInstr *, Type *> &TargetExtConstTypes) {
4884a602d92SVyacheslav Levytskyy   // Get access to information about available extensions
4894a602d92SVyacheslav Levytskyy   const SPIRVSubtarget *ST =
4904a602d92SVyacheslav Levytskyy       static_cast<const SPIRVSubtarget *>(&MIB.getMF().getSubtarget());
4914a602d92SVyacheslav Levytskyy 
4920098f2aeSIlia Diachkov   MachineRegisterInfo &MRI = MF.getRegInfo();
4930098f2aeSIlia Diachkov   SmallVector<MachineInstr *, 10> ToErase;
4940d9172ecSVyacheslav Levytskyy   DenseMap<MachineInstr *, Register> RegsAlreadyAddedToDT;
4950098f2aeSIlia Diachkov 
49667d3ef74SVyacheslav Levytskyy   bool IsExtendedInts =
49767d3ef74SVyacheslav Levytskyy       ST->canUseExtension(
49867d3ef74SVyacheslav Levytskyy           SPIRV::Extension::SPV_INTEL_arbitrary_precision_integers) ||
49967d3ef74SVyacheslav Levytskyy       ST->canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions);
50067d3ef74SVyacheslav Levytskyy 
5010098f2aeSIlia Diachkov   for (MachineBasicBlock *MBB : post_order(&MF)) {
5020098f2aeSIlia Diachkov     if (MBB->empty())
5030098f2aeSIlia Diachkov       continue;
5040098f2aeSIlia Diachkov 
5050098f2aeSIlia Diachkov     bool ReachedBegin = false;
5060098f2aeSIlia Diachkov     for (auto MII = std::prev(MBB->end()), Begin = MBB->begin();
5070098f2aeSIlia Diachkov          !ReachedBegin;) {
5080098f2aeSIlia Diachkov       MachineInstr &MI = *MII;
5097c917e82SVyacheslav Levytskyy       unsigned MIOp = MI.getOpcode();
5100098f2aeSIlia Diachkov 
51167d3ef74SVyacheslav Levytskyy       if (!IsExtendedInts) {
512163d036dSVyacheslav Levytskyy         // validate bit width of scalar registers
513163d036dSVyacheslav Levytskyy         for (const auto &MOP : MI.operands())
514163d036dSVyacheslav Levytskyy           if (MOP.isReg())
515163d036dSVyacheslav Levytskyy             widenScalarLLTNextPow2(MOP.getReg(), MRI);
51667d3ef74SVyacheslav Levytskyy       }
517163d036dSVyacheslav Levytskyy 
518ec7baca1SMichal Paszkowski       if (isSpvIntrinsic(MI, Intrinsic::spv_assign_ptr_type)) {
519ec7baca1SMichal Paszkowski         Register Reg = MI.getOperand(1).getReg();
520ec7baca1SMichal Paszkowski         MIB.setInsertPt(*MI.getParent(), MI.getIterator());
5219a737109SVyacheslav Levytskyy         Type *ElementTy = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);
5229a737109SVyacheslav Levytskyy         SPIRVType *BaseTy = GR->getOrCreateSPIRVType(ElementTy, MIB);
523ec7baca1SMichal Paszkowski         SPIRVType *AssignedPtrType = GR->getOrCreateSPIRVPointerType(
5242616c279SMichal Paszkowski             BaseTy, MI, *MF.getSubtarget<SPIRVSubtarget>().getInstrInfo(),
5254a602d92SVyacheslav Levytskyy             addressSpaceToStorageClass(MI.getOperand(3).getImm(), *ST));
526ec7baca1SMichal Paszkowski         MachineInstr *Def = MRI.getVRegDef(Reg);
527ec7baca1SMichal Paszkowski         assert(Def && "Expecting an instruction that defines the register");
52843222bd3SMichal Paszkowski         // G_GLOBAL_VALUE already has type info.
529505cd125SVyacheslav Levytskyy         if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE &&
530505cd125SVyacheslav Levytskyy             Def->getOpcode() != SPIRV::ASSIGN_TYPE)
531ec7baca1SMichal Paszkowski           insertAssignInstr(Reg, nullptr, AssignedPtrType, GR, MIB,
532ec7baca1SMichal Paszkowski                             MF.getRegInfo());
533ec7baca1SMichal Paszkowski         ToErase.push_back(&MI);
534ec7baca1SMichal Paszkowski       } else if (isSpvIntrinsic(MI, Intrinsic::spv_assign_type)) {
5350098f2aeSIlia Diachkov         Register Reg = MI.getOperand(1).getReg();
5360098f2aeSIlia Diachkov         Type *Ty = getMDOperandAsType(MI.getOperand(2).getMetadata(), 0);
5370098f2aeSIlia Diachkov         MachineInstr *Def = MRI.getVRegDef(Reg);
5380098f2aeSIlia Diachkov         assert(Def && "Expecting an instruction that defines the register");
5390098f2aeSIlia Diachkov         // G_GLOBAL_VALUE already has type info.
540505cd125SVyacheslav Levytskyy         if (Def->getOpcode() != TargetOpcode::G_GLOBAL_VALUE &&
541505cd125SVyacheslav Levytskyy             Def->getOpcode() != SPIRV::ASSIGN_TYPE)
5420098f2aeSIlia Diachkov           insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MF.getRegInfo());
5430098f2aeSIlia Diachkov         ToErase.push_back(&MI);
544a059b299SVyacheslav Levytskyy       } else if (MIOp == TargetOpcode::FAKE_USE && MI.getNumOperands() > 0) {
545a059b299SVyacheslav Levytskyy         MachineInstr *MdMI = MI.getPrevNode();
546a059b299SVyacheslav Levytskyy         if (MdMI && isSpvIntrinsic(*MdMI, Intrinsic::spv_value_md)) {
547a059b299SVyacheslav Levytskyy           // It's an internal service info from before IRTranslator passes.
548a059b299SVyacheslav Levytskyy           MachineInstr *Def = getVRegDef(MRI, MI.getOperand(0).getReg());
549a059b299SVyacheslav Levytskyy           for (unsigned I = 1, E = MI.getNumOperands(); I != E && Def; ++I)
550a059b299SVyacheslav Levytskyy             if (getVRegDef(MRI, MI.getOperand(I).getReg()) != Def)
551a059b299SVyacheslav Levytskyy               Def = nullptr;
552a059b299SVyacheslav Levytskyy           if (Def) {
553a059b299SVyacheslav Levytskyy             const MDNode *MD = MdMI->getOperand(1).getMetadata();
554a059b299SVyacheslav Levytskyy             StringRef ValueName =
555a059b299SVyacheslav Levytskyy                 cast<MDString>(MD->getOperand(1))->getString();
556a059b299SVyacheslav Levytskyy             const MDNode *TypeMD = cast<MDNode>(MD->getOperand(0));
557a059b299SVyacheslav Levytskyy             Type *ValueTy = getMDOperandAsType(TypeMD, 0);
558a059b299SVyacheslav Levytskyy             GR->addValueAttrs(Def, std::make_pair(ValueTy, ValueName.str()));
559a059b299SVyacheslav Levytskyy           }
560a059b299SVyacheslav Levytskyy           ToErase.push_back(MdMI);
561a059b299SVyacheslav Levytskyy         }
562a059b299SVyacheslav Levytskyy         ToErase.push_back(&MI);
5637c917e82SVyacheslav Levytskyy       } else if (MIOp == TargetOpcode::G_CONSTANT ||
5647c917e82SVyacheslav Levytskyy                  MIOp == TargetOpcode::G_FCONSTANT ||
5657c917e82SVyacheslav Levytskyy                  MIOp == TargetOpcode::G_BUILD_VECTOR) {
5660098f2aeSIlia Diachkov         // %rc = G_CONSTANT ty Val
5670098f2aeSIlia Diachkov         // ===>
5680098f2aeSIlia Diachkov         // %cty = OpType* ty
5690098f2aeSIlia Diachkov         // %rctmp = G_CONSTANT ty Val
5700098f2aeSIlia Diachkov         // %rc = ASSIGN_TYPE %rctmp, %cty
5710098f2aeSIlia Diachkov         Register Reg = MI.getOperand(0).getReg();
5720d9172ecSVyacheslav Levytskyy         bool NeedAssignType = true;
5730098f2aeSIlia Diachkov         if (MRI.hasOneUse(Reg)) {
5740098f2aeSIlia Diachkov           MachineInstr &UseMI = *MRI.use_instr_begin(Reg);
5750098f2aeSIlia Diachkov           if (isSpvIntrinsic(UseMI, Intrinsic::spv_assign_type) ||
5760098f2aeSIlia Diachkov               isSpvIntrinsic(UseMI, Intrinsic::spv_assign_name))
5770098f2aeSIlia Diachkov             continue;
57867d3ef74SVyacheslav Levytskyy           if (UseMI.getOpcode() == SPIRV::ASSIGN_TYPE)
57967d3ef74SVyacheslav Levytskyy             NeedAssignType = false;
5800098f2aeSIlia Diachkov         }
5810098f2aeSIlia Diachkov         Type *Ty = nullptr;
5827c917e82SVyacheslav Levytskyy         if (MIOp == TargetOpcode::G_CONSTANT) {
5831ed1ec9aSVyacheslav Levytskyy           auto TargetExtIt = TargetExtConstTypes.find(&MI);
5841ed1ec9aSVyacheslav Levytskyy           Ty = TargetExtIt == TargetExtConstTypes.end()
5851ed1ec9aSVyacheslav Levytskyy                    ? MI.getOperand(1).getCImm()->getType()
5861ed1ec9aSVyacheslav Levytskyy                    : TargetExtIt->second;
5870d9172ecSVyacheslav Levytskyy           const ConstantInt *OpCI = MI.getOperand(1).getCImm();
5883e79c7feSVyacheslav Levytskyy           // TODO: we may wish to analyze here if OpCI is zero and LLT RegType =
5893e79c7feSVyacheslav Levytskyy           // MRI.getType(Reg); RegType.isPointer() is true, so that we observe
5903e79c7feSVyacheslav Levytskyy           // at this point not i64/i32 constant but null pointer in the
5913e79c7feSVyacheslav Levytskyy           // corresponding address space of RegType.getAddressSpace(). This may
5923e79c7feSVyacheslav Levytskyy           // help to successfully validate the case when a OpConstantComposite's
5933e79c7feSVyacheslav Levytskyy           // constituent has type that does not match Result Type of
5943e79c7feSVyacheslav Levytskyy           // OpConstantComposite (see, for example,
5953e79c7feSVyacheslav Levytskyy           // pointers/PtrCast-null-in-OpSpecConstantOp.ll).
5960d9172ecSVyacheslav Levytskyy           Register PrimaryReg = GR->find(OpCI, &MF);
5970d9172ecSVyacheslav Levytskyy           if (!PrimaryReg.isValid()) {
5980d9172ecSVyacheslav Levytskyy             GR->add(OpCI, &MF, Reg);
5990d9172ecSVyacheslav Levytskyy           } else if (PrimaryReg != Reg &&
6000d9172ecSVyacheslav Levytskyy                      MRI.getType(Reg) == MRI.getType(PrimaryReg)) {
6010d9172ecSVyacheslav Levytskyy             auto *RCReg = MRI.getRegClassOrNull(Reg);
6020d9172ecSVyacheslav Levytskyy             auto *RCPrimary = MRI.getRegClassOrNull(PrimaryReg);
6030d9172ecSVyacheslav Levytskyy             if (!RCReg || RCPrimary == RCReg) {
6040d9172ecSVyacheslav Levytskyy               RegsAlreadyAddedToDT[&MI] = PrimaryReg;
6050d9172ecSVyacheslav Levytskyy               ToErase.push_back(&MI);
6060d9172ecSVyacheslav Levytskyy               NeedAssignType = false;
6070d9172ecSVyacheslav Levytskyy             }
6080d9172ecSVyacheslav Levytskyy           }
6097c917e82SVyacheslav Levytskyy         } else if (MIOp == TargetOpcode::G_FCONSTANT) {
6100098f2aeSIlia Diachkov           Ty = MI.getOperand(1).getFPImm()->getType();
6111ed1ec9aSVyacheslav Levytskyy         } else {
6127c917e82SVyacheslav Levytskyy           assert(MIOp == TargetOpcode::G_BUILD_VECTOR);
6130098f2aeSIlia Diachkov           Type *ElemTy = nullptr;
6140098f2aeSIlia Diachkov           MachineInstr *ElemMI = MRI.getVRegDef(MI.getOperand(1).getReg());
6150098f2aeSIlia Diachkov           assert(ElemMI);
6160098f2aeSIlia Diachkov 
6172fc7a727SVyacheslav Levytskyy           if (ElemMI->getOpcode() == TargetOpcode::G_CONSTANT) {
6180098f2aeSIlia Diachkov             ElemTy = ElemMI->getOperand(1).getCImm()->getType();
6192fc7a727SVyacheslav Levytskyy           } else if (ElemMI->getOpcode() == TargetOpcode::G_FCONSTANT) {
6200098f2aeSIlia Diachkov             ElemTy = ElemMI->getOperand(1).getFPImm()->getType();
6212fc7a727SVyacheslav Levytskyy           } else {
6222fc7a727SVyacheslav Levytskyy             // There may be a case when we already know Reg's type.
6232fc7a727SVyacheslav Levytskyy             MachineInstr *NextMI = MI.getNextNode();
6242fc7a727SVyacheslav Levytskyy             if (!NextMI || NextMI->getOpcode() != SPIRV::ASSIGN_TYPE ||
6252fc7a727SVyacheslav Levytskyy                 NextMI->getOperand(1).getReg() != Reg)
6260098f2aeSIlia Diachkov               llvm_unreachable("Unexpected opcode");
6272fc7a727SVyacheslav Levytskyy           }
6282fc7a727SVyacheslav Levytskyy           if (ElemTy)
6292fc7a727SVyacheslav Levytskyy             Ty = VectorType::get(
6302fc7a727SVyacheslav Levytskyy                 ElemTy, MI.getNumExplicitOperands() - MI.getNumExplicitDefs(),
6312fc7a727SVyacheslav Levytskyy                 false);
6322fc7a727SVyacheslav Levytskyy           else
6332fc7a727SVyacheslav Levytskyy             NeedAssignType = false;
6340098f2aeSIlia Diachkov         }
6350d9172ecSVyacheslav Levytskyy         if (NeedAssignType)
6360098f2aeSIlia Diachkov           insertAssignInstr(Reg, Ty, nullptr, GR, MIB, MRI);
6377c917e82SVyacheslav Levytskyy       } else if (MIOp == TargetOpcode::G_GLOBAL_VALUE) {
6380098f2aeSIlia Diachkov         propagateSPIRVType(&MI, GR, MRI, MIB);
6390098f2aeSIlia Diachkov       }
6400098f2aeSIlia Diachkov 
6410098f2aeSIlia Diachkov       if (MII == Begin)
6420098f2aeSIlia Diachkov         ReachedBegin = true;
6430098f2aeSIlia Diachkov       else
6440098f2aeSIlia Diachkov         --MII;
6450098f2aeSIlia Diachkov     }
6460098f2aeSIlia Diachkov   }
6470d9172ecSVyacheslav Levytskyy   for (MachineInstr *MI : ToErase) {
6480d9172ecSVyacheslav Levytskyy     auto It = RegsAlreadyAddedToDT.find(MI);
6490d9172ecSVyacheslav Levytskyy     if (RegsAlreadyAddedToDT.contains(MI))
6500d9172ecSVyacheslav Levytskyy       MRI.replaceRegWith(MI->getOperand(0).getReg(), It->second);
6510098f2aeSIlia Diachkov     MI->eraseFromParent();
6520d9172ecSVyacheslav Levytskyy   }
653214e6b40SVyacheslav Levytskyy 
654214e6b40SVyacheslav Levytskyy   // Address the case when IRTranslator introduces instructions with new
655214e6b40SVyacheslav Levytskyy   // registers without SPIRVType associated.
656214e6b40SVyacheslav Levytskyy   for (MachineBasicBlock &MBB : MF) {
657214e6b40SVyacheslav Levytskyy     for (MachineInstr &MI : MBB) {
658214e6b40SVyacheslav Levytskyy       switch (MI.getOpcode()) {
659214e6b40SVyacheslav Levytskyy       case TargetOpcode::G_TRUNC:
660214e6b40SVyacheslav Levytskyy       case TargetOpcode::G_ANYEXT:
661214e6b40SVyacheslav Levytskyy       case TargetOpcode::G_SEXT:
662214e6b40SVyacheslav Levytskyy       case TargetOpcode::G_ZEXT:
663214e6b40SVyacheslav Levytskyy       case TargetOpcode::G_PTRTOINT:
664214e6b40SVyacheslav Levytskyy       case TargetOpcode::COPY:
665214e6b40SVyacheslav Levytskyy       case TargetOpcode::G_ADDRSPACE_CAST:
666214e6b40SVyacheslav Levytskyy         propagateSPIRVType(&MI, GR, MRI, MIB);
667214e6b40SVyacheslav Levytskyy         break;
668214e6b40SVyacheslav Levytskyy       }
669214e6b40SVyacheslav Levytskyy     }
670214e6b40SVyacheslav Levytskyy   }
6710098f2aeSIlia Diachkov }
6720098f2aeSIlia Diachkov 
6730098f2aeSIlia Diachkov // Defined in SPIRVLegalizerInfo.cpp.
6740098f2aeSIlia Diachkov extern bool isTypeFoldingSupported(unsigned Opcode);
6750098f2aeSIlia Diachkov 
6760098f2aeSIlia Diachkov static void processInstrsWithTypeFolding(MachineFunction &MF,
6770098f2aeSIlia Diachkov                                          SPIRVGlobalRegistry *GR,
6780098f2aeSIlia Diachkov                                          MachineIRBuilder MIB) {
6790098f2aeSIlia Diachkov   MachineRegisterInfo &MRI = MF.getRegInfo();
680978de2d6SVyacheslav Levytskyy   for (MachineBasicBlock &MBB : MF)
681978de2d6SVyacheslav Levytskyy     for (MachineInstr &MI : MBB)
6820098f2aeSIlia Diachkov       if (isTypeFoldingSupported(MI.getOpcode()))
6830098f2aeSIlia Diachkov         processInstr(MI, MIB, MRI, GR);
6840098f2aeSIlia Diachkov }
6850098f2aeSIlia Diachkov 
68667d3ef74SVyacheslav Levytskyy static Register
68767d3ef74SVyacheslav Levytskyy collectInlineAsmInstrOperands(MachineInstr *MI,
68867d3ef74SVyacheslav Levytskyy                               SmallVector<unsigned, 4> *Ops = nullptr) {
68967d3ef74SVyacheslav Levytskyy   Register DefReg;
69067d3ef74SVyacheslav Levytskyy   unsigned StartOp = InlineAsm::MIOp_FirstOperand,
69167d3ef74SVyacheslav Levytskyy            AsmDescOp = InlineAsm::MIOp_FirstOperand;
69267d3ef74SVyacheslav Levytskyy   for (unsigned Idx = StartOp, MISz = MI->getNumOperands(); Idx != MISz;
69367d3ef74SVyacheslav Levytskyy        ++Idx) {
69467d3ef74SVyacheslav Levytskyy     const MachineOperand &MO = MI->getOperand(Idx);
69567d3ef74SVyacheslav Levytskyy     if (MO.isMetadata())
69667d3ef74SVyacheslav Levytskyy       continue;
69767d3ef74SVyacheslav Levytskyy     if (Idx == AsmDescOp && MO.isImm()) {
69867d3ef74SVyacheslav Levytskyy       // compute the index of the next operand descriptor
69967d3ef74SVyacheslav Levytskyy       const InlineAsm::Flag F(MO.getImm());
70067d3ef74SVyacheslav Levytskyy       AsmDescOp += 1 + F.getNumOperandRegisters();
70167d3ef74SVyacheslav Levytskyy       continue;
70267d3ef74SVyacheslav Levytskyy     }
70367d3ef74SVyacheslav Levytskyy     if (MO.isReg() && MO.isDef()) {
70467d3ef74SVyacheslav Levytskyy       if (!Ops)
70567d3ef74SVyacheslav Levytskyy         return MO.getReg();
70667d3ef74SVyacheslav Levytskyy       else
70767d3ef74SVyacheslav Levytskyy         DefReg = MO.getReg();
70867d3ef74SVyacheslav Levytskyy     } else if (Ops) {
70967d3ef74SVyacheslav Levytskyy       Ops->push_back(Idx);
71067d3ef74SVyacheslav Levytskyy     }
71167d3ef74SVyacheslav Levytskyy   }
71267d3ef74SVyacheslav Levytskyy   return DefReg;
71367d3ef74SVyacheslav Levytskyy }
71467d3ef74SVyacheslav Levytskyy 
715214e6b40SVyacheslav Levytskyy static void
716214e6b40SVyacheslav Levytskyy insertInlineAsmProcess(MachineFunction &MF, SPIRVGlobalRegistry *GR,
717214e6b40SVyacheslav Levytskyy                        const SPIRVSubtarget &ST, MachineIRBuilder MIRBuilder,
718214e6b40SVyacheslav Levytskyy                        const SmallVector<MachineInstr *> &ToProcess) {
719214e6b40SVyacheslav Levytskyy   MachineRegisterInfo &MRI = MF.getRegInfo();
720214e6b40SVyacheslav Levytskyy   Register AsmTargetReg;
721214e6b40SVyacheslav Levytskyy   for (unsigned i = 0, Sz = ToProcess.size(); i + 1 < Sz; i += 2) {
722214e6b40SVyacheslav Levytskyy     MachineInstr *I1 = ToProcess[i], *I2 = ToProcess[i + 1];
723214e6b40SVyacheslav Levytskyy     assert(isSpvIntrinsic(*I1, Intrinsic::spv_inline_asm) && I2->isInlineAsm());
72467d3ef74SVyacheslav Levytskyy     MIRBuilder.setInsertPt(*I2->getParent(), *I2);
725214e6b40SVyacheslav Levytskyy 
726214e6b40SVyacheslav Levytskyy     if (!AsmTargetReg.isValid()) {
727214e6b40SVyacheslav Levytskyy       // define vendor specific assembly target or dialect
728214e6b40SVyacheslav Levytskyy       AsmTargetReg = MRI.createGenericVirtualRegister(LLT::scalar(32));
729f9c98068SVyacheslav Levytskyy       MRI.setRegClass(AsmTargetReg, &SPIRV::iIDRegClass);
730214e6b40SVyacheslav Levytskyy       auto AsmTargetMIB =
731214e6b40SVyacheslav Levytskyy           MIRBuilder.buildInstr(SPIRV::OpAsmTargetINTEL).addDef(AsmTargetReg);
732214e6b40SVyacheslav Levytskyy       addStringImm(ST.getTargetTripleAsStr(), AsmTargetMIB);
733214e6b40SVyacheslav Levytskyy       GR->add(AsmTargetMIB.getInstr(), &MF, AsmTargetReg);
734214e6b40SVyacheslav Levytskyy     }
735214e6b40SVyacheslav Levytskyy 
736214e6b40SVyacheslav Levytskyy     // create types
737214e6b40SVyacheslav Levytskyy     const MDNode *IAMD = I1->getOperand(1).getMetadata();
738214e6b40SVyacheslav Levytskyy     FunctionType *FTy = cast<FunctionType>(getMDOperandAsType(IAMD, 0));
739214e6b40SVyacheslav Levytskyy     SmallVector<SPIRVType *, 4> ArgTypes;
740214e6b40SVyacheslav Levytskyy     for (const auto &ArgTy : FTy->params())
741214e6b40SVyacheslav Levytskyy       ArgTypes.push_back(GR->getOrCreateSPIRVType(ArgTy, MIRBuilder));
742214e6b40SVyacheslav Levytskyy     SPIRVType *RetType =
743214e6b40SVyacheslav Levytskyy         GR->getOrCreateSPIRVType(FTy->getReturnType(), MIRBuilder);
744214e6b40SVyacheslav Levytskyy     SPIRVType *FuncType = GR->getOrCreateOpTypeFunctionWithArgs(
745214e6b40SVyacheslav Levytskyy         FTy, RetType, ArgTypes, MIRBuilder);
746214e6b40SVyacheslav Levytskyy 
747214e6b40SVyacheslav Levytskyy     // define vendor specific assembly instructions string
748214e6b40SVyacheslav Levytskyy     Register AsmReg = MRI.createGenericVirtualRegister(LLT::scalar(32));
749f9c98068SVyacheslav Levytskyy     MRI.setRegClass(AsmReg, &SPIRV::iIDRegClass);
750214e6b40SVyacheslav Levytskyy     auto AsmMIB = MIRBuilder.buildInstr(SPIRV::OpAsmINTEL)
751214e6b40SVyacheslav Levytskyy                       .addDef(AsmReg)
752214e6b40SVyacheslav Levytskyy                       .addUse(GR->getSPIRVTypeID(RetType))
753214e6b40SVyacheslav Levytskyy                       .addUse(GR->getSPIRVTypeID(FuncType))
754214e6b40SVyacheslav Levytskyy                       .addUse(AsmTargetReg);
755214e6b40SVyacheslav Levytskyy     // inline asm string:
756214e6b40SVyacheslav Levytskyy     addStringImm(I2->getOperand(InlineAsm::MIOp_AsmString).getSymbolName(),
757214e6b40SVyacheslav Levytskyy                  AsmMIB);
758214e6b40SVyacheslav Levytskyy     // inline asm constraint string:
759214e6b40SVyacheslav Levytskyy     addStringImm(cast<MDString>(I1->getOperand(2).getMetadata()->getOperand(0))
760214e6b40SVyacheslav Levytskyy                      ->getString(),
761214e6b40SVyacheslav Levytskyy                  AsmMIB);
762214e6b40SVyacheslav Levytskyy     GR->add(AsmMIB.getInstr(), &MF, AsmReg);
763214e6b40SVyacheslav Levytskyy 
764214e6b40SVyacheslav Levytskyy     // calls the inline assembly instruction
765214e6b40SVyacheslav Levytskyy     unsigned ExtraInfo = I2->getOperand(InlineAsm::MIOp_ExtraInfo).getImm();
766214e6b40SVyacheslav Levytskyy     if (ExtraInfo & InlineAsm::Extra_HasSideEffects)
767214e6b40SVyacheslav Levytskyy       MIRBuilder.buildInstr(SPIRV::OpDecorate)
768214e6b40SVyacheslav Levytskyy           .addUse(AsmReg)
769214e6b40SVyacheslav Levytskyy           .addImm(static_cast<uint32_t>(SPIRV::Decoration::SideEffectsINTEL));
77067d3ef74SVyacheslav Levytskyy 
77167d3ef74SVyacheslav Levytskyy     Register DefReg = collectInlineAsmInstrOperands(I2);
772214e6b40SVyacheslav Levytskyy     if (!DefReg.isValid()) {
773214e6b40SVyacheslav Levytskyy       DefReg = MRI.createGenericVirtualRegister(LLT::scalar(32));
774f9c98068SVyacheslav Levytskyy       MRI.setRegClass(DefReg, &SPIRV::iIDRegClass);
775214e6b40SVyacheslav Levytskyy       SPIRVType *VoidType = GR->getOrCreateSPIRVType(
776214e6b40SVyacheslav Levytskyy           Type::getVoidTy(MF.getFunction().getContext()), MIRBuilder);
777214e6b40SVyacheslav Levytskyy       GR->assignSPIRVTypeToVReg(VoidType, DefReg, MF);
778214e6b40SVyacheslav Levytskyy     }
77967d3ef74SVyacheslav Levytskyy 
780214e6b40SVyacheslav Levytskyy     auto AsmCall = MIRBuilder.buildInstr(SPIRV::OpAsmCallINTEL)
781214e6b40SVyacheslav Levytskyy                        .addDef(DefReg)
782214e6b40SVyacheslav Levytskyy                        .addUse(GR->getSPIRVTypeID(RetType))
783214e6b40SVyacheslav Levytskyy                        .addUse(AsmReg);
78467d3ef74SVyacheslav Levytskyy     for (unsigned IntrIdx = 3; IntrIdx < I1->getNumOperands(); ++IntrIdx)
785214e6b40SVyacheslav Levytskyy       AsmCall.addUse(I1->getOperand(IntrIdx).getReg());
786214e6b40SVyacheslav Levytskyy   }
787214e6b40SVyacheslav Levytskyy   for (MachineInstr *MI : ToProcess)
788214e6b40SVyacheslav Levytskyy     MI->eraseFromParent();
789214e6b40SVyacheslav Levytskyy }
790214e6b40SVyacheslav Levytskyy 
791214e6b40SVyacheslav Levytskyy static void insertInlineAsm(MachineFunction &MF, SPIRVGlobalRegistry *GR,
792214e6b40SVyacheslav Levytskyy                             const SPIRVSubtarget &ST,
793214e6b40SVyacheslav Levytskyy                             MachineIRBuilder MIRBuilder) {
794214e6b40SVyacheslav Levytskyy   SmallVector<MachineInstr *> ToProcess;
795214e6b40SVyacheslav Levytskyy   for (MachineBasicBlock &MBB : MF) {
796214e6b40SVyacheslav Levytskyy     for (MachineInstr &MI : MBB) {
797214e6b40SVyacheslav Levytskyy       if (isSpvIntrinsic(MI, Intrinsic::spv_inline_asm) ||
798214e6b40SVyacheslav Levytskyy           MI.getOpcode() == TargetOpcode::INLINEASM)
799214e6b40SVyacheslav Levytskyy         ToProcess.push_back(&MI);
800214e6b40SVyacheslav Levytskyy     }
801214e6b40SVyacheslav Levytskyy   }
802214e6b40SVyacheslav Levytskyy   if (ToProcess.size() == 0)
803214e6b40SVyacheslav Levytskyy     return;
804214e6b40SVyacheslav Levytskyy 
805214e6b40SVyacheslav Levytskyy   if (!ST.canUseExtension(SPIRV::Extension::SPV_INTEL_inline_assembly))
806214e6b40SVyacheslav Levytskyy     report_fatal_error("Inline assembly instructions require the "
807214e6b40SVyacheslav Levytskyy                        "following SPIR-V extension: SPV_INTEL_inline_assembly",
808214e6b40SVyacheslav Levytskyy                        false);
809214e6b40SVyacheslav Levytskyy 
810214e6b40SVyacheslav Levytskyy   insertInlineAsmProcess(MF, GR, ST, MIRBuilder, ToProcess);
811214e6b40SVyacheslav Levytskyy }
812214e6b40SVyacheslav Levytskyy 
813be9b4dabSVyacheslav Levytskyy static void insertSpirvDecorations(MachineFunction &MF, MachineIRBuilder MIB) {
814be9b4dabSVyacheslav Levytskyy   SmallVector<MachineInstr *, 10> ToErase;
815be9b4dabSVyacheslav Levytskyy   for (MachineBasicBlock &MBB : MF) {
816be9b4dabSVyacheslav Levytskyy     for (MachineInstr &MI : MBB) {
817be9b4dabSVyacheslav Levytskyy       if (!isSpvIntrinsic(MI, Intrinsic::spv_assign_decoration))
818be9b4dabSVyacheslav Levytskyy         continue;
819e41df5cbSNathan Gauër       MIB.setInsertPt(*MI.getParent(), MI.getNextNode());
820be9b4dabSVyacheslav Levytskyy       buildOpSpirvDecorations(MI.getOperand(1).getReg(), MIB,
821be9b4dabSVyacheslav Levytskyy                               MI.getOperand(2).getMetadata());
822be9b4dabSVyacheslav Levytskyy       ToErase.push_back(&MI);
823be9b4dabSVyacheslav Levytskyy     }
824be9b4dabSVyacheslav Levytskyy   }
825be9b4dabSVyacheslav Levytskyy   for (MachineInstr *MI : ToErase)
826be9b4dabSVyacheslav Levytskyy     MI->eraseFromParent();
827be9b4dabSVyacheslav Levytskyy }
828be9b4dabSVyacheslav Levytskyy 
8291ed65febSNathan Gauër // LLVM allows the switches to use registers as cases, while SPIR-V required
8301ed65febSNathan Gauër // those to be immediate values. This function replaces such operands with the
8311ed65febSNathan Gauër // equivalent immediate constant.
8321ed65febSNathan Gauër static void processSwitchesConstants(MachineFunction &MF,
8331ed65febSNathan Gauër                                      SPIRVGlobalRegistry *GR,
8340098f2aeSIlia Diachkov                                      MachineIRBuilder MIB) {
83523b058cbSVyacheslav Levytskyy   MachineRegisterInfo &MRI = MF.getRegInfo();
8361ed65febSNathan Gauër   for (MachineBasicBlock &MBB : MF) {
8370098f2aeSIlia Diachkov     for (MachineInstr &MI : MBB) {
83823b058cbSVyacheslav Levytskyy       if (!isSpvIntrinsic(MI, Intrinsic::spv_switch))
83923b058cbSVyacheslav Levytskyy         continue;
8401ed65febSNathan Gauër 
8411ed65febSNathan Gauër       SmallVector<MachineOperand, 8> NewOperands;
8421ed65febSNathan Gauër       NewOperands.push_back(MI.getOperand(0)); // Opcode
8431ed65febSNathan Gauër       NewOperands.push_back(MI.getOperand(1)); // Condition
8441ed65febSNathan Gauër       NewOperands.push_back(MI.getOperand(2)); // Default
8451ed65febSNathan Gauër       for (unsigned i = 3; i < MI.getNumOperands(); i += 2) {
84623b058cbSVyacheslav Levytskyy         Register Reg = MI.getOperand(i).getReg();
84723b058cbSVyacheslav Levytskyy         MachineInstr *ConstInstr = getDefInstrMaybeConstant(Reg, &MRI);
8481ed65febSNathan Gauër         NewOperands.push_back(
8491ed65febSNathan Gauër             MachineOperand::CreateCImm(ConstInstr->getOperand(1).getCImm()));
8501ed65febSNathan Gauër 
8511ed65febSNathan Gauër         NewOperands.push_back(MI.getOperand(i + 1));
852e461bdf6SMichal Paszkowski       }
8531ed65febSNathan Gauër 
8541ed65febSNathan Gauër       assert(MI.getNumOperands() == NewOperands.size());
8551ed65febSNathan Gauër       while (MI.getNumOperands() > 0)
8561ed65febSNathan Gauër         MI.removeOperand(0);
8571ed65febSNathan Gauër       for (auto &MO : NewOperands)
8581ed65febSNathan Gauër         MI.addOperand(MO);
859e461bdf6SMichal Paszkowski     }
8608bfb2b6dSMichal Paszkowski   }
8610098f2aeSIlia Diachkov }
862e461bdf6SMichal Paszkowski 
8631ed65febSNathan Gauër // Some instructions are used during CodeGen but should never be emitted.
8641ed65febSNathan Gauër // Cleaning up those.
8651ed65febSNathan Gauër static void cleanupHelperInstructions(MachineFunction &MF) {
8661ed65febSNathan Gauër   SmallVector<MachineInstr *, 8> ToEraseMI;
8671ed65febSNathan Gauër   for (MachineBasicBlock &MBB : MF) {
8681ed65febSNathan Gauër     for (MachineInstr &MI : MBB) {
8691ed65febSNathan Gauër       if (isSpvIntrinsic(MI, Intrinsic::spv_track_constant) ||
8701ed65febSNathan Gauër           MI.getOpcode() == TargetOpcode::G_BRINDIRECT)
8711ed65febSNathan Gauër         ToEraseMI.push_back(&MI);
8721ed65febSNathan Gauër     }
8731ed65febSNathan Gauër   }
8741ed65febSNathan Gauër 
8751ed65febSNathan Gauër   for (MachineInstr *MI : ToEraseMI)
8761ed65febSNathan Gauër     MI->eraseFromParent();
8771ed65febSNathan Gauër }
8781ed65febSNathan Gauër 
8791ed65febSNathan Gauër // Find all usages of G_BLOCK_ADDR in our intrinsics and replace those
8801ed65febSNathan Gauër // operands/registers by the actual MBB it references.
8811ed65febSNathan Gauër static void processBlockAddr(MachineFunction &MF, SPIRVGlobalRegistry *GR,
8821ed65febSNathan Gauër                              MachineIRBuilder MIB) {
8831ed65febSNathan Gauër   // Gather the reverse-mapping BB -> MBB.
8841ed65febSNathan Gauër   DenseMap<const BasicBlock *, MachineBasicBlock *> BB2MBB;
8851ed65febSNathan Gauër   for (MachineBasicBlock &MBB : MF)
8861ed65febSNathan Gauër     BB2MBB[MBB.getBasicBlock()] = &MBB;
8871ed65febSNathan Gauër 
8881ed65febSNathan Gauër   // Gather instructions requiring patching. For now, only those can use
8891ed65febSNathan Gauër   // G_BLOCK_ADDR.
8901ed65febSNathan Gauër   SmallVector<MachineInstr *, 8> InstructionsToPatch;
8911ed65febSNathan Gauër   for (MachineBasicBlock &MBB : MF) {
8921ed65febSNathan Gauër     for (MachineInstr &MI : MBB) {
8931ed65febSNathan Gauër       if (isSpvIntrinsic(MI, Intrinsic::spv_switch) ||
8941ed65febSNathan Gauër           isSpvIntrinsic(MI, Intrinsic::spv_loop_merge) ||
8951ed65febSNathan Gauër           isSpvIntrinsic(MI, Intrinsic::spv_selection_merge))
8961ed65febSNathan Gauër         InstructionsToPatch.push_back(&MI);
8971ed65febSNathan Gauër     }
8981ed65febSNathan Gauër   }
8991ed65febSNathan Gauër 
9001ed65febSNathan Gauër   // For each instruction to fix, we replace all the G_BLOCK_ADDR operands by
9011ed65febSNathan Gauër   // the actual MBB it references. Once those references have been updated, we
9021ed65febSNathan Gauër   // can cleanup remaining G_BLOCK_ADDR references.
903ebdadcfeSVyacheslav Levytskyy   SmallPtrSet<MachineBasicBlock *, 8> ClearAddressTaken;
9041ed65febSNathan Gauër   SmallPtrSet<MachineInstr *, 8> ToEraseMI;
9051ed65febSNathan Gauër   MachineRegisterInfo &MRI = MF.getRegInfo();
9061ed65febSNathan Gauër   for (MachineInstr *MI : InstructionsToPatch) {
90723b058cbSVyacheslav Levytskyy     SmallVector<MachineOperand, 8> NewOps;
9081ed65febSNathan Gauër     for (unsigned i = 0; i < MI->getNumOperands(); ++i) {
9091ed65febSNathan Gauër       // The operand is not a register, keep as-is.
9101ed65febSNathan Gauër       if (!MI->getOperand(i).isReg()) {
9111ed65febSNathan Gauër         NewOps.push_back(MI->getOperand(i));
9121ed65febSNathan Gauër         continue;
9131ed65febSNathan Gauër       }
9141ed65febSNathan Gauër 
9151ed65febSNathan Gauër       Register Reg = MI->getOperand(i).getReg();
9161ed65febSNathan Gauër       MachineInstr *BuildMBB = MRI.getVRegDef(Reg);
9171ed65febSNathan Gauër       // The register is not the result of G_BLOCK_ADDR, keep as-is.
9181ed65febSNathan Gauër       if (!BuildMBB || BuildMBB->getOpcode() != TargetOpcode::G_BLOCK_ADDR) {
9191ed65febSNathan Gauër         NewOps.push_back(MI->getOperand(i));
9201ed65febSNathan Gauër         continue;
9211ed65febSNathan Gauër       }
9221ed65febSNathan Gauër 
9231ed65febSNathan Gauër       assert(BuildMBB && BuildMBB->getOpcode() == TargetOpcode::G_BLOCK_ADDR &&
9241ed65febSNathan Gauër              BuildMBB->getOperand(1).isBlockAddress() &&
9251ed65febSNathan Gauër              BuildMBB->getOperand(1).getBlockAddress());
9261ed65febSNathan Gauër       BasicBlock *BB =
9271ed65febSNathan Gauër           BuildMBB->getOperand(1).getBlockAddress()->getBasicBlock();
9281ed65febSNathan Gauër       auto It = BB2MBB.find(BB);
92923b058cbSVyacheslav Levytskyy       if (It == BB2MBB.end())
9301ed65febSNathan Gauër         report_fatal_error("cannot find a machine basic block by a basic block "
9311ed65febSNathan Gauër                            "in a switch statement");
9321ed65febSNathan Gauër       MachineBasicBlock *ReferencedBlock = It->second;
9331ed65febSNathan Gauër       NewOps.push_back(MachineOperand::CreateMBB(ReferencedBlock));
9341ed65febSNathan Gauër 
9351ed65febSNathan Gauër       ClearAddressTaken.insert(ReferencedBlock);
9361ed65febSNathan Gauër       ToEraseMI.insert(BuildMBB);
9370098f2aeSIlia Diachkov     }
9381ed65febSNathan Gauër 
9391ed65febSNathan Gauër     // Replace the operands.
9401ed65febSNathan Gauër     assert(MI->getNumOperands() == NewOps.size());
9411ed65febSNathan Gauër     while (MI->getNumOperands() > 0)
9421ed65febSNathan Gauër       MI->removeOperand(0);
94323b058cbSVyacheslav Levytskyy     for (auto &MO : NewOps)
9441ed65febSNathan Gauër       MI->addOperand(MO);
9451ed65febSNathan Gauër 
9461ed65febSNathan Gauër     if (MachineInstr *Next = MI->getNextNode()) {
94723b058cbSVyacheslav Levytskyy       if (isSpvIntrinsic(*Next, Intrinsic::spv_track_constant)) {
94823b058cbSVyacheslav Levytskyy         ToEraseMI.insert(Next);
9491ed65febSNathan Gauër         Next = MI->getNextNode();
95023b058cbSVyacheslav Levytskyy       }
95123b058cbSVyacheslav Levytskyy       if (Next && Next->getOpcode() == TargetOpcode::G_BRINDIRECT)
95223b058cbSVyacheslav Levytskyy         ToEraseMI.insert(Next);
9538bfb2b6dSMichal Paszkowski     }
9548bfb2b6dSMichal Paszkowski   }
955e3e06135SVyacheslav Levytskyy 
9561ed65febSNathan Gauër   // BlockAddress operands were used to keep information between passes,
9571ed65febSNathan Gauër   // let's undo the "address taken" status to reflect that Succ doesn't
9581ed65febSNathan Gauër   // actually correspond to an IR-level basic block.
9591ed65febSNathan Gauër   for (MachineBasicBlock *Succ : ClearAddressTaken)
9601ed65febSNathan Gauër     Succ->setAddressTakenIRBlock(nullptr);
9611ed65febSNathan Gauër 
962e3e06135SVyacheslav Levytskyy   // If we just delete G_BLOCK_ADDR instructions with BlockAddress operands,
963e3e06135SVyacheslav Levytskyy   // this leaves their BasicBlock counterparts in a "address taken" status. This
964e3e06135SVyacheslav Levytskyy   // would make AsmPrinter to generate a series of unneeded labels of a "Address
965e3e06135SVyacheslav Levytskyy   // of block that was removed by CodeGen" kind. Let's first ensure that we
966e3e06135SVyacheslav Levytskyy   // don't have a dangling BlockAddress constants by zapping the BlockAddress
967e3e06135SVyacheslav Levytskyy   // nodes, and only after that proceed with erasing G_BLOCK_ADDR instructions.
968e3e06135SVyacheslav Levytskyy   Constant *Replacement =
969e3e06135SVyacheslav Levytskyy       ConstantInt::get(Type::getInt32Ty(MF.getFunction().getContext()), 1);
970e3e06135SVyacheslav Levytskyy   for (MachineInstr *BlockAddrI : ToEraseMI) {
971e3e06135SVyacheslav Levytskyy     if (BlockAddrI->getOpcode() == TargetOpcode::G_BLOCK_ADDR) {
972e3e06135SVyacheslav Levytskyy       BlockAddress *BA = const_cast<BlockAddress *>(
973e3e06135SVyacheslav Levytskyy           BlockAddrI->getOperand(1).getBlockAddress());
974e3e06135SVyacheslav Levytskyy       BA->replaceAllUsesWith(
975e3e06135SVyacheslav Levytskyy           ConstantExpr::getIntToPtr(Replacement, BA->getType()));
976e3e06135SVyacheslav Levytskyy       BA->destroyConstant();
977e3e06135SVyacheslav Levytskyy     }
97823b058cbSVyacheslav Levytskyy     BlockAddrI->eraseFromParent();
9790098f2aeSIlia Diachkov   }
980e3e06135SVyacheslav Levytskyy }
9810098f2aeSIlia Diachkov 
982a9ffc92fSNathan Gauër static bool isImplicitFallthrough(MachineBasicBlock &MBB) {
983a9ffc92fSNathan Gauër   if (MBB.empty())
984a9ffc92fSNathan Gauër     return true;
985a9ffc92fSNathan Gauër 
986a9ffc92fSNathan Gauër   // Branching SPIR-V intrinsics are not detected by this generic method.
987a9ffc92fSNathan Gauër   // Thus, we can only trust negative result.
988a9ffc92fSNathan Gauër   if (!MBB.canFallThrough())
989a9ffc92fSNathan Gauër     return false;
990a9ffc92fSNathan Gauër 
991a9ffc92fSNathan Gauër   // Otherwise, we must manually check if we have a SPIR-V intrinsic which
992a9ffc92fSNathan Gauër   // prevent an implicit fallthrough.
993a9ffc92fSNathan Gauër   for (MachineBasicBlock::reverse_iterator It = MBB.rbegin(), E = MBB.rend();
994a9ffc92fSNathan Gauër        It != E; ++It) {
995a9ffc92fSNathan Gauër     if (isSpvIntrinsic(*It, Intrinsic::spv_switch))
996a9ffc92fSNathan Gauër       return false;
997a9ffc92fSNathan Gauër   }
998a9ffc92fSNathan Gauër   return true;
999a9ffc92fSNathan Gauër }
1000a9ffc92fSNathan Gauër 
1001a9ffc92fSNathan Gauër static void removeImplicitFallthroughs(MachineFunction &MF,
1002a9ffc92fSNathan Gauër                                        MachineIRBuilder MIB) {
1003a9ffc92fSNathan Gauër   // It is valid for MachineBasicBlocks to not finish with a branch instruction.
1004a9ffc92fSNathan Gauër   // In such cases, they will simply fallthrough their immediate successor.
1005a9ffc92fSNathan Gauër   for (MachineBasicBlock &MBB : MF) {
1006a9ffc92fSNathan Gauër     if (!isImplicitFallthrough(MBB))
1007a9ffc92fSNathan Gauër       continue;
1008a9ffc92fSNathan Gauër 
1009a9ffc92fSNathan Gauër     assert(std::distance(MBB.successors().begin(), MBB.successors().end()) ==
1010a9ffc92fSNathan Gauër            1);
1011a9ffc92fSNathan Gauër     MIB.setInsertPt(MBB, MBB.end());
1012a9ffc92fSNathan Gauër     MIB.buildBr(**MBB.successors().begin());
1013a9ffc92fSNathan Gauër   }
1014a9ffc92fSNathan Gauër }
1015a9ffc92fSNathan Gauër 
10160098f2aeSIlia Diachkov bool SPIRVPreLegalizer::runOnMachineFunction(MachineFunction &MF) {
10170098f2aeSIlia Diachkov   // Initialize the type registry.
10180098f2aeSIlia Diachkov   const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>();
10190098f2aeSIlia Diachkov   SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
10200098f2aeSIlia Diachkov   GR->setCurrentFunc(MF);
10210098f2aeSIlia Diachkov   MachineIRBuilder MIB(MF);
10221ed1ec9aSVyacheslav Levytskyy   // a registry of target extension constants
10231ed1ec9aSVyacheslav Levytskyy   DenseMap<MachineInstr *, Type *> TargetExtConstTypes;
10249c29217aSVyacheslav Levytskyy   // to keep record of tracked constants
10259c29217aSVyacheslav Levytskyy   SmallSet<Register, 4> TrackedConstRegs;
10269c29217aSVyacheslav Levytskyy   addConstantsToTrack(MF, GR, ST, TargetExtConstTypes, TrackedConstRegs);
10279c29217aSVyacheslav Levytskyy   foldConstantsIntoIntrinsics(MF, TrackedConstRegs);
10280098f2aeSIlia Diachkov   insertBitcasts(MF, GR, MIB);
10291ed1ec9aSVyacheslav Levytskyy   generateAssignInstrs(MF, GR, MIB, TargetExtConstTypes);
10301ed65febSNathan Gauër 
10311ed65febSNathan Gauër   processSwitchesConstants(MF, GR, MIB);
10321ed65febSNathan Gauër   processBlockAddr(MF, GR, MIB);
10331ed65febSNathan Gauër   cleanupHelperInstructions(MF);
10341ed65febSNathan Gauër 
1035df871307SIlia Diachkov   processInstrsWithTypeFolding(MF, GR, MIB);
1036a9ffc92fSNathan Gauër   removeImplicitFallthroughs(MF, MIB);
1037be9b4dabSVyacheslav Levytskyy   insertSpirvDecorations(MF, MIB);
1038214e6b40SVyacheslav Levytskyy   insertInlineAsm(MF, GR, ST, MIB);
1039c616f24bSVyacheslav Levytskyy   selectOpBitcasts(MF, GR, MIB);
10400098f2aeSIlia Diachkov 
10410098f2aeSIlia Diachkov   return true;
10420098f2aeSIlia Diachkov }
10430098f2aeSIlia Diachkov 
10440098f2aeSIlia Diachkov INITIALIZE_PASS(SPIRVPreLegalizer, DEBUG_TYPE, "SPIRV pre legalizer", false,
10450098f2aeSIlia Diachkov                 false)
10460098f2aeSIlia Diachkov 
10470098f2aeSIlia Diachkov char SPIRVPreLegalizer::ID = 0;
10480098f2aeSIlia Diachkov 
10490098f2aeSIlia Diachkov FunctionPass *llvm::createSPIRVPreLegalizerPass() {
10500098f2aeSIlia Diachkov   return new SPIRVPreLegalizer();
10510098f2aeSIlia Diachkov }
1052