10b57cec5SDimitry Andric //===- AMDGPUMCInstLower.cpp - Lower AMDGPU MachineInstr to an MCInst -----===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric /// \file 100b57cec5SDimitry Andric /// Code to lower AMDGPU MachineInstrs to their corresponding MCInst. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric // 140b57cec5SDimitry Andric 15*349cc55cSDimitry Andric #include "AMDGPUMCInstLower.h" 160b57cec5SDimitry Andric #include "AMDGPUAsmPrinter.h" 170b57cec5SDimitry Andric #include "AMDGPUTargetMachine.h" 180b57cec5SDimitry Andric #include "MCTargetDesc/AMDGPUInstPrinter.h" 190b57cec5SDimitry Andric #include "MCTargetDesc/AMDGPUMCTargetDesc.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 220b57cec5SDimitry Andric #include "llvm/IR/Constants.h" 230b57cec5SDimitry Andric #include "llvm/IR/Function.h" 240b57cec5SDimitry Andric #include "llvm/IR/GlobalVariable.h" 250b57cec5SDimitry Andric #include "llvm/MC/MCCodeEmitter.h" 260b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 270b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h" 280b57cec5SDimitry Andric #include "llvm/MC/MCInst.h" 290b57cec5SDimitry Andric #include "llvm/MC/MCObjectStreamer.h" 300b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h" 310b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 320b57cec5SDimitry Andric #include "llvm/Support/Format.h" 330b57cec5SDimitry Andric #include <algorithm> 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric using namespace llvm; 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric #include "AMDGPUGenMCPseudoLowering.inc" 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric AMDGPUMCInstLower::AMDGPUMCInstLower(MCContext &ctx, 400b57cec5SDimitry Andric const TargetSubtargetInfo &st, 410b57cec5SDimitry Andric const AsmPrinter &ap): 420b57cec5SDimitry Andric Ctx(ctx), ST(st), AP(ap) { } 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric static MCSymbolRefExpr::VariantKind getVariantKind(unsigned MOFlags) { 450b57cec5SDimitry Andric switch (MOFlags) { 460b57cec5SDimitry Andric default: 470b57cec5SDimitry Andric return MCSymbolRefExpr::VK_None; 480b57cec5SDimitry Andric case SIInstrInfo::MO_GOTPCREL: 490b57cec5SDimitry Andric return MCSymbolRefExpr::VK_GOTPCREL; 500b57cec5SDimitry Andric case SIInstrInfo::MO_GOTPCREL32_LO: 510b57cec5SDimitry Andric return MCSymbolRefExpr::VK_AMDGPU_GOTPCREL32_LO; 520b57cec5SDimitry Andric case SIInstrInfo::MO_GOTPCREL32_HI: 530b57cec5SDimitry Andric return MCSymbolRefExpr::VK_AMDGPU_GOTPCREL32_HI; 540b57cec5SDimitry Andric case SIInstrInfo::MO_REL32_LO: 550b57cec5SDimitry Andric return MCSymbolRefExpr::VK_AMDGPU_REL32_LO; 560b57cec5SDimitry Andric case SIInstrInfo::MO_REL32_HI: 570b57cec5SDimitry Andric return MCSymbolRefExpr::VK_AMDGPU_REL32_HI; 580b57cec5SDimitry Andric case SIInstrInfo::MO_ABS32_LO: 590b57cec5SDimitry Andric return MCSymbolRefExpr::VK_AMDGPU_ABS32_LO; 600b57cec5SDimitry Andric case SIInstrInfo::MO_ABS32_HI: 610b57cec5SDimitry Andric return MCSymbolRefExpr::VK_AMDGPU_ABS32_HI; 620b57cec5SDimitry Andric } 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric bool AMDGPUMCInstLower::lowerOperand(const MachineOperand &MO, 660b57cec5SDimitry Andric MCOperand &MCOp) const { 670b57cec5SDimitry Andric switch (MO.getType()) { 680b57cec5SDimitry Andric default: 69fe6060f1SDimitry Andric break; 700b57cec5SDimitry Andric case MachineOperand::MO_Immediate: 710b57cec5SDimitry Andric MCOp = MCOperand::createImm(MO.getImm()); 720b57cec5SDimitry Andric return true; 730b57cec5SDimitry Andric case MachineOperand::MO_Register: 740b57cec5SDimitry Andric MCOp = MCOperand::createReg(AMDGPU::getMCReg(MO.getReg(), ST)); 750b57cec5SDimitry Andric return true; 76fe6060f1SDimitry Andric case MachineOperand::MO_MachineBasicBlock: 770b57cec5SDimitry Andric MCOp = MCOperand::createExpr( 780b57cec5SDimitry Andric MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx)); 790b57cec5SDimitry Andric return true; 800b57cec5SDimitry Andric case MachineOperand::MO_GlobalAddress: { 810b57cec5SDimitry Andric const GlobalValue *GV = MO.getGlobal(); 820b57cec5SDimitry Andric SmallString<128> SymbolName; 830b57cec5SDimitry Andric AP.getNameWithPrefix(SymbolName, GV); 840b57cec5SDimitry Andric MCSymbol *Sym = Ctx.getOrCreateSymbol(SymbolName); 850b57cec5SDimitry Andric const MCExpr *Expr = 860b57cec5SDimitry Andric MCSymbolRefExpr::create(Sym, getVariantKind(MO.getTargetFlags()),Ctx); 870b57cec5SDimitry Andric int64_t Offset = MO.getOffset(); 880b57cec5SDimitry Andric if (Offset != 0) { 890b57cec5SDimitry Andric Expr = MCBinaryExpr::createAdd(Expr, 900b57cec5SDimitry Andric MCConstantExpr::create(Offset, Ctx), Ctx); 910b57cec5SDimitry Andric } 920b57cec5SDimitry Andric MCOp = MCOperand::createExpr(Expr); 930b57cec5SDimitry Andric return true; 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric case MachineOperand::MO_ExternalSymbol: { 960b57cec5SDimitry Andric MCSymbol *Sym = Ctx.getOrCreateSymbol(StringRef(MO.getSymbolName())); 970b57cec5SDimitry Andric Sym->setExternal(true); 980b57cec5SDimitry Andric const MCSymbolRefExpr *Expr = MCSymbolRefExpr::create(Sym, Ctx); 990b57cec5SDimitry Andric MCOp = MCOperand::createExpr(Expr); 1000b57cec5SDimitry Andric return true; 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric case MachineOperand::MO_RegisterMask: 1030b57cec5SDimitry Andric // Regmasks are like implicit defs. 1040b57cec5SDimitry Andric return false; 105fe6060f1SDimitry Andric case MachineOperand::MO_MCSymbol: 106fe6060f1SDimitry Andric if (MO.getTargetFlags() == SIInstrInfo::MO_FAR_BRANCH_OFFSET) { 107fe6060f1SDimitry Andric MCSymbol *Sym = MO.getMCSymbol(); 108fe6060f1SDimitry Andric MCOp = MCOperand::createExpr(Sym->getVariableValue()); 109fe6060f1SDimitry Andric return true; 1100b57cec5SDimitry Andric } 111fe6060f1SDimitry Andric break; 112fe6060f1SDimitry Andric } 113fe6060f1SDimitry Andric llvm_unreachable("unknown operand type"); 1140b57cec5SDimitry Andric } 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric void AMDGPUMCInstLower::lower(const MachineInstr *MI, MCInst &OutMI) const { 1170b57cec5SDimitry Andric unsigned Opcode = MI->getOpcode(); 1180b57cec5SDimitry Andric const auto *TII = static_cast<const SIInstrInfo*>(ST.getInstrInfo()); 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric // FIXME: Should be able to handle this with emitPseudoExpansionLowering. We 1210b57cec5SDimitry Andric // need to select it to the subtarget specific version, and there's no way to 1220b57cec5SDimitry Andric // do that with a single pseudo source operation. 123*349cc55cSDimitry Andric if (Opcode == AMDGPU::S_SETPC_B64_return || 124*349cc55cSDimitry Andric Opcode == AMDGPU::S_SETPC_B64_return_gfx) 1250b57cec5SDimitry Andric Opcode = AMDGPU::S_SETPC_B64; 1260b57cec5SDimitry Andric else if (Opcode == AMDGPU::SI_CALL) { 1270b57cec5SDimitry Andric // SI_CALL is just S_SWAPPC_B64 with an additional operand to track the 1280b57cec5SDimitry Andric // called function (which we need to remove here). 1290b57cec5SDimitry Andric OutMI.setOpcode(TII->pseudoToMCOpcode(AMDGPU::S_SWAPPC_B64)); 1300b57cec5SDimitry Andric MCOperand Dest, Src; 1310b57cec5SDimitry Andric lowerOperand(MI->getOperand(0), Dest); 1320b57cec5SDimitry Andric lowerOperand(MI->getOperand(1), Src); 1330b57cec5SDimitry Andric OutMI.addOperand(Dest); 1340b57cec5SDimitry Andric OutMI.addOperand(Src); 1350b57cec5SDimitry Andric return; 1360b57cec5SDimitry Andric } else if (Opcode == AMDGPU::SI_TCRETURN) { 1370b57cec5SDimitry Andric // TODO: How to use branch immediate and avoid register+add? 1380b57cec5SDimitry Andric Opcode = AMDGPU::S_SETPC_B64; 1390b57cec5SDimitry Andric } 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric int MCOpcode = TII->pseudoToMCOpcode(Opcode); 1420b57cec5SDimitry Andric if (MCOpcode == -1) { 1430b57cec5SDimitry Andric LLVMContext &C = MI->getParent()->getParent()->getFunction().getContext(); 1440b57cec5SDimitry Andric C.emitError("AMDGPUMCInstLower::lower - Pseudo instruction doesn't have " 1450b57cec5SDimitry Andric "a target-specific version: " + Twine(MI->getOpcode())); 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric OutMI.setOpcode(MCOpcode); 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric for (const MachineOperand &MO : MI->explicit_operands()) { 1510b57cec5SDimitry Andric MCOperand MCOp; 1520b57cec5SDimitry Andric lowerOperand(MO, MCOp); 1530b57cec5SDimitry Andric OutMI.addOperand(MCOp); 1540b57cec5SDimitry Andric } 1558bcb0991SDimitry Andric 1568bcb0991SDimitry Andric int FIIdx = AMDGPU::getNamedOperandIdx(MCOpcode, AMDGPU::OpName::fi); 1578bcb0991SDimitry Andric if (FIIdx >= (int)OutMI.getNumOperands()) 1588bcb0991SDimitry Andric OutMI.addOperand(MCOperand::createImm(0)); 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric bool AMDGPUAsmPrinter::lowerOperand(const MachineOperand &MO, 1620b57cec5SDimitry Andric MCOperand &MCOp) const { 1630b57cec5SDimitry Andric const GCNSubtarget &STI = MF->getSubtarget<GCNSubtarget>(); 1640b57cec5SDimitry Andric AMDGPUMCInstLower MCInstLowering(OutContext, STI, *this); 1650b57cec5SDimitry Andric return MCInstLowering.lowerOperand(MO, MCOp); 1660b57cec5SDimitry Andric } 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric const MCExpr *AMDGPUAsmPrinter::lowerConstant(const Constant *CV) { 1690b57cec5SDimitry Andric if (const MCExpr *E = lowerAddrSpaceCast(TM, CV, OutContext)) 1700b57cec5SDimitry Andric return E; 1710b57cec5SDimitry Andric return AsmPrinter::lowerConstant(CV); 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric 1745ffd83dbSDimitry Andric void AMDGPUAsmPrinter::emitInstruction(const MachineInstr *MI) { 1750b57cec5SDimitry Andric if (emitPseudoExpansionLowering(*OutStreamer, MI)) 1760b57cec5SDimitry Andric return; 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric const GCNSubtarget &STI = MF->getSubtarget<GCNSubtarget>(); 1790b57cec5SDimitry Andric AMDGPUMCInstLower MCInstLowering(OutContext, STI, *this); 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric StringRef Err; 1820b57cec5SDimitry Andric if (!STI.getInstrInfo()->verifyInstruction(*MI, Err)) { 1830b57cec5SDimitry Andric LLVMContext &C = MI->getParent()->getParent()->getFunction().getContext(); 1840b57cec5SDimitry Andric C.emitError("Illegal instruction detected: " + Err); 1850b57cec5SDimitry Andric MI->print(errs()); 1860b57cec5SDimitry Andric } 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric if (MI->isBundle()) { 1890b57cec5SDimitry Andric const MachineBasicBlock *MBB = MI->getParent(); 1900b57cec5SDimitry Andric MachineBasicBlock::const_instr_iterator I = ++MI->getIterator(); 1910b57cec5SDimitry Andric while (I != MBB->instr_end() && I->isInsideBundle()) { 1925ffd83dbSDimitry Andric emitInstruction(&*I); 1930b57cec5SDimitry Andric ++I; 1940b57cec5SDimitry Andric } 1950b57cec5SDimitry Andric } else { 196fe6060f1SDimitry Andric // We don't want these pseudo instructions encoded. They are 1970b57cec5SDimitry Andric // placeholder terminator instructions and should only be printed as 1980b57cec5SDimitry Andric // comments. 1990b57cec5SDimitry Andric if (MI->getOpcode() == AMDGPU::SI_RETURN_TO_EPILOG) { 2000b57cec5SDimitry Andric if (isVerbose()) 2010b57cec5SDimitry Andric OutStreamer->emitRawComment(" return to shader part epilog"); 2020b57cec5SDimitry Andric return; 2030b57cec5SDimitry Andric } 2040b57cec5SDimitry Andric 2050b57cec5SDimitry Andric if (MI->getOpcode() == AMDGPU::WAVE_BARRIER) { 2060b57cec5SDimitry Andric if (isVerbose()) 2070b57cec5SDimitry Andric OutStreamer->emitRawComment(" wave barrier"); 2080b57cec5SDimitry Andric return; 2090b57cec5SDimitry Andric } 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric if (MI->getOpcode() == AMDGPU::SI_MASKED_UNREACHABLE) { 2120b57cec5SDimitry Andric if (isVerbose()) 2130b57cec5SDimitry Andric OutStreamer->emitRawComment(" divergent unreachable"); 2140b57cec5SDimitry Andric return; 2150b57cec5SDimitry Andric } 2160b57cec5SDimitry Andric 217*349cc55cSDimitry Andric if (MI->isMetaInstruction()) { 218*349cc55cSDimitry Andric if (isVerbose()) 219*349cc55cSDimitry Andric OutStreamer->emitRawComment(" meta instruction"); 220*349cc55cSDimitry Andric return; 221*349cc55cSDimitry Andric } 222*349cc55cSDimitry Andric 2230b57cec5SDimitry Andric MCInst TmpInst; 2240b57cec5SDimitry Andric MCInstLowering.lower(MI, TmpInst); 2250b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, TmpInst); 2260b57cec5SDimitry Andric 2270b57cec5SDimitry Andric #ifdef EXPENSIVE_CHECKS 228*349cc55cSDimitry Andric // Check getInstSizeInBytes on explicitly specified CPUs (it cannot 2290b57cec5SDimitry Andric // work correctly for the generic CPU). 2300b57cec5SDimitry Andric // 2310b57cec5SDimitry Andric // The isPseudo check really shouldn't be here, but unfortunately there are 2320b57cec5SDimitry Andric // some negative lit tests that depend on being able to continue through 2330b57cec5SDimitry Andric // here even when pseudo instructions haven't been lowered. 234e8d8bef9SDimitry Andric // 235e8d8bef9SDimitry Andric // We also overestimate branch sizes with the offset bug. 236e8d8bef9SDimitry Andric if (!MI->isPseudo() && STI.isCPUStringValid(STI.getCPU()) && 237e8d8bef9SDimitry Andric (!STI.hasOffset3fBug() || !MI->isBranch())) { 2380b57cec5SDimitry Andric SmallVector<MCFixup, 4> Fixups; 2390b57cec5SDimitry Andric SmallVector<char, 16> CodeBytes; 2400b57cec5SDimitry Andric raw_svector_ostream CodeStream(CodeBytes); 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric std::unique_ptr<MCCodeEmitter> InstEmitter(createSIMCCodeEmitter( 2430b57cec5SDimitry Andric *STI.getInstrInfo(), *OutContext.getRegisterInfo(), OutContext)); 2440b57cec5SDimitry Andric InstEmitter->encodeInstruction(TmpInst, CodeStream, Fixups, STI); 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric assert(CodeBytes.size() == STI.getInstrInfo()->getInstSizeInBytes(*MI)); 2470b57cec5SDimitry Andric } 2480b57cec5SDimitry Andric #endif 2490b57cec5SDimitry Andric 2500b57cec5SDimitry Andric if (DumpCodeInstEmitter) { 2510b57cec5SDimitry Andric // Disassemble instruction/operands to text 2520b57cec5SDimitry Andric DisasmLines.resize(DisasmLines.size() + 1); 2530b57cec5SDimitry Andric std::string &DisasmLine = DisasmLines.back(); 2540b57cec5SDimitry Andric raw_string_ostream DisasmStream(DisasmLine); 2550b57cec5SDimitry Andric 2560b57cec5SDimitry Andric AMDGPUInstPrinter InstPrinter(*TM.getMCAsmInfo(), *STI.getInstrInfo(), 2570b57cec5SDimitry Andric *STI.getRegisterInfo()); 258480093f4SDimitry Andric InstPrinter.printInst(&TmpInst, 0, StringRef(), STI, DisasmStream); 2590b57cec5SDimitry Andric 2600b57cec5SDimitry Andric // Disassemble instruction/operands to hex representation. 2610b57cec5SDimitry Andric SmallVector<MCFixup, 4> Fixups; 2620b57cec5SDimitry Andric SmallVector<char, 16> CodeBytes; 2630b57cec5SDimitry Andric raw_svector_ostream CodeStream(CodeBytes); 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric DumpCodeInstEmitter->encodeInstruction( 2660b57cec5SDimitry Andric TmpInst, CodeStream, Fixups, MF->getSubtarget<MCSubtargetInfo>()); 2670b57cec5SDimitry Andric HexLines.resize(HexLines.size() + 1); 2680b57cec5SDimitry Andric std::string &HexLine = HexLines.back(); 2690b57cec5SDimitry Andric raw_string_ostream HexStream(HexLine); 2700b57cec5SDimitry Andric 2710b57cec5SDimitry Andric for (size_t i = 0; i < CodeBytes.size(); i += 4) { 2720b57cec5SDimitry Andric unsigned int CodeDWord = *(unsigned int *)&CodeBytes[i]; 2730b57cec5SDimitry Andric HexStream << format("%s%08X", (i > 0 ? " " : ""), CodeDWord); 2740b57cec5SDimitry Andric } 2750b57cec5SDimitry Andric 2760b57cec5SDimitry Andric DisasmStream.flush(); 2770b57cec5SDimitry Andric DisasmLineMaxLen = std::max(DisasmLineMaxLen, DisasmLine.size()); 2780b57cec5SDimitry Andric } 2790b57cec5SDimitry Andric } 2800b57cec5SDimitry Andric } 281