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