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#include "llvm/Support/ErrorHandling.h"
20
21#define GET_INSTRINFO_CTOR_DTOR
22#include "SPIRVGenInstrInfo.inc"
23
24using namespace llvm;
25
26SPIRVInstrInfo::SPIRVInstrInfo() : SPIRVGenInstrInfo() {}
27
28bool SPIRVInstrInfo::isConstantInstr(const MachineInstr &MI) const {
29 switch (MI.getOpcode()) {
30 case SPIRV::OpConstantTrue:
31 case SPIRV::OpConstantFalse:
32 case SPIRV::OpConstantI:
33 case SPIRV::OpConstantF:
34 case SPIRV::OpConstantComposite:
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::OpSpecConstantOp:
42 case SPIRV::OpUndef:
43 case SPIRV::OpConstantFunctionPointerINTEL:
44 return true;
45 default:
46 return false;
47 }
48}
49
50bool SPIRVInstrInfo::isTypeDeclInstr(const MachineInstr &MI) const {
51 auto &MRI = MI.getMF()->getRegInfo();
52 if (MI.getNumDefs() >= 1 && MI.getOperand(i: 0).isReg()) {
53 auto DefRegClass = MRI.getRegClassOrNull(Reg: MI.getOperand(i: 0).getReg());
54 return DefRegClass && DefRegClass->getID() == SPIRV::TYPERegClass.getID();
55 } else {
56 return MI.getOpcode() == SPIRV::OpTypeForwardPointer;
57 }
58}
59
60bool SPIRVInstrInfo::isDecorationInstr(const MachineInstr &MI) const {
61 switch (MI.getOpcode()) {
62 case SPIRV::OpDecorate:
63 case SPIRV::OpDecorateId:
64 case SPIRV::OpDecorateString:
65 case SPIRV::OpMemberDecorate:
66 case SPIRV::OpMemberDecorateString:
67 return true;
68 default:
69 return false;
70 }
71}
72
73bool SPIRVInstrInfo::isHeaderInstr(const MachineInstr &MI) const {
74 switch (MI.getOpcode()) {
75 case SPIRV::OpCapability:
76 case SPIRV::OpExtension:
77 case SPIRV::OpExtInstImport:
78 case SPIRV::OpMemoryModel:
79 case SPIRV::OpEntryPoint:
80 case SPIRV::OpExecutionMode:
81 case SPIRV::OpExecutionModeId:
82 case SPIRV::OpString:
83 case SPIRV::OpSourceExtension:
84 case SPIRV::OpSource:
85 case SPIRV::OpSourceContinued:
86 case SPIRV::OpName:
87 case SPIRV::OpMemberName:
88 case SPIRV::OpModuleProcessed:
89 return true;
90 default:
91 return isTypeDeclInstr(MI) || isConstantInstr(MI) || isDecorationInstr(MI);
92 }
93}
94
95bool SPIRVInstrInfo::canUseFastMathFlags(const MachineInstr &MI) const {
96 switch (MI.getOpcode()) {
97 case SPIRV::OpFAddS:
98 case SPIRV::OpFSubS:
99 case SPIRV::OpFMulS:
100 case SPIRV::OpFDivS:
101 case SPIRV::OpFRemS:
102 case SPIRV::OpFAddV:
103 case SPIRV::OpFSubV:
104 case SPIRV::OpFMulV:
105 case SPIRV::OpFDivV:
106 case SPIRV::OpFRemV:
107 case SPIRV::OpFMod:
108 return true;
109 default:
110 return false;
111 }
112}
113
114bool SPIRVInstrInfo::canUseNSW(const MachineInstr &MI) const {
115 switch (MI.getOpcode()) {
116 case SPIRV::OpIAddS:
117 case SPIRV::OpIAddV:
118 case SPIRV::OpISubS:
119 case SPIRV::OpISubV:
120 case SPIRV::OpIMulS:
121 case SPIRV::OpIMulV:
122 case SPIRV::OpShiftLeftLogicalS:
123 case SPIRV::OpShiftLeftLogicalV:
124 case SPIRV::OpSNegate:
125 return true;
126 default:
127 return false;
128 }
129}
130
131bool SPIRVInstrInfo::canUseNUW(const MachineInstr &MI) const {
132 switch (MI.getOpcode()) {
133 case SPIRV::OpIAddS:
134 case SPIRV::OpIAddV:
135 case SPIRV::OpISubS:
136 case SPIRV::OpISubV:
137 case SPIRV::OpIMulS:
138 case SPIRV::OpIMulV:
139 return true;
140 default:
141 return false;
142 }
143}
144
145// Analyze the branching code at the end of MBB, returning
146// true if it cannot be understood (e.g. it's a switch dispatch or isn't
147// implemented for a target). Upon success, this returns false and returns
148// with the following information in various cases:
149//
150// 1. If this block ends with no branches (it just falls through to its succ)
151// just return false, leaving TBB/FBB null.
152// 2. If this block ends with only an unconditional branch, it sets TBB to be
153// the destination block.
154// 3. If this block ends with a conditional branch and it falls through to a
155// successor block, it sets TBB to be the branch destination block and a
156// list of operands that evaluate the condition. These operands can be
157// passed to other TargetInstrInfo methods to create new branches.
158// 4. If this block ends with a conditional branch followed by an
159// unconditional branch, it returns the 'true' destination in TBB, the
160// 'false' destination in FBB, and a list of operands that evaluate the
161// condition. These operands can be passed to other TargetInstrInfo
162// methods to create new branches.
163//
164// Note that removeBranch and insertBranch must be implemented to support
165// cases where this method returns success.
166//
167// If AllowModify is true, then this routine is allowed to modify the basic
168// block (e.g. delete instructions after the unconditional branch).
169//
170// The CFG information in MBB.Predecessors and MBB.Successors must be valid
171// before calling this function.
172bool SPIRVInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
173 MachineBasicBlock *&TBB,
174 MachineBasicBlock *&FBB,
175 SmallVectorImpl<MachineOperand> &Cond,
176 bool AllowModify) const {
177 TBB = nullptr;
178 FBB = nullptr;
179 if (MBB.empty())
180 return false;
181 auto MI = MBB.getLastNonDebugInstr();
182 if (!MI.isValid())
183 return false;
184 if (MI->getOpcode() == SPIRV::OpBranch) {
185 TBB = MI->getOperand(i: 0).getMBB();
186 return false;
187 } else if (MI->getOpcode() == SPIRV::OpBranchConditional) {
188 Cond.push_back(Elt: MI->getOperand(i: 0));
189 TBB = MI->getOperand(i: 1).getMBB();
190 if (MI->getNumOperands() == 3) {
191 FBB = MI->getOperand(i: 2).getMBB();
192 }
193 return false;
194 } else {
195 return true;
196 }
197}
198
199// Remove the branching code at the end of the specific MBB.
200// This is only invoked in cases where analyzeBranch returns success. It
201// returns the number of instructions that were removed.
202// If \p BytesRemoved is non-null, report the change in code size from the
203// removed instructions.
204unsigned SPIRVInstrInfo::removeBranch(MachineBasicBlock &MBB,
205 int *BytesRemoved) const {
206 report_fatal_error(reason: "Branch removal not supported, as MBB info not propagated"
207 " to OpPhi instructions. Try using -O0 instead.");
208}
209
210// Insert branch code into the end of the specified MachineBasicBlock. The
211// operands to this method are the same as those returned by analyzeBranch.
212// This is only invoked in cases where analyzeBranch returns success. It
213// returns the number of instructions inserted. If \p BytesAdded is non-null,
214// report the change in code size from the added instructions.
215//
216// It is also invoked by tail merging to add unconditional branches in
217// cases where analyzeBranch doesn't apply because there was no original
218// branch to analyze. At least this much must be implemented, else tail
219// merging needs to be disabled.
220//
221// The CFG information in MBB.Predecessors and MBB.Successors must be valid
222// before calling this function.
223unsigned SPIRVInstrInfo::insertBranch(
224 MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,
225 ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {
226 report_fatal_error(reason: "Branch insertion not supported, as MBB info not "
227 "propagated to OpPhi instructions. Try using "
228 "-O0 instead.");
229}
230
231void SPIRVInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
232 MachineBasicBlock::iterator I,
233 const DebugLoc &DL, MCRegister DestReg,
234 MCRegister SrcReg, bool KillSrc) const {
235 // Actually we don't need this COPY instruction. However if we do nothing with
236 // it, post RA pseudo instrs expansion just removes it and we get the code
237 // with undef registers. Therefore, we need to replace all uses of dst with
238 // the src register. COPY instr itself will be safely removed later.
239 assert(I->isCopy() && "Copy instruction is expected");
240 auto DstOp = I->getOperand(i: 0);
241 auto SrcOp = I->getOperand(i: 1);
242 assert(DstOp.isReg() && SrcOp.isReg() &&
243 "Register operands are expected in COPY");
244 auto &MRI = I->getMF()->getRegInfo();
245 MRI.replaceRegWith(FromReg: DstOp.getReg(), ToReg: SrcOp.getReg());
246}
247
248bool SPIRVInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
249 if (MI.getOpcode() == SPIRV::GET_ID || MI.getOpcode() == SPIRV::GET_fID ||
250 MI.getOpcode() == SPIRV::GET_pID32 ||
251 MI.getOpcode() == SPIRV::GET_pID64 || MI.getOpcode() == SPIRV::GET_vfID ||
252 MI.getOpcode() == SPIRV::GET_vID || MI.getOpcode() == SPIRV::GET_vpID32 ||
253 MI.getOpcode() == SPIRV::GET_vpID64) {
254 auto &MRI = MI.getMF()->getRegInfo();
255 MRI.replaceRegWith(FromReg: MI.getOperand(i: 0).getReg(), ToReg: MI.getOperand(i: 1).getReg());
256 MI.eraseFromParent();
257 return true;
258 }
259 return false;
260}
261

source code of llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp