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 | |