525 lines · cpp
1//===-- SparcAsmPrinter.cpp - Sparc LLVM assembly writer ------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains a printer that converts from our internal representation10// of machine-dependent LLVM code to GAS-format SPARC assembly language.11//12//===----------------------------------------------------------------------===//13 14#include "MCTargetDesc/SparcInstPrinter.h"15#include "MCTargetDesc/SparcMCAsmInfo.h"16#include "MCTargetDesc/SparcMCTargetDesc.h"17#include "MCTargetDesc/SparcTargetStreamer.h"18#include "Sparc.h"19#include "SparcInstrInfo.h"20#include "SparcTargetMachine.h"21#include "TargetInfo/SparcTargetInfo.h"22#include "llvm/BinaryFormat/ELF.h"23#include "llvm/CodeGen/AsmPrinter.h"24#include "llvm/CodeGen/MachineInstr.h"25#include "llvm/CodeGen/MachineModuleInfoImpls.h"26#include "llvm/CodeGen/MachineRegisterInfo.h"27#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"28#include "llvm/IR/Mangler.h"29#include "llvm/MC/MCAsmInfo.h"30#include "llvm/MC/MCContext.h"31#include "llvm/MC/MCInst.h"32#include "llvm/MC/MCStreamer.h"33#include "llvm/MC/MCSymbol.h"34#include "llvm/MC/TargetRegistry.h"35#include "llvm/Support/Compiler.h"36#include "llvm/Support/raw_ostream.h"37using namespace llvm;38 39#define DEBUG_TYPE "asm-printer"40 41namespace {42class SparcAsmPrinter : public AsmPrinter {43 SparcTargetStreamer &getTargetStreamer() {44 return static_cast<SparcTargetStreamer &>(45 *OutStreamer->getTargetStreamer());46 }47 48public:49 explicit SparcAsmPrinter(TargetMachine &TM,50 std::unique_ptr<MCStreamer> Streamer)51 : AsmPrinter(TM, std::move(Streamer), ID) {}52 53 StringRef getPassName() const override { return "Sparc Assembly Printer"; }54 55 void printOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);56 void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);57 58 void emitFunctionBodyStart() override;59 void emitInstruction(const MachineInstr *MI) override;60 61 static const char *getRegisterName(MCRegister Reg) {62 return SparcInstPrinter::getRegisterName(Reg);63 }64 65 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,66 const char *ExtraCode, raw_ostream &O) override;67 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,68 const char *ExtraCode, raw_ostream &O) override;69 70 void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI,71 const MCSubtargetInfo &STI);72 73 MCOperand lowerOperand(const MachineOperand &MO) const;74 75private:76 void lowerToMCInst(const MachineInstr *MI, MCInst &OutMI);77 78public:79 static char ID;80};81} // end of anonymous namespace82 83static MCOperand createSparcMCOperand(uint16_t Kind, MCSymbol *Sym,84 MCContext &OutContext) {85 const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::create(Sym, OutContext);86 auto *expr = MCSpecifierExpr::create(MCSym, Kind, OutContext);87 return MCOperand::createExpr(expr);88}89static MCOperand createPCXCallOP(MCSymbol *Label,90 MCContext &OutContext) {91 return MCOperand::createExpr(MCSymbolRefExpr::create(Label, OutContext));92}93 94static MCOperand createPCXRelExprOp(uint16_t Spec, MCSymbol *GOTLabel,95 MCSymbol *StartLabel, MCSymbol *CurLabel,96 MCContext &OutContext) {97 const MCSymbolRefExpr *GOT = MCSymbolRefExpr::create(GOTLabel, OutContext);98 const MCSymbolRefExpr *Start = MCSymbolRefExpr::create(StartLabel,99 OutContext);100 const MCSymbolRefExpr *Cur = MCSymbolRefExpr::create(CurLabel,101 OutContext);102 103 const MCBinaryExpr *Sub = MCBinaryExpr::createSub(Cur, Start, OutContext);104 const MCBinaryExpr *Add = MCBinaryExpr::createAdd(GOT, Sub, OutContext);105 auto *expr = MCSpecifierExpr::create(Add, Spec, OutContext);106 return MCOperand::createExpr(expr);107}108 109static void EmitCall(MCStreamer &OutStreamer,110 MCOperand &Callee,111 const MCSubtargetInfo &STI)112{113 MCInst CallInst;114 CallInst.setOpcode(SP::CALL);115 CallInst.addOperand(Callee);116 OutStreamer.emitInstruction(CallInst, STI);117}118 119static void EmitRDPC(MCStreamer &OutStreamer, MCOperand &RD,120 const MCSubtargetInfo &STI) {121 MCInst RDPCInst;122 RDPCInst.setOpcode(SP::RDASR);123 RDPCInst.addOperand(RD);124 RDPCInst.addOperand(MCOperand::createReg(SP::ASR5));125 OutStreamer.emitInstruction(RDPCInst, STI);126}127 128static void EmitSETHI(MCStreamer &OutStreamer,129 MCOperand &Imm, MCOperand &RD,130 const MCSubtargetInfo &STI)131{132 MCInst SETHIInst;133 SETHIInst.setOpcode(SP::SETHIi);134 SETHIInst.addOperand(RD);135 SETHIInst.addOperand(Imm);136 OutStreamer.emitInstruction(SETHIInst, STI);137}138 139static void EmitBinary(MCStreamer &OutStreamer, unsigned Opcode,140 MCOperand &RS1, MCOperand &Src2, MCOperand &RD,141 const MCSubtargetInfo &STI)142{143 MCInst Inst;144 Inst.setOpcode(Opcode);145 Inst.addOperand(RD);146 Inst.addOperand(RS1);147 Inst.addOperand(Src2);148 OutStreamer.emitInstruction(Inst, STI);149}150 151static void EmitOR(MCStreamer &OutStreamer,152 MCOperand &RS1, MCOperand &Imm, MCOperand &RD,153 const MCSubtargetInfo &STI) {154 EmitBinary(OutStreamer, SP::ORri, RS1, Imm, RD, STI);155}156 157static void EmitADD(MCStreamer &OutStreamer,158 MCOperand &RS1, MCOperand &RS2, MCOperand &RD,159 const MCSubtargetInfo &STI) {160 EmitBinary(OutStreamer, SP::ADDrr, RS1, RS2, RD, STI);161}162 163static void EmitSHL(MCStreamer &OutStreamer,164 MCOperand &RS1, MCOperand &Imm, MCOperand &RD,165 const MCSubtargetInfo &STI) {166 EmitBinary(OutStreamer, SP::SLLri, RS1, Imm, RD, STI);167}168 169static void emitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym, uint16_t HiKind,170 uint16_t LoKind, MCOperand &RD, MCContext &OutContext,171 const MCSubtargetInfo &STI) {172 MCOperand hi = createSparcMCOperand(HiKind, GOTSym, OutContext);173 MCOperand lo = createSparcMCOperand(LoKind, GOTSym, OutContext);174 EmitSETHI(OutStreamer, hi, RD, STI);175 EmitOR(OutStreamer, RD, lo, RD, STI);176}177 178void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr *MI,179 const MCSubtargetInfo &STI)180{181 MCSymbol *GOTLabel =182 OutContext.getOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));183 184 const MachineOperand &MO = MI->getOperand(0);185 assert(MO.getReg() != SP::O7 &&186 "%o7 is assigned as destination for getpcx!");187 188 MCOperand MCRegOP = MCOperand::createReg(MO.getReg());189 190 191 if (!isPositionIndependent()) {192 // Just load the address of GOT to MCRegOP.193 switch(TM.getCodeModel()) {194 default:195 llvm_unreachable("Unsupported absolute code model");196 case CodeModel::Small:197 emitHiLo(*OutStreamer, GOTLabel, ELF::R_SPARC_HI22, ELF::R_SPARC_LO10,198 MCRegOP, OutContext, STI);199 break;200 case CodeModel::Medium: {201 emitHiLo(*OutStreamer, GOTLabel, ELF::R_SPARC_H44, ELF::R_SPARC_M44,202 MCRegOP, OutContext, STI);203 MCOperand imm = MCOperand::createExpr(MCConstantExpr::create(12,204 OutContext));205 EmitSHL(*OutStreamer, MCRegOP, imm, MCRegOP, STI);206 MCOperand lo =207 createSparcMCOperand(ELF::R_SPARC_L44, GOTLabel, OutContext);208 EmitOR(*OutStreamer, MCRegOP, lo, MCRegOP, STI);209 break;210 }211 case CodeModel::Large: {212 emitHiLo(*OutStreamer, GOTLabel, ELF::R_SPARC_HH22, ELF::R_SPARC_HM10,213 MCRegOP, OutContext, STI);214 MCOperand imm = MCOperand::createExpr(MCConstantExpr::create(32,215 OutContext));216 EmitSHL(*OutStreamer, MCRegOP, imm, MCRegOP, STI);217 // Use register %o7 to load the lower 32 bits.218 MCOperand RegO7 = MCOperand::createReg(SP::O7);219 emitHiLo(*OutStreamer, GOTLabel, ELF::R_SPARC_HI22, ELF::R_SPARC_LO10,220 RegO7, OutContext, STI);221 EmitADD(*OutStreamer, MCRegOP, RegO7, MCRegOP, STI);222 }223 }224 return;225 }226 227 MCSymbol *StartLabel = OutContext.createTempSymbol();228 MCSymbol *EndLabel = OutContext.createTempSymbol();229 MCSymbol *SethiLabel = OutContext.createTempSymbol();230 231 MCOperand RegO7 = MCOperand::createReg(SP::O7);232 233 // <StartLabel>:234 // <GET-PC> // This will be either `call <EndLabel>` or `rd %pc, %o7`.235 // <SethiLabel>:236 // sethi %hi(_GLOBAL_OFFSET_TABLE_+(<SethiLabel>-<StartLabel>)), <MO>237 // <EndLabel>:238 // or <MO>, %lo(_GLOBAL_OFFSET_TABLE_+(<EndLabel>-<StartLabel>))), <MO>239 // add <MO>, %o7, <MO>240 241 OutStreamer->emitLabel(StartLabel);242 if (!STI.getTargetTriple().isSPARC64() ||243 STI.hasFeature(Sparc::TuneSlowRDPC)) {244 MCOperand Callee = createPCXCallOP(EndLabel, OutContext);245 EmitCall(*OutStreamer, Callee, STI);246 } else {247 // TODO find out whether it is possible to store PC248 // in other registers, to enable leaf function optimization.249 // (On the other hand, approx. over 97.8% of GETPCXes happen250 // in non-leaf functions, so would this be worth the effort?)251 EmitRDPC(*OutStreamer, RegO7, STI);252 }253 OutStreamer->emitLabel(SethiLabel);254 MCOperand hiImm = createPCXRelExprOp(ELF::R_SPARC_PC22, GOTLabel, StartLabel,255 SethiLabel, OutContext);256 EmitSETHI(*OutStreamer, hiImm, MCRegOP, STI);257 OutStreamer->emitLabel(EndLabel);258 MCOperand loImm = createPCXRelExprOp(ELF::R_SPARC_PC10, GOTLabel, StartLabel,259 EndLabel, OutContext);260 EmitOR(*OutStreamer, MCRegOP, loImm, MCRegOP, STI);261 EmitADD(*OutStreamer, MCRegOP, RegO7, MCRegOP, STI);262}263 264MCOperand SparcAsmPrinter::lowerOperand(const MachineOperand &MO) const {265 switch (MO.getType()) {266 default:267 llvm_unreachable("unknown operand type");268 break;269 case MachineOperand::MO_Register:270 if (MO.isImplicit())271 break;272 return MCOperand::createReg(MO.getReg());273 274 case MachineOperand::MO_Immediate:275 return MCOperand::createImm(MO.getImm());276 277 case MachineOperand::MO_MachineBasicBlock:278 case MachineOperand::MO_GlobalAddress:279 case MachineOperand::MO_BlockAddress:280 case MachineOperand::MO_ExternalSymbol:281 case MachineOperand::MO_ConstantPoolIndex: {282 auto RelType = MO.getTargetFlags();283 const MCSymbol *Symbol = nullptr;284 switch (MO.getType()) {285 default:286 llvm_unreachable("");287 case MachineOperand::MO_MachineBasicBlock:288 Symbol = MO.getMBB()->getSymbol();289 break;290 case MachineOperand::MO_GlobalAddress:291 Symbol = getSymbol(MO.getGlobal());292 break;293 case MachineOperand::MO_BlockAddress:294 Symbol = GetBlockAddressSymbol(MO.getBlockAddress());295 break;296 case MachineOperand::MO_ExternalSymbol:297 Symbol = GetExternalSymbolSymbol(MO.getSymbolName());298 break;299 case MachineOperand::MO_ConstantPoolIndex:300 Symbol = GetCPISymbol(MO.getIndex());301 break;302 }303 304 const MCExpr *expr = MCSymbolRefExpr::create(Symbol, OutContext);305 if (RelType)306 expr = MCSpecifierExpr::create(expr, RelType, OutContext);307 return MCOperand::createExpr(expr);308 }309 310 case MachineOperand::MO_RegisterMask:311 break;312 }313 return MCOperand();314}315 316void SparcAsmPrinter::lowerToMCInst(const MachineInstr *MI, MCInst &OutMI) {317 OutMI.setOpcode(MI->getOpcode());318 319 for (const MachineOperand &MO : MI->operands()) {320 MCOperand MCOp = lowerOperand(MO);321 if (MCOp.isValid())322 OutMI.addOperand(MCOp);323 }324}325 326void SparcAsmPrinter::emitInstruction(const MachineInstr *MI) {327 Sparc_MC::verifyInstructionPredicates(MI->getOpcode(),328 getSubtargetInfo().getFeatureBits());329 if (MI->isBundle()) {330 const MachineBasicBlock *MBB = MI->getParent();331 MachineBasicBlock::const_instr_iterator I = ++MI->getIterator();332 while (I != MBB->instr_end() && I->isInsideBundle()) {333 emitInstruction(&*I);334 ++I;335 }336 return;337 }338 339 switch (MI->getOpcode()) {340 default: break;341 case TargetOpcode::DBG_VALUE:342 // FIXME: Debug Value.343 return;344 case SP::CASArr:345 case SP::SWAPrr:346 case SP::SWAPri:347 if (MF->getSubtarget<SparcSubtarget>().fixTN0011())348 OutStreamer->emitCodeAlignment(Align(16), &getSubtargetInfo());349 break;350 case SP::GETPCX:351 LowerGETPCXAndEmitMCInsts(MI, getSubtargetInfo());352 return;353 }354 MachineBasicBlock::const_instr_iterator I = MI->getIterator();355 MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();356 do {357 MCInst TmpInst;358 lowerToMCInst(&*I, TmpInst);359 EmitToStreamer(*OutStreamer, TmpInst);360 } while ((++I != E) && I->isInsideBundle()); // Delay slot check.361}362 363void SparcAsmPrinter::emitFunctionBodyStart() {364 if (!MF->getSubtarget<SparcSubtarget>().is64Bit())365 return;366 367 const MachineRegisterInfo &MRI = MF->getRegInfo();368 const unsigned globalRegs[] = { SP::G2, SP::G3, SP::G6, SP::G7, 0 };369 for (unsigned i = 0; globalRegs[i] != 0; ++i) {370 unsigned reg = globalRegs[i];371 if (MRI.use_empty(reg))372 continue;373 374 if (reg == SP::G6 || reg == SP::G7)375 getTargetStreamer().emitSparcRegisterIgnore(reg);376 else377 getTargetStreamer().emitSparcRegisterScratch(reg);378 }379}380 381void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum,382 raw_ostream &O) {383 const DataLayout &DL = getDataLayout();384 const MachineOperand &MO = MI->getOperand(opNum);385 switch (MO.getType()) {386 case MachineOperand::MO_Register:387 O << "%" << StringRef(getRegisterName(MO.getReg())).lower();388 break;389 390 case MachineOperand::MO_Immediate:391 O << MO.getImm();392 break;393 case MachineOperand::MO_MachineBasicBlock:394 MO.getMBB()->getSymbol()->print(O, MAI);395 return;396 case MachineOperand::MO_GlobalAddress:397 PrintSymbolOperand(MO, O);398 break;399 case MachineOperand::MO_BlockAddress:400 O << GetBlockAddressSymbol(MO.getBlockAddress())->getName();401 break;402 case MachineOperand::MO_ExternalSymbol:403 O << MO.getSymbolName();404 break;405 case MachineOperand::MO_ConstantPoolIndex:406 O << DL.getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_"407 << MO.getIndex();408 break;409 case MachineOperand::MO_Metadata:410 MO.getMetadata()->printAsOperand(O, MMI->getModule());411 break;412 default:413 llvm_unreachable("<unknown operand type>");414 }415}416 417void SparcAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum,418 raw_ostream &O) {419 printOperand(MI, opNum, O);420 421 if (MI->getOperand(opNum+1).isReg() &&422 MI->getOperand(opNum+1).getReg() == SP::G0)423 return; // don't print "+%g0"424 if (MI->getOperand(opNum+1).isImm() &&425 MI->getOperand(opNum+1).getImm() == 0)426 return; // don't print "+0"427 428 O << "+";429 printOperand(MI, opNum+1, O);430}431 432/// PrintAsmOperand - Print out an operand for an inline asm expression.433///434bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,435 const char *ExtraCode,436 raw_ostream &O) {437 if (ExtraCode && ExtraCode[0]) {438 if (ExtraCode[1] != 0) return true; // Unknown modifier.439 440 switch (ExtraCode[0]) {441 default:442 // See if this is a generic print operand443 return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);444 case 'L': // Low order register of a twin word register operand445 case 'H': // High order register of a twin word register operand446 {447 const SparcSubtarget &Subtarget = MF->getSubtarget<SparcSubtarget>();448 const MachineOperand &MO = MI->getOperand(OpNo);449 const SparcRegisterInfo *RegisterInfo = Subtarget.getRegisterInfo();450 Register MOReg = MO.getReg();451 452 Register HiReg, LoReg;453 if (!SP::IntPairRegClass.contains(MOReg)) {454 // If we aren't given a register pair already, find out which pair it455 // belongs to. Note that here, the specified register operand, which456 // refers to the high part of the twinword, needs to be an even-numbered457 // register.458 MOReg = RegisterInfo->getMatchingSuperReg(MOReg, SP::sub_even,459 &SP::IntPairRegClass);460 if (!MOReg) {461 SMLoc Loc;462 OutContext.reportError(463 Loc, "Hi part of pair should point to an even-numbered register");464 OutContext.reportError(465 Loc, "(note that in some cases it might be necessary to manually "466 "bind the input/output registers instead of relying on "467 "automatic allocation)");468 return true;469 }470 }471 472 HiReg = RegisterInfo->getSubReg(MOReg, SP::sub_even);473 LoReg = RegisterInfo->getSubReg(MOReg, SP::sub_odd);474 475 Register Reg;476 switch (ExtraCode[0]) {477 case 'L':478 Reg = LoReg;479 break;480 case 'H':481 Reg = HiReg;482 break;483 }484 485 O << '%' << SparcInstPrinter::getRegisterName(Reg);486 return false;487 }488 case 'f':489 case 'r':490 break;491 }492 }493 494 printOperand(MI, OpNo, O);495 496 return false;497}498 499bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,500 unsigned OpNo,501 const char *ExtraCode,502 raw_ostream &O) {503 if (ExtraCode && ExtraCode[0])504 return true; // Unknown modifier505 506 O << '[';507 printMemOperand(MI, OpNo, O);508 O << ']';509 510 return false;511}512 513char SparcAsmPrinter::ID = 0;514 515INITIALIZE_PASS(SparcAsmPrinter, "sparc-asm-printer", "Sparc Assembly Printer",516 false, false)517 518// Force static initialization.519extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void520LLVMInitializeSparcAsmPrinter() {521 RegisterAsmPrinter<SparcAsmPrinter> X(getTheSparcTarget());522 RegisterAsmPrinter<SparcAsmPrinter> Y(getTheSparcV9Target());523 RegisterAsmPrinter<SparcAsmPrinter> Z(getTheSparcelTarget());524}525