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 {
getTargetStreamer()410b57cec5SDimitry Andric SparcTargetStreamer &getTargetStreamer() {
420b57cec5SDimitry Andric return static_cast<SparcTargetStreamer &>(
430b57cec5SDimitry Andric *OutStreamer->getTargetStreamer());
440b57cec5SDimitry Andric }
450b57cec5SDimitry Andric public:
SparcAsmPrinter(TargetMachine & TM,std::unique_ptr<MCStreamer> Streamer)460b57cec5SDimitry Andric explicit SparcAsmPrinter(TargetMachine &TM,
470b57cec5SDimitry Andric std::unique_ptr<MCStreamer> Streamer)
480b57cec5SDimitry Andric : AsmPrinter(TM, std::move(Streamer)) {}
490b57cec5SDimitry Andric
getPassName() const500b57cec5SDimitry 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
getRegisterName(MCRegister Reg)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
createSparcMCOperand(SparcMCExpr::VariantKind Kind,MCSymbol * Sym,MCContext & OutContext)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 }
createPCXCallOP(MCSymbol * Label,MCContext & OutContext)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
createPCXRelExprOp(SparcMCExpr::VariantKind Kind,MCSymbol * GOTLabel,MCSymbol * StartLabel,MCSymbol * CurLabel,MCContext & OutContext)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
EmitCall(MCStreamer & OutStreamer,MCOperand & Callee,const MCSubtargetInfo & STI)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
EmitRDPC(MCStreamer & OutStreamer,MCOperand & RD,const MCSubtargetInfo & STI)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
EmitSETHI(MCStreamer & OutStreamer,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & STI)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
EmitBinary(MCStreamer & OutStreamer,unsigned Opcode,MCOperand & RS1,MCOperand & Src2,MCOperand & RD,const MCSubtargetInfo & STI)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
EmitOR(MCStreamer & OutStreamer,MCOperand & RS1,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & STI)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
EmitADD(MCStreamer & OutStreamer,MCOperand & RS1,MCOperand & RS2,MCOperand & RD,const MCSubtargetInfo & STI)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
EmitSHL(MCStreamer & OutStreamer,MCOperand & RS1,MCOperand & Imm,MCOperand & RD,const MCSubtargetInfo & STI)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
EmitHiLo(MCStreamer & OutStreamer,MCSymbol * GOTSym,SparcMCExpr::VariantKind HiKind,SparcMCExpr::VariantKind LoKind,MCOperand & RD,MCContext & OutContext,const MCSubtargetInfo & STI)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
LowerGETPCXAndEmitMCInsts(const MachineInstr * MI,const MCSubtargetInfo & STI)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
emitInstruction(const MachineInstr * MI)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
emitFunctionBodyStart()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
printOperand(const MachineInstr * MI,int opNum,raw_ostream & O)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
printMemOperand(const MachineInstr * MI,int opNum,raw_ostream & O,const char * Modifier)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 ///
PrintAsmOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & O)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
PrintAsmMemoryOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & O)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.
LLVMInitializeSparcAsmPrinter()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