xref: /freebsd/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVInstrInfo.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
20 #define GET_INSTRINFO_CTOR_DTOR
21 #include "SPIRVGenInstrInfo.inc"
22 
23 using namespace llvm;
24 
SPIRVInstrInfo()25 SPIRVInstrInfo::SPIRVInstrInfo() : SPIRVGenInstrInfo() {}
26 
isConstantInstr(const MachineInstr & MI) const27 bool SPIRVInstrInfo::isConstantInstr(const MachineInstr &MI) const {
28   switch (MI.getOpcode()) {
29   case SPIRV::OpConstantTrue:
30   case SPIRV::OpConstantFalse:
31   case SPIRV::OpConstantI:
32   case SPIRV::OpConstantF:
33   case SPIRV::OpConstantComposite:
34   case SPIRV::OpConstantCompositeContinuedINTEL:
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::OpSpecConstantCompositeContinuedINTEL:
42   case SPIRV::OpSpecConstantOp:
43   case SPIRV::OpUndef:
44   case SPIRV::OpConstantFunctionPointerINTEL:
45     return true;
46   default:
47     return false;
48   }
49 }
50 
isSpecConstantInstr(const MachineInstr & MI) const51 bool SPIRVInstrInfo::isSpecConstantInstr(const MachineInstr &MI) const {
52   switch (MI.getOpcode()) {
53   case SPIRV::OpSpecConstantTrue:
54   case SPIRV::OpSpecConstantFalse:
55   case SPIRV::OpSpecConstant:
56   case SPIRV::OpSpecConstantComposite:
57   case SPIRV::OpSpecConstantCompositeContinuedINTEL:
58   case SPIRV::OpSpecConstantOp:
59     return true;
60   default:
61     return false;
62   }
63 }
64 
isInlineAsmDefInstr(const MachineInstr & MI) const65 bool SPIRVInstrInfo::isInlineAsmDefInstr(const MachineInstr &MI) const {
66   switch (MI.getOpcode()) {
67   case SPIRV::OpAsmTargetINTEL:
68   case SPIRV::OpAsmINTEL:
69     return true;
70   default:
71     return false;
72   }
73 }
74 
isTypeDeclInstr(const MachineInstr & MI) const75 bool SPIRVInstrInfo::isTypeDeclInstr(const MachineInstr &MI) const {
76   auto &MRI = MI.getMF()->getRegInfo();
77   if (MI.getNumDefs() >= 1 && MI.getOperand(0).isReg()) {
78     auto DefRegClass = MRI.getRegClassOrNull(MI.getOperand(0).getReg());
79     return DefRegClass && DefRegClass->getID() == SPIRV::TYPERegClass.getID();
80   } else {
81     return MI.getOpcode() == SPIRV::OpTypeForwardPointer ||
82            MI.getOpcode() == SPIRV::OpTypeStructContinuedINTEL;
83   }
84 }
85 
isDecorationInstr(const MachineInstr & MI) const86 bool SPIRVInstrInfo::isDecorationInstr(const MachineInstr &MI) const {
87   switch (MI.getOpcode()) {
88   case SPIRV::OpDecorate:
89   case SPIRV::OpDecorateId:
90   case SPIRV::OpDecorateString:
91   case SPIRV::OpMemberDecorate:
92   case SPIRV::OpMemberDecorateString:
93     return true;
94   default:
95     return false;
96   }
97 }
98 
isAliasingInstr(const MachineInstr & MI) const99 bool SPIRVInstrInfo::isAliasingInstr(const MachineInstr &MI) const {
100   switch (MI.getOpcode()) {
101   case SPIRV::OpAliasDomainDeclINTEL:
102   case SPIRV::OpAliasScopeDeclINTEL:
103   case SPIRV::OpAliasScopeListDeclINTEL:
104     return true;
105   default:
106     return false;
107   }
108 }
109 
isHeaderInstr(const MachineInstr & MI) const110 bool SPIRVInstrInfo::isHeaderInstr(const MachineInstr &MI) const {
111   switch (MI.getOpcode()) {
112   case SPIRV::OpCapability:
113   case SPIRV::OpExtension:
114   case SPIRV::OpExtInstImport:
115   case SPIRV::OpMemoryModel:
116   case SPIRV::OpEntryPoint:
117   case SPIRV::OpExecutionMode:
118   case SPIRV::OpExecutionModeId:
119   case SPIRV::OpString:
120   case SPIRV::OpSourceExtension:
121   case SPIRV::OpSource:
122   case SPIRV::OpSourceContinued:
123   case SPIRV::OpName:
124   case SPIRV::OpMemberName:
125   case SPIRV::OpModuleProcessed:
126     return true;
127   default:
128     return isTypeDeclInstr(MI) || isConstantInstr(MI) ||
129            isDecorationInstr(MI) || isAliasingInstr(MI);
130   }
131 }
132 
canUseFastMathFlags(const MachineInstr & MI) const133 bool SPIRVInstrInfo::canUseFastMathFlags(const MachineInstr &MI) const {
134   switch (MI.getOpcode()) {
135   case SPIRV::OpFAddS:
136   case SPIRV::OpFSubS:
137   case SPIRV::OpFMulS:
138   case SPIRV::OpFDivS:
139   case SPIRV::OpFRemS:
140   case SPIRV::OpFAddV:
141   case SPIRV::OpFSubV:
142   case SPIRV::OpFMulV:
143   case SPIRV::OpFDivV:
144   case SPIRV::OpFRemV:
145   case SPIRV::OpFMod:
146     return true;
147   default:
148     return false;
149   }
150 }
151 
canUseNSW(const MachineInstr & MI) const152 bool SPIRVInstrInfo::canUseNSW(const MachineInstr &MI) const {
153   switch (MI.getOpcode()) {
154   case SPIRV::OpIAddS:
155   case SPIRV::OpIAddV:
156   case SPIRV::OpISubS:
157   case SPIRV::OpISubV:
158   case SPIRV::OpIMulS:
159   case SPIRV::OpIMulV:
160   case SPIRV::OpShiftLeftLogicalS:
161   case SPIRV::OpShiftLeftLogicalV:
162   case SPIRV::OpSNegate:
163     return true;
164   default:
165     return false;
166   }
167 }
168 
canUseNUW(const MachineInstr & MI) const169 bool SPIRVInstrInfo::canUseNUW(const MachineInstr &MI) const {
170   switch (MI.getOpcode()) {
171   case SPIRV::OpIAddS:
172   case SPIRV::OpIAddV:
173   case SPIRV::OpISubS:
174   case SPIRV::OpISubV:
175   case SPIRV::OpIMulS:
176   case SPIRV::OpIMulV:
177     return true;
178   default:
179     return false;
180   }
181 }
182 
183 // Analyze the branching code at the end of MBB, returning
184 // true if it cannot be understood (e.g. it's a switch dispatch or isn't
185 // implemented for a target).  Upon success, this returns false and returns
186 // with the following information in various cases:
187 //
188 // 1. If this block ends with no branches (it just falls through to its succ)
189 //    just return false, leaving TBB/FBB null.
190 // 2. If this block ends with only an unconditional branch, it sets TBB to be
191 //    the destination block.
192 // 3. If this block ends with a conditional branch and it falls through to a
193 //    successor block, it sets TBB to be the branch destination block and a
194 //    list of operands that evaluate the condition. These operands can be
195 //    passed to other TargetInstrInfo methods to create new branches.
196 // 4. If this block ends with a conditional branch followed by an
197 //    unconditional branch, it returns the 'true' destination in TBB, the
198 //    'false' destination in FBB, and a list of operands that evaluate the
199 //    condition.  These operands can be passed to other TargetInstrInfo
200 //    methods to create new branches.
201 //
202 // Note that removeBranch and insertBranch must be implemented to support
203 // cases where this method returns success.
204 //
205 // If AllowModify is true, then this routine is allowed to modify the basic
206 // block (e.g. delete instructions after the unconditional branch).
207 //
208 // The CFG information in MBB.Predecessors and MBB.Successors must be valid
209 // before calling this function.
analyzeBranch(MachineBasicBlock & MBB,MachineBasicBlock * & TBB,MachineBasicBlock * & FBB,SmallVectorImpl<MachineOperand> & Cond,bool AllowModify) const210 bool SPIRVInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
211                                    MachineBasicBlock *&TBB,
212                                    MachineBasicBlock *&FBB,
213                                    SmallVectorImpl<MachineOperand> &Cond,
214                                    bool AllowModify) const {
215   // We do not allow to restructure blocks by results of analyzeBranch(),
216   // because it may potentially break structured control flow and anyway
217   // doubtedly may be useful in SPIRV, including such reasons as, e.g.:
218   // 1) there is no way to encode `if (Cond) then Stmt` logic, only full
219   // if-then-else is supported by OpBranchConditional, so if we supported
220   // splitting of blocks ending with OpBranchConditional MachineBasicBlock.cpp
221   // would expect successfull implementation of calls to insertBranch() setting
222   // FBB to null that is not feasible; 2) it's not possible to delete
223   // instructions after the unconditional branch, because this instruction must
224   // be the last instruction in a block.
225   return true;
226 }
227 
228 // Remove the branching code at the end of the specific MBB.
229 // This is only invoked in cases where analyzeBranch returns success. It
230 // returns the number of instructions that were removed.
231 // If \p BytesRemoved is non-null, report the change in code size from the
232 // removed instructions.
removeBranch(MachineBasicBlock & MBB,int *) const233 unsigned SPIRVInstrInfo::removeBranch(MachineBasicBlock &MBB,
234                                       int * /*BytesRemoved*/) const {
235   MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr();
236   if (I == MBB.end())
237     return 0;
238 
239   if (I->getOpcode() == SPIRV::OpBranch) {
240     I->eraseFromParent();
241     return 1;
242   }
243   return 0;
244 }
245 
246 // Insert branch code into the end of the specified MachineBasicBlock. The
247 // operands to this method are the same as those returned by analyzeBranch.
248 // This is only invoked in cases where analyzeBranch returns success. It
249 // returns the number of instructions inserted. If \p BytesAdded is non-null,
250 // report the change in code size from the added instructions.
251 //
252 // It is also invoked by tail merging to add unconditional branches in
253 // cases where analyzeBranch doesn't apply because there was no original
254 // branch to analyze.  At least this much must be implemented, else tail
255 // merging needs to be disabled.
256 //
257 // The CFG information in MBB.Predecessors and MBB.Successors must be valid
258 // before calling this function.
insertBranch(MachineBasicBlock & MBB,MachineBasicBlock * TBB,MachineBasicBlock * FBB,ArrayRef<MachineOperand> Cond,const DebugLoc & DL,int *) const259 unsigned SPIRVInstrInfo::insertBranch(MachineBasicBlock &MBB,
260                                       MachineBasicBlock *TBB,
261                                       MachineBasicBlock *FBB,
262                                       ArrayRef<MachineOperand> Cond,
263                                       const DebugLoc &DL,
264                                       int * /*BytesAdded*/) const {
265   if (!TBB)
266     return 0;
267   BuildMI(&MBB, DL, get(SPIRV::OpBranch)).addMBB(TBB);
268   return 1;
269 }
270 
copyPhysReg(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,const DebugLoc & DL,Register DestReg,Register SrcReg,bool KillSrc,bool RenamableDest,bool RenamableSrc) const271 void SPIRVInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
272                                  MachineBasicBlock::iterator I,
273                                  const DebugLoc &DL, Register DestReg,
274                                  Register SrcReg, bool KillSrc,
275                                  bool RenamableDest, bool RenamableSrc) const {
276   // Actually we don't need this COPY instruction. However if we do nothing with
277   // it, post RA pseudo instrs expansion just removes it and we get the code
278   // with undef registers. Therefore, we need to replace all uses of dst with
279   // the src register. COPY instr itself will be safely removed later.
280   assert(I->isCopy() && "Copy instruction is expected");
281   auto DstOp = I->getOperand(0);
282   auto SrcOp = I->getOperand(1);
283   assert(DstOp.isReg() && SrcOp.isReg() &&
284          "Register operands are expected in COPY");
285   auto &MRI = I->getMF()->getRegInfo();
286   MRI.replaceRegWith(DstOp.getReg(), SrcOp.getReg());
287 }
288