10b57cec5SDimitry Andric //===-- SparcAsmPrinter.cpp - Sparc LLVM assembly writer ------------------===// 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 // This file contains a printer that converts from our internal representation 100b57cec5SDimitry Andric // of machine-dependent LLVM code to GAS-format SPARC assembly language. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "MCTargetDesc/SparcInstPrinter.h" 150b57cec5SDimitry Andric #include "MCTargetDesc/SparcMCExpr.h" 167a6dacacSDimitry Andric #include "MCTargetDesc/SparcMCTargetDesc.h" 170b57cec5SDimitry Andric #include "MCTargetDesc/SparcTargetStreamer.h" 180b57cec5SDimitry Andric #include "Sparc.h" 190b57cec5SDimitry Andric #include "SparcInstrInfo.h" 200b57cec5SDimitry Andric #include "SparcTargetMachine.h" 210b57cec5SDimitry Andric #include "TargetInfo/SparcTargetInfo.h" 220b57cec5SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h" 230b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 240b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfoImpls.h" 250b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 260b57cec5SDimitry Andric #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" 270b57cec5SDimitry Andric #include "llvm/IR/Mangler.h" 280b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h" 290b57cec5SDimitry Andric #include "llvm/MC/MCContext.h" 300b57cec5SDimitry Andric #include "llvm/MC/MCInst.h" 310b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h" 320b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h" 33349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h" 340b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 350b57cec5SDimitry Andric using namespace llvm; 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric #define DEBUG_TYPE "asm-printer" 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric namespace { 400b57cec5SDimitry Andric class SparcAsmPrinter : public AsmPrinter { 410b57cec5SDimitry Andric SparcTargetStreamer &getTargetStreamer() { 420b57cec5SDimitry Andric return static_cast<SparcTargetStreamer &>( 430b57cec5SDimitry Andric *OutStreamer->getTargetStreamer()); 440b57cec5SDimitry Andric } 450b57cec5SDimitry Andric public: 460b57cec5SDimitry Andric explicit SparcAsmPrinter(TargetMachine &TM, 470b57cec5SDimitry Andric std::unique_ptr<MCStreamer> Streamer) 480b57cec5SDimitry Andric : AsmPrinter(TM, std::move(Streamer)) {} 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric StringRef getPassName() const override { return "Sparc Assembly Printer"; } 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric void printOperand(const MachineInstr *MI, int opNum, raw_ostream &OS); 530b57cec5SDimitry Andric void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &OS, 540b57cec5SDimitry Andric const char *Modifier = nullptr); 550b57cec5SDimitry Andric 565ffd83dbSDimitry Andric void emitFunctionBodyStart() override; 575ffd83dbSDimitry Andric void emitInstruction(const MachineInstr *MI) override; 580b57cec5SDimitry Andric 59bdd1243dSDimitry Andric static const char *getRegisterName(MCRegister Reg) { 60bdd1243dSDimitry Andric return SparcInstPrinter::getRegisterName(Reg); 610b57cec5SDimitry Andric } 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 640b57cec5SDimitry Andric const char *ExtraCode, raw_ostream &O) override; 650b57cec5SDimitry Andric bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, 660b57cec5SDimitry Andric const char *ExtraCode, raw_ostream &O) override; 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI, 690b57cec5SDimitry Andric const MCSubtargetInfo &STI); 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric }; 720b57cec5SDimitry Andric } // end of anonymous namespace 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric static MCOperand createSparcMCOperand(SparcMCExpr::VariantKind Kind, 750b57cec5SDimitry Andric MCSymbol *Sym, MCContext &OutContext) { 760b57cec5SDimitry Andric const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::create(Sym, 770b57cec5SDimitry Andric OutContext); 780b57cec5SDimitry Andric const SparcMCExpr *expr = SparcMCExpr::create(Kind, MCSym, OutContext); 790b57cec5SDimitry Andric return MCOperand::createExpr(expr); 800b57cec5SDimitry Andric 810b57cec5SDimitry Andric } 820b57cec5SDimitry Andric static MCOperand createPCXCallOP(MCSymbol *Label, 830b57cec5SDimitry Andric MCContext &OutContext) { 84e8d8bef9SDimitry Andric return createSparcMCOperand(SparcMCExpr::VK_Sparc_WDISP30, Label, OutContext); 850b57cec5SDimitry Andric } 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric static MCOperand createPCXRelExprOp(SparcMCExpr::VariantKind Kind, 880b57cec5SDimitry Andric MCSymbol *GOTLabel, MCSymbol *StartLabel, 890b57cec5SDimitry Andric MCSymbol *CurLabel, 900b57cec5SDimitry Andric MCContext &OutContext) 910b57cec5SDimitry Andric { 920b57cec5SDimitry Andric const MCSymbolRefExpr *GOT = MCSymbolRefExpr::create(GOTLabel, OutContext); 930b57cec5SDimitry Andric const MCSymbolRefExpr *Start = MCSymbolRefExpr::create(StartLabel, 940b57cec5SDimitry Andric OutContext); 950b57cec5SDimitry Andric const MCSymbolRefExpr *Cur = MCSymbolRefExpr::create(CurLabel, 960b57cec5SDimitry Andric OutContext); 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric const MCBinaryExpr *Sub = MCBinaryExpr::createSub(Cur, Start, OutContext); 990b57cec5SDimitry Andric const MCBinaryExpr *Add = MCBinaryExpr::createAdd(GOT, Sub, OutContext); 1000b57cec5SDimitry Andric const SparcMCExpr *expr = SparcMCExpr::create(Kind, 1010b57cec5SDimitry Andric Add, OutContext); 1020b57cec5SDimitry Andric return MCOperand::createExpr(expr); 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric static void EmitCall(MCStreamer &OutStreamer, 1060b57cec5SDimitry Andric MCOperand &Callee, 1070b57cec5SDimitry Andric const MCSubtargetInfo &STI) 1080b57cec5SDimitry Andric { 1090b57cec5SDimitry Andric MCInst CallInst; 1100b57cec5SDimitry Andric CallInst.setOpcode(SP::CALL); 1110b57cec5SDimitry Andric CallInst.addOperand(Callee); 1125ffd83dbSDimitry Andric OutStreamer.emitInstruction(CallInst, STI); 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric 1157a6dacacSDimitry Andric static void EmitRDPC(MCStreamer &OutStreamer, MCOperand &RD, 1167a6dacacSDimitry Andric const MCSubtargetInfo &STI) { 1177a6dacacSDimitry Andric MCInst RDPCInst; 1187a6dacacSDimitry Andric RDPCInst.setOpcode(SP::RDASR); 1197a6dacacSDimitry Andric RDPCInst.addOperand(RD); 1207a6dacacSDimitry Andric RDPCInst.addOperand(MCOperand::createReg(SP::ASR5)); 1217a6dacacSDimitry Andric OutStreamer.emitInstruction(RDPCInst, STI); 1227a6dacacSDimitry Andric } 1237a6dacacSDimitry Andric 1240b57cec5SDimitry Andric static void EmitSETHI(MCStreamer &OutStreamer, 1250b57cec5SDimitry Andric MCOperand &Imm, MCOperand &RD, 1260b57cec5SDimitry Andric const MCSubtargetInfo &STI) 1270b57cec5SDimitry Andric { 1280b57cec5SDimitry Andric MCInst SETHIInst; 1290b57cec5SDimitry Andric SETHIInst.setOpcode(SP::SETHIi); 1300b57cec5SDimitry Andric SETHIInst.addOperand(RD); 1310b57cec5SDimitry Andric SETHIInst.addOperand(Imm); 1325ffd83dbSDimitry Andric OutStreamer.emitInstruction(SETHIInst, STI); 1330b57cec5SDimitry Andric } 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric static void EmitBinary(MCStreamer &OutStreamer, unsigned Opcode, 1360b57cec5SDimitry Andric MCOperand &RS1, MCOperand &Src2, MCOperand &RD, 1370b57cec5SDimitry Andric const MCSubtargetInfo &STI) 1380b57cec5SDimitry Andric { 1390b57cec5SDimitry Andric MCInst Inst; 1400b57cec5SDimitry Andric Inst.setOpcode(Opcode); 1410b57cec5SDimitry Andric Inst.addOperand(RD); 1420b57cec5SDimitry Andric Inst.addOperand(RS1); 1430b57cec5SDimitry Andric Inst.addOperand(Src2); 1445ffd83dbSDimitry Andric OutStreamer.emitInstruction(Inst, STI); 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric static void EmitOR(MCStreamer &OutStreamer, 1480b57cec5SDimitry Andric MCOperand &RS1, MCOperand &Imm, MCOperand &RD, 1490b57cec5SDimitry Andric const MCSubtargetInfo &STI) { 1500b57cec5SDimitry Andric EmitBinary(OutStreamer, SP::ORri, RS1, Imm, RD, STI); 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric static void EmitADD(MCStreamer &OutStreamer, 1540b57cec5SDimitry Andric MCOperand &RS1, MCOperand &RS2, MCOperand &RD, 1550b57cec5SDimitry Andric const MCSubtargetInfo &STI) { 1560b57cec5SDimitry Andric EmitBinary(OutStreamer, SP::ADDrr, RS1, RS2, RD, STI); 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric static void EmitSHL(MCStreamer &OutStreamer, 1600b57cec5SDimitry Andric MCOperand &RS1, MCOperand &Imm, MCOperand &RD, 1610b57cec5SDimitry Andric const MCSubtargetInfo &STI) { 1620b57cec5SDimitry Andric EmitBinary(OutStreamer, SP::SLLri, RS1, Imm, RD, STI); 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric 1660b57cec5SDimitry Andric static void EmitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym, 1670b57cec5SDimitry Andric SparcMCExpr::VariantKind HiKind, 1680b57cec5SDimitry Andric SparcMCExpr::VariantKind LoKind, 1690b57cec5SDimitry Andric MCOperand &RD, 1700b57cec5SDimitry Andric MCContext &OutContext, 1710b57cec5SDimitry Andric const MCSubtargetInfo &STI) { 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric MCOperand hi = createSparcMCOperand(HiKind, GOTSym, OutContext); 1740b57cec5SDimitry Andric MCOperand lo = createSparcMCOperand(LoKind, GOTSym, OutContext); 1750b57cec5SDimitry Andric EmitSETHI(OutStreamer, hi, RD, STI); 1760b57cec5SDimitry Andric EmitOR(OutStreamer, RD, lo, RD, STI); 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr *MI, 1800b57cec5SDimitry Andric const MCSubtargetInfo &STI) 1810b57cec5SDimitry Andric { 1820b57cec5SDimitry Andric MCSymbol *GOTLabel = 1830b57cec5SDimitry Andric OutContext.getOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_")); 1840b57cec5SDimitry Andric 1850b57cec5SDimitry Andric const MachineOperand &MO = MI->getOperand(0); 1860b57cec5SDimitry Andric assert(MO.getReg() != SP::O7 && 1870b57cec5SDimitry Andric "%o7 is assigned as destination for getpcx!"); 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric MCOperand MCRegOP = MCOperand::createReg(MO.getReg()); 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric if (!isPositionIndependent()) { 1930b57cec5SDimitry Andric // Just load the address of GOT to MCRegOP. 1940b57cec5SDimitry Andric switch(TM.getCodeModel()) { 1950b57cec5SDimitry Andric default: 1960b57cec5SDimitry Andric llvm_unreachable("Unsupported absolute code model"); 1970b57cec5SDimitry Andric case CodeModel::Small: 1980b57cec5SDimitry Andric EmitHiLo(*OutStreamer, GOTLabel, 1990b57cec5SDimitry Andric SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO, 2000b57cec5SDimitry Andric MCRegOP, OutContext, STI); 2010b57cec5SDimitry Andric break; 2020b57cec5SDimitry Andric case CodeModel::Medium: { 2030b57cec5SDimitry Andric EmitHiLo(*OutStreamer, GOTLabel, 2040b57cec5SDimitry Andric SparcMCExpr::VK_Sparc_H44, SparcMCExpr::VK_Sparc_M44, 2050b57cec5SDimitry Andric MCRegOP, OutContext, STI); 2060b57cec5SDimitry Andric MCOperand imm = MCOperand::createExpr(MCConstantExpr::create(12, 2070b57cec5SDimitry Andric OutContext)); 2080b57cec5SDimitry Andric EmitSHL(*OutStreamer, MCRegOP, imm, MCRegOP, STI); 2090b57cec5SDimitry Andric MCOperand lo = createSparcMCOperand(SparcMCExpr::VK_Sparc_L44, 2100b57cec5SDimitry Andric GOTLabel, OutContext); 2110b57cec5SDimitry Andric EmitOR(*OutStreamer, MCRegOP, lo, MCRegOP, STI); 2120b57cec5SDimitry Andric break; 2130b57cec5SDimitry Andric } 2140b57cec5SDimitry Andric case CodeModel::Large: { 2150b57cec5SDimitry Andric EmitHiLo(*OutStreamer, GOTLabel, 2160b57cec5SDimitry Andric SparcMCExpr::VK_Sparc_HH, SparcMCExpr::VK_Sparc_HM, 2170b57cec5SDimitry Andric MCRegOP, OutContext, STI); 2180b57cec5SDimitry Andric MCOperand imm = MCOperand::createExpr(MCConstantExpr::create(32, 2190b57cec5SDimitry Andric OutContext)); 2200b57cec5SDimitry Andric EmitSHL(*OutStreamer, MCRegOP, imm, MCRegOP, STI); 2210b57cec5SDimitry Andric // Use register %o7 to load the lower 32 bits. 2220b57cec5SDimitry Andric MCOperand RegO7 = MCOperand::createReg(SP::O7); 2230b57cec5SDimitry Andric EmitHiLo(*OutStreamer, GOTLabel, 2240b57cec5SDimitry Andric SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO, 2250b57cec5SDimitry Andric RegO7, OutContext, STI); 2260b57cec5SDimitry Andric EmitADD(*OutStreamer, MCRegOP, RegO7, MCRegOP, STI); 2270b57cec5SDimitry Andric } 2280b57cec5SDimitry Andric } 2290b57cec5SDimitry Andric return; 2300b57cec5SDimitry Andric } 2310b57cec5SDimitry Andric 2320b57cec5SDimitry Andric MCSymbol *StartLabel = OutContext.createTempSymbol(); 2330b57cec5SDimitry Andric MCSymbol *EndLabel = OutContext.createTempSymbol(); 2340b57cec5SDimitry Andric MCSymbol *SethiLabel = OutContext.createTempSymbol(); 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric MCOperand RegO7 = MCOperand::createReg(SP::O7); 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric // <StartLabel>: 2397a6dacacSDimitry Andric // <GET-PC> // This will be either `call <EndLabel>` or `rd %pc, %o7`. 2400b57cec5SDimitry Andric // <SethiLabel>: 2410b57cec5SDimitry Andric // sethi %hi(_GLOBAL_OFFSET_TABLE_+(<SethiLabel>-<StartLabel>)), <MO> 2420b57cec5SDimitry Andric // <EndLabel>: 2430b57cec5SDimitry Andric // or <MO>, %lo(_GLOBAL_OFFSET_TABLE_+(<EndLabel>-<StartLabel>))), <MO> 2440b57cec5SDimitry Andric // add <MO>, %o7, <MO> 2450b57cec5SDimitry Andric 2465ffd83dbSDimitry Andric OutStreamer->emitLabel(StartLabel); 2477a6dacacSDimitry Andric if (!STI.getTargetTriple().isSPARC64() || 2487a6dacacSDimitry Andric STI.hasFeature(Sparc::TuneSlowRDPC)) { 2490b57cec5SDimitry Andric MCOperand Callee = createPCXCallOP(EndLabel, OutContext); 2500b57cec5SDimitry Andric EmitCall(*OutStreamer, Callee, STI); 2517a6dacacSDimitry Andric } else { 2527a6dacacSDimitry Andric // TODO find out whether it is possible to store PC 2537a6dacacSDimitry Andric // in other registers, to enable leaf function optimization. 2547a6dacacSDimitry Andric // (On the other hand, approx. over 97.8% of GETPCXes happen 2557a6dacacSDimitry Andric // in non-leaf functions, so would this be worth the effort?) 2567a6dacacSDimitry Andric EmitRDPC(*OutStreamer, RegO7, STI); 2577a6dacacSDimitry Andric } 2585ffd83dbSDimitry Andric OutStreamer->emitLabel(SethiLabel); 2590b57cec5SDimitry Andric MCOperand hiImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC22, 2600b57cec5SDimitry Andric GOTLabel, StartLabel, SethiLabel, 2610b57cec5SDimitry Andric OutContext); 2620b57cec5SDimitry Andric EmitSETHI(*OutStreamer, hiImm, MCRegOP, STI); 2635ffd83dbSDimitry Andric OutStreamer->emitLabel(EndLabel); 2640b57cec5SDimitry Andric MCOperand loImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC10, 2650b57cec5SDimitry Andric GOTLabel, StartLabel, EndLabel, 2660b57cec5SDimitry Andric OutContext); 2670b57cec5SDimitry Andric EmitOR(*OutStreamer, MCRegOP, loImm, MCRegOP, STI); 2680b57cec5SDimitry Andric EmitADD(*OutStreamer, MCRegOP, RegO7, MCRegOP, STI); 2690b57cec5SDimitry Andric } 2700b57cec5SDimitry Andric 2715ffd83dbSDimitry Andric void SparcAsmPrinter::emitInstruction(const MachineInstr *MI) { 272753f127fSDimitry Andric Sparc_MC::verifyInstructionPredicates(MI->getOpcode(), 273753f127fSDimitry Andric getSubtargetInfo().getFeatureBits()); 2740b57cec5SDimitry Andric 2750b57cec5SDimitry Andric switch (MI->getOpcode()) { 2760b57cec5SDimitry Andric default: break; 2770b57cec5SDimitry Andric case TargetOpcode::DBG_VALUE: 2780b57cec5SDimitry Andric // FIXME: Debug Value. 2790b57cec5SDimitry Andric return; 2800b57cec5SDimitry Andric case SP::GETPCX: 2810b57cec5SDimitry Andric LowerGETPCXAndEmitMCInsts(MI, getSubtargetInfo()); 2820b57cec5SDimitry Andric return; 2830b57cec5SDimitry Andric } 2840b57cec5SDimitry Andric MachineBasicBlock::const_instr_iterator I = MI->getIterator(); 2850b57cec5SDimitry Andric MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end(); 2860b57cec5SDimitry Andric do { 2870b57cec5SDimitry Andric MCInst TmpInst; 2880b57cec5SDimitry Andric LowerSparcMachineInstrToMCInst(&*I, TmpInst, *this); 2890b57cec5SDimitry Andric EmitToStreamer(*OutStreamer, TmpInst); 2900b57cec5SDimitry Andric } while ((++I != E) && I->isInsideBundle()); // Delay slot check. 2910b57cec5SDimitry Andric } 2920b57cec5SDimitry Andric 2935ffd83dbSDimitry Andric void SparcAsmPrinter::emitFunctionBodyStart() { 2940b57cec5SDimitry Andric if (!MF->getSubtarget<SparcSubtarget>().is64Bit()) 2950b57cec5SDimitry Andric return; 2960b57cec5SDimitry Andric 2970b57cec5SDimitry Andric const MachineRegisterInfo &MRI = MF->getRegInfo(); 2980b57cec5SDimitry Andric const unsigned globalRegs[] = { SP::G2, SP::G3, SP::G6, SP::G7, 0 }; 2990b57cec5SDimitry Andric for (unsigned i = 0; globalRegs[i] != 0; ++i) { 3000b57cec5SDimitry Andric unsigned reg = globalRegs[i]; 3010b57cec5SDimitry Andric if (MRI.use_empty(reg)) 3020b57cec5SDimitry Andric continue; 3030b57cec5SDimitry Andric 3040b57cec5SDimitry Andric if (reg == SP::G6 || reg == SP::G7) 3050b57cec5SDimitry Andric getTargetStreamer().emitSparcRegisterIgnore(reg); 3060b57cec5SDimitry Andric else 3070b57cec5SDimitry Andric getTargetStreamer().emitSparcRegisterScratch(reg); 3080b57cec5SDimitry Andric } 3090b57cec5SDimitry Andric } 3100b57cec5SDimitry Andric 3110b57cec5SDimitry Andric void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum, 3120b57cec5SDimitry Andric raw_ostream &O) { 3130b57cec5SDimitry Andric const DataLayout &DL = getDataLayout(); 3140b57cec5SDimitry Andric const MachineOperand &MO = MI->getOperand (opNum); 3150b57cec5SDimitry Andric SparcMCExpr::VariantKind TF = (SparcMCExpr::VariantKind) MO.getTargetFlags(); 3160b57cec5SDimitry Andric 3170b57cec5SDimitry Andric bool CloseParen = SparcMCExpr::printVariantKind(O, TF); 3180b57cec5SDimitry Andric 3190b57cec5SDimitry Andric switch (MO.getType()) { 3200b57cec5SDimitry Andric case MachineOperand::MO_Register: 3210b57cec5SDimitry Andric O << "%" << StringRef(getRegisterName(MO.getReg())).lower(); 3220b57cec5SDimitry Andric break; 3230b57cec5SDimitry Andric 3240b57cec5SDimitry Andric case MachineOperand::MO_Immediate: 325eaeb601bSDimitry Andric O << MO.getImm(); 3260b57cec5SDimitry Andric break; 3270b57cec5SDimitry Andric case MachineOperand::MO_MachineBasicBlock: 3280b57cec5SDimitry Andric MO.getMBB()->getSymbol()->print(O, MAI); 3290b57cec5SDimitry Andric return; 3300b57cec5SDimitry Andric case MachineOperand::MO_GlobalAddress: 3310b57cec5SDimitry Andric PrintSymbolOperand(MO, O); 3320b57cec5SDimitry Andric break; 3330b57cec5SDimitry Andric case MachineOperand::MO_BlockAddress: 3340b57cec5SDimitry Andric O << GetBlockAddressSymbol(MO.getBlockAddress())->getName(); 3350b57cec5SDimitry Andric break; 3360b57cec5SDimitry Andric case MachineOperand::MO_ExternalSymbol: 3370b57cec5SDimitry Andric O << MO.getSymbolName(); 3380b57cec5SDimitry Andric break; 3390b57cec5SDimitry Andric case MachineOperand::MO_ConstantPoolIndex: 3400b57cec5SDimitry Andric O << DL.getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_" 3410b57cec5SDimitry Andric << MO.getIndex(); 3420b57cec5SDimitry Andric break; 3430b57cec5SDimitry Andric case MachineOperand::MO_Metadata: 3440b57cec5SDimitry Andric MO.getMetadata()->printAsOperand(O, MMI->getModule()); 3450b57cec5SDimitry Andric break; 3460b57cec5SDimitry Andric default: 3470b57cec5SDimitry Andric llvm_unreachable("<unknown operand type>"); 3480b57cec5SDimitry Andric } 3490b57cec5SDimitry Andric if (CloseParen) O << ")"; 3500b57cec5SDimitry Andric } 3510b57cec5SDimitry Andric 3520b57cec5SDimitry Andric void SparcAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum, 3530b57cec5SDimitry Andric raw_ostream &O, const char *Modifier) { 3540b57cec5SDimitry Andric printOperand(MI, opNum, O); 3550b57cec5SDimitry Andric 3560b57cec5SDimitry Andric // If this is an ADD operand, emit it like normal operands. 3570b57cec5SDimitry Andric if (Modifier && !strcmp(Modifier, "arith")) { 3580b57cec5SDimitry Andric O << ", "; 3590b57cec5SDimitry Andric printOperand(MI, opNum+1, O); 3600b57cec5SDimitry Andric return; 3610b57cec5SDimitry Andric } 3620b57cec5SDimitry Andric 3630b57cec5SDimitry Andric if (MI->getOperand(opNum+1).isReg() && 3640b57cec5SDimitry Andric MI->getOperand(opNum+1).getReg() == SP::G0) 3650b57cec5SDimitry Andric return; // don't print "+%g0" 3660b57cec5SDimitry Andric if (MI->getOperand(opNum+1).isImm() && 3670b57cec5SDimitry Andric MI->getOperand(opNum+1).getImm() == 0) 3680b57cec5SDimitry Andric return; // don't print "+0" 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric O << "+"; 3710b57cec5SDimitry Andric printOperand(MI, opNum+1, O); 3720b57cec5SDimitry Andric } 3730b57cec5SDimitry Andric 3740b57cec5SDimitry Andric /// PrintAsmOperand - Print out an operand for an inline asm expression. 3750b57cec5SDimitry Andric /// 3760b57cec5SDimitry Andric bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, 3770b57cec5SDimitry Andric const char *ExtraCode, 3780b57cec5SDimitry Andric raw_ostream &O) { 3790b57cec5SDimitry Andric if (ExtraCode && ExtraCode[0]) { 3800b57cec5SDimitry Andric if (ExtraCode[1] != 0) return true; // Unknown modifier. 3810b57cec5SDimitry Andric 3820b57cec5SDimitry Andric switch (ExtraCode[0]) { 3830b57cec5SDimitry Andric default: 3840b57cec5SDimitry Andric // See if this is a generic print operand 3850b57cec5SDimitry Andric return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O); 386*dfa39133SDimitry Andric case 'L': // Low order register of a twin word register operand 387*dfa39133SDimitry Andric case 'H': // High order register of a twin word register operand 388*dfa39133SDimitry Andric { 389*dfa39133SDimitry Andric const SparcSubtarget &Subtarget = MF->getSubtarget<SparcSubtarget>(); 390*dfa39133SDimitry Andric const MachineOperand &MO = MI->getOperand(OpNo); 391*dfa39133SDimitry Andric const SparcRegisterInfo *RegisterInfo = Subtarget.getRegisterInfo(); 392*dfa39133SDimitry Andric Register MOReg = MO.getReg(); 393*dfa39133SDimitry Andric 394*dfa39133SDimitry Andric Register HiReg, LoReg; 395*dfa39133SDimitry Andric if (!SP::IntPairRegClass.contains(MOReg)) { 396*dfa39133SDimitry Andric // If we aren't given a register pair already, find out which pair it 397*dfa39133SDimitry Andric // belongs to. Note that here, the specified register operand, which 398*dfa39133SDimitry Andric // refers to the high part of the twinword, needs to be an even-numbered 399*dfa39133SDimitry Andric // register. 400*dfa39133SDimitry Andric MOReg = RegisterInfo->getMatchingSuperReg(MOReg, SP::sub_even, 401*dfa39133SDimitry Andric &SP::IntPairRegClass); 402*dfa39133SDimitry Andric if (!MOReg) { 403*dfa39133SDimitry Andric SMLoc Loc; 404*dfa39133SDimitry Andric OutContext.reportError( 405*dfa39133SDimitry Andric Loc, "Hi part of pair should point to an even-numbered register"); 406*dfa39133SDimitry Andric OutContext.reportError( 407*dfa39133SDimitry Andric Loc, "(note that in some cases it might be necessary to manually " 408*dfa39133SDimitry Andric "bind the input/output registers instead of relying on " 409*dfa39133SDimitry Andric "automatic allocation)"); 410*dfa39133SDimitry Andric return true; 411*dfa39133SDimitry Andric } 412*dfa39133SDimitry Andric } 413*dfa39133SDimitry Andric 414*dfa39133SDimitry Andric HiReg = RegisterInfo->getSubReg(MOReg, SP::sub_even); 415*dfa39133SDimitry Andric LoReg = RegisterInfo->getSubReg(MOReg, SP::sub_odd); 416*dfa39133SDimitry Andric 417*dfa39133SDimitry Andric Register Reg; 418*dfa39133SDimitry Andric switch (ExtraCode[0]) { 419*dfa39133SDimitry Andric case 'L': 420*dfa39133SDimitry Andric Reg = LoReg; 421*dfa39133SDimitry Andric break; 422*dfa39133SDimitry Andric case 'H': 423*dfa39133SDimitry Andric Reg = HiReg; 424*dfa39133SDimitry Andric break; 425*dfa39133SDimitry Andric } 426*dfa39133SDimitry Andric 427*dfa39133SDimitry Andric O << '%' << SparcInstPrinter::getRegisterName(Reg); 428*dfa39133SDimitry Andric return false; 429*dfa39133SDimitry Andric } 4300b57cec5SDimitry Andric case 'f': 4310b57cec5SDimitry Andric case 'r': 4320b57cec5SDimitry Andric break; 4330b57cec5SDimitry Andric } 4340b57cec5SDimitry Andric } 4350b57cec5SDimitry Andric 4360b57cec5SDimitry Andric printOperand(MI, OpNo, O); 4370b57cec5SDimitry Andric 4380b57cec5SDimitry Andric return false; 4390b57cec5SDimitry Andric } 4400b57cec5SDimitry Andric 4410b57cec5SDimitry Andric bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 4420b57cec5SDimitry Andric unsigned OpNo, 4430b57cec5SDimitry Andric const char *ExtraCode, 4440b57cec5SDimitry Andric raw_ostream &O) { 4450b57cec5SDimitry Andric if (ExtraCode && ExtraCode[0]) 4460b57cec5SDimitry Andric return true; // Unknown modifier 4470b57cec5SDimitry Andric 4480b57cec5SDimitry Andric O << '['; 4490b57cec5SDimitry Andric printMemOperand(MI, OpNo, O); 4500b57cec5SDimitry Andric O << ']'; 4510b57cec5SDimitry Andric 4520b57cec5SDimitry Andric return false; 4530b57cec5SDimitry Andric } 4540b57cec5SDimitry Andric 4550b57cec5SDimitry Andric // Force static initialization. 456480093f4SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSparcAsmPrinter() { 4570b57cec5SDimitry Andric RegisterAsmPrinter<SparcAsmPrinter> X(getTheSparcTarget()); 4580b57cec5SDimitry Andric RegisterAsmPrinter<SparcAsmPrinter> Y(getTheSparcV9Target()); 4590b57cec5SDimitry Andric RegisterAsmPrinter<SparcAsmPrinter> Z(getTheSparcelTarget()); 4600b57cec5SDimitry Andric } 461