1*0b57cec5SDimitry Andric //===- AMDGPUMCInstLower.cpp - Lower AMDGPU MachineInstr to an MCInst -----===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric /// \file 10*0b57cec5SDimitry Andric /// Code to lower AMDGPU MachineInstrs to their corresponding MCInst. 11*0b57cec5SDimitry Andric // 12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 13*0b57cec5SDimitry Andric // 14*0b57cec5SDimitry Andric 15*0b57cec5SDimitry Andric #include "AMDGPUAsmPrinter.h" 16*0b57cec5SDimitry Andric #include "AMDGPUSubtarget.h" 17*0b57cec5SDimitry Andric #include "AMDGPUTargetMachine.h" 18*0b57cec5SDimitry Andric #include "MCTargetDesc/AMDGPUInstPrinter.h" 19*0b57cec5SDimitry Andric #include "MCTargetDesc/AMDGPUMCTargetDesc.h" 20*0b57cec5SDimitry Andric #include "R600AsmPrinter.h" 21*0b57cec5SDimitry Andric #include "SIInstrInfo.h" 22*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 23*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 24*0b57cec5SDimitry Andric #include "llvm/IR/Constants.h" 25*0b57cec5SDimitry Andric #include "llvm/IR/Function.h" 26*0b57cec5SDimitry Andric #include "llvm/IR/GlobalVariable.h" 27*0b57cec5SDimitry Andric #include "llvm/MC/MCCodeEmitter.h" 28*0b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 29*0b57cec5SDimitry Andric #include "llvm/MC/MCExpr.h" 30*0b57cec5SDimitry Andric #include "llvm/MC/MCInst.h" 31*0b57cec5SDimitry Andric #include "llvm/MC/MCObjectStreamer.h" 32*0b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h" 33*0b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h" 34*0b57cec5SDimitry Andric #include "llvm/Support/Format.h" 35*0b57cec5SDimitry Andric #include <algorithm> 36*0b57cec5SDimitry Andric 37*0b57cec5SDimitry Andric using namespace llvm; 38*0b57cec5SDimitry Andric 39*0b57cec5SDimitry Andric namespace { 40*0b57cec5SDimitry Andric 41*0b57cec5SDimitry Andric class AMDGPUMCInstLower { 42*0b57cec5SDimitry Andric MCContext &Ctx; 43*0b57cec5SDimitry Andric const TargetSubtargetInfo &ST; 44*0b57cec5SDimitry Andric const AsmPrinter &AP; 45*0b57cec5SDimitry Andric 46*0b57cec5SDimitry Andric const MCExpr *getLongBranchBlockExpr(const MachineBasicBlock &SrcBB, 47*0b57cec5SDimitry Andric const MachineOperand &MO) const; 48*0b57cec5SDimitry Andric 49*0b57cec5SDimitry Andric public: 50*0b57cec5SDimitry Andric AMDGPUMCInstLower(MCContext &ctx, const TargetSubtargetInfo &ST, 51*0b57cec5SDimitry Andric const AsmPrinter &AP); 52*0b57cec5SDimitry Andric 53*0b57cec5SDimitry Andric bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const; 54*0b57cec5SDimitry Andric 55*0b57cec5SDimitry Andric /// Lower a MachineInstr to an MCInst 56*0b57cec5SDimitry Andric void lower(const MachineInstr *MI, MCInst &OutMI) const; 57*0b57cec5SDimitry Andric 58*0b57cec5SDimitry Andric }; 59*0b57cec5SDimitry Andric 60*0b57cec5SDimitry Andric class R600MCInstLower : public AMDGPUMCInstLower { 61*0b57cec5SDimitry Andric public: 62*0b57cec5SDimitry Andric R600MCInstLower(MCContext &ctx, const R600Subtarget &ST, 63*0b57cec5SDimitry Andric const AsmPrinter &AP); 64*0b57cec5SDimitry Andric 65*0b57cec5SDimitry Andric /// Lower a MachineInstr to an MCInst 66*0b57cec5SDimitry Andric void lower(const MachineInstr *MI, MCInst &OutMI) const; 67*0b57cec5SDimitry Andric }; 68*0b57cec5SDimitry Andric 69*0b57cec5SDimitry Andric 70*0b57cec5SDimitry Andric } // End anonymous namespace 71*0b57cec5SDimitry Andric 72*0b57cec5SDimitry Andric #include "AMDGPUGenMCPseudoLowering.inc" 73*0b57cec5SDimitry Andric 74*0b57cec5SDimitry Andric AMDGPUMCInstLower::AMDGPUMCInstLower(MCContext &ctx, 75*0b57cec5SDimitry Andric const TargetSubtargetInfo &st, 76*0b57cec5SDimitry Andric const AsmPrinter &ap): 77*0b57cec5SDimitry Andric Ctx(ctx), ST(st), AP(ap) { } 78*0b57cec5SDimitry Andric 79*0b57cec5SDimitry Andric static MCSymbolRefExpr::VariantKind getVariantKind(unsigned MOFlags) { 80*0b57cec5SDimitry Andric switch (MOFlags) { 81*0b57cec5SDimitry Andric default: 82*0b57cec5SDimitry Andric return MCSymbolRefExpr::VK_None; 83*0b57cec5SDimitry Andric case SIInstrInfo::MO_GOTPCREL: 84*0b57cec5SDimitry Andric return MCSymbolRefExpr::VK_GOTPCREL; 85*0b57cec5SDimitry Andric case SIInstrInfo::MO_GOTPCREL32_LO: 86*0b57cec5SDimitry Andric return MCSymbolRefExpr::VK_AMDGPU_GOTPCREL32_LO; 87*0b57cec5SDimitry Andric case SIInstrInfo::MO_GOTPCREL32_HI: 88*0b57cec5SDimitry Andric return MCSymbolRefExpr::VK_AMDGPU_GOTPCREL32_HI; 89*0b57cec5SDimitry Andric case SIInstrInfo::MO_REL32_LO: 90*0b57cec5SDimitry Andric return MCSymbolRefExpr::VK_AMDGPU_REL32_LO; 91*0b57cec5SDimitry Andric case SIInstrInfo::MO_REL32_HI: 92*0b57cec5SDimitry Andric return MCSymbolRefExpr::VK_AMDGPU_REL32_HI; 93*0b57cec5SDimitry Andric case SIInstrInfo::MO_ABS32_LO: 94*0b57cec5SDimitry Andric return MCSymbolRefExpr::VK_AMDGPU_ABS32_LO; 95*0b57cec5SDimitry Andric case SIInstrInfo::MO_ABS32_HI: 96*0b57cec5SDimitry Andric return MCSymbolRefExpr::VK_AMDGPU_ABS32_HI; 97*0b57cec5SDimitry Andric } 98*0b57cec5SDimitry Andric } 99*0b57cec5SDimitry Andric 100*0b57cec5SDimitry Andric const MCExpr *AMDGPUMCInstLower::getLongBranchBlockExpr( 101*0b57cec5SDimitry Andric const MachineBasicBlock &SrcBB, 102*0b57cec5SDimitry Andric const MachineOperand &MO) const { 103*0b57cec5SDimitry Andric const MCExpr *DestBBSym 104*0b57cec5SDimitry Andric = MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx); 105*0b57cec5SDimitry Andric const MCExpr *SrcBBSym = MCSymbolRefExpr::create(SrcBB.getSymbol(), Ctx); 106*0b57cec5SDimitry Andric 107*0b57cec5SDimitry Andric // FIXME: The first half of this assert should be removed. This should 108*0b57cec5SDimitry Andric // probably be PC relative instead of using the source block symbol, and 109*0b57cec5SDimitry Andric // therefore the indirect branch expansion should use a bundle. 110*0b57cec5SDimitry Andric assert( 111*0b57cec5SDimitry Andric skipDebugInstructionsForward(SrcBB.begin(), SrcBB.end())->getOpcode() == 112*0b57cec5SDimitry Andric AMDGPU::S_GETPC_B64 && 113*0b57cec5SDimitry Andric ST.getInstrInfo()->get(AMDGPU::S_GETPC_B64).Size == 4); 114*0b57cec5SDimitry Andric 115*0b57cec5SDimitry Andric // s_getpc_b64 returns the address of next instruction. 116*0b57cec5SDimitry Andric const MCConstantExpr *One = MCConstantExpr::create(4, Ctx); 117*0b57cec5SDimitry Andric SrcBBSym = MCBinaryExpr::createAdd(SrcBBSym, One, Ctx); 118*0b57cec5SDimitry Andric 119*0b57cec5SDimitry Andric if (MO.getTargetFlags() == SIInstrInfo::MO_LONG_BRANCH_FORWARD) 120*0b57cec5SDimitry Andric return MCBinaryExpr::createSub(DestBBSym, SrcBBSym, Ctx); 121*0b57cec5SDimitry Andric 122*0b57cec5SDimitry Andric assert(MO.getTargetFlags() == SIInstrInfo::MO_LONG_BRANCH_BACKWARD); 123*0b57cec5SDimitry Andric return MCBinaryExpr::createSub(SrcBBSym, DestBBSym, Ctx); 124*0b57cec5SDimitry Andric } 125*0b57cec5SDimitry Andric 126*0b57cec5SDimitry Andric bool AMDGPUMCInstLower::lowerOperand(const MachineOperand &MO, 127*0b57cec5SDimitry Andric MCOperand &MCOp) const { 128*0b57cec5SDimitry Andric switch (MO.getType()) { 129*0b57cec5SDimitry Andric default: 130*0b57cec5SDimitry Andric llvm_unreachable("unknown operand type"); 131*0b57cec5SDimitry Andric case MachineOperand::MO_Immediate: 132*0b57cec5SDimitry Andric MCOp = MCOperand::createImm(MO.getImm()); 133*0b57cec5SDimitry Andric return true; 134*0b57cec5SDimitry Andric case MachineOperand::MO_Register: 135*0b57cec5SDimitry Andric MCOp = MCOperand::createReg(AMDGPU::getMCReg(MO.getReg(), ST)); 136*0b57cec5SDimitry Andric return true; 137*0b57cec5SDimitry Andric case MachineOperand::MO_MachineBasicBlock: { 138*0b57cec5SDimitry Andric if (MO.getTargetFlags() != 0) { 139*0b57cec5SDimitry Andric MCOp = MCOperand::createExpr( 140*0b57cec5SDimitry Andric getLongBranchBlockExpr(*MO.getParent()->getParent(), MO)); 141*0b57cec5SDimitry Andric } else { 142*0b57cec5SDimitry Andric MCOp = MCOperand::createExpr( 143*0b57cec5SDimitry Andric MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), Ctx)); 144*0b57cec5SDimitry Andric } 145*0b57cec5SDimitry Andric 146*0b57cec5SDimitry Andric return true; 147*0b57cec5SDimitry Andric } 148*0b57cec5SDimitry Andric case MachineOperand::MO_GlobalAddress: { 149*0b57cec5SDimitry Andric const GlobalValue *GV = MO.getGlobal(); 150*0b57cec5SDimitry Andric SmallString<128> SymbolName; 151*0b57cec5SDimitry Andric AP.getNameWithPrefix(SymbolName, GV); 152*0b57cec5SDimitry Andric MCSymbol *Sym = Ctx.getOrCreateSymbol(SymbolName); 153*0b57cec5SDimitry Andric const MCExpr *Expr = 154*0b57cec5SDimitry Andric MCSymbolRefExpr::create(Sym, getVariantKind(MO.getTargetFlags()),Ctx); 155*0b57cec5SDimitry Andric int64_t Offset = MO.getOffset(); 156*0b57cec5SDimitry Andric if (Offset != 0) { 157*0b57cec5SDimitry Andric Expr = MCBinaryExpr::createAdd(Expr, 158*0b57cec5SDimitry Andric MCConstantExpr::create(Offset, Ctx), Ctx); 159*0b57cec5SDimitry Andric } 160*0b57cec5SDimitry Andric MCOp = MCOperand::createExpr(Expr); 161*0b57cec5SDimitry Andric return true; 162*0b57cec5SDimitry Andric } 163*0b57cec5SDimitry Andric case MachineOperand::MO_ExternalSymbol: { 164*0b57cec5SDimitry Andric MCSymbol *Sym = Ctx.getOrCreateSymbol(StringRef(MO.getSymbolName())); 165*0b57cec5SDimitry Andric Sym->setExternal(true); 166*0b57cec5SDimitry Andric const MCSymbolRefExpr *Expr = MCSymbolRefExpr::create(Sym, Ctx); 167*0b57cec5SDimitry Andric MCOp = MCOperand::createExpr(Expr); 168*0b57cec5SDimitry Andric return true; 169*0b57cec5SDimitry Andric } 170*0b57cec5SDimitry Andric case MachineOperand::MO_RegisterMask: 171*0b57cec5SDimitry Andric // Regmasks are like implicit defs. 172*0b57cec5SDimitry Andric return false; 173*0b57cec5SDimitry Andric } 174*0b57cec5SDimitry Andric } 175*0b57cec5SDimitry Andric 176*0b57cec5SDimitry Andric void AMDGPUMCInstLower::lower(const MachineInstr *MI, MCInst &OutMI) const { 177*0b57cec5SDimitry Andric unsigned Opcode = MI->getOpcode(); 178*0b57cec5SDimitry Andric const auto *TII = static_cast<const SIInstrInfo*>(ST.getInstrInfo()); 179*0b57cec5SDimitry Andric 180*0b57cec5SDimitry Andric // FIXME: Should be able to handle this with emitPseudoExpansionLowering. We 181*0b57cec5SDimitry Andric // need to select it to the subtarget specific version, and there's no way to 182*0b57cec5SDimitry Andric // do that with a single pseudo source operation. 183*0b57cec5SDimitry Andric if (Opcode == AMDGPU::S_SETPC_B64_return) 184*0b57cec5SDimitry Andric Opcode = AMDGPU::S_SETPC_B64; 185*0b57cec5SDimitry Andric else if (Opcode == AMDGPU::SI_CALL) { 186*0b57cec5SDimitry Andric // SI_CALL is just S_SWAPPC_B64 with an additional operand to track the 187*0b57cec5SDimitry Andric // called function (which we need to remove here). 188*0b57cec5SDimitry Andric OutMI.setOpcode(TII->pseudoToMCOpcode(AMDGPU::S_SWAPPC_B64)); 189*0b57cec5SDimitry Andric MCOperand Dest, Src; 190*0b57cec5SDimitry Andric lowerOperand(MI->getOperand(0), Dest); 191*0b57cec5SDimitry Andric lowerOperand(MI->getOperand(1), Src); 192*0b57cec5SDimitry Andric OutMI.addOperand(Dest); 193*0b57cec5SDimitry Andric OutMI.addOperand(Src); 194*0b57cec5SDimitry Andric return; 195*0b57cec5SDimitry Andric } else if (Opcode == AMDGPU::SI_TCRETURN) { 196*0b57cec5SDimitry Andric // TODO: How to use branch immediate and avoid register+add? 197*0b57cec5SDimitry Andric Opcode = AMDGPU::S_SETPC_B64; 198*0b57cec5SDimitry Andric } 199*0b57cec5SDimitry Andric 200*0b57cec5SDimitry Andric int MCOpcode = TII->pseudoToMCOpcode(Opcode); 201*0b57cec5SDimitry Andric if (MCOpcode == -1) { 202*0b57cec5SDimitry Andric LLVMContext &C = MI->getParent()->getParent()->getFunction().getContext(); 203*0b57cec5SDimitry Andric C.emitError("AMDGPUMCInstLower::lower - Pseudo instruction doesn't have " 204*0b57cec5SDimitry Andric "a target-specific version: " + Twine(MI->getOpcode())); 205*0b57cec5SDimitry Andric } 206*0b57cec5SDimitry Andric 207*0b57cec5SDimitry Andric OutMI.setOpcode(MCOpcode); 208*0b57cec5SDimitry Andric 209*0b57cec5SDimitry Andric for (const MachineOperand &MO : MI->explicit_operands()) { 210*0b57cec5SDimitry Andric MCOperand MCOp; 211*0b57cec5SDimitry Andric lowerOperand(MO, MCOp); 212*0b57cec5SDimitry Andric OutMI.addOperand(MCOp); 213*0b57cec5SDimitry Andric } 214*0b57cec5SDimitry Andric } 215*0b57cec5SDimitry Andric 216*0b57cec5SDimitry Andric bool AMDGPUAsmPrinter::lowerOperand(const MachineOperand &MO, 217*0b57cec5SDimitry Andric MCOperand &MCOp) const { 218*0b57cec5SDimitry Andric const GCNSubtarget &STI = MF->getSubtarget<GCNSubtarget>(); 219*0b57cec5SDimitry Andric AMDGPUMCInstLower MCInstLowering(OutContext, STI, *this); 220*0b57cec5SDimitry Andric return MCInstLowering.lowerOperand(MO, MCOp); 221*0b57cec5SDimitry Andric } 222*0b57cec5SDimitry Andric 223*0b57cec5SDimitry Andric static const MCExpr *lowerAddrSpaceCast(const TargetMachine &TM, 224*0b57cec5SDimitry Andric const Constant *CV, 225*0b57cec5SDimitry Andric MCContext &OutContext) { 226*0b57cec5SDimitry Andric // TargetMachine does not support llvm-style cast. Use C++-style cast. 227*0b57cec5SDimitry Andric // This is safe since TM is always of type AMDGPUTargetMachine or its 228*0b57cec5SDimitry Andric // derived class. 229*0b57cec5SDimitry Andric auto &AT = static_cast<const AMDGPUTargetMachine&>(TM); 230*0b57cec5SDimitry Andric auto *CE = dyn_cast<ConstantExpr>(CV); 231*0b57cec5SDimitry Andric 232*0b57cec5SDimitry Andric // Lower null pointers in private and local address space. 233*0b57cec5SDimitry Andric // Clang generates addrspacecast for null pointers in private and local 234*0b57cec5SDimitry Andric // address space, which needs to be lowered. 235*0b57cec5SDimitry Andric if (CE && CE->getOpcode() == Instruction::AddrSpaceCast) { 236*0b57cec5SDimitry Andric auto Op = CE->getOperand(0); 237*0b57cec5SDimitry Andric auto SrcAddr = Op->getType()->getPointerAddressSpace(); 238*0b57cec5SDimitry Andric if (Op->isNullValue() && AT.getNullPointerValue(SrcAddr) == 0) { 239*0b57cec5SDimitry Andric auto DstAddr = CE->getType()->getPointerAddressSpace(); 240*0b57cec5SDimitry Andric return MCConstantExpr::create(AT.getNullPointerValue(DstAddr), 241*0b57cec5SDimitry Andric OutContext); 242*0b57cec5SDimitry Andric } 243*0b57cec5SDimitry Andric } 244*0b57cec5SDimitry Andric return nullptr; 245*0b57cec5SDimitry Andric } 246*0b57cec5SDimitry Andric 247*0b57cec5SDimitry Andric const MCExpr *AMDGPUAsmPrinter::lowerConstant(const Constant *CV) { 248*0b57cec5SDimitry Andric if (const MCExpr *E = lowerAddrSpaceCast(TM, CV, OutContext)) 249*0b57cec5SDimitry Andric return E; 250*0b57cec5SDimitry Andric return AsmPrinter::lowerConstant(CV); 251*0b57cec5SDimitry Andric } 252*0b57cec5SDimitry Andric 253*0b57cec5SDimitry Andric void AMDGPUAsmPrinter::EmitInstruction(const MachineInstr *MI) { 254*0b57cec5SDimitry Andric if (emitPseudoExpansionLowering(*OutStreamer, MI)) 255*0b57cec5SDimitry Andric return; 256*0b57cec5SDimitry Andric 257*0b57cec5SDimitry Andric const GCNSubtarget &STI = MF->getSubtarget<GCNSubtarget>(); 258*0b57cec5SDimitry Andric AMDGPUMCInstLower MCInstLowering(OutContext, STI, *this); 259*0b57cec5SDimitry Andric 260*0b57cec5SDimitry Andric StringRef Err; 261*0b57cec5SDimitry Andric if (!STI.getInstrInfo()->verifyInstruction(*MI, Err)) { 262*0b57cec5SDimitry Andric LLVMContext &C = MI->getParent()->getParent()->getFunction().getContext(); 263*0b57cec5SDimitry Andric C.emitError("Illegal instruction detected: " + Err); 264*0b57cec5SDimitry Andric MI->print(errs()); 265*0b57cec5SDimitry Andric } 266*0b57cec5SDimitry Andric 267*0b57cec5SDimitry Andric if (MI->isBundle()) { 268*0b57cec5SDimitry Andric const MachineBasicBlock *MBB = MI->getParent(); 269*0b57cec5SDimitry Andric MachineBasicBlock::const_instr_iterator I = ++MI->getIterator(); 270*0b57cec5SDimitry Andric while (I != MBB->instr_end() && I->isInsideBundle()) { 271*0b57cec5SDimitry Andric EmitInstruction(&*I); 272*0b57cec5SDimitry Andric ++I; 273*0b57cec5SDimitry Andric } 274*0b57cec5SDimitry Andric } else { 275*0b57cec5SDimitry Andric // We don't want SI_MASK_BRANCH/SI_RETURN_TO_EPILOG encoded. They are 276*0b57cec5SDimitry Andric // placeholder terminator instructions and should only be printed as 277*0b57cec5SDimitry Andric // comments. 278*0b57cec5SDimitry Andric if (MI->getOpcode() == AMDGPU::SI_MASK_BRANCH) { 279*0b57cec5SDimitry Andric if (isVerbose()) { 280*0b57cec5SDimitry Andric SmallVector<char, 16> BBStr; 281*0b57cec5SDimitry Andric raw_svector_ostream Str(BBStr); 282*0b57cec5SDimitry Andric 283*0b57cec5SDimitry Andric const MachineBasicBlock *MBB = MI->getOperand(0).getMBB(); 284*0b57cec5SDimitry Andric const MCSymbolRefExpr *Expr 285*0b57cec5SDimitry Andric = MCSymbolRefExpr::create(MBB->getSymbol(), OutContext); 286*0b57cec5SDimitry Andric Expr->print(Str, MAI); 287*0b57cec5SDimitry Andric OutStreamer->emitRawComment(Twine(" mask branch ") + BBStr); 288*0b57cec5SDimitry Andric } 289*0b57cec5SDimitry Andric 290*0b57cec5SDimitry Andric return; 291*0b57cec5SDimitry Andric } 292*0b57cec5SDimitry Andric 293*0b57cec5SDimitry Andric if (MI->getOpcode() == AMDGPU::SI_RETURN_TO_EPILOG) { 294*0b57cec5SDimitry Andric if (isVerbose()) 295*0b57cec5SDimitry Andric OutStreamer->emitRawComment(" return to shader part epilog"); 296*0b57cec5SDimitry Andric return; 297*0b57cec5SDimitry Andric } 298*0b57cec5SDimitry Andric 299*0b57cec5SDimitry Andric if (MI->getOpcode() == AMDGPU::WAVE_BARRIER) { 300*0b57cec5SDimitry Andric if (isVerbose()) 301*0b57cec5SDimitry Andric OutStreamer->emitRawComment(" wave barrier"); 302*0b57cec5SDimitry Andric return; 303*0b57cec5SDimitry Andric } 304*0b57cec5SDimitry Andric 305*0b57cec5SDimitry Andric if (MI->getOpcode() == AMDGPU::SI_MASKED_UNREACHABLE) { 306*0b57cec5SDimitry Andric if (isVerbose()) 307*0b57cec5SDimitry Andric OutStreamer->emitRawComment(" divergent unreachable"); 308*0b57cec5SDimitry Andric return; 309*0b57cec5SDimitry Andric } 310*0b57cec5SDimitry Andric 311*0b57cec5SDimitry Andric MCInst TmpInst; 312*0b57cec5SDimitry Andric MCInstLowering.lower(MI, TmpInst); 313*0b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, TmpInst); 314*0b57cec5SDimitry Andric 315*0b57cec5SDimitry Andric #ifdef EXPENSIVE_CHECKS 316*0b57cec5SDimitry Andric // Sanity-check getInstSizeInBytes on explicitly specified CPUs (it cannot 317*0b57cec5SDimitry Andric // work correctly for the generic CPU). 318*0b57cec5SDimitry Andric // 319*0b57cec5SDimitry Andric // The isPseudo check really shouldn't be here, but unfortunately there are 320*0b57cec5SDimitry Andric // some negative lit tests that depend on being able to continue through 321*0b57cec5SDimitry Andric // here even when pseudo instructions haven't been lowered. 322*0b57cec5SDimitry Andric if (!MI->isPseudo() && STI.isCPUStringValid(STI.getCPU())) { 323*0b57cec5SDimitry Andric SmallVector<MCFixup, 4> Fixups; 324*0b57cec5SDimitry Andric SmallVector<char, 16> CodeBytes; 325*0b57cec5SDimitry Andric raw_svector_ostream CodeStream(CodeBytes); 326*0b57cec5SDimitry Andric 327*0b57cec5SDimitry Andric std::unique_ptr<MCCodeEmitter> InstEmitter(createSIMCCodeEmitter( 328*0b57cec5SDimitry Andric *STI.getInstrInfo(), *OutContext.getRegisterInfo(), OutContext)); 329*0b57cec5SDimitry Andric InstEmitter->encodeInstruction(TmpInst, CodeStream, Fixups, STI); 330*0b57cec5SDimitry Andric 331*0b57cec5SDimitry Andric assert(CodeBytes.size() == STI.getInstrInfo()->getInstSizeInBytes(*MI)); 332*0b57cec5SDimitry Andric } 333*0b57cec5SDimitry Andric #endif 334*0b57cec5SDimitry Andric 335*0b57cec5SDimitry Andric if (DumpCodeInstEmitter) { 336*0b57cec5SDimitry Andric // Disassemble instruction/operands to text 337*0b57cec5SDimitry Andric DisasmLines.resize(DisasmLines.size() + 1); 338*0b57cec5SDimitry Andric std::string &DisasmLine = DisasmLines.back(); 339*0b57cec5SDimitry Andric raw_string_ostream DisasmStream(DisasmLine); 340*0b57cec5SDimitry Andric 341*0b57cec5SDimitry Andric AMDGPUInstPrinter InstPrinter(*TM.getMCAsmInfo(), *STI.getInstrInfo(), 342*0b57cec5SDimitry Andric *STI.getRegisterInfo()); 343*0b57cec5SDimitry Andric InstPrinter.printInst(&TmpInst, DisasmStream, StringRef(), STI); 344*0b57cec5SDimitry Andric 345*0b57cec5SDimitry Andric // Disassemble instruction/operands to hex representation. 346*0b57cec5SDimitry Andric SmallVector<MCFixup, 4> Fixups; 347*0b57cec5SDimitry Andric SmallVector<char, 16> CodeBytes; 348*0b57cec5SDimitry Andric raw_svector_ostream CodeStream(CodeBytes); 349*0b57cec5SDimitry Andric 350*0b57cec5SDimitry Andric DumpCodeInstEmitter->encodeInstruction( 351*0b57cec5SDimitry Andric TmpInst, CodeStream, Fixups, MF->getSubtarget<MCSubtargetInfo>()); 352*0b57cec5SDimitry Andric HexLines.resize(HexLines.size() + 1); 353*0b57cec5SDimitry Andric std::string &HexLine = HexLines.back(); 354*0b57cec5SDimitry Andric raw_string_ostream HexStream(HexLine); 355*0b57cec5SDimitry Andric 356*0b57cec5SDimitry Andric for (size_t i = 0; i < CodeBytes.size(); i += 4) { 357*0b57cec5SDimitry Andric unsigned int CodeDWord = *(unsigned int *)&CodeBytes[i]; 358*0b57cec5SDimitry Andric HexStream << format("%s%08X", (i > 0 ? " " : ""), CodeDWord); 359*0b57cec5SDimitry Andric } 360*0b57cec5SDimitry Andric 361*0b57cec5SDimitry Andric DisasmStream.flush(); 362*0b57cec5SDimitry Andric DisasmLineMaxLen = std::max(DisasmLineMaxLen, DisasmLine.size()); 363*0b57cec5SDimitry Andric } 364*0b57cec5SDimitry Andric } 365*0b57cec5SDimitry Andric } 366*0b57cec5SDimitry Andric 367*0b57cec5SDimitry Andric R600MCInstLower::R600MCInstLower(MCContext &Ctx, const R600Subtarget &ST, 368*0b57cec5SDimitry Andric const AsmPrinter &AP) : 369*0b57cec5SDimitry Andric AMDGPUMCInstLower(Ctx, ST, AP) { } 370*0b57cec5SDimitry Andric 371*0b57cec5SDimitry Andric void R600MCInstLower::lower(const MachineInstr *MI, MCInst &OutMI) const { 372*0b57cec5SDimitry Andric OutMI.setOpcode(MI->getOpcode()); 373*0b57cec5SDimitry Andric for (const MachineOperand &MO : MI->explicit_operands()) { 374*0b57cec5SDimitry Andric MCOperand MCOp; 375*0b57cec5SDimitry Andric lowerOperand(MO, MCOp); 376*0b57cec5SDimitry Andric OutMI.addOperand(MCOp); 377*0b57cec5SDimitry Andric } 378*0b57cec5SDimitry Andric } 379*0b57cec5SDimitry Andric 380*0b57cec5SDimitry Andric void R600AsmPrinter::EmitInstruction(const MachineInstr *MI) { 381*0b57cec5SDimitry Andric const R600Subtarget &STI = MF->getSubtarget<R600Subtarget>(); 382*0b57cec5SDimitry Andric R600MCInstLower MCInstLowering(OutContext, STI, *this); 383*0b57cec5SDimitry Andric 384*0b57cec5SDimitry Andric StringRef Err; 385*0b57cec5SDimitry Andric if (!STI.getInstrInfo()->verifyInstruction(*MI, Err)) { 386*0b57cec5SDimitry Andric LLVMContext &C = MI->getParent()->getParent()->getFunction().getContext(); 387*0b57cec5SDimitry Andric C.emitError("Illegal instruction detected: " + Err); 388*0b57cec5SDimitry Andric MI->print(errs()); 389*0b57cec5SDimitry Andric } 390*0b57cec5SDimitry Andric 391*0b57cec5SDimitry Andric if (MI->isBundle()) { 392*0b57cec5SDimitry Andric const MachineBasicBlock *MBB = MI->getParent(); 393*0b57cec5SDimitry Andric MachineBasicBlock::const_instr_iterator I = ++MI->getIterator(); 394*0b57cec5SDimitry Andric while (I != MBB->instr_end() && I->isInsideBundle()) { 395*0b57cec5SDimitry Andric EmitInstruction(&*I); 396*0b57cec5SDimitry Andric ++I; 397*0b57cec5SDimitry Andric } 398*0b57cec5SDimitry Andric } else { 399*0b57cec5SDimitry Andric MCInst TmpInst; 400*0b57cec5SDimitry Andric MCInstLowering.lower(MI, TmpInst); 401*0b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, TmpInst); 402*0b57cec5SDimitry Andric } 403*0b57cec5SDimitry Andric } 404*0b57cec5SDimitry Andric 405*0b57cec5SDimitry Andric const MCExpr *R600AsmPrinter::lowerConstant(const Constant *CV) { 406*0b57cec5SDimitry Andric if (const MCExpr *E = lowerAddrSpaceCast(TM, CV, OutContext)) 407*0b57cec5SDimitry Andric return E; 408*0b57cec5SDimitry Andric return AsmPrinter::lowerConstant(CV); 409*0b57cec5SDimitry Andric } 410