LLVM 19.0.0git
AMDGPUMCInstLower.cpp
Go to the documentation of this file.
1//===- AMDGPUMCInstLower.cpp - Lower AMDGPU MachineInstr to an MCInst -----===//
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/// \file
10/// Code to lower AMDGPU MachineInstrs to their corresponding MCInst.
11//
12//===----------------------------------------------------------------------===//
13//
14
15#include "AMDGPUMCInstLower.h"
16#include "AMDGPU.h"
17#include "AMDGPUAsmPrinter.h"
19#include "AMDGPUTargetMachine.h"
24#include "llvm/IR/Constants.h"
25#include "llvm/IR/Function.h"
28#include "llvm/MC/MCContext.h"
29#include "llvm/MC/MCExpr.h"
30#include "llvm/MC/MCInst.h"
32#include "llvm/MC/MCStreamer.h"
34#include "llvm/Support/Format.h"
35#include <algorithm>
36
37using namespace llvm;
38
39#include "AMDGPUGenMCPseudoLowering.inc"
40
42 const TargetSubtargetInfo &st,
43 const AsmPrinter &ap):
44 Ctx(ctx), ST(st), AP(ap) { }
45
47 switch (MOFlags) {
48 default:
64 }
65}
66
68 MCOperand &MCOp) const {
69 switch (MO.getType()) {
70 default:
71 break;
73 MCOp = MCOperand::createImm(MO.getImm());
74 return true;
77 return true;
81 return true;
83 const GlobalValue *GV = MO.getGlobal();
84 SmallString<128> SymbolName;
85 AP.getNameWithPrefix(SymbolName, GV);
86 MCSymbol *Sym = Ctx.getOrCreateSymbol(SymbolName);
87 const MCExpr *Expr =
89 int64_t Offset = MO.getOffset();
90 if (Offset != 0) {
91 Expr = MCBinaryExpr::createAdd(Expr,
93 }
94 MCOp = MCOperand::createExpr(Expr);
95 return true;
96 }
99 Sym->setExternal(true);
100 const MCSymbolRefExpr *Expr = MCSymbolRefExpr::create(Sym, Ctx);
101 MCOp = MCOperand::createExpr(Expr);
102 return true;
103 }
105 // Regmasks are like implicit defs.
106 return false;
109 MCSymbol *Sym = MO.getMCSymbol();
110 MCOp = MCOperand::createExpr(Sym->getVariableValue());
111 return true;
112 }
113 break;
114 }
115 llvm_unreachable("unknown operand type");
116}
117
118void AMDGPUMCInstLower::lower(const MachineInstr *MI, MCInst &OutMI) const {
119 unsigned Opcode = MI->getOpcode();
120 const auto *TII = static_cast<const SIInstrInfo*>(ST.getInstrInfo());
121
122 // FIXME: Should be able to handle this with emitPseudoExpansionLowering. We
123 // need to select it to the subtarget specific version, and there's no way to
124 // do that with a single pseudo source operation.
125 if (Opcode == AMDGPU::S_SETPC_B64_return)
126 Opcode = AMDGPU::S_SETPC_B64;
127 else if (Opcode == AMDGPU::SI_CALL) {
128 // SI_CALL is just S_SWAPPC_B64 with an additional operand to track the
129 // called function (which we need to remove here).
130 OutMI.setOpcode(TII->pseudoToMCOpcode(AMDGPU::S_SWAPPC_B64));
131 MCOperand Dest, Src;
132 lowerOperand(MI->getOperand(0), Dest);
133 lowerOperand(MI->getOperand(1), Src);
134 OutMI.addOperand(Dest);
135 OutMI.addOperand(Src);
136 return;
137 } else if (Opcode == AMDGPU::SI_TCRETURN ||
138 Opcode == AMDGPU::SI_TCRETURN_GFX) {
139 // TODO: How to use branch immediate and avoid register+add?
140 Opcode = AMDGPU::S_SETPC_B64;
141 }
142
143 int MCOpcode = TII->pseudoToMCOpcode(Opcode);
144 if (MCOpcode == -1) {
145 LLVMContext &C = MI->getParent()->getParent()->getFunction().getContext();
146 C.emitError("AMDGPUMCInstLower::lower - Pseudo instruction doesn't have "
147 "a target-specific version: " + Twine(MI->getOpcode()));
148 }
149
150 OutMI.setOpcode(MCOpcode);
151
152 for (const MachineOperand &MO : MI->explicit_operands()) {
153 MCOperand MCOp;
154 lowerOperand(MO, MCOp);
155 OutMI.addOperand(MCOp);
156 }
157
158 int FIIdx = AMDGPU::getNamedOperandIdx(MCOpcode, AMDGPU::OpName::fi);
159 if (FIIdx >= (int)OutMI.getNumOperands())
161}
162
164 MCOperand &MCOp) const {
165 const GCNSubtarget &STI = MF->getSubtarget<GCNSubtarget>();
166 AMDGPUMCInstLower MCInstLowering(OutContext, STI, *this);
167 return MCInstLowering.lowerOperand(MO, MCOp);
168}
169
171
172 // Intercept LDS variables with known addresses
173 if (const GlobalVariable *GV = dyn_cast<const GlobalVariable>(CV)) {
174 if (std::optional<uint32_t> Address =
176 auto *IntTy = Type::getInt32Ty(CV->getContext());
177 return AsmPrinter::lowerConstant(ConstantInt::get(IntTy, *Address));
178 }
179 }
180
181 if (const MCExpr *E = lowerAddrSpaceCast(TM, CV, OutContext))
182 return E;
183 return AsmPrinter::lowerConstant(CV);
184}
185
187 // FIXME: Enable feature predicate checks once all the test pass.
188 // AMDGPU_MC::verifyInstructionPredicates(MI->getOpcode(),
189 // getSubtargetInfo().getFeatureBits());
190
192 return;
193
194 const GCNSubtarget &STI = MF->getSubtarget<GCNSubtarget>();
195 AMDGPUMCInstLower MCInstLowering(OutContext, STI, *this);
196
197 StringRef Err;
198 if (!STI.getInstrInfo()->verifyInstruction(*MI, Err)) {
199 LLVMContext &C = MI->getParent()->getParent()->getFunction().getContext();
200 C.emitError("Illegal instruction detected: " + Err);
201 MI->print(errs());
202 }
203
204 if (MI->isBundle()) {
205 const MachineBasicBlock *MBB = MI->getParent();
207 while (I != MBB->instr_end() && I->isInsideBundle()) {
209 ++I;
210 }
211 } else {
212 // We don't want these pseudo instructions encoded. They are
213 // placeholder terminator instructions and should only be printed as
214 // comments.
215 if (MI->getOpcode() == AMDGPU::SI_RETURN_TO_EPILOG) {
216 if (isVerbose())
217 OutStreamer->emitRawComment(" return to shader part epilog");
218 return;
219 }
220
221 if (MI->getOpcode() == AMDGPU::WAVE_BARRIER) {
222 if (isVerbose())
223 OutStreamer->emitRawComment(" wave barrier");
224 return;
225 }
226
227 if (MI->getOpcode() == AMDGPU::SCHED_BARRIER) {
228 if (isVerbose()) {
229 std::string HexString;
230 raw_string_ostream HexStream(HexString);
231 HexStream << format_hex(MI->getOperand(0).getImm(), 10, true);
232 OutStreamer->emitRawComment(" sched_barrier mask(" + HexString + ")");
233 }
234 return;
235 }
236
237 if (MI->getOpcode() == AMDGPU::SCHED_GROUP_BARRIER) {
238 if (isVerbose()) {
239 std::string HexString;
240 raw_string_ostream HexStream(HexString);
241 HexStream << format_hex(MI->getOperand(0).getImm(), 10, true);
242 OutStreamer->emitRawComment(
243 " sched_group_barrier mask(" + HexString + ") size(" +
244 Twine(MI->getOperand(1).getImm()) + ") SyncID(" +
245 Twine(MI->getOperand(2).getImm()) + ")");
246 }
247 return;
248 }
249
250 if (MI->getOpcode() == AMDGPU::IGLP_OPT) {
251 if (isVerbose()) {
252 std::string HexString;
253 raw_string_ostream HexStream(HexString);
254 HexStream << format_hex(MI->getOperand(0).getImm(), 10, true);
255 OutStreamer->emitRawComment(" iglp_opt mask(" + HexString + ")");
256 }
257 return;
258 }
259
260 if (MI->getOpcode() == AMDGPU::SI_MASKED_UNREACHABLE) {
261 if (isVerbose())
262 OutStreamer->emitRawComment(" divergent unreachable");
263 return;
264 }
265
266 if (MI->isMetaInstruction()) {
267 if (isVerbose())
268 OutStreamer->emitRawComment(" meta instruction");
269 return;
270 }
271
272 MCInst TmpInst;
273 MCInstLowering.lower(MI, TmpInst);
274 EmitToStreamer(*OutStreamer, TmpInst);
275
276#ifdef EXPENSIVE_CHECKS
277 // Check getInstSizeInBytes on explicitly specified CPUs (it cannot
278 // work correctly for the generic CPU).
279 //
280 // The isPseudo check really shouldn't be here, but unfortunately there are
281 // some negative lit tests that depend on being able to continue through
282 // here even when pseudo instructions haven't been lowered.
283 //
284 // We also overestimate branch sizes with the offset bug.
285 if (!MI->isPseudo() && STI.isCPUStringValid(STI.getCPU()) &&
286 (!STI.hasOffset3fBug() || !MI->isBranch())) {
288 SmallVector<char, 16> CodeBytes;
289
290 std::unique_ptr<MCCodeEmitter> InstEmitter(createAMDGPUMCCodeEmitter(
291 *STI.getInstrInfo(), OutContext));
292 InstEmitter->encodeInstruction(TmpInst, CodeBytes, Fixups, STI);
293
294 assert(CodeBytes.size() == STI.getInstrInfo()->getInstSizeInBytes(*MI));
295 }
296#endif
297
298 if (DumpCodeInstEmitter) {
299 // Disassemble instruction/operands to text
300 DisasmLines.resize(DisasmLines.size() + 1);
301 std::string &DisasmLine = DisasmLines.back();
302 raw_string_ostream DisasmStream(DisasmLine);
303
304 AMDGPUInstPrinter InstPrinter(*TM.getMCAsmInfo(), *STI.getInstrInfo(),
305 *STI.getRegisterInfo());
306 InstPrinter.printInst(&TmpInst, 0, StringRef(), STI, DisasmStream);
307
308 // Disassemble instruction/operands to hex representation.
310 SmallVector<char, 16> CodeBytes;
311
312 DumpCodeInstEmitter->encodeInstruction(
313 TmpInst, CodeBytes, Fixups, MF->getSubtarget<MCSubtargetInfo>());
314 HexLines.resize(HexLines.size() + 1);
315 std::string &HexLine = HexLines.back();
316 raw_string_ostream HexStream(HexLine);
317
318 for (size_t i = 0; i < CodeBytes.size(); i += 4) {
319 unsigned int CodeDWord = *(unsigned int *)&CodeBytes[i];
320 HexStream << format("%s%08X", (i > 0 ? " " : ""), CodeDWord);
321 }
322
323 DisasmStream.flush();
324 DisasmLineMaxLen = std::max(DisasmLineMaxLen, DisasmLine.size());
325 }
326 }
327}
MachineBasicBlock & MBB
AMDGPU Assembly printer class.
static MCSymbolRefExpr::VariantKind getVariantKind(unsigned MOFlags)
Header of lower AMDGPU MachineInstrs to their corresponding MCInst.
Provides AMDGPU specific target descriptions.
The AMDGPU TargetMachine interface definition for hw codegen targets.
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Symbol * Sym
Definition: ELF_riscv.cpp:479
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition: MD5.cpp:58
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const
AMDGPUMCInstLower(MCContext &ctx, const TargetSubtargetInfo &ST, const AsmPrinter &AP)
void lower(const MachineInstr *MI, MCInst &OutMI) const
Lower a MachineInstr to an MCInst.
std::vector< std::string > DisasmLines
std::vector< std::string > HexLines
bool emitPseudoExpansionLowering(MCStreamer &OutStreamer, const MachineInstr *MI)
tblgen'erated driver function for lowering simple MI->MC pseudo instructions.
bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const
Wrapper for MCInstLowering.lowerOperand() for the tblgen'erated pseudo lowering.
const MCExpr * lowerConstant(const Constant *CV) override
Lower the specified LLVM Constant to an MCExpr.
void emitInstruction(const MachineInstr *MI) override
Implemented in AMDGPUMCInstLower.cpp.
void printInst(const MCInst *MI, uint64_t Address, StringRef Annot, const MCSubtargetInfo &STI, raw_ostream &O) override
Print the specified MCInst to the specified raw_ostream.
static std::optional< uint32_t > getLDSAbsoluteAddress(const GlobalValue &GV)
This class is intended to be used as a driving class for all asm writers.
Definition: AsmPrinter.h:84
void EmitToStreamer(MCStreamer &S, const MCInst &Inst)
Definition: AsmPrinter.cpp:418
TargetMachine & TM
Target machine description.
Definition: AsmPrinter.h:87
MachineFunction * MF
The current machine function.
Definition: AsmPrinter.h:102
MCContext & OutContext
This is the context for the output file that we are streaming.
Definition: AsmPrinter.h:94
std::unique_ptr< MCStreamer > OutStreamer
This is the MCStreamer object for the file we are generating.
Definition: AsmPrinter.h:99
virtual const MCExpr * lowerConstant(const Constant *CV)
Lower the specified LLVM Constant to an MCExpr.
bool isVerbose() const
Return true if assembly output should contain comments.
Definition: AsmPrinter.h:265
void getNameWithPrefix(SmallVectorImpl< char > &Name, const GlobalValue *GV) const
Definition: AsmPrinter.cpp:695
This is an important base class in LLVM.
Definition: Constant.h:41
const SIInstrInfo * getInstrInfo() const override
Definition: GCNSubtarget.h:251
bool hasOffset3fBug() const
const SIRegisterInfo * getRegisterInfo() const override
Definition: GCNSubtarget.h:263
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition: MCExpr.h:536
virtual void encodeInstruction(const MCInst &Inst, SmallVectorImpl< char > &CB, SmallVectorImpl< MCFixup > &Fixups, const MCSubtargetInfo &STI) const =0
Encode the given Inst to bytes and append to CB.
static const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Definition: MCExpr.cpp:194
Context object for machine code objects.
Definition: MCContext.h:76
MCSymbol * getOrCreateSymbol(const Twine &Name)
Lookup the symbol inside with the specified Name.
Definition: MCContext.cpp:200
Base class for the full range of assembler expressions which are needed for parsing.
Definition: MCExpr.h:35
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:184
unsigned getNumOperands() const
Definition: MCInst.h:208
void addOperand(const MCOperand Op)
Definition: MCInst.h:210
void setOpcode(unsigned Op)
Definition: MCInst.h:197
Instances of this class represent operands of the MCInst class.
Definition: MCInst.h:36
static MCOperand createReg(unsigned Reg)
Definition: MCInst.h:134
static MCOperand createExpr(const MCExpr *Val)
Definition: MCInst.h:162
static MCOperand createImm(int64_t Val)
Definition: MCInst.h:141
Generic base class for all target subtargets.
Represent a reference to a symbol from inside an expression.
Definition: MCExpr.h:192
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx)
Definition: MCExpr.h:397
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:40
MCSymbol * getSymbol() const
Return the MCSymbol for this basic block.
instr_iterator instr_end()
Instructions::const_iterator const_instr_iterator
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Representation of each machine instruction.
Definition: MachineInstr.h:69
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
int64_t getImm() const
MachineBasicBlock * getMBB() const
unsigned getTargetFlags() const
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
const char * getSymbolName() const
Register getReg() const
getReg - Returns the register number.
MCSymbol * getMCSymbol() const
@ MO_Immediate
Immediate operand.
@ MO_MCSymbol
MCSymbol reference (for debug/eh info)
@ MO_GlobalAddress
Address of a global value.
@ MO_RegisterMask
Mask of preserved registers.
@ MO_MachineBasicBlock
MachineBasicBlock reference.
@ MO_Register
Register operand.
@ MO_ExternalSymbol
Name of external global symbol.
int64_t getOffset() const
Return the offset from the symbol in this operand.
virtual void print(raw_ostream &OS, const Module *M) const
print - Print out the internal state of the pass.
Definition: Pass.cpp:130
unsigned getInstSizeInBytes(const MachineInstr &MI) const override
bool verifyInstruction(const MachineInstr &MI, StringRef &ErrInfo) const override
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
size_t size() const
Definition: SmallVector.h:91
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
const MCAsmInfo * getMCAsmInfo() const
Return target specific asm information.
TargetSubtargetInfo - Generic base class for all target subtargets.
virtual const TargetInstrInfo * getInstrInfo() const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
static IntegerType * getInt32Ty(LLVMContext &C)
LLVMContext & getContext() const
All values hold a context through their type.
Definition: Value.cpp:1074
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:660
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
LLVM_READONLY int16_t getNamedOperandIdx(uint16_t Opcode, uint16_t NamedIdx)
unsigned getMCReg(unsigned Reg, const MCSubtargetInfo &STI)
If Reg is a pseudo reg, return the correct hardware register given STI otherwise return Reg.
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:456
FormattedNumber format_hex(uint64_t N, unsigned Width, bool Upper=false)
format_hex - Output N as a fixed width hexadecimal.
Definition: Format.h:187
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition: Format.h:125
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
MCCodeEmitter * createAMDGPUMCCodeEmitter(const MCInstrInfo &MCII, MCContext &Ctx)