brintos

brintos / llvm-project-archived public Read only

0
0
Text · 42.4 KiB · 9d8b9f8 Raw
1280 lines · cpp
1//===- MipsAsmPrinter.cpp - Mips LLVM Assembly Printer --------------------===//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 MIPS assembly language.11//12//===----------------------------------------------------------------------===//13 14#include "MipsAsmPrinter.h"15#include "MCTargetDesc/MipsABIInfo.h"16#include "MCTargetDesc/MipsBaseInfo.h"17#include "MCTargetDesc/MipsInstPrinter.h"18#include "MCTargetDesc/MipsMCAsmInfo.h"19#include "MCTargetDesc/MipsMCTargetDesc.h"20#include "MCTargetDesc/MipsTargetStreamer.h"21#include "Mips.h"22#include "MipsMCInstLower.h"23#include "MipsMachineFunction.h"24#include "MipsSubtarget.h"25#include "MipsTargetMachine.h"26#include "TargetInfo/MipsTargetInfo.h"27#include "llvm/ADT/SmallString.h"28#include "llvm/ADT/StringRef.h"29#include "llvm/ADT/Twine.h"30#include "llvm/BinaryFormat/ELF.h"31#include "llvm/CodeGen/MachineBasicBlock.h"32#include "llvm/CodeGen/MachineConstantPool.h"33#include "llvm/CodeGen/MachineFrameInfo.h"34#include "llvm/CodeGen/MachineFunction.h"35#include "llvm/CodeGen/MachineInstr.h"36#include "llvm/CodeGen/MachineJumpTableInfo.h"37#include "llvm/CodeGen/MachineOperand.h"38#include "llvm/CodeGen/TargetRegisterInfo.h"39#include "llvm/CodeGen/TargetSubtargetInfo.h"40#include "llvm/IR/Attributes.h"41#include "llvm/IR/BasicBlock.h"42#include "llvm/IR/DataLayout.h"43#include "llvm/IR/Function.h"44#include "llvm/IR/InlineAsm.h"45#include "llvm/IR/Instructions.h"46#include "llvm/IR/Module.h"47#include "llvm/MC/MCContext.h"48#include "llvm/MC/MCExpr.h"49#include "llvm/MC/MCInst.h"50#include "llvm/MC/MCInstBuilder.h"51#include "llvm/MC/MCObjectFileInfo.h"52#include "llvm/MC/MCSectionELF.h"53#include "llvm/MC/MCSymbol.h"54#include "llvm/MC/TargetRegistry.h"55#include "llvm/Support/Casting.h"56#include "llvm/Support/Compiler.h"57#include "llvm/Support/ErrorHandling.h"58#include "llvm/Support/raw_ostream.h"59#include "llvm/Target/TargetLoweringObjectFile.h"60#include "llvm/Target/TargetMachine.h"61#include "llvm/TargetParser/Triple.h"62#include <cassert>63#include <cstdint>64#include <map>65#include <memory>66#include <string>67#include <vector>68 69using namespace llvm;70 71#define DEBUG_TYPE "mips-asm-printer"72 73extern cl::opt<bool> EmitJalrReloc;74 75MipsTargetStreamer &MipsAsmPrinter::getTargetStreamer() const {76  return static_cast<MipsTargetStreamer &>(*OutStreamer->getTargetStreamer());77}78 79bool MipsAsmPrinter::runOnMachineFunction(MachineFunction &MF) {80  Subtarget = &MF.getSubtarget<MipsSubtarget>();81 82  MipsFI = MF.getInfo<MipsFunctionInfo>();83  if (Subtarget->inMips16Mode())84    for (const auto &I : MipsFI->StubsNeeded)85      StubsNeeded.insert(I);86  MCP = MF.getConstantPool();87 88  AsmPrinter::runOnMachineFunction(MF);89 90  emitXRayTable();91 92  return true;93}94 95bool MipsAsmPrinter::lowerOperand(const MachineOperand &MO, MCOperand &MCOp) {96  MCOp = MCInstLowering.LowerOperand(MO);97  return MCOp.isValid();98}99 100#include "MipsGenMCPseudoLowering.inc"101 102// Lower PseudoReturn/PseudoIndirectBranch/PseudoIndirectBranch64 to JR, JR_MM,103// JALR, or JALR64 as appropriate for the target.104void MipsAsmPrinter::emitPseudoIndirectBranch(MCStreamer &OutStreamer,105                                              const MachineInstr *MI) {106  bool HasLinkReg = false;107  bool InMicroMipsMode = Subtarget->inMicroMipsMode();108  MCInst TmpInst0;109 110  if (Subtarget->hasMips64r6()) {111    // MIPS64r6 should use (JALR64 ZERO_64, $rs)112    TmpInst0.setOpcode(Mips::JALR64);113    HasLinkReg = true;114  } else if (Subtarget->hasMips32r6()) {115    // MIPS32r6 should use (JALR ZERO, $rs)116    if (InMicroMipsMode)117      TmpInst0.setOpcode(Mips::JRC16_MMR6);118    else {119      TmpInst0.setOpcode(Mips::JALR);120      HasLinkReg = true;121    }122  } else if (Subtarget->inMicroMipsMode())123    // microMIPS should use (JR_MM $rs)124    TmpInst0.setOpcode(Mips::JR_MM);125  else {126    // Everything else should use (JR $rs)127    TmpInst0.setOpcode(Mips::JR);128  }129 130  MCOperand MCOp;131 132  if (HasLinkReg) {133    unsigned ZeroReg = Subtarget->isGP64bit() ? Mips::ZERO_64 : Mips::ZERO;134    TmpInst0.addOperand(MCOperand::createReg(ZeroReg));135  }136 137  lowerOperand(MI->getOperand(0), MCOp);138  TmpInst0.addOperand(MCOp);139 140  EmitToStreamer(OutStreamer, TmpInst0);141}142 143// If there is an MO_JALR operand, insert:144//145// .reloc tmplabel, R_{MICRO}MIPS_JALR, symbol146// tmplabel:147//148// This is an optimization hint for the linker which may then replace149// an indirect call with a direct branch.150static void emitDirectiveRelocJalr(const MachineInstr &MI,151                                   MCContext &OutContext,152                                   TargetMachine &TM,153                                   MCStreamer &OutStreamer,154                                   const MipsSubtarget &Subtarget) {155  for (const MachineOperand &MO :156       llvm::drop_begin(MI.operands(), MI.getDesc().getNumOperands())) {157    if (MO.isMCSymbol() && (MO.getTargetFlags() & MipsII::MO_JALR)) {158      MCSymbol *Callee = MO.getMCSymbol();159      if (Callee && !Callee->getName().empty()) {160        MCSymbol *OffsetLabel = OutContext.createTempSymbol();161        const MCExpr *OffsetExpr =162            MCSymbolRefExpr::create(OffsetLabel, OutContext);163        const MCExpr *CaleeExpr =164            MCSymbolRefExpr::create(Callee, OutContext);165        OutStreamer.emitRelocDirective(166            *OffsetExpr,167            Subtarget.inMicroMipsMode() ? "R_MICROMIPS_JALR" : "R_MIPS_JALR",168            CaleeExpr);169        OutStreamer.emitLabel(OffsetLabel);170        return;171      }172    }173  }174}175 176void MipsAsmPrinter::emitInstruction(const MachineInstr *MI) {177  // FIXME: Enable feature predicate checks once all the test pass.178  // Mips_MC::verifyInstructionPredicates(MI->getOpcode(),179  //                                      getSubtargetInfo().getFeatureBits());180 181  MipsTargetStreamer &TS = getTargetStreamer();182  unsigned Opc = MI->getOpcode();183  TS.forbidModuleDirective();184 185  if (MI->isDebugValue()) {186    SmallString<128> Str;187    raw_svector_ostream OS(Str);188 189    PrintDebugValueComment(MI, OS);190    return;191  }192  if (MI->isDebugLabel())193    return;194 195  // If we just ended a constant pool, mark it as such.196  if (InConstantPool && Opc != Mips::CONSTPOOL_ENTRY) {197    OutStreamer->emitDataRegion(MCDR_DataRegionEnd);198    InConstantPool = false;199  }200  if (Opc == Mips::CONSTPOOL_ENTRY) {201    // CONSTPOOL_ENTRY - This instruction represents a floating202    // constant pool in the function.  The first operand is the ID#203    // for this instruction, the second is the index into the204    // MachineConstantPool that this is, the third is the size in205    // bytes of this constant pool entry.206    // The required alignment is specified on the basic block holding this MI.207    //208    unsigned LabelId = (unsigned)MI->getOperand(0).getImm();209    unsigned CPIdx = (unsigned)MI->getOperand(1).getIndex();210 211    // If this is the first entry of the pool, mark it.212    if (!InConstantPool) {213      OutStreamer->emitDataRegion(MCDR_DataRegion);214      InConstantPool = true;215    }216 217    OutStreamer->emitLabel(GetCPISymbol(LabelId));218 219    const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPIdx];220    if (MCPE.isMachineConstantPoolEntry())221      emitMachineConstantPoolValue(MCPE.Val.MachineCPVal);222    else223      emitGlobalConstant(MF->getDataLayout(), MCPE.Val.ConstVal);224    return;225  }226 227  switch (Opc) {228  case Mips::PATCHABLE_FUNCTION_ENTER:229    LowerPATCHABLE_FUNCTION_ENTER(*MI);230    return;231  case Mips::PATCHABLE_FUNCTION_EXIT:232    LowerPATCHABLE_FUNCTION_EXIT(*MI);233    return;234  case Mips::PATCHABLE_TAIL_CALL:235    LowerPATCHABLE_TAIL_CALL(*MI);236    return;237  }238 239  if (EmitJalrReloc &&240      (MI->isReturn() || MI->isCall() || MI->isIndirectBranch())) {241    emitDirectiveRelocJalr(*MI, OutContext, TM, *OutStreamer, *Subtarget);242  }243 244  MachineBasicBlock::const_instr_iterator I = MI->getIterator();245  MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();246 247  do {248    // Do any auto-generated pseudo lowerings.249    if (MCInst OutInst; lowerPseudoInstExpansion(&*I, OutInst)) {250      EmitToStreamer(*OutStreamer, OutInst);251      continue;252    }253 254    // Skip the BUNDLE pseudo instruction and lower the contents255    if (I->isBundle())256      continue;257 258    if (I->getOpcode() == Mips::PseudoReturn ||259        I->getOpcode() == Mips::PseudoReturn64 ||260        I->getOpcode() == Mips::PseudoIndirectBranch ||261        I->getOpcode() == Mips::PseudoIndirectBranch64 ||262        I->getOpcode() == Mips::TAILCALLREG ||263        I->getOpcode() == Mips::TAILCALLREG64) {264      emitPseudoIndirectBranch(*OutStreamer, &*I);265      continue;266    }267 268    // The inMips16Mode() test is not permanent.269    // Some instructions are marked as pseudo right now which270    // would make the test fail for the wrong reason but271    // that will be fixed soon. We need this here because we are272    // removing another test for this situation downstream in the273    // callchain.274    //275    if (I->isPseudo() && !Subtarget->inMips16Mode()276        && !isLongBranchPseudo(I->getOpcode()))277      llvm_unreachable("Pseudo opcode found in emitInstruction()");278 279    MCInst TmpInst0;280    MCInstLowering.Lower(&*I, TmpInst0);281    EmitToStreamer(*OutStreamer, TmpInst0);282  } while ((++I != E) && I->isInsideBundle()); // Delay slot check283}284 285//===----------------------------------------------------------------------===//286//287//  Mips Asm Directives288//289//  -- Frame directive "frame Stackpointer, Stacksize, RARegister"290//  Describe the stack frame.291//292//  -- Mask directives "(f)mask  bitmask, offset"293//  Tells the assembler which registers are saved and where.294//  bitmask - contain a little endian bitset indicating which registers are295//            saved on function prologue (e.g. with a 0x80000000 mask, the296//            assembler knows the register 31 (RA) is saved at prologue.297//  offset  - the position before stack pointer subtraction indicating where298//            the first saved register on prologue is located. (e.g. with a299//300//  Consider the following function prologue:301//302//    .frame  $fp,48,$ra303//    .mask   0xc0000000,-8304//       addiu $sp, $sp, -48305//       sw $ra, 40($sp)306//       sw $fp, 36($sp)307//308//    With a 0xc0000000 mask, the assembler knows the register 31 (RA) and309//    30 (FP) are saved at prologue. As the save order on prologue is from310//    left to right, RA is saved first. A -8 offset means that after the311//    stack pointer subtration, the first register in the mask (RA) will be312//    saved at address 48-8=40.313//314//===----------------------------------------------------------------------===//315 316//===----------------------------------------------------------------------===//317// Mask directives318//===----------------------------------------------------------------------===//319 320// Create a bitmask with all callee saved registers for CPU or Floating Point321// registers. For CPU registers consider RA, GP and FP for saving if necessary.322void MipsAsmPrinter::printSavedRegsBitmask() {323  // CPU and FPU Saved Registers Bitmasks324  unsigned CPUBitmask = 0, FPUBitmask = 0;325  int CPUTopSavedRegOff, FPUTopSavedRegOff;326 327  // Set the CPU and FPU Bitmasks328  const MachineFrameInfo &MFI = MF->getFrameInfo();329  const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();330  const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();331  // size of stack area to which FP callee-saved regs are saved.332  unsigned CPURegSize = TRI->getRegSizeInBits(Mips::GPR32RegClass) / 8;333  unsigned FGR32RegSize = TRI->getRegSizeInBits(Mips::FGR32RegClass) / 8;334  unsigned AFGR64RegSize = TRI->getRegSizeInBits(Mips::AFGR64RegClass) / 8;335  bool HasAFGR64Reg = false;336  unsigned CSFPRegsSize = 0;337 338  for (const auto &I : CSI) {339    Register Reg = I.getReg();340    unsigned RegNum = TRI->getEncodingValue(Reg);341 342    // If it's a floating point register, set the FPU Bitmask.343    // If it's a general purpose register, set the CPU Bitmask.344    if (Mips::FGR32RegClass.contains(Reg)) {345      FPUBitmask |= (1 << RegNum);346      CSFPRegsSize += FGR32RegSize;347    } else if (Mips::AFGR64RegClass.contains(Reg)) {348      FPUBitmask |= (3 << RegNum);349      CSFPRegsSize += AFGR64RegSize;350      HasAFGR64Reg = true;351    } else if (Mips::GPR32RegClass.contains(Reg))352      CPUBitmask |= (1 << RegNum);353  }354 355  // FP Regs are saved right below where the virtual frame pointer points to.356  FPUTopSavedRegOff = FPUBitmask ?357    (HasAFGR64Reg ? -AFGR64RegSize : -FGR32RegSize) : 0;358 359  // CPU Regs are saved below FP Regs.360  CPUTopSavedRegOff = CPUBitmask ? -CSFPRegsSize - CPURegSize : 0;361 362  MipsTargetStreamer &TS = getTargetStreamer();363  // Print CPUBitmask364  TS.emitMask(CPUBitmask, CPUTopSavedRegOff);365 366  // Print FPUBitmask367  TS.emitFMask(FPUBitmask, FPUTopSavedRegOff);368}369 370//===----------------------------------------------------------------------===//371// Frame and Set directives372//===----------------------------------------------------------------------===//373 374/// Frame Directive375void MipsAsmPrinter::emitFrameDirective() {376  const TargetRegisterInfo &RI = *MF->getSubtarget().getRegisterInfo();377 378  Register stackReg = RI.getFrameRegister(*MF);379  MCRegister returnReg = RI.getRARegister();380  unsigned stackSize = MF->getFrameInfo().getStackSize();381 382  getTargetStreamer().emitFrame(stackReg, stackSize, returnReg);383}384 385/// Emit Set directives.386const char *MipsAsmPrinter::getCurrentABIString() const {387  switch (static_cast<MipsTargetMachine &>(TM).getABI().GetEnumValue()) {388  case MipsABIInfo::ABI::O32:  return "abi32";389  case MipsABIInfo::ABI::N32:  return "abiN32";390  case MipsABIInfo::ABI::N64:  return "abi64";391  default: llvm_unreachable("Unknown Mips ABI");392  }393}394 395void MipsAsmPrinter::emitFunctionEntryLabel() {396  MipsTargetStreamer &TS = getTargetStreamer();397 398  if (Subtarget->inMicroMipsMode()) {399    TS.emitDirectiveSetMicroMips();400    TS.setUsesMicroMips();401    TS.updateABIInfo(*Subtarget);402  } else403    TS.emitDirectiveSetNoMicroMips();404 405  if (Subtarget->inMips16Mode())406    TS.emitDirectiveSetMips16();407  else408    TS.emitDirectiveSetNoMips16();409 410  TS.emitDirectiveEnt(*CurrentFnSym);411  OutStreamer->emitLabel(CurrentFnSym);412}413 414/// EmitFunctionBodyStart - Targets can override this to emit stuff before415/// the first basic block in the function.416void MipsAsmPrinter::emitFunctionBodyStart() {417  MipsTargetStreamer &TS = getTargetStreamer();418 419  MCInstLowering.Initialize(&MF->getContext());420 421  bool IsNakedFunction = MF->getFunction().hasFnAttribute(Attribute::Naked);422  if (!IsNakedFunction)423    emitFrameDirective();424 425  if (!IsNakedFunction)426    printSavedRegsBitmask();427 428  if (!Subtarget->inMips16Mode()) {429    TS.emitDirectiveSetNoReorder();430    TS.emitDirectiveSetNoMacro();431    TS.emitDirectiveSetNoAt();432  }433}434 435/// EmitFunctionBodyEnd - Targets can override this to emit stuff after436/// the last basic block in the function.437void MipsAsmPrinter::emitFunctionBodyEnd() {438  MipsTargetStreamer &TS = getTargetStreamer();439 440  // There are instruction for this macros, but they must441  // always be at the function end, and we can't emit and442  // break with BB logic.443  if (!Subtarget->inMips16Mode()) {444    TS.emitDirectiveSetAt();445    TS.emitDirectiveSetMacro();446    TS.emitDirectiveSetReorder();447  }448  TS.emitDirectiveEnd(CurrentFnSym->getName());449  // Make sure to terminate any constant pools that were at the end450  // of the function.451  if (!InConstantPool)452    return;453  InConstantPool = false;454  OutStreamer->emitDataRegion(MCDR_DataRegionEnd);455}456 457void MipsAsmPrinter::emitBasicBlockEnd(const MachineBasicBlock &MBB) {458  AsmPrinter::emitBasicBlockEnd(MBB);459  MipsTargetStreamer &TS = getTargetStreamer();460  if (MBB.empty())461    TS.emitDirectiveInsn();462}463 464// Print out an operand for an inline asm expression.465bool MipsAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,466                                     const char *ExtraCode, raw_ostream &O) {467  // Does this asm operand have a single letter operand modifier?468  if (ExtraCode && ExtraCode[0]) {469    if (ExtraCode[1] != 0) return true; // Unknown modifier.470 471    const MachineOperand &MO = MI->getOperand(OpNum);472    switch (ExtraCode[0]) {473    default:474      // See if this is a generic print operand475      return AsmPrinter::PrintAsmOperand(MI, OpNum, ExtraCode, O);476    case 'X': // hex const int477      if (!MO.isImm())478        return true;479      O << "0x" << Twine::utohexstr(MO.getImm());480      return false;481    case 'x': // hex const int (low 16 bits)482      if (!MO.isImm())483        return true;484      O << "0x" << Twine::utohexstr(MO.getImm() & 0xffff);485      return false;486    case 'd': // decimal const int487      if (!MO.isImm())488        return true;489      O << MO.getImm();490      return false;491    case 'm': // decimal const int minus 1492      if (!MO.isImm())493        return true;494      O << MO.getImm() - 1;495      return false;496    case 'y': // exact log2497      if (!MO.isImm())498        return true;499      if (!isPowerOf2_64(MO.getImm()))500        return true;501      O << Log2_64(MO.getImm());502      return false;503    case 'z':504      // $0 if zero, regular printing otherwise505      if (MO.isImm() && MO.getImm() == 0) {506        O << "$0";507        return false;508      }509      // If not, call printOperand as normal.510      break;511    case 'D': // Second part of a double word register operand512    case 'L': // Low order register of a double word register operand513    case 'M': // High order register of a double word register operand514    {515      if (OpNum == 0)516        return true;517      const MachineOperand &FlagsOP = MI->getOperand(OpNum - 1);518      if (!FlagsOP.isImm())519        return true;520      const InlineAsm::Flag Flags(FlagsOP.getImm());521      const unsigned NumVals = Flags.getNumOperandRegisters();522      // Number of registers represented by this operand. We are looking523      // for 2 for 32 bit mode and 1 for 64 bit mode.524      if (NumVals != 2) {525        if (Subtarget->isGP64bit() && NumVals == 1 && MO.isReg()) {526          Register Reg = MO.getReg();527          O << '$' << MipsInstPrinter::getRegisterName(Reg);528          return false;529        }530        return true;531      }532 533      unsigned RegOp = OpNum;534      if (!Subtarget->isGP64bit()){535        // Endianness reverses which register holds the high or low value536        // between M and L.537        switch(ExtraCode[0]) {538        case 'M':539          RegOp = (Subtarget->isLittle()) ? OpNum + 1 : OpNum;540          break;541        case 'L':542          RegOp = (Subtarget->isLittle()) ? OpNum : OpNum + 1;543          break;544        case 'D': // Always the second part545          RegOp = OpNum + 1;546        }547        if (RegOp >= MI->getNumOperands())548          return true;549        const MachineOperand &MO = MI->getOperand(RegOp);550        if (!MO.isReg())551          return true;552        Register Reg = MO.getReg();553        O << '$' << MipsInstPrinter::getRegisterName(Reg);554        return false;555      }556      break;557    }558    case 'w': {559      MCRegister w = getMSARegFromFReg(MO.getReg());560      if (w != Mips::NoRegister) {561        O << '$' << MipsInstPrinter::getRegisterName(w);562        return false;563      }564      break;565    }566    }567  }568 569  printOperand(MI, OpNum, O);570  return false;571}572 573bool MipsAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,574                                           unsigned OpNum,575                                           const char *ExtraCode,576                                           raw_ostream &O) {577  assert(OpNum + 1 < MI->getNumOperands() && "Insufficient operands");578  const MachineOperand &BaseMO = MI->getOperand(OpNum);579  const MachineOperand &OffsetMO = MI->getOperand(OpNum + 1);580  assert(BaseMO.isReg() &&581         "Unexpected base pointer for inline asm memory operand.");582  assert(OffsetMO.isImm() &&583         "Unexpected offset for inline asm memory operand.");584  int Offset = OffsetMO.getImm();585 586  // Currently we are expecting either no ExtraCode or 'D','M','L'.587  if (ExtraCode) {588    switch (ExtraCode[0]) {589    case 'D':590      Offset += 4;591      break;592    case 'M':593      if (Subtarget->isLittle())594        Offset += 4;595      break;596    case 'L':597      if (!Subtarget->isLittle())598        Offset += 4;599      break;600    default:601      return true; // Unknown modifier.602    }603  }604 605  O << Offset << "($" << MipsInstPrinter::getRegisterName(BaseMO.getReg())606    << ")";607 608  return false;609}610 611void MipsAsmPrinter::printOperand(const MachineInstr *MI, int opNum,612                                  raw_ostream &O) {613  const MachineOperand &MO = MI->getOperand(opNum);614  bool closeP = false;615 616  if (MO.getTargetFlags())617    closeP = true;618 619  switch(MO.getTargetFlags()) {620  case MipsII::MO_GPREL:    O << "%gp_rel("; break;621  case MipsII::MO_GOT_CALL: O << "%call16("; break;622  case MipsII::MO_GOT:      O << "%got(";    break;623  case MipsII::MO_ABS_HI:   O << "%hi(";     break;624  case MipsII::MO_ABS_LO:   O << "%lo(";     break;625  case MipsII::MO_HIGHER:   O << "%higher("; break;626  case MipsII::MO_HIGHEST:  O << "%highest(("; break;627  case MipsII::MO_TLSGD:    O << "%tlsgd(";  break;628  case MipsII::MO_GOTTPREL: O << "%gottprel("; break;629  case MipsII::MO_TPREL_HI: O << "%tprel_hi("; break;630  case MipsII::MO_TPREL_LO: O << "%tprel_lo("; break;631  case MipsII::MO_GPOFF_HI: O << "%hi(%neg(%gp_rel("; break;632  case MipsII::MO_GPOFF_LO: O << "%lo(%neg(%gp_rel("; break;633  case MipsII::MO_GOT_DISP: O << "%got_disp("; break;634  case MipsII::MO_GOT_PAGE: O << "%got_page("; break;635  case MipsII::MO_GOT_OFST: O << "%got_ofst("; break;636  }637 638  switch (MO.getType()) {639    case MachineOperand::MO_Register:640      O << '$'641        << StringRef(MipsInstPrinter::getRegisterName(MO.getReg())).lower();642      break;643 644    case MachineOperand::MO_Immediate:645      O << MO.getImm();646      break;647 648    case MachineOperand::MO_MachineBasicBlock:649      MO.getMBB()->getSymbol()->print(O, MAI);650      return;651 652    case MachineOperand::MO_GlobalAddress:653      PrintSymbolOperand(MO, O);654      break;655 656    case MachineOperand::MO_BlockAddress: {657      MCSymbol *BA = GetBlockAddressSymbol(MO.getBlockAddress());658      O << BA->getName();659      break;660    }661 662    case MachineOperand::MO_ConstantPoolIndex:663      O << getDataLayout().getPrivateGlobalPrefix() << "CPI"664        << getFunctionNumber() << "_" << MO.getIndex();665      if (MO.getOffset())666        O << "+" << MO.getOffset();667      break;668 669    default:670      llvm_unreachable("<unknown operand type>");671  }672 673  if (closeP) O << ")";674}675 676void MipsAsmPrinter::677printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O) {678  // Load/Store memory operands -- imm($reg)679  // If PIC target the target is loaded as the680  // pattern lw $25,%call16($28)681 682  // opNum can be invalid if instruction has reglist as operand.683  // MemOperand is always last operand of instruction (base + offset).684  switch (MI->getOpcode()) {685  default:686    break;687  case Mips::SWM32_MM:688  case Mips::LWM32_MM:689    opNum = MI->getNumOperands() - 2;690    break;691  }692 693  printOperand(MI, opNum+1, O);694  O << "(";695  printOperand(MI, opNum, O);696  O << ")";697}698 699void MipsAsmPrinter::700printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O) {701  // when using stack locations for not load/store instructions702  // print the same way as all normal 3 operand instructions.703  printOperand(MI, opNum, O);704  O << ", ";705  printOperand(MI, opNum+1, O);706}707 708void MipsAsmPrinter::printFCCOperand(const MachineInstr *MI, int opNum,709                                     raw_ostream &O) {710  const MachineOperand &MO = MI->getOperand(opNum);711  O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm());712}713 714void MipsAsmPrinter::715printRegisterList(const MachineInstr *MI, int opNum, raw_ostream &O) {716  for (int i = opNum, e = MI->getNumOperands(); i != e; ++i) {717    if (i != opNum) O << ", ";718    printOperand(MI, i, O);719  }720}721 722void MipsAsmPrinter::emitStartOfAsmFile(Module &M) {723  const Triple &TT = TM.getTargetTriple();724 725  if (TT.isOSBinFormatELF()) {726    MipsTargetStreamer &TS = getTargetStreamer();727 728    // MipsTargetStreamer has an initialization order problem when emitting an729    // object file directly (see MipsTargetELFStreamer for full details). Work730    // around it by re-initializing the PIC state here.731    TS.setPic(OutContext.getObjectFileInfo()->isPositionIndependent());732 733    // Try to get target-features from the first function.734    StringRef FS = TM.getTargetFeatureString();735    Module::iterator F = M.begin();736    if (FS.empty() && M.size() && F->hasFnAttribute("target-features"))737      FS = F->getFnAttribute("target-features").getValueAsString();738 739    std::string strFS = FS.str();740    if (M.size() && F->getFnAttribute("use-soft-float").getValueAsBool())741      strFS += strFS.empty() ? "+soft-float" : ",+soft-float";742 743    // Compute MIPS architecture attributes based on the default subtarget744    // that we'd have constructed.745    // FIXME: For ifunc related functions we could iterate over and look746    // for a feature string that doesn't match the default one.747    StringRef CPU = MIPS_MC::selectMipsCPU(TT, TM.getTargetCPU());748    const MipsTargetMachine &MTM = static_cast<const MipsTargetMachine &>(TM);749    const MipsSubtarget STI(TT, CPU, StringRef(strFS), MTM.isLittleEndian(),750                            MTM, std::nullopt);751 752    bool IsABICalls = STI.isABICalls();753    const MipsABIInfo &ABI = MTM.getABI();754    if (IsABICalls) {755      TS.emitDirectiveAbiCalls();756      // FIXME: This condition should be a lot more complicated that it is here.757      //        Ideally it should test for properties of the ABI and not the ABI758      //        itself.759      //        For the moment, I'm only correcting enough to make MIPS-IV work.760      if (!isPositionIndependent() && STI.hasSym32())761        TS.emitDirectiveOptionPic0();762    }763 764    // Tell the assembler which ABI we are using765    std::string SectionName = std::string(".mdebug.") + getCurrentABIString();766    OutStreamer->switchSection(767        OutContext.getELFSection(SectionName, ELF::SHT_PROGBITS, 0));768 769    // NaN: At the moment we only support:770    // 1. .nan legacy (default)771    // 2. .nan 2008772    STI.isNaN2008() ? TS.emitDirectiveNaN2008() : TS.emitDirectiveNaNLegacy();773 774    // TODO: handle O64 ABI775 776    TS.updateABIInfo(STI);777 778    // We should always emit a '.module fp=...' but binutils 2.24 does not779    // accept it. We therefore emit it when it contradicts the ABI defaults780    // (-mfpxx or -mfp64) and omit it otherwise.781    if ((ABI.IsO32() && (STI.isABI_FPXX() || STI.isFP64bit())) ||782        STI.useSoftFloat())783      TS.emitDirectiveModuleFP();784 785    // We should always emit a '.module [no]oddspreg' but binutils 2.24 does not786    // accept it. We therefore emit it when it contradicts the default or an787    // option has changed the default (i.e. FPXX) and omit it otherwise.788    if (ABI.IsO32() && (!STI.useOddSPReg() || STI.isABI_FPXX()))789      TS.emitDirectiveModuleOddSPReg();790 791    // Switch to the .text section.792    OutStreamer->switchSection(getObjFileLowering().getTextSection());793  }794}795 796void MipsAsmPrinter::emitInlineAsmStart() const {797  MipsTargetStreamer &TS = getTargetStreamer();798 799  // GCC's choice of assembler options for inline assembly code ('at', 'macro'800  // and 'reorder') is different from LLVM's choice for generated code ('noat',801  // 'nomacro' and 'noreorder').802  // In order to maintain compatibility with inline assembly code which depends803  // on GCC's assembler options being used, we have to switch to those options804  // for the duration of the inline assembly block and then switch back.805  TS.emitDirectiveSetPush();806  TS.emitDirectiveSetAt();807  TS.emitDirectiveSetMacro();808  TS.emitDirectiveSetReorder();809  OutStreamer->addBlankLine();810}811 812void MipsAsmPrinter::emitInlineAsmEnd(const MCSubtargetInfo &StartInfo,813                                      const MCSubtargetInfo *EndInfo) const {814  OutStreamer->addBlankLine();815  getTargetStreamer().emitDirectiveSetPop();816}817 818void MipsAsmPrinter::emitJumpTableEntry(const MachineJumpTableInfo &MJTI,819                                        const MachineBasicBlock *MBB,820                                        unsigned uid) const {821  MCSymbol *MBBSym = MBB->getSymbol();822  switch (MJTI.getEntryKind()) {823  case MachineJumpTableInfo::EK_BlockAddress:824    OutStreamer->emitValue(MCSymbolRefExpr::create(MBBSym, OutContext),825                           getDataLayout().getPointerSize());826    break;827  case MachineJumpTableInfo::EK_GPRel32BlockAddress:828    // Each entry is a GP-relative value targeting the block symbol.829    getTargetStreamer().emitGPRel32Value(830        MCSymbolRefExpr::create(MBBSym, OutContext));831    break;832  case MachineJumpTableInfo::EK_GPRel64BlockAddress:833    getTargetStreamer().emitGPRel64Value(834        MCSymbolRefExpr::create(MBBSym, OutContext));835    break;836  default:837    llvm_unreachable("");838  }839}840 841void MipsAsmPrinter::EmitJal(const MCSubtargetInfo &STI, MCSymbol *Symbol) {842  MCInst I;843  I.setOpcode(Mips::JAL);844  I.addOperand(845      MCOperand::createExpr(MCSymbolRefExpr::create(Symbol, OutContext)));846  OutStreamer->emitInstruction(I, STI);847}848 849void MipsAsmPrinter::EmitInstrReg(const MCSubtargetInfo &STI, unsigned Opcode,850                                  unsigned Reg) {851  MCInst I;852  I.setOpcode(Opcode);853  I.addOperand(MCOperand::createReg(Reg));854  OutStreamer->emitInstruction(I, STI);855}856 857void MipsAsmPrinter::EmitInstrRegReg(const MCSubtargetInfo &STI,858                                     unsigned Opcode, unsigned Reg1,859                                     unsigned Reg2) {860  MCInst I;861  //862  // Because of the current td files for Mips32, the operands for MTC1863  // appear backwards from their normal assembly order. It's not a trivial864  // change to fix this in the td file so we adjust for it here.865  //866  if (Opcode == Mips::MTC1) {867    unsigned Temp = Reg1;868    Reg1 = Reg2;869    Reg2 = Temp;870  }871  I.setOpcode(Opcode);872  I.addOperand(MCOperand::createReg(Reg1));873  I.addOperand(MCOperand::createReg(Reg2));874  OutStreamer->emitInstruction(I, STI);875}876 877void MipsAsmPrinter::EmitInstrRegRegReg(const MCSubtargetInfo &STI,878                                        unsigned Opcode, unsigned Reg1,879                                        unsigned Reg2, unsigned Reg3) {880  MCInst I;881  I.setOpcode(Opcode);882  I.addOperand(MCOperand::createReg(Reg1));883  I.addOperand(MCOperand::createReg(Reg2));884  I.addOperand(MCOperand::createReg(Reg3));885  OutStreamer->emitInstruction(I, STI);886}887 888void MipsAsmPrinter::EmitMovFPIntPair(const MCSubtargetInfo &STI,889                                      unsigned MovOpc, unsigned Reg1,890                                      unsigned Reg2, unsigned FPReg1,891                                      unsigned FPReg2, bool LE) {892  if (!LE) {893    unsigned temp = Reg1;894    Reg1 = Reg2;895    Reg2 = temp;896  }897  EmitInstrRegReg(STI, MovOpc, Reg1, FPReg1);898  EmitInstrRegReg(STI, MovOpc, Reg2, FPReg2);899}900 901void MipsAsmPrinter::EmitSwapFPIntParams(const MCSubtargetInfo &STI,902                                         Mips16HardFloatInfo::FPParamVariant PV,903                                         bool LE, bool ToFP) {904  using namespace Mips16HardFloatInfo;905 906  unsigned MovOpc = ToFP ? Mips::MTC1 : Mips::MFC1;907  switch (PV) {908  case FSig:909    EmitInstrRegReg(STI, MovOpc, Mips::A0, Mips::F12);910    break;911  case FFSig:912    EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F14, LE);913    break;914  case FDSig:915    EmitInstrRegReg(STI, MovOpc, Mips::A0, Mips::F12);916    EmitMovFPIntPair(STI, MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE);917    break;918  case DSig:919    EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE);920    break;921  case DDSig:922    EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE);923    EmitMovFPIntPair(STI, MovOpc, Mips::A2, Mips::A3, Mips::F14, Mips::F15, LE);924    break;925  case DFSig:926    EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F12, Mips::F13, LE);927    EmitInstrRegReg(STI, MovOpc, Mips::A2, Mips::F14);928    break;929  case NoSig:930    return;931  }932}933 934void MipsAsmPrinter::EmitSwapFPIntRetval(935    const MCSubtargetInfo &STI, Mips16HardFloatInfo::FPReturnVariant RV,936    bool LE) {937  using namespace Mips16HardFloatInfo;938 939  unsigned MovOpc = Mips::MFC1;940  switch (RV) {941  case FRet:942    EmitInstrRegReg(STI, MovOpc, Mips::V0, Mips::F0);943    break;944  case DRet:945    EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE);946    break;947  case CFRet:948    EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE);949    break;950  case CDRet:951    EmitMovFPIntPair(STI, MovOpc, Mips::V0, Mips::V1, Mips::F0, Mips::F1, LE);952    EmitMovFPIntPair(STI, MovOpc, Mips::A0, Mips::A1, Mips::F2, Mips::F3, LE);953    break;954  case NoFPRet:955    break;956  }957}958 959void MipsAsmPrinter::EmitFPCallStub(960    const char *Symbol, const Mips16HardFloatInfo::FuncSignature *Signature) {961  using namespace Mips16HardFloatInfo;962 963  MCSymbol *MSymbol = OutContext.getOrCreateSymbol(StringRef(Symbol));964  bool LE = getDataLayout().isLittleEndian();965  // Construct a local MCSubtargetInfo here.966  // This is because the MachineFunction won't exist (but have not yet been967  // freed) and since we're at the global level we can use the default968  // constructed subtarget.969  std::unique_ptr<MCSubtargetInfo> STI(TM.getTarget().createMCSubtargetInfo(970      TM.getTargetTriple(), TM.getTargetCPU(), TM.getTargetFeatureString()));971 972  //973  // .global xxxx974  //975  OutStreamer->emitSymbolAttribute(MSymbol, MCSA_Global);976  const char *RetType;977  //978  // make the comment field identifying the return and parameter979  // types of the floating point stub980  // # Stub function to call rettype xxxx (params)981  //982  switch (Signature->RetSig) {983  case FRet:984    RetType = "float";985    break;986  case DRet:987    RetType = "double";988    break;989  case CFRet:990    RetType = "complex";991    break;992  case CDRet:993    RetType = "double complex";994    break;995  case NoFPRet:996    RetType = "";997    break;998  }999  const char *Parms;1000  switch (Signature->ParamSig) {1001  case FSig:1002    Parms = "float";1003    break;1004  case FFSig:1005    Parms = "float, float";1006    break;1007  case FDSig:1008    Parms = "float, double";1009    break;1010  case DSig:1011    Parms = "double";1012    break;1013  case DDSig:1014    Parms = "double, double";1015    break;1016  case DFSig:1017    Parms = "double, float";1018    break;1019  case NoSig:1020    Parms = "";1021    break;1022  }1023  OutStreamer->AddComment("\t# Stub function to call " + Twine(RetType) + " " +1024                          Twine(Symbol) + " (" + Twine(Parms) + ")");1025  //1026  // probably not necessary but we save and restore the current section state1027  //1028  OutStreamer->pushSection();1029  //1030  // .section mips16.call.fpxxxx,"ax",@progbits1031  //1032  MCSectionELF *M = OutContext.getELFSection(1033      ".mips16.call.fp." + std::string(Symbol), ELF::SHT_PROGBITS,1034      ELF::SHF_ALLOC | ELF::SHF_EXECINSTR);1035  OutStreamer->switchSection(M);1036  //1037  // .align 21038  //1039  OutStreamer->emitValueToAlignment(Align(4));1040  MipsTargetStreamer &TS = getTargetStreamer();1041  //1042  // .set nomips161043  // .set nomicromips1044  //1045  TS.emitDirectiveSetNoMips16();1046  TS.emitDirectiveSetNoMicroMips();1047  //1048  // .ent __call_stub_fp_xxxx1049  // .type  __call_stub_fp_xxxx,@function1050  //  __call_stub_fp_xxxx:1051  //1052  std::string x = "__call_stub_fp_" + std::string(Symbol);1053  MCSymbol *Stub = OutContext.getOrCreateSymbol(StringRef(x));1054  TS.emitDirectiveEnt(*Stub);1055  MCSymbol *MType =1056      OutContext.getOrCreateSymbol("__call_stub_fp_" + Twine(Symbol));1057  OutStreamer->emitSymbolAttribute(MType, MCSA_ELF_TypeFunction);1058  OutStreamer->emitLabel(Stub);1059 1060  // Only handle non-pic for now.1061  assert(!isPositionIndependent() &&1062         "should not be here if we are compiling pic");1063  TS.emitDirectiveSetReorder();1064  //1065  // We need to add a MipsMCExpr class to MCTargetDesc to fully implement1066  // stubs without raw text but this current patch is for compiler generated1067  // functions and they all return some value.1068  // The calling sequence for non pic is different in that case and we need1069  // to implement %lo and %hi in order to handle the case of no return value1070  // See the corresponding method in Mips16HardFloat for details.1071  //1072  // mov the return address to S2.1073  // we have no stack space to store it and we are about to make another call.1074  // We need to make sure that the enclosing function knows to save S21075  // This should have already been handled.1076  //1077  // Mov $18, $311078 1079  EmitInstrRegRegReg(*STI, Mips::OR, Mips::S2, Mips::RA, Mips::ZERO);1080 1081  EmitSwapFPIntParams(*STI, Signature->ParamSig, LE, true);1082 1083  // Jal xxxx1084  //1085  EmitJal(*STI, MSymbol);1086 1087  // fix return values1088  EmitSwapFPIntRetval(*STI, Signature->RetSig, LE);1089  //1090  // do the return1091  // if (Signature->RetSig == NoFPRet)1092  //  llvm_unreachable("should not be any stubs here with no return value");1093  // else1094  EmitInstrReg(*STI, Mips::JR, Mips::S2);1095 1096  MCSymbol *Tmp = OutContext.createTempSymbol();1097  OutStreamer->emitLabel(Tmp);1098  const MCSymbolRefExpr *E = MCSymbolRefExpr::create(Stub, OutContext);1099  const MCSymbolRefExpr *T = MCSymbolRefExpr::create(Tmp, OutContext);1100  const MCExpr *T_min_E = MCBinaryExpr::createSub(T, E, OutContext);1101  OutStreamer->emitELFSize(Stub, T_min_E);1102  TS.emitDirectiveEnd(x);1103  OutStreamer->popSection();1104}1105 1106void MipsAsmPrinter::emitEndOfAsmFile(Module &M) {1107  // Emit needed stubs1108  //1109  for (std::map<1110           const char *,1111           const Mips16HardFloatInfo::FuncSignature *>::const_iterator1112           it = StubsNeeded.begin();1113       it != StubsNeeded.end(); ++it) {1114    const char *Symbol = it->first;1115    const Mips16HardFloatInfo::FuncSignature *Signature = it->second;1116    EmitFPCallStub(Symbol, Signature);1117  }1118  // return to the text section1119  OutStreamer->switchSection(OutContext.getObjectFileInfo()->getTextSection());1120}1121 1122void MipsAsmPrinter::EmitSled(const MachineInstr &MI, SledKind Kind) {1123  const uint8_t NoopsInSledCount = Subtarget->isGP64bit() ? 15 : 11;1124  // For mips32 we want to emit the following pattern:1125  //1126  // .Lxray_sled_N:1127  //   ALIGN1128  //   B .tmpN1129  //   11 NOP instructions (44 bytes)1130  //   ADDIU T9, T9, 521131  // .tmpN1132  //1133  // We need the 44 bytes (11 instructions) because at runtime, we'd1134  // be patching over the full 48 bytes (12 instructions) with the following1135  // pattern:1136  //1137  //   ADDIU    SP, SP, -81138  //   NOP1139  //   SW       RA, 4(SP)1140  //   SW       T9, 0(SP)1141  //   LUI      T9, %hi(__xray_FunctionEntry/Exit)1142  //   ORI      T9, T9, %lo(__xray_FunctionEntry/Exit)1143  //   LUI      T0, %hi(function_id)1144  //   JALR     T91145  //   ORI      T0, T0, %lo(function_id)1146  //   LW       T9, 0(SP)1147  //   LW       RA, 4(SP)1148  //   ADDIU    SP, SP, 81149  //1150  // We add 52 bytes to t9 because we want to adjust the function pointer to1151  // the actual start of function i.e. the address just after the noop sled.1152  // We do this because gp displacement relocation is emitted at the start of1153  // of the function i.e after the nop sled and to correctly calculate the1154  // global offset table address, t9 must hold the address of the instruction1155  // containing the gp displacement relocation.1156  // FIXME: Is this correct for the static relocation model?1157  //1158  // For mips64 we want to emit the following pattern:1159  //1160  // .Lxray_sled_N:1161  //   ALIGN1162  //   B .tmpN1163  //   15 NOP instructions (60 bytes)1164  // .tmpN1165  //1166  // We need the 60 bytes (15 instructions) because at runtime, we'd1167  // be patching over the full 64 bytes (16 instructions) with the following1168  // pattern:1169  //1170  //   DADDIU   SP, SP, -161171  //   NOP1172  //   SD       RA, 8(SP)1173  //   SD       T9, 0(SP)1174  //   LUI      T9, %highest(__xray_FunctionEntry/Exit)1175  //   ORI      T9, T9, %higher(__xray_FunctionEntry/Exit)1176  //   DSLL     T9, T9, 161177  //   ORI      T9, T9, %hi(__xray_FunctionEntry/Exit)1178  //   DSLL     T9, T9, 161179  //   ORI      T9, T9, %lo(__xray_FunctionEntry/Exit)1180  //   LUI      T0, %hi(function_id)1181  //   JALR     T91182  //   ADDIU    T0, T0, %lo(function_id)1183  //   LD       T9, 0(SP)1184  //   LD       RA, 8(SP)1185  //   DADDIU   SP, SP, 161186  //1187  OutStreamer->emitCodeAlignment(Align(4), &getSubtargetInfo());1188  auto CurSled = OutContext.createTempSymbol("xray_sled_", true);1189  OutStreamer->emitLabel(CurSled);1190  auto Target = OutContext.createTempSymbol();1191 1192  // Emit "B .tmpN" instruction, which jumps over the nop sled to the actual1193  // start of function1194  const MCExpr *TargetExpr = MCSymbolRefExpr::create(Target, OutContext);1195  EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::BEQ)1196                                   .addReg(Mips::ZERO)1197                                   .addReg(Mips::ZERO)1198                                   .addExpr(TargetExpr));1199 1200  for (int8_t I = 0; I < NoopsInSledCount; I++)1201    EmitToStreamer(*OutStreamer, MCInstBuilder(Mips::SLL)1202                                     .addReg(Mips::ZERO)1203                                     .addReg(Mips::ZERO)1204                                     .addImm(0));1205 1206  OutStreamer->emitLabel(Target);1207 1208  if (!Subtarget->isGP64bit()) {1209    EmitToStreamer(*OutStreamer,1210                   MCInstBuilder(Mips::ADDiu)1211                       .addReg(Mips::T9)1212                       .addReg(Mips::T9)1213                       .addImm(0x34));1214  }1215 1216  recordSled(CurSled, MI, Kind, 2);1217}1218 1219void MipsAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI) {1220  EmitSled(MI, SledKind::FUNCTION_ENTER);1221}1222 1223void MipsAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) {1224  EmitSled(MI, SledKind::FUNCTION_EXIT);1225}1226 1227void MipsAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) {1228  EmitSled(MI, SledKind::TAIL_CALL);1229}1230 1231void MipsAsmPrinter::PrintDebugValueComment(const MachineInstr *MI,1232                                           raw_ostream &OS) {1233  // TODO: implement1234}1235 1236// Emit .dtprelword or .dtpreldword directive1237// and value for debug thread local expression.1238void MipsAsmPrinter::emitDebugValue(const MCExpr *Value, unsigned Size) const {1239  if (auto *MipsExpr = dyn_cast<MCSpecifierExpr>(Value)) {1240    if (MipsExpr && MipsExpr->getSpecifier() == Mips::S_DTPREL) {1241      switch (Size) {1242      case 4:1243        getTargetStreamer().emitDTPRel32Value(MipsExpr->getSubExpr());1244        break;1245      case 8:1246        getTargetStreamer().emitDTPRel64Value(MipsExpr->getSubExpr());1247        break;1248      default:1249        llvm_unreachable("Unexpected size of expression value.");1250      }1251      return;1252    }1253  }1254  AsmPrinter::emitDebugValue(Value, Size);1255}1256 1257bool MipsAsmPrinter::isLongBranchPseudo(int Opcode) const {1258  return (Opcode == Mips::LONG_BRANCH_LUi1259          || Opcode == Mips::LONG_BRANCH_LUi2Op1260          || Opcode == Mips::LONG_BRANCH_LUi2Op_641261          || Opcode == Mips::LONG_BRANCH_ADDiu1262          || Opcode == Mips::LONG_BRANCH_ADDiu2Op1263          || Opcode == Mips::LONG_BRANCH_DADDiu1264          || Opcode == Mips::LONG_BRANCH_DADDiu2Op);1265}1266 1267char MipsAsmPrinter::ID = 0;1268 1269INITIALIZE_PASS(MipsAsmPrinter, "mips-asm-printer", "Mips Assembly Printer",1270                false, false)1271 1272// Force static initialization.1273extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void1274LLVMInitializeMipsAsmPrinter() {1275  RegisterAsmPrinter<MipsAsmPrinter> X(getTheMipsTarget());1276  RegisterAsmPrinter<MipsAsmPrinter> Y(getTheMipselTarget());1277  RegisterAsmPrinter<MipsAsmPrinter> A(getTheMips64Target());1278  RegisterAsmPrinter<MipsAsmPrinter> B(getTheMips64elTarget());1279}1280