xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVPostLegalizer.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===-- SPIRVPostLegalizer.cpp - ammend info after legalization -*- C++ -*-===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // which may appear after the legalizer pass
4*0fca6ea1SDimitry Andric //
5*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
7*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8*0fca6ea1SDimitry Andric //
9*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
10*0fca6ea1SDimitry Andric //
11*0fca6ea1SDimitry Andric // The pass partially apply pre-legalization logic to new instructions inserted
12*0fca6ea1SDimitry Andric // as a result of legalization:
13*0fca6ea1SDimitry Andric // - assigns SPIR-V types to registers for new instructions.
14*0fca6ea1SDimitry Andric //
15*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
16*0fca6ea1SDimitry Andric 
17*0fca6ea1SDimitry Andric #include "SPIRV.h"
18*0fca6ea1SDimitry Andric #include "SPIRVSubtarget.h"
19*0fca6ea1SDimitry Andric #include "SPIRVUtils.h"
20*0fca6ea1SDimitry Andric #include "llvm/ADT/PostOrderIterator.h"
21*0fca6ea1SDimitry Andric #include "llvm/Analysis/OptimizationRemarkEmitter.h"
22*0fca6ea1SDimitry Andric #include "llvm/IR/Attributes.h"
23*0fca6ea1SDimitry Andric #include "llvm/IR/Constants.h"
24*0fca6ea1SDimitry Andric #include "llvm/IR/DebugInfoMetadata.h"
25*0fca6ea1SDimitry Andric #include "llvm/IR/IntrinsicsSPIRV.h"
26*0fca6ea1SDimitry Andric #include "llvm/Target/TargetIntrinsicInfo.h"
27*0fca6ea1SDimitry Andric 
28*0fca6ea1SDimitry Andric #define DEBUG_TYPE "spirv-postlegalizer"
29*0fca6ea1SDimitry Andric 
30*0fca6ea1SDimitry Andric using namespace llvm;
31*0fca6ea1SDimitry Andric 
32*0fca6ea1SDimitry Andric namespace {
33*0fca6ea1SDimitry Andric class SPIRVPostLegalizer : public MachineFunctionPass {
34*0fca6ea1SDimitry Andric public:
35*0fca6ea1SDimitry Andric   static char ID;
36*0fca6ea1SDimitry Andric   SPIRVPostLegalizer() : MachineFunctionPass(ID) {
37*0fca6ea1SDimitry Andric     initializeSPIRVPostLegalizerPass(*PassRegistry::getPassRegistry());
38*0fca6ea1SDimitry Andric   }
39*0fca6ea1SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
40*0fca6ea1SDimitry Andric };
41*0fca6ea1SDimitry Andric } // namespace
42*0fca6ea1SDimitry Andric 
43*0fca6ea1SDimitry Andric // Defined in SPIRVLegalizerInfo.cpp.
44*0fca6ea1SDimitry Andric extern bool isTypeFoldingSupported(unsigned Opcode);
45*0fca6ea1SDimitry Andric 
46*0fca6ea1SDimitry Andric namespace llvm {
47*0fca6ea1SDimitry Andric //  Defined in SPIRVPreLegalizer.cpp.
48*0fca6ea1SDimitry Andric extern Register insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy,
49*0fca6ea1SDimitry Andric                                   SPIRVGlobalRegistry *GR,
50*0fca6ea1SDimitry Andric                                   MachineIRBuilder &MIB,
51*0fca6ea1SDimitry Andric                                   MachineRegisterInfo &MRI);
52*0fca6ea1SDimitry Andric extern void processInstr(MachineInstr &MI, MachineIRBuilder &MIB,
53*0fca6ea1SDimitry Andric                          MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR);
54*0fca6ea1SDimitry Andric } // namespace llvm
55*0fca6ea1SDimitry Andric 
56*0fca6ea1SDimitry Andric static bool isMetaInstrGET(unsigned Opcode) {
57*0fca6ea1SDimitry Andric   return Opcode == SPIRV::GET_ID || Opcode == SPIRV::GET_ID64 ||
58*0fca6ea1SDimitry Andric          Opcode == SPIRV::GET_fID || Opcode == SPIRV::GET_fID64 ||
59*0fca6ea1SDimitry Andric          Opcode == SPIRV::GET_pID32 || Opcode == SPIRV::GET_pID64 ||
60*0fca6ea1SDimitry Andric          Opcode == SPIRV::GET_vID || Opcode == SPIRV::GET_vfID ||
61*0fca6ea1SDimitry Andric          Opcode == SPIRV::GET_vpID32 || Opcode == SPIRV::GET_vpID64;
62*0fca6ea1SDimitry Andric }
63*0fca6ea1SDimitry Andric 
64*0fca6ea1SDimitry Andric static bool mayBeInserted(unsigned Opcode) {
65*0fca6ea1SDimitry Andric   switch (Opcode) {
66*0fca6ea1SDimitry Andric   case TargetOpcode::G_SMAX:
67*0fca6ea1SDimitry Andric   case TargetOpcode::G_UMAX:
68*0fca6ea1SDimitry Andric   case TargetOpcode::G_SMIN:
69*0fca6ea1SDimitry Andric   case TargetOpcode::G_UMIN:
70*0fca6ea1SDimitry Andric   case TargetOpcode::G_FMINNUM:
71*0fca6ea1SDimitry Andric   case TargetOpcode::G_FMINIMUM:
72*0fca6ea1SDimitry Andric   case TargetOpcode::G_FMAXNUM:
73*0fca6ea1SDimitry Andric   case TargetOpcode::G_FMAXIMUM:
74*0fca6ea1SDimitry Andric     return true;
75*0fca6ea1SDimitry Andric   default:
76*0fca6ea1SDimitry Andric     return isTypeFoldingSupported(Opcode);
77*0fca6ea1SDimitry Andric   }
78*0fca6ea1SDimitry Andric }
79*0fca6ea1SDimitry Andric 
80*0fca6ea1SDimitry Andric static void processNewInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR,
81*0fca6ea1SDimitry Andric                              MachineIRBuilder MIB) {
82*0fca6ea1SDimitry Andric   MachineRegisterInfo &MRI = MF.getRegInfo();
83*0fca6ea1SDimitry Andric 
84*0fca6ea1SDimitry Andric   for (MachineBasicBlock &MBB : MF) {
85*0fca6ea1SDimitry Andric     for (MachineInstr &I : MBB) {
86*0fca6ea1SDimitry Andric       const unsigned Opcode = I.getOpcode();
87*0fca6ea1SDimitry Andric       if (Opcode == TargetOpcode::G_UNMERGE_VALUES) {
88*0fca6ea1SDimitry Andric         unsigned ArgI = I.getNumOperands() - 1;
89*0fca6ea1SDimitry Andric         Register SrcReg = I.getOperand(ArgI).isReg()
90*0fca6ea1SDimitry Andric                               ? I.getOperand(ArgI).getReg()
91*0fca6ea1SDimitry Andric                               : Register(0);
92*0fca6ea1SDimitry Andric         SPIRVType *DefType =
93*0fca6ea1SDimitry Andric             SrcReg.isValid() ? GR->getSPIRVTypeForVReg(SrcReg) : nullptr;
94*0fca6ea1SDimitry Andric         if (!DefType || DefType->getOpcode() != SPIRV::OpTypeVector)
95*0fca6ea1SDimitry Andric           report_fatal_error(
96*0fca6ea1SDimitry Andric               "cannot select G_UNMERGE_VALUES with a non-vector argument");
97*0fca6ea1SDimitry Andric         SPIRVType *ScalarType =
98*0fca6ea1SDimitry Andric             GR->getSPIRVTypeForVReg(DefType->getOperand(1).getReg());
99*0fca6ea1SDimitry Andric         for (unsigned i = 0; i < I.getNumDefs(); ++i) {
100*0fca6ea1SDimitry Andric           Register ResVReg = I.getOperand(i).getReg();
101*0fca6ea1SDimitry Andric           SPIRVType *ResType = GR->getSPIRVTypeForVReg(ResVReg);
102*0fca6ea1SDimitry Andric           if (!ResType) {
103*0fca6ea1SDimitry Andric             // There was no "assign type" actions, let's fix this now
104*0fca6ea1SDimitry Andric             ResType = ScalarType;
105*0fca6ea1SDimitry Andric             MRI.setRegClass(ResVReg, &SPIRV::IDRegClass);
106*0fca6ea1SDimitry Andric             MRI.setType(ResVReg,
107*0fca6ea1SDimitry Andric                         LLT::scalar(GR->getScalarOrVectorBitWidth(ResType)));
108*0fca6ea1SDimitry Andric             GR->assignSPIRVTypeToVReg(ResType, ResVReg, *GR->CurMF);
109*0fca6ea1SDimitry Andric           }
110*0fca6ea1SDimitry Andric         }
111*0fca6ea1SDimitry Andric       } else if (mayBeInserted(Opcode) && I.getNumDefs() == 1 &&
112*0fca6ea1SDimitry Andric                  I.getNumOperands() > 1 && I.getOperand(1).isReg()) {
113*0fca6ea1SDimitry Andric         // Legalizer may have added a new instructions and introduced new
114*0fca6ea1SDimitry Andric         // registers, we must decorate them as if they were introduced in a
115*0fca6ea1SDimitry Andric         // non-automatic way
116*0fca6ea1SDimitry Andric         Register ResVReg = I.getOperand(0).getReg();
117*0fca6ea1SDimitry Andric         SPIRVType *ResVType = GR->getSPIRVTypeForVReg(ResVReg);
118*0fca6ea1SDimitry Andric         // Check if the register defined by the instruction is newly generated
119*0fca6ea1SDimitry Andric         // or already processed
120*0fca6ea1SDimitry Andric         if (!ResVType) {
121*0fca6ea1SDimitry Andric           // Set type of the defined register
122*0fca6ea1SDimitry Andric           ResVType = GR->getSPIRVTypeForVReg(I.getOperand(1).getReg());
123*0fca6ea1SDimitry Andric           // Check if we have type defined for operands of the new instruction
124*0fca6ea1SDimitry Andric           if (!ResVType)
125*0fca6ea1SDimitry Andric             continue;
126*0fca6ea1SDimitry Andric           // Set type & class
127*0fca6ea1SDimitry Andric           MRI.setRegClass(ResVReg, &SPIRV::IDRegClass);
128*0fca6ea1SDimitry Andric           MRI.setType(ResVReg,
129*0fca6ea1SDimitry Andric                       LLT::scalar(GR->getScalarOrVectorBitWidth(ResVType)));
130*0fca6ea1SDimitry Andric           GR->assignSPIRVTypeToVReg(ResVType, ResVReg, *GR->CurMF);
131*0fca6ea1SDimitry Andric         }
132*0fca6ea1SDimitry Andric         // If this is a simple operation that is to be reduced by TableGen
133*0fca6ea1SDimitry Andric         // definition we must apply some of pre-legalizer rules here
134*0fca6ea1SDimitry Andric         if (isTypeFoldingSupported(Opcode)) {
135*0fca6ea1SDimitry Andric           // Check if the instruction newly generated or already processed
136*0fca6ea1SDimitry Andric           MachineInstr *NextMI = I.getNextNode();
137*0fca6ea1SDimitry Andric           if (NextMI && isMetaInstrGET(NextMI->getOpcode()))
138*0fca6ea1SDimitry Andric             continue;
139*0fca6ea1SDimitry Andric           // Restore usual instructions pattern for the newly inserted
140*0fca6ea1SDimitry Andric           // instruction
141*0fca6ea1SDimitry Andric           MRI.setRegClass(ResVReg, MRI.getType(ResVReg).isVector()
142*0fca6ea1SDimitry Andric                                        ? &SPIRV::IDRegClass
143*0fca6ea1SDimitry Andric                                        : &SPIRV::ANYIDRegClass);
144*0fca6ea1SDimitry Andric           MRI.setType(ResVReg, LLT::scalar(32));
145*0fca6ea1SDimitry Andric           insertAssignInstr(ResVReg, nullptr, ResVType, GR, MIB, MRI);
146*0fca6ea1SDimitry Andric           processInstr(I, MIB, MRI, GR);
147*0fca6ea1SDimitry Andric         }
148*0fca6ea1SDimitry Andric       }
149*0fca6ea1SDimitry Andric     }
150*0fca6ea1SDimitry Andric   }
151*0fca6ea1SDimitry Andric }
152*0fca6ea1SDimitry Andric 
153*0fca6ea1SDimitry Andric bool SPIRVPostLegalizer::runOnMachineFunction(MachineFunction &MF) {
154*0fca6ea1SDimitry Andric   // Initialize the type registry.
155*0fca6ea1SDimitry Andric   const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>();
156*0fca6ea1SDimitry Andric   SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry();
157*0fca6ea1SDimitry Andric   GR->setCurrentFunc(MF);
158*0fca6ea1SDimitry Andric   MachineIRBuilder MIB(MF);
159*0fca6ea1SDimitry Andric 
160*0fca6ea1SDimitry Andric   processNewInstrs(MF, GR, MIB);
161*0fca6ea1SDimitry Andric 
162*0fca6ea1SDimitry Andric   return true;
163*0fca6ea1SDimitry Andric }
164*0fca6ea1SDimitry Andric 
165*0fca6ea1SDimitry Andric INITIALIZE_PASS(SPIRVPostLegalizer, DEBUG_TYPE, "SPIRV post legalizer", false,
166*0fca6ea1SDimitry Andric                 false)
167*0fca6ea1SDimitry Andric 
168*0fca6ea1SDimitry Andric char SPIRVPostLegalizer::ID = 0;
169*0fca6ea1SDimitry Andric 
170*0fca6ea1SDimitry Andric FunctionPass *llvm::createSPIRVPostLegalizerPass() {
171*0fca6ea1SDimitry Andric   return new SPIRVPostLegalizer();
172*0fca6ea1SDimitry Andric }
173