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
SPIRVInstrInfo()26 SPIRVInstrInfo::SPIRVInstrInfo() : SPIRVGenInstrInfo() {}
27
isConstantInstr(const MachineInstr & MI) const28 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
isTypeDeclInstr(const MachineInstr & MI) const49 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
isDecorationInstr(const MachineInstr & MI) const59 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
isHeaderInstr(const MachineInstr & MI) const72 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 // Analyze the branching code at the end of MBB, returning
95 // true if it cannot be understood (e.g. it's a switch dispatch or isn't
96 // implemented for a target). Upon success, this returns false and returns
97 // with the following information in various cases:
98 //
99 // 1. If this block ends with no branches (it just falls through to its succ)
100 // just return false, leaving TBB/FBB null.
101 // 2. If this block ends with only an unconditional branch, it sets TBB to be
102 // the destination block.
103 // 3. If this block ends with a conditional branch and it falls through to a
104 // successor block, it sets TBB to be the branch destination block and a
105 // list of operands that evaluate the condition. These operands can be
106 // passed to other TargetInstrInfo methods to create new branches.
107 // 4. If this block ends with a conditional branch followed by an
108 // unconditional branch, it returns the 'true' destination in TBB, the
109 // 'false' destination in FBB, and a list of operands that evaluate the
110 // condition. These operands can be passed to other TargetInstrInfo
111 // methods to create new branches.
112 //
113 // Note that removeBranch and insertBranch must be implemented to support
114 // cases where this method returns success.
115 //
116 // If AllowModify is true, then this routine is allowed to modify the basic
117 // block (e.g. delete instructions after the unconditional branch).
118 //
119 // The CFG information in MBB.Predecessors and MBB.Successors must be valid
120 // before calling this function.
analyzeBranch(MachineBasicBlock & MBB,MachineBasicBlock * & TBB,MachineBasicBlock * & FBB,SmallVectorImpl<MachineOperand> & Cond,bool AllowModify) const121 bool SPIRVInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
122 MachineBasicBlock *&TBB,
123 MachineBasicBlock *&FBB,
124 SmallVectorImpl<MachineOperand> &Cond,
125 bool AllowModify) const {
126 TBB = nullptr;
127 FBB = nullptr;
128 if (MBB.empty())
129 return false;
130 auto MI = MBB.getLastNonDebugInstr();
131 if (!MI.isValid())
132 return false;
133 if (MI->getOpcode() == SPIRV::OpBranch) {
134 TBB = MI->getOperand(0).getMBB();
135 return false;
136 } else if (MI->getOpcode() == SPIRV::OpBranchConditional) {
137 Cond.push_back(MI->getOperand(0));
138 TBB = MI->getOperand(1).getMBB();
139 if (MI->getNumOperands() == 3) {
140 FBB = MI->getOperand(2).getMBB();
141 }
142 return false;
143 } else {
144 return true;
145 }
146 }
147
148 // Remove the branching code at the end of the specific MBB.
149 // This is only invoked in cases where analyzeBranch returns success. It
150 // returns the number of instructions that were removed.
151 // If \p BytesRemoved is non-null, report the change in code size from the
152 // removed instructions.
removeBranch(MachineBasicBlock & MBB,int * BytesRemoved) const153 unsigned SPIRVInstrInfo::removeBranch(MachineBasicBlock &MBB,
154 int *BytesRemoved) const {
155 report_fatal_error("Branch removal not supported, as MBB info not propagated"
156 " to OpPhi instructions. Try using -O0 instead.");
157 }
158
159 // Insert branch code into the end of the specified MachineBasicBlock. The
160 // operands to this method are the same as those returned by analyzeBranch.
161 // This is only invoked in cases where analyzeBranch returns success. It
162 // returns the number of instructions inserted. If \p BytesAdded is non-null,
163 // report the change in code size from the added instructions.
164 //
165 // It is also invoked by tail merging to add unconditional branches in
166 // cases where analyzeBranch doesn't apply because there was no original
167 // branch to analyze. At least this much must be implemented, else tail
168 // merging needs to be disabled.
169 //
170 // The CFG information in MBB.Predecessors and MBB.Successors must be valid
171 // before calling this function.
insertBranch(MachineBasicBlock & MBB,MachineBasicBlock * TBB,MachineBasicBlock * FBB,ArrayRef<MachineOperand> Cond,const DebugLoc & DL,int * BytesAdded) const172 unsigned SPIRVInstrInfo::insertBranch(
173 MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,
174 ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {
175 report_fatal_error("Branch insertion not supported, as MBB info not "
176 "propagated to OpPhi instructions. Try using "
177 "-O0 instead.");
178 }
179
copyPhysReg(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,const DebugLoc & DL,MCRegister DestReg,MCRegister SrcReg,bool KillSrc) const180 void SPIRVInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
181 MachineBasicBlock::iterator I,
182 const DebugLoc &DL, MCRegister DestReg,
183 MCRegister SrcReg, bool KillSrc) const {
184 // Actually we don't need this COPY instruction. However if we do nothing with
185 // it, post RA pseudo instrs expansion just removes it and we get the code
186 // with undef registers. Therefore, we need to replace all uses of dst with
187 // the src register. COPY instr itself will be safely removed later.
188 assert(I->isCopy() && "Copy instruction is expected");
189 auto DstOp = I->getOperand(0);
190 auto SrcOp = I->getOperand(1);
191 assert(DstOp.isReg() && SrcOp.isReg() &&
192 "Register operands are expected in COPY");
193 auto &MRI = I->getMF()->getRegInfo();
194 MRI.replaceRegWith(DstOp.getReg(), SrcOp.getReg());
195 }
196
expandPostRAPseudo(MachineInstr & MI) const197 bool SPIRVInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
198 if (MI.getOpcode() == SPIRV::GET_ID || MI.getOpcode() == SPIRV::GET_fID ||
199 MI.getOpcode() == SPIRV::GET_pID || MI.getOpcode() == SPIRV::GET_vfID ||
200 MI.getOpcode() == SPIRV::GET_vID) {
201 auto &MRI = MI.getMF()->getRegInfo();
202 MRI.replaceRegWith(MI.getOperand(0).getReg(), MI.getOperand(1).getReg());
203 MI.eraseFromParent();
204 return true;
205 }
206 return false;
207 }
208