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