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