| 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/IR/Attributes.h" |
| 21 | #include <stack> |
| 22 | |
| 23 | #define DEBUG_TYPE "spirv-postlegalizer" |
| 24 | |
| 25 | using namespace llvm; |
| 26 | |
| 27 | namespace { |
| 28 | class SPIRVPostLegalizer : public MachineFunctionPass { |
| 29 | public: |
| 30 | static char ID; |
| 31 | SPIRVPostLegalizer() : MachineFunctionPass(ID) {} |
| 32 | bool runOnMachineFunction(MachineFunction &MF) override; |
| 33 | }; |
| 34 | } // namespace |
| 35 | |
| 36 | namespace llvm { |
| 37 | // Defined in SPIRVPreLegalizer.cpp. |
| 38 | extern void insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy, |
| 39 | SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, |
| 40 | MachineRegisterInfo &MRI); |
| 41 | extern void processInstr(MachineInstr &MI, MachineIRBuilder &MIB, |
| 42 | MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR, |
| 43 | SPIRVType *KnownResType); |
| 44 | } // namespace llvm |
| 45 | |
| 46 | static bool mayBeInserted(unsigned Opcode) { |
| 47 | switch (Opcode) { |
| 48 | case TargetOpcode::G_SMAX: |
| 49 | case TargetOpcode::G_UMAX: |
| 50 | case TargetOpcode::G_SMIN: |
| 51 | case TargetOpcode::G_UMIN: |
| 52 | case TargetOpcode::G_FMINNUM: |
| 53 | case TargetOpcode::G_FMINIMUM: |
| 54 | case TargetOpcode::G_FMAXNUM: |
| 55 | case TargetOpcode::G_FMAXIMUM: |
| 56 | return true; |
| 57 | default: |
| 58 | return isTypeFoldingSupported(Opcode); |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | static void processNewInstrs(MachineFunction &MF, SPIRVGlobalRegistry *GR, |
| 63 | MachineIRBuilder MIB) { |
| 64 | MachineRegisterInfo &MRI = MF.getRegInfo(); |
| 65 | |
| 66 | for (MachineBasicBlock &MBB : MF) { |
| 67 | for (MachineInstr &I : MBB) { |
| 68 | const unsigned Opcode = I.getOpcode(); |
| 69 | if (Opcode == TargetOpcode::G_UNMERGE_VALUES) { |
| 70 | unsigned ArgI = I.getNumOperands() - 1; |
| 71 | Register SrcReg = I.getOperand(i: ArgI).isReg() |
| 72 | ? I.getOperand(i: ArgI).getReg() |
| 73 | : Register(0); |
| 74 | SPIRVType *DefType = |
| 75 | SrcReg.isValid() ? GR->getSPIRVTypeForVReg(VReg: SrcReg) : nullptr; |
| 76 | if (!DefType || DefType->getOpcode() != SPIRV::OpTypeVector) |
| 77 | report_fatal_error( |
| 78 | reason: "cannot select G_UNMERGE_VALUES with a non-vector argument" ); |
| 79 | SPIRVType *ScalarType = |
| 80 | GR->getSPIRVTypeForVReg(VReg: DefType->getOperand(i: 1).getReg()); |
| 81 | for (unsigned i = 0; i < I.getNumDefs(); ++i) { |
| 82 | Register ResVReg = I.getOperand(i).getReg(); |
| 83 | SPIRVType *ResType = GR->getSPIRVTypeForVReg(VReg: ResVReg); |
| 84 | if (!ResType) { |
| 85 | // There was no "assign type" actions, let's fix this now |
| 86 | ResType = ScalarType; |
| 87 | setRegClassType(Reg: ResVReg, SpvType: ResType, GR, MRI: &MRI, MF: *GR->CurMF, Force: true); |
| 88 | } |
| 89 | } |
| 90 | } else if (mayBeInserted(Opcode) && I.getNumDefs() == 1 && |
| 91 | I.getNumOperands() > 1 && I.getOperand(i: 1).isReg()) { |
| 92 | // Legalizer may have added a new instructions and introduced new |
| 93 | // registers, we must decorate them as if they were introduced in a |
| 94 | // non-automatic way |
| 95 | Register ResVReg = I.getOperand(i: 0).getReg(); |
| 96 | // Check if the register defined by the instruction is newly generated |
| 97 | // or already processed |
| 98 | // Check if we have type defined for operands of the new instruction |
| 99 | bool IsKnownReg = MRI.getRegClassOrNull(Reg: ResVReg); |
| 100 | SPIRVType *ResVType = GR->getSPIRVTypeForVReg( |
| 101 | VReg: IsKnownReg ? ResVReg : I.getOperand(i: 1).getReg()); |
| 102 | if (!ResVType) |
| 103 | continue; |
| 104 | // Set type & class |
| 105 | if (!IsKnownReg) |
| 106 | setRegClassType(Reg: ResVReg, SpvType: ResVType, GR, MRI: &MRI, MF: *GR->CurMF, Force: true); |
| 107 | // If this is a simple operation that is to be reduced by TableGen |
| 108 | // definition we must apply some of pre-legalizer rules here |
| 109 | if (isTypeFoldingSupported(Opcode)) { |
| 110 | processInstr(MI&: I, MIB, MRI, GR, KnownResType: GR->getSPIRVTypeForVReg(VReg: ResVReg)); |
| 111 | if (IsKnownReg && MRI.hasOneUse(RegNo: ResVReg)) { |
| 112 | MachineInstr &UseMI = *MRI.use_instr_begin(RegNo: ResVReg); |
| 113 | if (UseMI.getOpcode() == SPIRV::ASSIGN_TYPE) |
| 114 | continue; |
| 115 | } |
| 116 | insertAssignInstr(Reg: ResVReg, Ty: nullptr, SpirvTy: ResVType, GR, MIB, MRI); |
| 117 | } |
| 118 | } |
| 119 | } |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | // Do a preorder traversal of the CFG starting from the BB |Start|. |
| 124 | // point. Calls |op| on each basic block encountered during the traversal. |
| 125 | void visit(MachineFunction &MF, MachineBasicBlock &Start, |
| 126 | std::function<void(MachineBasicBlock *)> op) { |
| 127 | std::stack<MachineBasicBlock *> ToVisit; |
| 128 | SmallPtrSet<MachineBasicBlock *, 8> Seen; |
| 129 | |
| 130 | ToVisit.push(x: &Start); |
| 131 | Seen.insert(Ptr: ToVisit.top()); |
| 132 | while (ToVisit.size() != 0) { |
| 133 | MachineBasicBlock *MBB = ToVisit.top(); |
| 134 | ToVisit.pop(); |
| 135 | |
| 136 | op(MBB); |
| 137 | |
| 138 | for (auto Succ : MBB->successors()) { |
| 139 | if (Seen.contains(Ptr: Succ)) |
| 140 | continue; |
| 141 | ToVisit.push(x: Succ); |
| 142 | Seen.insert(Ptr: Succ); |
| 143 | } |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | // Do a preorder traversal of the CFG starting from the given function's entry |
| 148 | // point. Calls |op| on each basic block encountered during the traversal. |
| 149 | void visit(MachineFunction &MF, std::function<void(MachineBasicBlock *)> op) { |
| 150 | visit(MF, Start&: *MF.begin(), op); |
| 151 | } |
| 152 | |
| 153 | bool SPIRVPostLegalizer::runOnMachineFunction(MachineFunction &MF) { |
| 154 | // Initialize the type registry. |
| 155 | const SPIRVSubtarget &ST = MF.getSubtarget<SPIRVSubtarget>(); |
| 156 | SPIRVGlobalRegistry *GR = ST.getSPIRVGlobalRegistry(); |
| 157 | GR->setCurrentFunc(MF); |
| 158 | MachineIRBuilder MIB(MF); |
| 159 | |
| 160 | processNewInstrs(MF, GR, MIB); |
| 161 | |
| 162 | return true; |
| 163 | } |
| 164 | |
| 165 | INITIALIZE_PASS(SPIRVPostLegalizer, DEBUG_TYPE, "SPIRV post legalizer" , false, |
| 166 | false) |
| 167 | |
| 168 | char SPIRVPostLegalizer::ID = 0; |
| 169 | |
| 170 | FunctionPass *llvm::createSPIRVPostLegalizerPass() { |
| 171 | return new SPIRVPostLegalizer(); |
| 172 | } |
| 173 | |