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