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 case SPIRV::OpFunctionCall:
170 return KHRFloatControls2 ? true : false;
171 default:
172 return false;
173 }
174}
175
176bool SPIRVInstrInfo::canUseIntegerWrapDecoration(const MachineInstr &MI) const {
177 switch (MI.getOpcode()) {
178 case SPIRV::OpIAddS:
179 case SPIRV::OpIAddV:
180 case SPIRV::OpISubS:
181 case SPIRV::OpISubV:
182 case SPIRV::OpIMulS:
183 case SPIRV::OpIMulV:
184 case SPIRV::OpShiftLeftLogicalS:
185 case SPIRV::OpShiftLeftLogicalV:
186 case SPIRV::OpSNegate:
187 return true;
188 default:
189 return false;
190 }
191}
192
193// Analyze the branching code at the end of MBB, returning
194// true if it cannot be understood (e.g. it's a switch dispatch or isn't
195// implemented for a target). Upon success, this returns false and returns
196// with the following information in various cases:
197//
198// 1. If this block ends with no branches (it just falls through to its succ)
199// just return false, leaving TBB/FBB null.
200// 2. If this block ends with only an unconditional branch, it sets TBB to be
201// the destination block.
202// 3. If this block ends with a conditional branch and it falls through to a
203// successor block, it sets TBB to be the branch destination block and a
204// list of operands that evaluate the condition. These operands can be
205// passed to other TargetInstrInfo methods to create new branches.
206// 4. If this block ends with a conditional branch followed by an
207// unconditional branch, it returns the 'true' destination in TBB, the
208// 'false' destination in FBB, and a list of operands that evaluate the
209// condition. These operands can be passed to other TargetInstrInfo
210// methods to create new branches.
211//
212// Note that removeBranch and insertBranch must be implemented to support
213// cases where this method returns success.
214//
215// If AllowModify is true, then this routine is allowed to modify the basic
216// block (e.g. delete instructions after the unconditional branch).
217//
218// The CFG information in MBB.Predecessors and MBB.Successors must be valid
219// before calling this function.
220bool SPIRVInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
221 MachineBasicBlock *&TBB,
222 MachineBasicBlock *&FBB,
223 SmallVectorImpl<MachineOperand> &Cond,
224 bool AllowModify) const {
225 // We do not allow to restructure blocks by results of analyzeBranch(),
226 // because it may potentially break structured control flow and anyway
227 // doubtedly may be useful in SPIRV, including such reasons as, e.g.:
228 // 1) there is no way to encode `if (Cond) then Stmt` logic, only full
229 // if-then-else is supported by OpBranchConditional, so if we supported
230 // splitting of blocks ending with OpBranchConditional MachineBasicBlock.cpp
231 // would expect successfull implementation of calls to insertBranch() setting
232 // FBB to null that is not feasible; 2) it's not possible to delete
233 // instructions after the unconditional branch, because this instruction must
234 // be the last instruction in a block.
235 return true;
236}
237
238// Remove the branching code at the end of the specific MBB.
239// This is only invoked in cases where analyzeBranch returns success. It
240// returns the number of instructions that were removed.
241// If \p BytesRemoved is non-null, report the change in code size from the
242// removed instructions.
243unsigned SPIRVInstrInfo::removeBranch(MachineBasicBlock &MBB,
244 int * /*BytesRemoved*/) const {
245 MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
246 if (I == MBB.end())
247 return 0;
248
249 if (I->getOpcode() == SPIRV::OpBranch) {
250 I->eraseFromParent();
251 return 1;
252 }
253 return 0;
254}
255
256// Insert branch code into the end of the specified MachineBasicBlock. The
257// operands to this method are the same as those returned by analyzeBranch.
258// This is only invoked in cases where analyzeBranch returns success. It
259// returns the number of instructions inserted. If \p BytesAdded is non-null,
260// report the change in code size from the added instructions.
261//
262// It is also invoked by tail merging to add unconditional branches in
263// cases where analyzeBranch doesn't apply because there was no original
264// branch to analyze. At least this much must be implemented, else tail
265// merging needs to be disabled.
266//
267// The CFG information in MBB.Predecessors and MBB.Successors must be valid
268// before calling this function.
269unsigned SPIRVInstrInfo::insertBranch(MachineBasicBlock &MBB,
270 MachineBasicBlock *TBB,
271 MachineBasicBlock *FBB,
272 ArrayRef<MachineOperand> Cond,
273 const DebugLoc &DL,
274 int * /*BytesAdded*/) const {
275 if (!TBB)
276 return 0;
277 BuildMI(BB: &MBB, MIMD: DL, MCID: get(Opcode: SPIRV::OpBranch)).addMBB(MBB: TBB);
278 return 1;
279}
280
281void SPIRVInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
282 MachineBasicBlock::iterator I,
283 const DebugLoc &DL, Register DestReg,
284 Register SrcReg, bool KillSrc,
285 bool RenamableDest, bool RenamableSrc) const {
286 // Actually we don't need this COPY instruction. However if we do nothing with
287 // it, post RA pseudo instrs expansion just removes it and we get the code
288 // with undef registers. Therefore, we need to replace all uses of dst with
289 // the src register. COPY instr itself will be safely removed later.
290 assert(I->isCopy() && "Copy instruction is expected");
291 auto DstOp = I->getOperand(i: 0);
292 auto SrcOp = I->getOperand(i: 1);
293 assert(DstOp.isReg() && SrcOp.isReg() &&
294 "Register operands are expected in COPY");
295 auto &MRI = I->getMF()->getRegInfo();
296 MRI.replaceRegWith(FromReg: DstOp.getReg(), ToReg: SrcOp.getReg());
297}
298