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