Path: blob/main/contrib/llvm-project/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp
35294 views
//===-- SparcAsmPrinter.cpp - Sparc LLVM assembly writer ------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file contains a printer that converts from our internal representation9// of machine-dependent LLVM code to GAS-format SPARC assembly language.10//11//===----------------------------------------------------------------------===//1213#include "MCTargetDesc/SparcInstPrinter.h"14#include "MCTargetDesc/SparcMCExpr.h"15#include "MCTargetDesc/SparcMCTargetDesc.h"16#include "MCTargetDesc/SparcTargetStreamer.h"17#include "Sparc.h"18#include "SparcInstrInfo.h"19#include "SparcTargetMachine.h"20#include "TargetInfo/SparcTargetInfo.h"21#include "llvm/CodeGen/AsmPrinter.h"22#include "llvm/CodeGen/MachineInstr.h"23#include "llvm/CodeGen/MachineModuleInfoImpls.h"24#include "llvm/CodeGen/MachineRegisterInfo.h"25#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"26#include "llvm/IR/Mangler.h"27#include "llvm/MC/MCAsmInfo.h"28#include "llvm/MC/MCContext.h"29#include "llvm/MC/MCInst.h"30#include "llvm/MC/MCStreamer.h"31#include "llvm/MC/MCSymbol.h"32#include "llvm/MC/TargetRegistry.h"33#include "llvm/Support/raw_ostream.h"34using namespace llvm;3536#define DEBUG_TYPE "asm-printer"3738namespace {39class SparcAsmPrinter : public AsmPrinter {40SparcTargetStreamer &getTargetStreamer() {41return static_cast<SparcTargetStreamer &>(42*OutStreamer->getTargetStreamer());43}44public:45explicit SparcAsmPrinter(TargetMachine &TM,46std::unique_ptr<MCStreamer> Streamer)47: AsmPrinter(TM, std::move(Streamer)) {}4849StringRef getPassName() const override { return "Sparc Assembly Printer"; }5051void printOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);52void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &OS,53const char *Modifier = nullptr);5455void emitFunctionBodyStart() override;56void emitInstruction(const MachineInstr *MI) override;5758static const char *getRegisterName(MCRegister Reg) {59return SparcInstPrinter::getRegisterName(Reg);60}6162bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,63const char *ExtraCode, raw_ostream &O) override;64bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,65const char *ExtraCode, raw_ostream &O) override;6667void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI,68const MCSubtargetInfo &STI);6970};71} // end of anonymous namespace7273static MCOperand createSparcMCOperand(SparcMCExpr::VariantKind Kind,74MCSymbol *Sym, MCContext &OutContext) {75const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::create(Sym,76OutContext);77const SparcMCExpr *expr = SparcMCExpr::create(Kind, MCSym, OutContext);78return MCOperand::createExpr(expr);7980}81static MCOperand createPCXCallOP(MCSymbol *Label,82MCContext &OutContext) {83return createSparcMCOperand(SparcMCExpr::VK_Sparc_WDISP30, Label, OutContext);84}8586static MCOperand createPCXRelExprOp(SparcMCExpr::VariantKind Kind,87MCSymbol *GOTLabel, MCSymbol *StartLabel,88MCSymbol *CurLabel,89MCContext &OutContext)90{91const MCSymbolRefExpr *GOT = MCSymbolRefExpr::create(GOTLabel, OutContext);92const MCSymbolRefExpr *Start = MCSymbolRefExpr::create(StartLabel,93OutContext);94const MCSymbolRefExpr *Cur = MCSymbolRefExpr::create(CurLabel,95OutContext);9697const MCBinaryExpr *Sub = MCBinaryExpr::createSub(Cur, Start, OutContext);98const MCBinaryExpr *Add = MCBinaryExpr::createAdd(GOT, Sub, OutContext);99const SparcMCExpr *expr = SparcMCExpr::create(Kind,100Add, OutContext);101return MCOperand::createExpr(expr);102}103104static void EmitCall(MCStreamer &OutStreamer,105MCOperand &Callee,106const MCSubtargetInfo &STI)107{108MCInst CallInst;109CallInst.setOpcode(SP::CALL);110CallInst.addOperand(Callee);111OutStreamer.emitInstruction(CallInst, STI);112}113114static void EmitRDPC(MCStreamer &OutStreamer, MCOperand &RD,115const MCSubtargetInfo &STI) {116MCInst RDPCInst;117RDPCInst.setOpcode(SP::RDASR);118RDPCInst.addOperand(RD);119RDPCInst.addOperand(MCOperand::createReg(SP::ASR5));120OutStreamer.emitInstruction(RDPCInst, STI);121}122123static void EmitSETHI(MCStreamer &OutStreamer,124MCOperand &Imm, MCOperand &RD,125const MCSubtargetInfo &STI)126{127MCInst SETHIInst;128SETHIInst.setOpcode(SP::SETHIi);129SETHIInst.addOperand(RD);130SETHIInst.addOperand(Imm);131OutStreamer.emitInstruction(SETHIInst, STI);132}133134static void EmitBinary(MCStreamer &OutStreamer, unsigned Opcode,135MCOperand &RS1, MCOperand &Src2, MCOperand &RD,136const MCSubtargetInfo &STI)137{138MCInst Inst;139Inst.setOpcode(Opcode);140Inst.addOperand(RD);141Inst.addOperand(RS1);142Inst.addOperand(Src2);143OutStreamer.emitInstruction(Inst, STI);144}145146static void EmitOR(MCStreamer &OutStreamer,147MCOperand &RS1, MCOperand &Imm, MCOperand &RD,148const MCSubtargetInfo &STI) {149EmitBinary(OutStreamer, SP::ORri, RS1, Imm, RD, STI);150}151152static void EmitADD(MCStreamer &OutStreamer,153MCOperand &RS1, MCOperand &RS2, MCOperand &RD,154const MCSubtargetInfo &STI) {155EmitBinary(OutStreamer, SP::ADDrr, RS1, RS2, RD, STI);156}157158static void EmitSHL(MCStreamer &OutStreamer,159MCOperand &RS1, MCOperand &Imm, MCOperand &RD,160const MCSubtargetInfo &STI) {161EmitBinary(OutStreamer, SP::SLLri, RS1, Imm, RD, STI);162}163164165static void EmitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym,166SparcMCExpr::VariantKind HiKind,167SparcMCExpr::VariantKind LoKind,168MCOperand &RD,169MCContext &OutContext,170const MCSubtargetInfo &STI) {171172MCOperand hi = createSparcMCOperand(HiKind, GOTSym, OutContext);173MCOperand lo = createSparcMCOperand(LoKind, GOTSym, OutContext);174EmitSETHI(OutStreamer, hi, RD, STI);175EmitOR(OutStreamer, RD, lo, RD, STI);176}177178void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr *MI,179const MCSubtargetInfo &STI)180{181MCSymbol *GOTLabel =182OutContext.getOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));183184const MachineOperand &MO = MI->getOperand(0);185assert(MO.getReg() != SP::O7 &&186"%o7 is assigned as destination for getpcx!");187188MCOperand MCRegOP = MCOperand::createReg(MO.getReg());189190191if (!isPositionIndependent()) {192// Just load the address of GOT to MCRegOP.193switch(TM.getCodeModel()) {194default:195llvm_unreachable("Unsupported absolute code model");196case CodeModel::Small:197EmitHiLo(*OutStreamer, GOTLabel,198SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO,199MCRegOP, OutContext, STI);200break;201case CodeModel::Medium: {202EmitHiLo(*OutStreamer, GOTLabel,203SparcMCExpr::VK_Sparc_H44, SparcMCExpr::VK_Sparc_M44,204MCRegOP, OutContext, STI);205MCOperand imm = MCOperand::createExpr(MCConstantExpr::create(12,206OutContext));207EmitSHL(*OutStreamer, MCRegOP, imm, MCRegOP, STI);208MCOperand lo = createSparcMCOperand(SparcMCExpr::VK_Sparc_L44,209GOTLabel, OutContext);210EmitOR(*OutStreamer, MCRegOP, lo, MCRegOP, STI);211break;212}213case CodeModel::Large: {214EmitHiLo(*OutStreamer, GOTLabel,215SparcMCExpr::VK_Sparc_HH, SparcMCExpr::VK_Sparc_HM,216MCRegOP, OutContext, STI);217MCOperand imm = MCOperand::createExpr(MCConstantExpr::create(32,218OutContext));219EmitSHL(*OutStreamer, MCRegOP, imm, MCRegOP, STI);220// Use register %o7 to load the lower 32 bits.221MCOperand RegO7 = MCOperand::createReg(SP::O7);222EmitHiLo(*OutStreamer, GOTLabel,223SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO,224RegO7, OutContext, STI);225EmitADD(*OutStreamer, MCRegOP, RegO7, MCRegOP, STI);226}227}228return;229}230231MCSymbol *StartLabel = OutContext.createTempSymbol();232MCSymbol *EndLabel = OutContext.createTempSymbol();233MCSymbol *SethiLabel = OutContext.createTempSymbol();234235MCOperand RegO7 = MCOperand::createReg(SP::O7);236237// <StartLabel>:238// <GET-PC> // This will be either `call <EndLabel>` or `rd %pc, %o7`.239// <SethiLabel>:240// sethi %hi(_GLOBAL_OFFSET_TABLE_+(<SethiLabel>-<StartLabel>)), <MO>241// <EndLabel>:242// or <MO>, %lo(_GLOBAL_OFFSET_TABLE_+(<EndLabel>-<StartLabel>))), <MO>243// add <MO>, %o7, <MO>244245OutStreamer->emitLabel(StartLabel);246if (!STI.getTargetTriple().isSPARC64() ||247STI.hasFeature(Sparc::TuneSlowRDPC)) {248MCOperand Callee = createPCXCallOP(EndLabel, OutContext);249EmitCall(*OutStreamer, Callee, STI);250} else {251// TODO find out whether it is possible to store PC252// in other registers, to enable leaf function optimization.253// (On the other hand, approx. over 97.8% of GETPCXes happen254// in non-leaf functions, so would this be worth the effort?)255EmitRDPC(*OutStreamer, RegO7, STI);256}257OutStreamer->emitLabel(SethiLabel);258MCOperand hiImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC22,259GOTLabel, StartLabel, SethiLabel,260OutContext);261EmitSETHI(*OutStreamer, hiImm, MCRegOP, STI);262OutStreamer->emitLabel(EndLabel);263MCOperand loImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC10,264GOTLabel, StartLabel, EndLabel,265OutContext);266EmitOR(*OutStreamer, MCRegOP, loImm, MCRegOP, STI);267EmitADD(*OutStreamer, MCRegOP, RegO7, MCRegOP, STI);268}269270void SparcAsmPrinter::emitInstruction(const MachineInstr *MI) {271Sparc_MC::verifyInstructionPredicates(MI->getOpcode(),272getSubtargetInfo().getFeatureBits());273274switch (MI->getOpcode()) {275default: break;276case TargetOpcode::DBG_VALUE:277// FIXME: Debug Value.278return;279case SP::GETPCX:280LowerGETPCXAndEmitMCInsts(MI, getSubtargetInfo());281return;282}283MachineBasicBlock::const_instr_iterator I = MI->getIterator();284MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();285do {286MCInst TmpInst;287LowerSparcMachineInstrToMCInst(&*I, TmpInst, *this);288EmitToStreamer(*OutStreamer, TmpInst);289} while ((++I != E) && I->isInsideBundle()); // Delay slot check.290}291292void SparcAsmPrinter::emitFunctionBodyStart() {293if (!MF->getSubtarget<SparcSubtarget>().is64Bit())294return;295296const MachineRegisterInfo &MRI = MF->getRegInfo();297const unsigned globalRegs[] = { SP::G2, SP::G3, SP::G6, SP::G7, 0 };298for (unsigned i = 0; globalRegs[i] != 0; ++i) {299unsigned reg = globalRegs[i];300if (MRI.use_empty(reg))301continue;302303if (reg == SP::G6 || reg == SP::G7)304getTargetStreamer().emitSparcRegisterIgnore(reg);305else306getTargetStreamer().emitSparcRegisterScratch(reg);307}308}309310void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum,311raw_ostream &O) {312const DataLayout &DL = getDataLayout();313const MachineOperand &MO = MI->getOperand (opNum);314SparcMCExpr::VariantKind TF = (SparcMCExpr::VariantKind) MO.getTargetFlags();315316bool CloseParen = SparcMCExpr::printVariantKind(O, TF);317318switch (MO.getType()) {319case MachineOperand::MO_Register:320O << "%" << StringRef(getRegisterName(MO.getReg())).lower();321break;322323case MachineOperand::MO_Immediate:324O << MO.getImm();325break;326case MachineOperand::MO_MachineBasicBlock:327MO.getMBB()->getSymbol()->print(O, MAI);328return;329case MachineOperand::MO_GlobalAddress:330PrintSymbolOperand(MO, O);331break;332case MachineOperand::MO_BlockAddress:333O << GetBlockAddressSymbol(MO.getBlockAddress())->getName();334break;335case MachineOperand::MO_ExternalSymbol:336O << MO.getSymbolName();337break;338case MachineOperand::MO_ConstantPoolIndex:339O << DL.getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_"340<< MO.getIndex();341break;342case MachineOperand::MO_Metadata:343MO.getMetadata()->printAsOperand(O, MMI->getModule());344break;345default:346llvm_unreachable("<unknown operand type>");347}348if (CloseParen) O << ")";349}350351void SparcAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum,352raw_ostream &O, const char *Modifier) {353printOperand(MI, opNum, O);354355// If this is an ADD operand, emit it like normal operands.356if (Modifier && !strcmp(Modifier, "arith")) {357O << ", ";358printOperand(MI, opNum+1, O);359return;360}361362if (MI->getOperand(opNum+1).isReg() &&363MI->getOperand(opNum+1).getReg() == SP::G0)364return; // don't print "+%g0"365if (MI->getOperand(opNum+1).isImm() &&366MI->getOperand(opNum+1).getImm() == 0)367return; // don't print "+0"368369O << "+";370printOperand(MI, opNum+1, O);371}372373/// PrintAsmOperand - Print out an operand for an inline asm expression.374///375bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,376const char *ExtraCode,377raw_ostream &O) {378if (ExtraCode && ExtraCode[0]) {379if (ExtraCode[1] != 0) return true; // Unknown modifier.380381switch (ExtraCode[0]) {382default:383// See if this is a generic print operand384return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);385case 'L': // Low order register of a twin word register operand386case 'H': // High order register of a twin word register operand387{388const SparcSubtarget &Subtarget = MF->getSubtarget<SparcSubtarget>();389const MachineOperand &MO = MI->getOperand(OpNo);390const SparcRegisterInfo *RegisterInfo = Subtarget.getRegisterInfo();391Register MOReg = MO.getReg();392393Register HiReg, LoReg;394if (!SP::IntPairRegClass.contains(MOReg)) {395// If we aren't given a register pair already, find out which pair it396// belongs to. Note that here, the specified register operand, which397// refers to the high part of the twinword, needs to be an even-numbered398// register.399MOReg = RegisterInfo->getMatchingSuperReg(MOReg, SP::sub_even,400&SP::IntPairRegClass);401if (!MOReg) {402SMLoc Loc;403OutContext.reportError(404Loc, "Hi part of pair should point to an even-numbered register");405OutContext.reportError(406Loc, "(note that in some cases it might be necessary to manually "407"bind the input/output registers instead of relying on "408"automatic allocation)");409return true;410}411}412413HiReg = RegisterInfo->getSubReg(MOReg, SP::sub_even);414LoReg = RegisterInfo->getSubReg(MOReg, SP::sub_odd);415416Register Reg;417switch (ExtraCode[0]) {418case 'L':419Reg = LoReg;420break;421case 'H':422Reg = HiReg;423break;424}425426O << '%' << SparcInstPrinter::getRegisterName(Reg);427return false;428}429case 'f':430case 'r':431break;432}433}434435printOperand(MI, OpNo, O);436437return false;438}439440bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,441unsigned OpNo,442const char *ExtraCode,443raw_ostream &O) {444if (ExtraCode && ExtraCode[0])445return true; // Unknown modifier446447O << '[';448printMemOperand(MI, OpNo, O);449O << ']';450451return false;452}453454// Force static initialization.455extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSparcAsmPrinter() {456RegisterAsmPrinter<SparcAsmPrinter> X(getTheSparcTarget());457RegisterAsmPrinter<SparcAsmPrinter> Y(getTheSparcV9Target());458RegisterAsmPrinter<SparcAsmPrinter> Z(getTheSparcelTarget());459}460461462