1 //===- AMDGPUMCInstLower.cpp - Lower AMDGPU MachineInstr to an MCInst -----===//
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
7 //===----------------------------------------------------------------------===//
10 /// Code to lower AMDGPU MachineInstrs to their corresponding MCInst.
12 //===----------------------------------------------------------------------===//
15 #include "AMDGPUAsmPrinter.h"
16 #include "AMDGPUTargetMachine.h"
17 #include "MCTargetDesc/AMDGPUInstPrinter.h"
18 #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
19 #include "R600AsmPrinter.h"
20 #include "llvm/CodeGen/MachineBasicBlock.h"
21 #include "llvm/CodeGen/MachineInstr.h"
22 #include "llvm/IR/Constants.h"
23 #include "llvm/IR/Function.h"
24 #include "llvm/IR/GlobalVariable.h"
25 #include "llvm/MC/MCCodeEmitter.h"
26 #include "llvm/MC/MCContext.h"
27 #include "llvm/MC/MCExpr.h"
28 #include "llvm/MC/MCInst.h"
29 #include "llvm/MC/MCObjectStreamer.h"
30 #include "llvm/MC/MCStreamer.h"
31 #include "llvm/Support/ErrorHandling.h"
32 #include "llvm/Support/Format.h"
39 class AMDGPUMCInstLower
{
41 const TargetSubtargetInfo
&ST
;
45 AMDGPUMCInstLower(MCContext
&ctx
, const TargetSubtargetInfo
&ST
,
46 const AsmPrinter
&AP
);
48 bool lowerOperand(const MachineOperand
&MO
, MCOperand
&MCOp
) const;
50 /// Lower a MachineInstr to an MCInst
51 void lower(const MachineInstr
*MI
, MCInst
&OutMI
) const;
55 class R600MCInstLower
: public AMDGPUMCInstLower
{
57 R600MCInstLower(MCContext
&ctx
, const R600Subtarget
&ST
,
58 const AsmPrinter
&AP
);
60 /// Lower a MachineInstr to an MCInst
61 void lower(const MachineInstr
*MI
, MCInst
&OutMI
) const;
65 } // End anonymous namespace
67 #include "AMDGPUGenMCPseudoLowering.inc"
69 AMDGPUMCInstLower::AMDGPUMCInstLower(MCContext
&ctx
,
70 const TargetSubtargetInfo
&st
,
71 const AsmPrinter
&ap
):
72 Ctx(ctx
), ST(st
), AP(ap
) { }
74 static MCSymbolRefExpr::VariantKind
getVariantKind(unsigned MOFlags
) {
77 return MCSymbolRefExpr::VK_None
;
78 case SIInstrInfo::MO_GOTPCREL
:
79 return MCSymbolRefExpr::VK_GOTPCREL
;
80 case SIInstrInfo::MO_GOTPCREL32_LO
:
81 return MCSymbolRefExpr::VK_AMDGPU_GOTPCREL32_LO
;
82 case SIInstrInfo::MO_GOTPCREL32_HI
:
83 return MCSymbolRefExpr::VK_AMDGPU_GOTPCREL32_HI
;
84 case SIInstrInfo::MO_REL32_LO
:
85 return MCSymbolRefExpr::VK_AMDGPU_REL32_LO
;
86 case SIInstrInfo::MO_REL32_HI
:
87 return MCSymbolRefExpr::VK_AMDGPU_REL32_HI
;
88 case SIInstrInfo::MO_ABS32_LO
:
89 return MCSymbolRefExpr::VK_AMDGPU_ABS32_LO
;
90 case SIInstrInfo::MO_ABS32_HI
:
91 return MCSymbolRefExpr::VK_AMDGPU_ABS32_HI
;
95 bool AMDGPUMCInstLower::lowerOperand(const MachineOperand
&MO
,
96 MCOperand
&MCOp
) const {
97 switch (MO
.getType()) {
100 case MachineOperand::MO_Immediate
:
101 MCOp
= MCOperand::createImm(MO
.getImm());
103 case MachineOperand::MO_Register
:
104 MCOp
= MCOperand::createReg(AMDGPU::getMCReg(MO
.getReg(), ST
));
106 case MachineOperand::MO_MachineBasicBlock
:
107 MCOp
= MCOperand::createExpr(
108 MCSymbolRefExpr::create(MO
.getMBB()->getSymbol(), Ctx
));
110 case MachineOperand::MO_GlobalAddress
: {
111 const GlobalValue
*GV
= MO
.getGlobal();
112 SmallString
<128> SymbolName
;
113 AP
.getNameWithPrefix(SymbolName
, GV
);
114 MCSymbol
*Sym
= Ctx
.getOrCreateSymbol(SymbolName
);
116 MCSymbolRefExpr::create(Sym
, getVariantKind(MO
.getTargetFlags()),Ctx
);
117 int64_t Offset
= MO
.getOffset();
119 Expr
= MCBinaryExpr::createAdd(Expr
,
120 MCConstantExpr::create(Offset
, Ctx
), Ctx
);
122 MCOp
= MCOperand::createExpr(Expr
);
125 case MachineOperand::MO_ExternalSymbol
: {
126 MCSymbol
*Sym
= Ctx
.getOrCreateSymbol(StringRef(MO
.getSymbolName()));
127 Sym
->setExternal(true);
128 const MCSymbolRefExpr
*Expr
= MCSymbolRefExpr::create(Sym
, Ctx
);
129 MCOp
= MCOperand::createExpr(Expr
);
132 case MachineOperand::MO_RegisterMask
:
133 // Regmasks are like implicit defs.
135 case MachineOperand::MO_MCSymbol
:
136 if (MO
.getTargetFlags() == SIInstrInfo::MO_FAR_BRANCH_OFFSET
) {
137 MCSymbol
*Sym
= MO
.getMCSymbol();
138 MCOp
= MCOperand::createExpr(Sym
->getVariableValue());
143 llvm_unreachable("unknown operand type");
146 void AMDGPUMCInstLower::lower(const MachineInstr
*MI
, MCInst
&OutMI
) const {
147 unsigned Opcode
= MI
->getOpcode();
148 const auto *TII
= static_cast<const SIInstrInfo
*>(ST
.getInstrInfo());
150 // FIXME: Should be able to handle this with emitPseudoExpansionLowering. We
151 // need to select it to the subtarget specific version, and there's no way to
152 // do that with a single pseudo source operation.
153 if (Opcode
== AMDGPU::S_SETPC_B64_return
)
154 Opcode
= AMDGPU::S_SETPC_B64
;
155 else if (Opcode
== AMDGPU::SI_CALL
) {
156 // SI_CALL is just S_SWAPPC_B64 with an additional operand to track the
157 // called function (which we need to remove here).
158 OutMI
.setOpcode(TII
->pseudoToMCOpcode(AMDGPU::S_SWAPPC_B64
));
160 lowerOperand(MI
->getOperand(0), Dest
);
161 lowerOperand(MI
->getOperand(1), Src
);
162 OutMI
.addOperand(Dest
);
163 OutMI
.addOperand(Src
);
165 } else if (Opcode
== AMDGPU::SI_TCRETURN
) {
166 // TODO: How to use branch immediate and avoid register+add?
167 Opcode
= AMDGPU::S_SETPC_B64
;
170 int MCOpcode
= TII
->pseudoToMCOpcode(Opcode
);
171 if (MCOpcode
== -1) {
172 LLVMContext
&C
= MI
->getParent()->getParent()->getFunction().getContext();
173 C
.emitError("AMDGPUMCInstLower::lower - Pseudo instruction doesn't have "
174 "a target-specific version: " + Twine(MI
->getOpcode()));
177 OutMI
.setOpcode(MCOpcode
);
179 for (const MachineOperand
&MO
: MI
->explicit_operands()) {
181 lowerOperand(MO
, MCOp
);
182 OutMI
.addOperand(MCOp
);
185 int FIIdx
= AMDGPU::getNamedOperandIdx(MCOpcode
, AMDGPU::OpName::fi
);
186 if (FIIdx
>= (int)OutMI
.getNumOperands())
187 OutMI
.addOperand(MCOperand::createImm(0));
190 bool AMDGPUAsmPrinter::lowerOperand(const MachineOperand
&MO
,
191 MCOperand
&MCOp
) const {
192 const GCNSubtarget
&STI
= MF
->getSubtarget
<GCNSubtarget
>();
193 AMDGPUMCInstLower
MCInstLowering(OutContext
, STI
, *this);
194 return MCInstLowering
.lowerOperand(MO
, MCOp
);
197 static const MCExpr
*lowerAddrSpaceCast(const TargetMachine
&TM
,
199 MCContext
&OutContext
) {
200 // TargetMachine does not support llvm-style cast. Use C++-style cast.
201 // This is safe since TM is always of type AMDGPUTargetMachine or its
203 auto &AT
= static_cast<const AMDGPUTargetMachine
&>(TM
);
204 auto *CE
= dyn_cast
<ConstantExpr
>(CV
);
206 // Lower null pointers in private and local address space.
207 // Clang generates addrspacecast for null pointers in private and local
208 // address space, which needs to be lowered.
209 if (CE
&& CE
->getOpcode() == Instruction::AddrSpaceCast
) {
210 auto Op
= CE
->getOperand(0);
211 auto SrcAddr
= Op
->getType()->getPointerAddressSpace();
212 if (Op
->isNullValue() && AT
.getNullPointerValue(SrcAddr
) == 0) {
213 auto DstAddr
= CE
->getType()->getPointerAddressSpace();
214 return MCConstantExpr::create(AT
.getNullPointerValue(DstAddr
),
221 const MCExpr
*AMDGPUAsmPrinter::lowerConstant(const Constant
*CV
) {
222 if (const MCExpr
*E
= lowerAddrSpaceCast(TM
, CV
, OutContext
))
224 return AsmPrinter::lowerConstant(CV
);
227 void AMDGPUAsmPrinter::emitInstruction(const MachineInstr
*MI
) {
228 if (emitPseudoExpansionLowering(*OutStreamer
, MI
))
231 const GCNSubtarget
&STI
= MF
->getSubtarget
<GCNSubtarget
>();
232 AMDGPUMCInstLower
MCInstLowering(OutContext
, STI
, *this);
235 if (!STI
.getInstrInfo()->verifyInstruction(*MI
, Err
)) {
236 LLVMContext
&C
= MI
->getParent()->getParent()->getFunction().getContext();
237 C
.emitError("Illegal instruction detected: " + Err
);
241 if (MI
->isBundle()) {
242 const MachineBasicBlock
*MBB
= MI
->getParent();
243 MachineBasicBlock::const_instr_iterator I
= ++MI
->getIterator();
244 while (I
!= MBB
->instr_end() && I
->isInsideBundle()) {
245 emitInstruction(&*I
);
249 // We don't want these pseudo instructions encoded. They are
250 // placeholder terminator instructions and should only be printed as
252 if (MI
->getOpcode() == AMDGPU::SI_RETURN_TO_EPILOG
) {
254 OutStreamer
->emitRawComment(" return to shader part epilog");
258 if (MI
->getOpcode() == AMDGPU::WAVE_BARRIER
) {
260 OutStreamer
->emitRawComment(" wave barrier");
264 if (MI
->getOpcode() == AMDGPU::SI_MASKED_UNREACHABLE
) {
266 OutStreamer
->emitRawComment(" divergent unreachable");
271 MCInstLowering
.lower(MI
, TmpInst
);
272 EmitToStreamer(*OutStreamer
, TmpInst
);
274 #ifdef EXPENSIVE_CHECKS
275 // Sanity-check getInstSizeInBytes on explicitly specified CPUs (it cannot
276 // work correctly for the generic CPU).
278 // The isPseudo check really shouldn't be here, but unfortunately there are
279 // some negative lit tests that depend on being able to continue through
280 // here even when pseudo instructions haven't been lowered.
282 // We also overestimate branch sizes with the offset bug.
283 if (!MI
->isPseudo() && STI
.isCPUStringValid(STI
.getCPU()) &&
284 (!STI
.hasOffset3fBug() || !MI
->isBranch())) {
285 SmallVector
<MCFixup
, 4> Fixups
;
286 SmallVector
<char, 16> CodeBytes
;
287 raw_svector_ostream
CodeStream(CodeBytes
);
289 std::unique_ptr
<MCCodeEmitter
> InstEmitter(createSIMCCodeEmitter(
290 *STI
.getInstrInfo(), *OutContext
.getRegisterInfo(), OutContext
));
291 InstEmitter
->encodeInstruction(TmpInst
, CodeStream
, Fixups
, STI
);
293 assert(CodeBytes
.size() == STI
.getInstrInfo()->getInstSizeInBytes(*MI
));
297 if (DumpCodeInstEmitter
) {
298 // Disassemble instruction/operands to text
299 DisasmLines
.resize(DisasmLines
.size() + 1);
300 std::string
&DisasmLine
= DisasmLines
.back();
301 raw_string_ostream
DisasmStream(DisasmLine
);
303 AMDGPUInstPrinter
InstPrinter(*TM
.getMCAsmInfo(), *STI
.getInstrInfo(),
304 *STI
.getRegisterInfo());
305 InstPrinter
.printInst(&TmpInst
, 0, StringRef(), STI
, DisasmStream
);
307 // Disassemble instruction/operands to hex representation.
308 SmallVector
<MCFixup
, 4> Fixups
;
309 SmallVector
<char, 16> CodeBytes
;
310 raw_svector_ostream
CodeStream(CodeBytes
);
312 DumpCodeInstEmitter
->encodeInstruction(
313 TmpInst
, CodeStream
, Fixups
, MF
->getSubtarget
<MCSubtargetInfo
>());
314 HexLines
.resize(HexLines
.size() + 1);
315 std::string
&HexLine
= HexLines
.back();
316 raw_string_ostream
HexStream(HexLine
);
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
);
323 DisasmStream
.flush();
324 DisasmLineMaxLen
= std::max(DisasmLineMaxLen
, DisasmLine
.size());
329 R600MCInstLower::R600MCInstLower(MCContext
&Ctx
, const R600Subtarget
&ST
,
330 const AsmPrinter
&AP
) :
331 AMDGPUMCInstLower(Ctx
, ST
, AP
) { }
333 void R600MCInstLower::lower(const MachineInstr
*MI
, MCInst
&OutMI
) const {
334 OutMI
.setOpcode(MI
->getOpcode());
335 for (const MachineOperand
&MO
: MI
->explicit_operands()) {
337 lowerOperand(MO
, MCOp
);
338 OutMI
.addOperand(MCOp
);
342 void R600AsmPrinter::emitInstruction(const MachineInstr
*MI
) {
343 const R600Subtarget
&STI
= MF
->getSubtarget
<R600Subtarget
>();
344 R600MCInstLower
MCInstLowering(OutContext
, STI
, *this);
347 if (!STI
.getInstrInfo()->verifyInstruction(*MI
, Err
)) {
348 LLVMContext
&C
= MI
->getParent()->getParent()->getFunction().getContext();
349 C
.emitError("Illegal instruction detected: " + Err
);
353 if (MI
->isBundle()) {
354 const MachineBasicBlock
*MBB
= MI
->getParent();
355 MachineBasicBlock::const_instr_iterator I
= ++MI
->getIterator();
356 while (I
!= MBB
->instr_end() && I
->isInsideBundle()) {
357 emitInstruction(&*I
);
362 MCInstLowering
.lower(MI
, TmpInst
);
363 EmitToStreamer(*OutStreamer
, TmpInst
);
367 const MCExpr
*R600AsmPrinter::lowerConstant(const Constant
*CV
) {
368 if (const MCExpr
*E
= lowerAddrSpaceCast(TM
, CV
, OutContext
))
370 return AsmPrinter::lowerConstant(CV
);