brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.8 KiB · 2ab2a98 Raw
318 lines · cpp
1//===- LoongArchAsmPrinter.cpp - LoongArch LLVM Assembly Printer -*- C++ -*--=//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 LoongArch assembly language.11//12//===----------------------------------------------------------------------===//13 14#include "LoongArchAsmPrinter.h"15#include "LoongArch.h"16#include "LoongArchMachineFunctionInfo.h"17#include "MCTargetDesc/LoongArchInstPrinter.h"18#include "MCTargetDesc/LoongArchMCTargetDesc.h"19#include "TargetInfo/LoongArchTargetInfo.h"20#include "llvm/CodeGen/AsmPrinter.h"21#include "llvm/CodeGen/MachineJumpTableInfo.h"22#include "llvm/CodeGen/MachineModuleInfoImpls.h"23#include "llvm/MC/MCAsmInfo.h"24#include "llvm/MC/MCContext.h"25#include "llvm/MC/MCInstBuilder.h"26#include "llvm/MC/MCSectionELF.h"27#include "llvm/MC/TargetRegistry.h"28#include "llvm/Support/Compiler.h"29 30using namespace llvm;31 32#define DEBUG_TYPE "loongarch-asm-printer"33 34cl::opt<bool> LArchAnnotateTableJump(35    "loongarch-annotate-tablejump", cl::Hidden,36    cl::desc(37        "Annotate table jump instruction to correlate it with the jump table."),38    cl::init(false));39 40// Simple pseudo-instructions have their lowering (with expansion to real41// instructions) auto-generated.42#include "LoongArchGenMCPseudoLowering.inc"43 44void LoongArchAsmPrinter::emitInstruction(const MachineInstr *MI) {45  LoongArch_MC::verifyInstructionPredicates(46      MI->getOpcode(), getSubtargetInfo().getFeatureBits());47 48  // Do any auto-generated pseudo lowerings.49  if (MCInst OutInst; lowerPseudoInstExpansion(MI, OutInst)) {50    EmitToStreamer(*OutStreamer, OutInst);51    return;52  }53 54  switch (MI->getOpcode()) {55  case TargetOpcode::STATEPOINT:56    LowerSTATEPOINT(*MI);57    return;58  case TargetOpcode::PATCHABLE_FUNCTION_ENTER:59    LowerPATCHABLE_FUNCTION_ENTER(*MI);60    return;61  case TargetOpcode::PATCHABLE_FUNCTION_EXIT:62    LowerPATCHABLE_FUNCTION_EXIT(*MI);63    return;64  case TargetOpcode::PATCHABLE_TAIL_CALL:65    LowerPATCHABLE_TAIL_CALL(*MI);66    return;67  }68 69  MCInst TmpInst;70  if (!lowerLoongArchMachineInstrToMCInst(MI, TmpInst, *this))71    EmitToStreamer(*OutStreamer, TmpInst);72}73 74bool LoongArchAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,75                                          const char *ExtraCode,76                                          raw_ostream &OS) {77  // First try the generic code, which knows about modifiers like 'c' and 'n'.78  if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))79    return false;80 81  const MachineOperand &MO = MI->getOperand(OpNo);82  if (ExtraCode && ExtraCode[0]) {83    if (ExtraCode[1] != 0)84      return true; // Unknown modifier.85 86    switch (ExtraCode[0]) {87    default:88      return true; // Unknown modifier.89    case 'z':      // Print $zero register if zero, regular printing otherwise.90      if (MO.isImm() && MO.getImm() == 0) {91        OS << '$' << LoongArchInstPrinter::getRegisterName(LoongArch::R0);92        return false;93      }94      break;95    case 'u': // Print LASX registers.96    case 'w': // Print LSX registers.97    {98      // If the operand is an LASX, LSX or floating point register, print the99      // name of LASX or LSX register with the same index in that register100      // class.101      unsigned RegID = MO.getReg().id(), FirstReg;102      if (RegID >= LoongArch::XR0 && RegID <= LoongArch::XR31)103        FirstReg = LoongArch::XR0;104      else if (RegID >= LoongArch::VR0 && RegID <= LoongArch::VR31)105        FirstReg = LoongArch::VR0;106      else if (RegID >= LoongArch::F0_64 && RegID <= LoongArch::F31_64)107        FirstReg = LoongArch::F0_64;108      else if (RegID >= LoongArch::F0 && RegID <= LoongArch::F31)109        FirstReg = LoongArch::F0;110      else111        return true;112      OS << '$'113         << LoongArchInstPrinter::getRegisterName(114                RegID - FirstReg +115                (ExtraCode[0] == 'u' ? LoongArch::XR0 : LoongArch::VR0));116      return false;117    }118      // TODO: handle other extra codes if any.119    }120  }121 122  switch (MO.getType()) {123  case MachineOperand::MO_Immediate:124    OS << MO.getImm();125    return false;126  case MachineOperand::MO_Register:127    OS << '$' << LoongArchInstPrinter::getRegisterName(MO.getReg());128    return false;129  case MachineOperand::MO_GlobalAddress:130    PrintSymbolOperand(MO, OS);131    return false;132  default:133    llvm_unreachable("not implemented");134  }135 136  return true;137}138 139bool LoongArchAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,140                                                unsigned OpNo,141                                                const char *ExtraCode,142                                                raw_ostream &OS) {143  // TODO: handle extra code.144  if (ExtraCode)145    return true;146 147  // We only support memory operands like "Base + Offset", where base must be a148  // register, and offset can be a register or an immediate value.149  const MachineOperand &BaseMO = MI->getOperand(OpNo);150  // Base address must be a register.151  if (!BaseMO.isReg())152    return true;153  // Print the base address register.154  OS << "$" << LoongArchInstPrinter::getRegisterName(BaseMO.getReg());155  // Print the offset operand.156  const MachineOperand &OffsetMO = MI->getOperand(OpNo + 1);157  MCOperand MCO;158  if (!lowerOperand(OffsetMO, MCO))159    return true;160  if (OffsetMO.isReg())161    OS << ", $" << LoongArchInstPrinter::getRegisterName(OffsetMO.getReg());162  else if (OffsetMO.isImm())163    OS << ", " << OffsetMO.getImm();164  else if (OffsetMO.isGlobal() || OffsetMO.isBlockAddress() ||165           OffsetMO.isMCSymbol() || OffsetMO.isCPI()) {166    OS << ", ";167    MAI->printExpr(OS, *MCO.getExpr());168  } else169    return true;170 171  return false;172}173 174void LoongArchAsmPrinter::LowerSTATEPOINT(const MachineInstr &MI) {175  StatepointOpers SOpers(&MI);176  if (unsigned PatchBytes = SOpers.getNumPatchBytes()) {177    assert(PatchBytes % 4 == 0 && "Invalid number of NOP bytes requested!");178    emitNops(PatchBytes / 4);179  } else {180    // Lower call target and choose correct opcode.181    const MachineOperand &CallTarget = SOpers.getCallTarget();182    MCOperand CallTargetMCOp;183    switch (CallTarget.getType()) {184    case MachineOperand::MO_GlobalAddress:185    case MachineOperand::MO_ExternalSymbol:186      lowerOperand(CallTarget, CallTargetMCOp);187      EmitToStreamer(*OutStreamer,188                     MCInstBuilder(LoongArch::BL).addOperand(CallTargetMCOp));189      break;190    case MachineOperand::MO_Immediate:191      CallTargetMCOp = MCOperand::createImm(CallTarget.getImm());192      EmitToStreamer(*OutStreamer,193                     MCInstBuilder(LoongArch::BL).addOperand(CallTargetMCOp));194      break;195    case MachineOperand::MO_Register:196      CallTargetMCOp = MCOperand::createReg(CallTarget.getReg());197      EmitToStreamer(*OutStreamer, MCInstBuilder(LoongArch::JIRL)198                                       .addReg(LoongArch::R1)199                                       .addOperand(CallTargetMCOp)200                                       .addImm(0));201      break;202    default:203      llvm_unreachable("Unsupported operand type in statepoint call target");204      break;205    }206  }207 208  auto &Ctx = OutStreamer->getContext();209  MCSymbol *MILabel = Ctx.createTempSymbol();210  OutStreamer->emitLabel(MILabel);211  SM.recordStatepoint(*MILabel, MI);212}213 214void LoongArchAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(215    const MachineInstr &MI) {216  const Function &F = MF->getFunction();217  if (F.hasFnAttribute("patchable-function-entry")) {218    unsigned Num;219    if (F.getFnAttribute("patchable-function-entry")220            .getValueAsString()221            .getAsInteger(10, Num))222      return;223    emitNops(Num);224    return;225  }226 227  emitSled(MI, SledKind::FUNCTION_ENTER);228}229 230void LoongArchAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) {231  emitSled(MI, SledKind::FUNCTION_EXIT);232}233 234void LoongArchAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) {235  emitSled(MI, SledKind::TAIL_CALL);236}237 238void LoongArchAsmPrinter::emitSled(const MachineInstr &MI, SledKind Kind) {239  // For loongarch64 we want to emit the following pattern:240  //241  // .Lxray_sled_beginN:242  //   B .Lxray_sled_endN243  //   11 NOPs (44 bytes)244  // .Lxray_sled_endN:245  //246  // We need the extra bytes because at runtime they may be used for the247  // actual pattern defined at compiler-rt/lib/xray/xray_loongarch64.cpp.248  // The count here should be adjusted accordingly if the implementation249  // changes.250  const int8_t NoopsInSledCount = 11;251  OutStreamer->emitCodeAlignment(Align(4), &getSubtargetInfo());252  MCSymbol *BeginOfSled = OutContext.createTempSymbol("xray_sled_begin");253  MCSymbol *EndOfSled = OutContext.createTempSymbol("xray_sled_end");254  OutStreamer->emitLabel(BeginOfSled);255  EmitToStreamer(*OutStreamer,256                 MCInstBuilder(LoongArch::B)257                     .addExpr(MCSymbolRefExpr::create(EndOfSled, OutContext)));258  emitNops(NoopsInSledCount);259  OutStreamer->emitLabel(EndOfSled);260  recordSled(BeginOfSled, MI, Kind, 2);261}262 263void LoongArchAsmPrinter::emitJumpTableInfo() {264  AsmPrinter::emitJumpTableInfo();265 266  if (!LArchAnnotateTableJump)267    return;268 269  assert(TM.getTargetTriple().isOSBinFormatELF());270 271  auto *LAFI = MF->getInfo<LoongArchMachineFunctionInfo>();272  unsigned EntrySize = LAFI->getJumpInfoSize();273  auto JTI = MF->getJumpTableInfo();274 275  if (!JTI || 0 == EntrySize)276    return;277 278  unsigned Size = getDataLayout().getPointerSize();279  auto JT = JTI->getJumpTables();280 281  // Emit an additional section to store the correlation info as pairs of282  // addresses, each pair contains the address of a jump instruction (jr) and283  // the address of the jump table.284  OutStreamer->switchSection(MMI->getContext().getELFSection(285      ".discard.tablejump_annotate", ELF::SHT_PROGBITS, 0));286 287  for (unsigned Idx = 0; Idx < EntrySize; ++Idx) {288    int JTIIdx = LAFI->getJumpInfoJTIIndex(Idx);289    if (JT[JTIIdx].MBBs.empty())290      continue;291    OutStreamer->emitValue(292        MCSymbolRefExpr::create(LAFI->getJumpInfoJrMI(Idx)->getPreInstrSymbol(),293                                OutContext),294        Size);295    OutStreamer->emitValue(296        MCSymbolRefExpr::create(GetJTISymbol(JTIIdx), OutContext), Size);297  }298}299 300bool LoongArchAsmPrinter::runOnMachineFunction(MachineFunction &MF) {301  AsmPrinter::runOnMachineFunction(MF);302  // Emit the XRay table for this function.303  emitXRayTable();304  return true;305}306 307char LoongArchAsmPrinter::ID = 0;308 309INITIALIZE_PASS(LoongArchAsmPrinter, "loongarch-asm-printer",310                "LoongArch Assembly Printer", false, false)311 312// Force static initialization.313extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void314LLVMInitializeLoongArchAsmPrinter() {315  RegisterAsmPrinter<LoongArchAsmPrinter> X(getTheLoongArch32Target());316  RegisterAsmPrinter<LoongArchAsmPrinter> Y(getTheLoongArch64Target());317}318