145bb48eaSTom Stellard //===- AMDGPUMCInstLower.cpp - Lower AMDGPU MachineInstr to an MCInst -----===//
245bb48eaSTom Stellard //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
645bb48eaSTom Stellard //
745bb48eaSTom Stellard //===----------------------------------------------------------------------===//
845bb48eaSTom Stellard //
945bb48eaSTom Stellard /// \file
105f8f34e4SAdrian Prantl /// Code to lower AMDGPU MachineInstrs to their corresponding MCInst.
1145bb48eaSTom Stellard //
1245bb48eaSTom Stellard //===----------------------------------------------------------------------===//
1345bb48eaSTom Stellard //
1445bb48eaSTom Stellard
1547d6274dSDaniil Fukalov #include "AMDGPUMCInstLower.h"
1645bb48eaSTom Stellard #include "AMDGPUAsmPrinter.h"
1745bb48eaSTom Stellard #include "AMDGPUTargetMachine.h"
18c0bd7bd4SRichard Trieu #include "MCTargetDesc/AMDGPUInstPrinter.h"
19560d7e04Sdfukalov #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
2045bb48eaSTom Stellard #include "llvm/CodeGen/MachineBasicBlock.h"
2145bb48eaSTom Stellard #include "llvm/CodeGen/MachineInstr.h"
2245bb48eaSTom Stellard #include "llvm/IR/Constants.h"
2345bb48eaSTom Stellard #include "llvm/IR/Function.h"
2445bb48eaSTom Stellard #include "llvm/IR/GlobalVariable.h"
2545bb48eaSTom Stellard #include "llvm/MC/MCCodeEmitter.h"
2645bb48eaSTom Stellard #include "llvm/MC/MCContext.h"
2745bb48eaSTom Stellard #include "llvm/MC/MCExpr.h"
2845bb48eaSTom Stellard #include "llvm/MC/MCInst.h"
2945bb48eaSTom Stellard #include "llvm/MC/MCObjectStreamer.h"
3045bb48eaSTom Stellard #include "llvm/MC/MCStreamer.h"
3145bb48eaSTom Stellard #include "llvm/Support/ErrorHandling.h"
3245bb48eaSTom Stellard #include "llvm/Support/Format.h"
3345bb48eaSTom Stellard #include <algorithm>
3445bb48eaSTom Stellard
3545bb48eaSTom Stellard using namespace llvm;
3645bb48eaSTom Stellard
3711f74020SMatt Arsenault #include "AMDGPUGenMCPseudoLowering.inc"
3811f74020SMatt Arsenault
AMDGPUMCInstLower(MCContext & ctx,const TargetSubtargetInfo & st,const AsmPrinter & ap)3957b9342cSTom Stellard AMDGPUMCInstLower::AMDGPUMCInstLower(MCContext &ctx,
4057b9342cSTom Stellard const TargetSubtargetInfo &st,
411b9748c6STom Stellard const AsmPrinter &ap):
421b9748c6STom Stellard Ctx(ctx), ST(st), AP(ap) { }
4345bb48eaSTom Stellard
getVariantKind(unsigned MOFlags)44418beb76STom Stellard static MCSymbolRefExpr::VariantKind getVariantKind(unsigned MOFlags) {
45418beb76STom Stellard switch (MOFlags) {
46c96b5d70SKonstantin Zhuravlyov default:
47c96b5d70SKonstantin Zhuravlyov return MCSymbolRefExpr::VK_None;
48c96b5d70SKonstantin Zhuravlyov case SIInstrInfo::MO_GOTPCREL:
49c96b5d70SKonstantin Zhuravlyov return MCSymbolRefExpr::VK_GOTPCREL;
50c96b5d70SKonstantin Zhuravlyov case SIInstrInfo::MO_GOTPCREL32_LO:
51c96b5d70SKonstantin Zhuravlyov return MCSymbolRefExpr::VK_AMDGPU_GOTPCREL32_LO;
52c96b5d70SKonstantin Zhuravlyov case SIInstrInfo::MO_GOTPCREL32_HI:
53c96b5d70SKonstantin Zhuravlyov return MCSymbolRefExpr::VK_AMDGPU_GOTPCREL32_HI;
54c96b5d70SKonstantin Zhuravlyov case SIInstrInfo::MO_REL32_LO:
55c96b5d70SKonstantin Zhuravlyov return MCSymbolRefExpr::VK_AMDGPU_REL32_LO;
56c96b5d70SKonstantin Zhuravlyov case SIInstrInfo::MO_REL32_HI:
57c96b5d70SKonstantin Zhuravlyov return MCSymbolRefExpr::VK_AMDGPU_REL32_HI;
5841abf276SNicolai Haehnle case SIInstrInfo::MO_ABS32_LO:
5941abf276SNicolai Haehnle return MCSymbolRefExpr::VK_AMDGPU_ABS32_LO;
6041abf276SNicolai Haehnle case SIInstrInfo::MO_ABS32_HI:
6141abf276SNicolai Haehnle return MCSymbolRefExpr::VK_AMDGPU_ABS32_HI;
62418beb76STom Stellard }
63418beb76STom Stellard }
64418beb76STom Stellard
lowerOperand(const MachineOperand & MO,MCOperand & MCOp) const6511f74020SMatt Arsenault bool AMDGPUMCInstLower::lowerOperand(const MachineOperand &MO,
6611f74020SMatt Arsenault MCOperand &MCOp) const {
6711f74020SMatt Arsenault switch (MO.getType()) {
6811f74020SMatt Arsenault default:
69b0402a35SMichael Liao break;
7011f74020SMatt Arsenault case MachineOperand::MO_Immediate:
7111f74020SMatt Arsenault MCOp = MCOperand::createImm(MO.getImm());
7211f74020SMatt Arsenault return true;
7311f74020SMatt Arsenault case MachineOperand::MO_Register:
7411f74020SMatt Arsenault MCOp = MCOperand::createReg(AMDGPU::getMCReg(MO.getReg(), ST));
7511f74020SMatt Arsenault return true;
76b0402a35SMichael Liao case MachineOperand::MO_MachineBasicBlock:
7711f74020SMatt Arsenault MCOp = MCOperand::createExpr(
7811f74020SMatt Arsenault MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx));
7911f74020SMatt Arsenault return true;
8011f74020SMatt Arsenault case MachineOperand::MO_GlobalAddress: {
8111f74020SMatt Arsenault const GlobalValue *GV = MO.getGlobal();
8211f74020SMatt Arsenault SmallString<128> SymbolName;
8311f74020SMatt Arsenault AP.getNameWithPrefix(SymbolName, GV);
8411f74020SMatt Arsenault MCSymbol *Sym = Ctx.getOrCreateSymbol(SymbolName);
8541abf276SNicolai Haehnle const MCExpr *Expr =
8611f74020SMatt Arsenault MCSymbolRefExpr::create(Sym, getVariantKind(MO.getTargetFlags()),Ctx);
8741abf276SNicolai Haehnle int64_t Offset = MO.getOffset();
8841abf276SNicolai Haehnle if (Offset != 0) {
8941abf276SNicolai Haehnle Expr = MCBinaryExpr::createAdd(Expr,
9041abf276SNicolai Haehnle MCConstantExpr::create(Offset, Ctx), Ctx);
9141abf276SNicolai Haehnle }
9211f74020SMatt Arsenault MCOp = MCOperand::createExpr(Expr);
9311f74020SMatt Arsenault return true;
9411f74020SMatt Arsenault }
9511f74020SMatt Arsenault case MachineOperand::MO_ExternalSymbol: {
9611f74020SMatt Arsenault MCSymbol *Sym = Ctx.getOrCreateSymbol(StringRef(MO.getSymbolName()));
9711f74020SMatt Arsenault Sym->setExternal(true);
9811f74020SMatt Arsenault const MCSymbolRefExpr *Expr = MCSymbolRefExpr::create(Sym, Ctx);
9911f74020SMatt Arsenault MCOp = MCOperand::createExpr(Expr);
10011f74020SMatt Arsenault return true;
10111f74020SMatt Arsenault }
102b62a4eb5SMatt Arsenault case MachineOperand::MO_RegisterMask:
103b62a4eb5SMatt Arsenault // Regmasks are like implicit defs.
104b62a4eb5SMatt Arsenault return false;
105b0402a35SMichael Liao case MachineOperand::MO_MCSymbol:
106b0402a35SMichael Liao if (MO.getTargetFlags() == SIInstrInfo::MO_FAR_BRANCH_OFFSET) {
107b0402a35SMichael Liao MCSymbol *Sym = MO.getMCSymbol();
108b0402a35SMichael Liao MCOp = MCOperand::createExpr(Sym->getVariableValue());
109b0402a35SMichael Liao return true;
11011f74020SMatt Arsenault }
111b0402a35SMichael Liao break;
112b0402a35SMichael Liao }
113b0402a35SMichael Liao llvm_unreachable("unknown operand type");
11411f74020SMatt Arsenault }
11511f74020SMatt Arsenault
lower(const MachineInstr * MI,MCInst & OutMI) const11645bb48eaSTom Stellard void AMDGPUMCInstLower::lower(const MachineInstr *MI, MCInst &OutMI) const {
1172b1f9aa5SMatt Arsenault unsigned Opcode = MI->getOpcode();
11857b9342cSTom Stellard const auto *TII = static_cast<const SIInstrInfo*>(ST.getInstrInfo());
11945bb48eaSTom Stellard
1202b1f9aa5SMatt Arsenault // FIXME: Should be able to handle this with emitPseudoExpansionLowering. We
1212b1f9aa5SMatt Arsenault // need to select it to the subtarget specific version, and there's no way to
1222b1f9aa5SMatt Arsenault // do that with a single pseudo source operation.
12304fff547SVenkata Ramanaiah Nalamothu if (Opcode == AMDGPU::S_SETPC_B64_return)
1242b1f9aa5SMatt Arsenault Opcode = AMDGPU::S_SETPC_B64;
1256ed7b9bfSMatt Arsenault else if (Opcode == AMDGPU::SI_CALL) {
1266ed7b9bfSMatt Arsenault // SI_CALL is just S_SWAPPC_B64 with an additional operand to track the
1271d6317c3SMatt Arsenault // called function (which we need to remove here).
1281d6317c3SMatt Arsenault OutMI.setOpcode(TII->pseudoToMCOpcode(AMDGPU::S_SWAPPC_B64));
1291d6317c3SMatt Arsenault MCOperand Dest, Src;
1301d6317c3SMatt Arsenault lowerOperand(MI->getOperand(0), Dest);
1311d6317c3SMatt Arsenault lowerOperand(MI->getOperand(1), Src);
1321d6317c3SMatt Arsenault OutMI.addOperand(Dest);
1331d6317c3SMatt Arsenault OutMI.addOperand(Src);
1341d6317c3SMatt Arsenault return;
13571bcbd45SMatt Arsenault } else if (Opcode == AMDGPU::SI_TCRETURN) {
13671bcbd45SMatt Arsenault // TODO: How to use branch immediate and avoid register+add?
13771bcbd45SMatt Arsenault Opcode = AMDGPU::S_SETPC_B64;
1386ed7b9bfSMatt Arsenault }
13945bb48eaSTom Stellard
1401d6317c3SMatt Arsenault int MCOpcode = TII->pseudoToMCOpcode(Opcode);
14145bb48eaSTom Stellard if (MCOpcode == -1) {
142f1caa283SMatthias Braun LLVMContext &C = MI->getParent()->getParent()->getFunction().getContext();
14345bb48eaSTom Stellard C.emitError("AMDGPUMCInstLower::lower - Pseudo instruction doesn't have "
14445bb48eaSTom Stellard "a target-specific version: " + Twine(MI->getOpcode()));
14545bb48eaSTom Stellard }
14645bb48eaSTom Stellard
14745bb48eaSTom Stellard OutMI.setOpcode(MCOpcode);
14845bb48eaSTom Stellard
14945bb48eaSTom Stellard for (const MachineOperand &MO : MI->explicit_operands()) {
15045bb48eaSTom Stellard MCOperand MCOp;
15111f74020SMatt Arsenault lowerOperand(MO, MCOp);
15245bb48eaSTom Stellard OutMI.addOperand(MCOp);
15345bb48eaSTom Stellard }
154e2d104f6SStanislav Mekhanoshin
155e2d104f6SStanislav Mekhanoshin int FIIdx = AMDGPU::getNamedOperandIdx(MCOpcode, AMDGPU::OpName::fi);
156e2d104f6SStanislav Mekhanoshin if (FIIdx >= (int)OutMI.getNumOperands())
157e2d104f6SStanislav Mekhanoshin OutMI.addOperand(MCOperand::createImm(0));
15845bb48eaSTom Stellard }
15945bb48eaSTom Stellard
lowerOperand(const MachineOperand & MO,MCOperand & MCOp) const16011f74020SMatt Arsenault bool AMDGPUAsmPrinter::lowerOperand(const MachineOperand &MO,
16111f74020SMatt Arsenault MCOperand &MCOp) const {
1625bfbae5cSTom Stellard const GCNSubtarget &STI = MF->getSubtarget<GCNSubtarget>();
16311f74020SMatt Arsenault AMDGPUMCInstLower MCInstLowering(OutContext, STI, *this);
16411f74020SMatt Arsenault return MCInstLowering.lowerOperand(MO, MCOp);
16511f74020SMatt Arsenault }
16611f74020SMatt Arsenault
lowerConstant(const Constant * CV)167c5015010STom Stellard const MCExpr *AMDGPUAsmPrinter::lowerConstant(const Constant *CV) {
168c5015010STom Stellard if (const MCExpr *E = lowerAddrSpaceCast(TM, CV, OutContext))
169c5015010STom Stellard return E;
1708f844f39SYaxun Liu return AsmPrinter::lowerConstant(CV);
1718f844f39SYaxun Liu }
1728f844f39SYaxun Liu
emitInstruction(const MachineInstr * MI)173bcd24b2dSFangrui Song void AMDGPUAsmPrinter::emitInstruction(const MachineInstr *MI) {
174*3e0bf1c7SDavid Green // FIXME: Enable feature predicate checks once all the test pass.
175*3e0bf1c7SDavid Green // AMDGPU_MC::verifyInstructionPredicates(MI->getOpcode(),
176*3e0bf1c7SDavid Green // getSubtargetInfo().getFeatureBits());
177*3e0bf1c7SDavid Green
17811f74020SMatt Arsenault if (emitPseudoExpansionLowering(*OutStreamer, MI))
17911f74020SMatt Arsenault return;
18011f74020SMatt Arsenault
1815bfbae5cSTom Stellard const GCNSubtarget &STI = MF->getSubtarget<GCNSubtarget>();
1821b9748c6STom Stellard AMDGPUMCInstLower MCInstLowering(OutContext, STI, *this);
18345bb48eaSTom Stellard
18445bb48eaSTom Stellard StringRef Err;
1859cfc75c2SDuncan P. N. Exon Smith if (!STI.getInstrInfo()->verifyInstruction(*MI, Err)) {
186f1caa283SMatthias Braun LLVMContext &C = MI->getParent()->getParent()->getFunction().getContext();
187302f83acSMichel Danzer C.emitError("Illegal instruction detected: " + Err);
1888c209aa8SMatthias Braun MI->print(errs());
18945bb48eaSTom Stellard }
190302f83acSMichel Danzer
19145bb48eaSTom Stellard if (MI->isBundle()) {
19245bb48eaSTom Stellard const MachineBasicBlock *MBB = MI->getParent();
193c5b668deSDuncan P. N. Exon Smith MachineBasicBlock::const_instr_iterator I = ++MI->getIterator();
194a73371a9SDuncan P. N. Exon Smith while (I != MBB->instr_end() && I->isInsideBundle()) {
195bcd24b2dSFangrui Song emitInstruction(&*I);
19645bb48eaSTom Stellard ++I;
19745bb48eaSTom Stellard }
19845bb48eaSTom Stellard } else {
199f0ccdde3SRuiling Song // We don't want these pseudo instructions encoded. They are
2005b20fbb7SMatt Arsenault // placeholder terminator instructions and should only be printed as
2015b20fbb7SMatt Arsenault // comments.
2025b20fbb7SMatt Arsenault if (MI->getOpcode() == AMDGPU::SI_RETURN_TO_EPILOG) {
2039babdf42SMatt Arsenault if (isVerbose())
2045b20fbb7SMatt Arsenault OutStreamer->emitRawComment(" return to shader part epilog");
2059babdf42SMatt Arsenault return;
2069babdf42SMatt Arsenault }
2079babdf42SMatt Arsenault
208ea91cca5SStanislav Mekhanoshin if (MI->getOpcode() == AMDGPU::WAVE_BARRIER) {
209ea91cca5SStanislav Mekhanoshin if (isVerbose())
210ea91cca5SStanislav Mekhanoshin OutStreamer->emitRawComment(" wave barrier");
211ea91cca5SStanislav Mekhanoshin return;
212ea91cca5SStanislav Mekhanoshin }
213ea91cca5SStanislav Mekhanoshin
2142db70021SAustin Kerbow if (MI->getOpcode() == AMDGPU::SCHED_BARRIER) {
2152db70021SAustin Kerbow if (isVerbose()) {
2162db70021SAustin Kerbow std::string HexString;
2172db70021SAustin Kerbow raw_string_ostream HexStream(HexString);
2182db70021SAustin Kerbow HexStream << format_hex(MI->getOperand(0).getImm(), 10, true);
2192db70021SAustin Kerbow OutStreamer->emitRawComment(" sched_barrier mask(" + HexString + ")");
2202db70021SAustin Kerbow }
2212db70021SAustin Kerbow return;
2222db70021SAustin Kerbow }
2232db70021SAustin Kerbow
22415a96b1dSYaxun Liu if (MI->getOpcode() == AMDGPU::SI_MASKED_UNREACHABLE) {
22515a96b1dSYaxun Liu if (isVerbose())
22615a96b1dSYaxun Liu OutStreamer->emitRawComment(" divergent unreachable");
22715a96b1dSYaxun Liu return;
22815a96b1dSYaxun Liu }
22915a96b1dSYaxun Liu
230bf980930SSebastian Neubauer if (MI->isMetaInstruction()) {
231bf980930SSebastian Neubauer if (isVerbose())
232bf980930SSebastian Neubauer OutStreamer->emitRawComment(" meta instruction");
233bf980930SSebastian Neubauer return;
234bf980930SSebastian Neubauer }
235bf980930SSebastian Neubauer
23645bb48eaSTom Stellard MCInst TmpInst;
23745bb48eaSTom Stellard MCInstLowering.lower(MI, TmpInst);
23845bb48eaSTom Stellard EmitToStreamer(*OutStreamer, TmpInst);
23945bb48eaSTom Stellard
240283b9950SNicolai Haehnle #ifdef EXPENSIVE_CHECKS
2415b8bbbecSZarko Todorovski // Check getInstSizeInBytes on explicitly specified CPUs (it cannot
242283b9950SNicolai Haehnle // work correctly for the generic CPU).
243283b9950SNicolai Haehnle //
244283b9950SNicolai Haehnle // The isPseudo check really shouldn't be here, but unfortunately there are
245283b9950SNicolai Haehnle // some negative lit tests that depend on being able to continue through
246283b9950SNicolai Haehnle // here even when pseudo instructions haven't been lowered.
247d6199647SMatt Arsenault //
248d6199647SMatt Arsenault // We also overestimate branch sizes with the offset bug.
249d6199647SMatt Arsenault if (!MI->isPseudo() && STI.isCPUStringValid(STI.getCPU()) &&
250d6199647SMatt Arsenault (!STI.hasOffset3fBug() || !MI->isBranch())) {
251283b9950SNicolai Haehnle SmallVector<MCFixup, 4> Fixups;
252283b9950SNicolai Haehnle SmallVector<char, 16> CodeBytes;
253283b9950SNicolai Haehnle raw_svector_ostream CodeStream(CodeBytes);
254283b9950SNicolai Haehnle
255283b9950SNicolai Haehnle std::unique_ptr<MCCodeEmitter> InstEmitter(createSIMCCodeEmitter(
2562aed07e9SShao-Ce SUN *STI.getInstrInfo(), OutContext));
257283b9950SNicolai Haehnle InstEmitter->encodeInstruction(TmpInst, CodeStream, Fixups, STI);
258283b9950SNicolai Haehnle
259283b9950SNicolai Haehnle assert(CodeBytes.size() == STI.getInstrInfo()->getInstSizeInBytes(*MI));
260283b9950SNicolai Haehnle }
261283b9950SNicolai Haehnle #endif
262283b9950SNicolai Haehnle
26333cb8f5bSTim Renouf if (DumpCodeInstEmitter) {
26433cb8f5bSTim Renouf // Disassemble instruction/operands to text
26545bb48eaSTom Stellard DisasmLines.resize(DisasmLines.size() + 1);
26645bb48eaSTom Stellard std::string &DisasmLine = DisasmLines.back();
26745bb48eaSTom Stellard raw_string_ostream DisasmStream(DisasmLine);
26845bb48eaSTom Stellard
26933cb8f5bSTim Renouf AMDGPUInstPrinter InstPrinter(*TM.getMCAsmInfo(), *STI.getInstrInfo(),
27043e92fe3SMatt Arsenault *STI.getRegisterInfo());
271aa708763SFangrui Song InstPrinter.printInst(&TmpInst, 0, StringRef(), STI, DisasmStream);
27245bb48eaSTom Stellard
27345bb48eaSTom Stellard // Disassemble instruction/operands to hex representation.
27445bb48eaSTom Stellard SmallVector<MCFixup, 4> Fixups;
27545bb48eaSTom Stellard SmallVector<char, 16> CodeBytes;
27645bb48eaSTom Stellard raw_svector_ostream CodeStream(CodeBytes);
27745bb48eaSTom Stellard
27833cb8f5bSTim Renouf DumpCodeInstEmitter->encodeInstruction(
27933cb8f5bSTim Renouf TmpInst, CodeStream, Fixups, MF->getSubtarget<MCSubtargetInfo>());
28045bb48eaSTom Stellard HexLines.resize(HexLines.size() + 1);
28145bb48eaSTom Stellard std::string &HexLine = HexLines.back();
28245bb48eaSTom Stellard raw_string_ostream HexStream(HexLine);
28345bb48eaSTom Stellard
28445bb48eaSTom Stellard for (size_t i = 0; i < CodeBytes.size(); i += 4) {
28545bb48eaSTom Stellard unsigned int CodeDWord = *(unsigned int *)&CodeBytes[i];
28645bb48eaSTom Stellard HexStream << format("%s%08X", (i > 0 ? " " : ""), CodeDWord);
28745bb48eaSTom Stellard }
28845bb48eaSTom Stellard
28945bb48eaSTom Stellard DisasmStream.flush();
29045bb48eaSTom Stellard DisasmLineMaxLen = std::max(DisasmLineMaxLen, DisasmLine.size());
29145bb48eaSTom Stellard }
29245bb48eaSTom Stellard }
29345bb48eaSTom Stellard }
294