brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.9 KiB · f1d487c Raw
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