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