xref: /freebsd/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp (revision 5f4c09dd85bff675e0ca63c55ea3c517e0fddfcc)
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 
24 using namespace llvm;
25 
26 SPIRVInstrInfo::SPIRVInstrInfo() : SPIRVGenInstrInfo() {}
27 
28 bool 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 
49 bool 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 
59 bool 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 
72 bool 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 
94 bool 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 
113 bool 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 
130 bool 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.
171 bool 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.
203 unsigned 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.
222 unsigned 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 
230 void 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 
247 bool 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