1 //===-- SPIRVInstrInfo.cpp - SPIR-V Instruction Information ------*- C++-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains the SPIR-V implementation of the TargetInstrInfo class.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "SPIRVInstrInfo.h"
14 #include "SPIRV.h"
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
17 #include "llvm/CodeGen/MachineBasicBlock.h"
18 #include "llvm/IR/DebugLoc.h"
19
20 #define GET_INSTRINFO_CTOR_DTOR
21 #include "SPIRVGenInstrInfo.inc"
22
23 using namespace llvm;
24
SPIRVInstrInfo()25 SPIRVInstrInfo::SPIRVInstrInfo() : SPIRVGenInstrInfo() {}
26
isConstantInstr(const MachineInstr & MI) const27 bool SPIRVInstrInfo::isConstantInstr(const MachineInstr &MI) const {
28 switch (MI.getOpcode()) {
29 case SPIRV::OpConstantTrue:
30 case SPIRV::OpConstantFalse:
31 case SPIRV::OpConstantI:
32 case SPIRV::OpConstantF:
33 case SPIRV::OpConstantComposite:
34 case SPIRV::OpConstantCompositeContinuedINTEL:
35 case SPIRV::OpConstantSampler:
36 case SPIRV::OpConstantNull:
37 case SPIRV::OpSpecConstantTrue:
38 case SPIRV::OpSpecConstantFalse:
39 case SPIRV::OpSpecConstant:
40 case SPIRV::OpSpecConstantComposite:
41 case SPIRV::OpSpecConstantCompositeContinuedINTEL:
42 case SPIRV::OpSpecConstantOp:
43 case SPIRV::OpUndef:
44 case SPIRV::OpConstantFunctionPointerINTEL:
45 return true;
46 default:
47 return false;
48 }
49 }
50
isSpecConstantInstr(const MachineInstr & MI) const51 bool SPIRVInstrInfo::isSpecConstantInstr(const MachineInstr &MI) const {
52 switch (MI.getOpcode()) {
53 case SPIRV::OpSpecConstantTrue:
54 case SPIRV::OpSpecConstantFalse:
55 case SPIRV::OpSpecConstant:
56 case SPIRV::OpSpecConstantComposite:
57 case SPIRV::OpSpecConstantCompositeContinuedINTEL:
58 case SPIRV::OpSpecConstantOp:
59 return true;
60 default:
61 return false;
62 }
63 }
64
isInlineAsmDefInstr(const MachineInstr & MI) const65 bool SPIRVInstrInfo::isInlineAsmDefInstr(const MachineInstr &MI) const {
66 switch (MI.getOpcode()) {
67 case SPIRV::OpAsmTargetINTEL:
68 case SPIRV::OpAsmINTEL:
69 return true;
70 default:
71 return false;
72 }
73 }
74
isTypeDeclInstr(const MachineInstr & MI) const75 bool SPIRVInstrInfo::isTypeDeclInstr(const MachineInstr &MI) const {
76 auto &MRI = MI.getMF()->getRegInfo();
77 if (MI.getNumDefs() >= 1 && MI.getOperand(0).isReg()) {
78 auto DefRegClass = MRI.getRegClassOrNull(MI.getOperand(0).getReg());
79 return DefRegClass && DefRegClass->getID() == SPIRV::TYPERegClass.getID();
80 } else {
81 return MI.getOpcode() == SPIRV::OpTypeForwardPointer ||
82 MI.getOpcode() == SPIRV::OpTypeStructContinuedINTEL;
83 }
84 }
85
isDecorationInstr(const MachineInstr & MI) const86 bool SPIRVInstrInfo::isDecorationInstr(const MachineInstr &MI) const {
87 switch (MI.getOpcode()) {
88 case SPIRV::OpDecorate:
89 case SPIRV::OpDecorateId:
90 case SPIRV::OpDecorateString:
91 case SPIRV::OpMemberDecorate:
92 case SPIRV::OpMemberDecorateString:
93 return true;
94 default:
95 return false;
96 }
97 }
98
isAliasingInstr(const MachineInstr & MI) const99 bool SPIRVInstrInfo::isAliasingInstr(const MachineInstr &MI) const {
100 switch (MI.getOpcode()) {
101 case SPIRV::OpAliasDomainDeclINTEL:
102 case SPIRV::OpAliasScopeDeclINTEL:
103 case SPIRV::OpAliasScopeListDeclINTEL:
104 return true;
105 default:
106 return false;
107 }
108 }
109
isHeaderInstr(const MachineInstr & MI) const110 bool SPIRVInstrInfo::isHeaderInstr(const MachineInstr &MI) const {
111 switch (MI.getOpcode()) {
112 case SPIRV::OpCapability:
113 case SPIRV::OpExtension:
114 case SPIRV::OpExtInstImport:
115 case SPIRV::OpMemoryModel:
116 case SPIRV::OpEntryPoint:
117 case SPIRV::OpExecutionMode:
118 case SPIRV::OpExecutionModeId:
119 case SPIRV::OpString:
120 case SPIRV::OpSourceExtension:
121 case SPIRV::OpSource:
122 case SPIRV::OpSourceContinued:
123 case SPIRV::OpName:
124 case SPIRV::OpMemberName:
125 case SPIRV::OpModuleProcessed:
126 return true;
127 default:
128 return isTypeDeclInstr(MI) || isConstantInstr(MI) ||
129 isDecorationInstr(MI) || isAliasingInstr(MI);
130 }
131 }
132
canUseFastMathFlags(const MachineInstr & MI) const133 bool SPIRVInstrInfo::canUseFastMathFlags(const MachineInstr &MI) const {
134 switch (MI.getOpcode()) {
135 case SPIRV::OpFAddS:
136 case SPIRV::OpFSubS:
137 case SPIRV::OpFMulS:
138 case SPIRV::OpFDivS:
139 case SPIRV::OpFRemS:
140 case SPIRV::OpFAddV:
141 case SPIRV::OpFSubV:
142 case SPIRV::OpFMulV:
143 case SPIRV::OpFDivV:
144 case SPIRV::OpFRemV:
145 case SPIRV::OpFMod:
146 return true;
147 default:
148 return false;
149 }
150 }
151
canUseNSW(const MachineInstr & MI) const152 bool SPIRVInstrInfo::canUseNSW(const MachineInstr &MI) const {
153 switch (MI.getOpcode()) {
154 case SPIRV::OpIAddS:
155 case SPIRV::OpIAddV:
156 case SPIRV::OpISubS:
157 case SPIRV::OpISubV:
158 case SPIRV::OpIMulS:
159 case SPIRV::OpIMulV:
160 case SPIRV::OpShiftLeftLogicalS:
161 case SPIRV::OpShiftLeftLogicalV:
162 case SPIRV::OpSNegate:
163 return true;
164 default:
165 return false;
166 }
167 }
168
canUseNUW(const MachineInstr & MI) const169 bool SPIRVInstrInfo::canUseNUW(const MachineInstr &MI) const {
170 switch (MI.getOpcode()) {
171 case SPIRV::OpIAddS:
172 case SPIRV::OpIAddV:
173 case SPIRV::OpISubS:
174 case SPIRV::OpISubV:
175 case SPIRV::OpIMulS:
176 case SPIRV::OpIMulV:
177 return true;
178 default:
179 return false;
180 }
181 }
182
183 // Analyze the branching code at the end of MBB, returning
184 // true if it cannot be understood (e.g. it's a switch dispatch or isn't
185 // implemented for a target). Upon success, this returns false and returns
186 // with the following information in various cases:
187 //
188 // 1. If this block ends with no branches (it just falls through to its succ)
189 // just return false, leaving TBB/FBB null.
190 // 2. If this block ends with only an unconditional branch, it sets TBB to be
191 // the destination block.
192 // 3. If this block ends with a conditional branch and it falls through to a
193 // successor block, it sets TBB to be the branch destination block and a
194 // list of operands that evaluate the condition. These operands can be
195 // passed to other TargetInstrInfo methods to create new branches.
196 // 4. If this block ends with a conditional branch followed by an
197 // unconditional branch, it returns the 'true' destination in TBB, the
198 // 'false' destination in FBB, and a list of operands that evaluate the
199 // condition. These operands can be passed to other TargetInstrInfo
200 // methods to create new branches.
201 //
202 // Note that removeBranch and insertBranch must be implemented to support
203 // cases where this method returns success.
204 //
205 // If AllowModify is true, then this routine is allowed to modify the basic
206 // block (e.g. delete instructions after the unconditional branch).
207 //
208 // The CFG information in MBB.Predecessors and MBB.Successors must be valid
209 // before calling this function.
analyzeBranch(MachineBasicBlock & MBB,MachineBasicBlock * & TBB,MachineBasicBlock * & FBB,SmallVectorImpl<MachineOperand> & Cond,bool AllowModify) const210 bool SPIRVInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
211 MachineBasicBlock *&TBB,
212 MachineBasicBlock *&FBB,
213 SmallVectorImpl<MachineOperand> &Cond,
214 bool AllowModify) const {
215 // We do not allow to restructure blocks by results of analyzeBranch(),
216 // because it may potentially break structured control flow and anyway
217 // doubtedly may be useful in SPIRV, including such reasons as, e.g.:
218 // 1) there is no way to encode `if (Cond) then Stmt` logic, only full
219 // if-then-else is supported by OpBranchConditional, so if we supported
220 // splitting of blocks ending with OpBranchConditional MachineBasicBlock.cpp
221 // would expect successfull implementation of calls to insertBranch() setting
222 // FBB to null that is not feasible; 2) it's not possible to delete
223 // instructions after the unconditional branch, because this instruction must
224 // be the last instruction in a block.
225 return true;
226 }
227
228 // Remove the branching code at the end of the specific MBB.
229 // This is only invoked in cases where analyzeBranch returns success. It
230 // returns the number of instructions that were removed.
231 // If \p BytesRemoved is non-null, report the change in code size from the
232 // removed instructions.
removeBranch(MachineBasicBlock & MBB,int *) const233 unsigned SPIRVInstrInfo::removeBranch(MachineBasicBlock &MBB,
234 int * /*BytesRemoved*/) const {
235 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
236 if (I == MBB.end())
237 return 0;
238
239 if (I->getOpcode() == SPIRV::OpBranch) {
240 I->eraseFromParent();
241 return 1;
242 }
243 return 0;
244 }
245
246 // Insert branch code into the end of the specified MachineBasicBlock. The
247 // operands to this method are the same as those returned by analyzeBranch.
248 // This is only invoked in cases where analyzeBranch returns success. It
249 // returns the number of instructions inserted. If \p BytesAdded is non-null,
250 // report the change in code size from the added instructions.
251 //
252 // It is also invoked by tail merging to add unconditional branches in
253 // cases where analyzeBranch doesn't apply because there was no original
254 // branch to analyze. At least this much must be implemented, else tail
255 // merging needs to be disabled.
256 //
257 // The CFG information in MBB.Predecessors and MBB.Successors must be valid
258 // before calling this function.
insertBranch(MachineBasicBlock & MBB,MachineBasicBlock * TBB,MachineBasicBlock * FBB,ArrayRef<MachineOperand> Cond,const DebugLoc & DL,int *) const259 unsigned SPIRVInstrInfo::insertBranch(MachineBasicBlock &MBB,
260 MachineBasicBlock *TBB,
261 MachineBasicBlock *FBB,
262 ArrayRef<MachineOperand> Cond,
263 const DebugLoc &DL,
264 int * /*BytesAdded*/) const {
265 if (!TBB)
266 return 0;
267 BuildMI(&MBB, DL, get(SPIRV::OpBranch)).addMBB(TBB);
268 return 1;
269 }
270
copyPhysReg(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,const DebugLoc & DL,Register DestReg,Register SrcReg,bool KillSrc,bool RenamableDest,bool RenamableSrc) const271 void SPIRVInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
272 MachineBasicBlock::iterator I,
273 const DebugLoc &DL, Register DestReg,
274 Register SrcReg, bool KillSrc,
275 bool RenamableDest, bool RenamableSrc) const {
276 // Actually we don't need this COPY instruction. However if we do nothing with
277 // it, post RA pseudo instrs expansion just removes it and we get the code
278 // with undef registers. Therefore, we need to replace all uses of dst with
279 // the src register. COPY instr itself will be safely removed later.
280 assert(I->isCopy() && "Copy instruction is expected");
281 auto DstOp = I->getOperand(0);
282 auto SrcOp = I->getOperand(1);
283 assert(DstOp.isReg() && SrcOp.isReg() &&
284 "Register operands are expected in COPY");
285 auto &MRI = I->getMF()->getRegInfo();
286 MRI.replaceRegWith(DstOp.getReg(), SrcOp.getReg());
287 }
288