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