brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.7 KiB · 08fa51d Raw
326 lines · cpp
1//=- LoongArchMCCodeEmitter.cpp - Convert LoongArch code to machine code --===//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 implements the LoongArchMCCodeEmitter class.10//11//===----------------------------------------------------------------------===//12 13#include "LoongArchFixupKinds.h"14#include "MCTargetDesc/LoongArchMCAsmInfo.h"15#include "MCTargetDesc/LoongArchMCTargetDesc.h"16#include "llvm/BinaryFormat/ELF.h"17#include "llvm/MC/MCCodeEmitter.h"18#include "llvm/MC/MCContext.h"19#include "llvm/MC/MCInstBuilder.h"20#include "llvm/MC/MCInstrInfo.h"21#include "llvm/MC/MCRegisterInfo.h"22#include "llvm/MC/MCSubtargetInfo.h"23#include "llvm/Support/Casting.h"24#include "llvm/Support/EndianStream.h"25 26using namespace llvm;27 28#define DEBUG_TYPE "mccodeemitter"29 30namespace {31class LoongArchMCCodeEmitter : public MCCodeEmitter {32  LoongArchMCCodeEmitter(const LoongArchMCCodeEmitter &) = delete;33  void operator=(const LoongArchMCCodeEmitter &) = delete;34  MCContext &Ctx;35  MCInstrInfo const &MCII;36 37public:38  LoongArchMCCodeEmitter(MCContext &ctx, MCInstrInfo const &MCII)39      : Ctx(ctx), MCII(MCII) {}40 41  ~LoongArchMCCodeEmitter() override = default;42 43  void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,44                         SmallVectorImpl<MCFixup> &Fixups,45                         const MCSubtargetInfo &STI) const override;46 47  template <unsigned Opc>48  void expandToVectorLDI(const MCInst &MI, SmallVectorImpl<char> &CB,49                         SmallVectorImpl<MCFixup> &Fixups,50                         const MCSubtargetInfo &STI) const;51 52  void expandAddTPRel(const MCInst &MI, SmallVectorImpl<char> &CB,53                      SmallVectorImpl<MCFixup> &Fixups,54                      const MCSubtargetInfo &STI) const;55 56  /// TableGen'erated function for getting the binary encoding for an57  /// instruction.58  uint64_t getBinaryCodeForInstr(const MCInst &MI,59                                 SmallVectorImpl<MCFixup> &Fixups,60                                 const MCSubtargetInfo &STI) const;61 62  /// Return binary encoding of operand. If the machine operand requires63  /// relocation, record the relocation and return zero.64  unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,65                             SmallVectorImpl<MCFixup> &Fixups,66                             const MCSubtargetInfo &STI) const;67 68  /// Return binary encoding of an immediate operand specified by OpNo.69  /// The value returned is the value of the immediate minus 1.70  /// Note that this function is dedicated to specific immediate types,71  /// e.g. uimm2_plus1.72  unsigned getImmOpValueSub1(const MCInst &MI, unsigned OpNo,73                             SmallVectorImpl<MCFixup> &Fixups,74                             const MCSubtargetInfo &STI) const;75 76  /// Return binary encoding of an immediate operand specified by OpNo.77  /// The value returned is the value of the immediate shifted right78  //  arithmetically by N.79  /// Note that this function is dedicated to specific immediate types,80  /// e.g. simm14_lsl2, simm16_lsl2, simm21_lsl2 and simm26_lsl2.81  template <unsigned N>82  unsigned getImmOpValueAsr(const MCInst &MI, unsigned OpNo,83                            SmallVectorImpl<MCFixup> &Fixups,84                            const MCSubtargetInfo &STI) const {85    const MCOperand &MO = MI.getOperand(OpNo);86    if (MO.isImm()) {87      unsigned Res = MI.getOperand(OpNo).getImm();88      assert((Res & ((1U << N) - 1U)) == 0 && "lowest N bits are non-zero");89      return Res >> N;90    }91    return getExprOpValue(MI, MO, Fixups, STI);92  }93 94  unsigned getExprOpValue(const MCInst &MI, const MCOperand &MO,95                          SmallVectorImpl<MCFixup> &Fixups,96                          const MCSubtargetInfo &STI) const;97};98} // end namespace99 100static void addFixup(SmallVectorImpl<MCFixup> &Fixups, uint32_t Offset,101                     const MCExpr *Value, uint16_t Kind) {102  bool PCRel = false;103  switch (Kind) {104  case LoongArch::fixup_loongarch_b16:105  case LoongArch::fixup_loongarch_b21:106  case LoongArch::fixup_loongarch_b26:107    PCRel = true;108  }109  Fixups.push_back(MCFixup::create(Offset, Value, Kind, PCRel));110}111 112unsigned113LoongArchMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO,114                                          SmallVectorImpl<MCFixup> &Fixups,115                                          const MCSubtargetInfo &STI) const {116 117  if (MO.isReg())118    return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg());119 120  if (MO.isImm())121    return static_cast<unsigned>(MO.getImm());122 123  // MO must be an Expr.124  assert(MO.isExpr());125  return getExprOpValue(MI, MO, Fixups, STI);126}127 128unsigned129LoongArchMCCodeEmitter::getImmOpValueSub1(const MCInst &MI, unsigned OpNo,130                                          SmallVectorImpl<MCFixup> &Fixups,131                                          const MCSubtargetInfo &STI) const {132  return MI.getOperand(OpNo).getImm() - 1;133}134 135unsigned136LoongArchMCCodeEmitter::getExprOpValue(const MCInst &MI, const MCOperand &MO,137                                       SmallVectorImpl<MCFixup> &Fixups,138                                       const MCSubtargetInfo &STI) const {139  assert(MO.isExpr() && "getExprOpValue expects only expressions");140  bool RelaxCandidate = false;141  bool EnableRelax = STI.hasFeature(LoongArch::FeatureRelax);142  const MCExpr *Expr = MO.getExpr();143  MCExpr::ExprKind Kind = Expr->getKind();144  unsigned FixupKind = LoongArch::fixup_loongarch_invalid;145  if (Kind == MCExpr::Specifier) {146    const LoongArchMCExpr *LAExpr = cast<LoongArchMCExpr>(Expr);147    FixupKind = LAExpr->getSpecifier();148    RelaxCandidate = LAExpr->getRelaxHint();149    switch (uint16_t(LAExpr->getSpecifier())) {150    case LoongArchMCExpr::VK_None:151      llvm_unreachable("Unhandled fixup kind!");152    case ELF::R_LARCH_TLS_LE_ADD_R:153      llvm_unreachable("ELF::R_LARCH_TLS_LE_ADD_R should not represent an "154                       "instruction operand");155    case ELF::R_LARCH_B16:156      FixupKind = LoongArch::fixup_loongarch_b16;157      break;158    case ELF::R_LARCH_B21:159      FixupKind = LoongArch::fixup_loongarch_b21;160      break;161    case ELF::R_LARCH_B26:162      FixupKind = LoongArch::fixup_loongarch_b26;163      break;164    case ELF::R_LARCH_MARK_LA:165      // Match gas behavior: generate `R_LARCH_MARK_LA` relocation when using166      // `la.abs`.167      Fixups.push_back(168          MCFixup::create(0, MCConstantExpr::create(0, Ctx),169                          FirstLiteralRelocationKind + ELF::R_LARCH_MARK_LA));170      [[fallthrough]];171    case ELF::R_LARCH_ABS_HI20:172      FixupKind = LoongArch::fixup_loongarch_abs_hi20;173      break;174    case ELF::R_LARCH_ABS_LO12:175      FixupKind = LoongArch::fixup_loongarch_abs_lo12;176      break;177    case ELF::R_LARCH_ABS64_LO20:178      FixupKind = LoongArch::fixup_loongarch_abs64_lo20;179      break;180    case ELF::R_LARCH_ABS64_HI12:181      FixupKind = LoongArch::fixup_loongarch_abs64_hi12;182      break;183    case ELF::R_LARCH_CALL36:184    case ELF::R_LARCH_TLS_LE_HI20_R:185    case ELF::R_LARCH_TLS_LE_LO12_R:186      RelaxCandidate = true;187      break;188    }189  } else if (Kind == MCExpr::SymbolRef) {190    switch (MI.getOpcode()) {191    default:192      break;193    case LoongArch::BEQ:194    case LoongArch::BNE:195    case LoongArch::BLT:196    case LoongArch::BGE:197    case LoongArch::BLTU:198    case LoongArch::BGEU:199      FixupKind = LoongArch::fixup_loongarch_b16;200      break;201    case LoongArch::BEQZ:202    case LoongArch::BNEZ:203    case LoongArch::BCEQZ:204    case LoongArch::BCNEZ:205      FixupKind = LoongArch::fixup_loongarch_b21;206      break;207    case LoongArch::B:208    case LoongArch::BL:209      FixupKind = LoongArch::fixup_loongarch_b26;210      break;211    }212  }213 214  assert(FixupKind != LoongArch::fixup_loongarch_invalid &&215         "Unhandled expression!");216 217  addFixup(Fixups, 0, Expr, FixupKind);218  // If linker relaxation is enabled and supported by this relocation, set219  // a bit so that if fixup is unresolved, a R_LARCH_RELAX relocation will be220  // appended.221  if (EnableRelax && RelaxCandidate)222    Fixups.back().setLinkerRelaxable();223 224  return 0;225}226 227template <unsigned Opc>228void LoongArchMCCodeEmitter::expandToVectorLDI(229    const MCInst &MI, SmallVectorImpl<char> &CB,230    SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {231  int64_t Imm = MI.getOperand(1).getImm() & 0x3FF;232  switch (MI.getOpcode()) {233  case LoongArch::PseudoVREPLI_B:234  case LoongArch::PseudoXVREPLI_B:235    break;236  case LoongArch::PseudoVREPLI_H:237  case LoongArch::PseudoXVREPLI_H:238    Imm |= 0x400;239    break;240  case LoongArch::PseudoVREPLI_W:241  case LoongArch::PseudoXVREPLI_W:242    Imm |= 0x800;243    break;244  case LoongArch::PseudoVREPLI_D:245  case LoongArch::PseudoXVREPLI_D:246    Imm |= 0xC00;247    break;248  }249  MCInst TmpInst = MCInstBuilder(Opc).addOperand(MI.getOperand(0)).addImm(Imm);250  uint32_t Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI);251  support::endian::write(CB, Binary, llvm::endianness::little);252}253 254void LoongArchMCCodeEmitter::expandAddTPRel(const MCInst &MI,255                                            SmallVectorImpl<char> &CB,256                                            SmallVectorImpl<MCFixup> &Fixups,257                                            const MCSubtargetInfo &STI) const {258  MCOperand Rd = MI.getOperand(0);259  MCOperand Rj = MI.getOperand(1);260  MCOperand Rk = MI.getOperand(2);261  MCOperand Symbol = MI.getOperand(3);262  assert(Symbol.isExpr() &&263         "Expected expression as third input to TP-relative add");264 265  const LoongArchMCExpr *Expr = dyn_cast<LoongArchMCExpr>(Symbol.getExpr());266  assert(Expr && Expr->getSpecifier() == ELF::R_LARCH_TLS_LE_ADD_R &&267         "Expected %le_add_r relocation on TP-relative symbol");268 269  // Emit the correct %le_add_r relocation for the symbol.270  addFixup(Fixups, 0, Expr, ELF::R_LARCH_TLS_LE_ADD_R);271  if (STI.hasFeature(LoongArch::FeatureRelax))272    Fixups.back().setLinkerRelaxable();273 274  // Emit a normal ADD instruction with the given operands.275  unsigned ADD = MI.getOpcode() == LoongArch::PseudoAddTPRel_D276                     ? LoongArch::ADD_D277                     : LoongArch::ADD_W;278  MCInst TmpInst =279      MCInstBuilder(ADD).addOperand(Rd).addOperand(Rj).addOperand(Rk);280  uint32_t Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI);281  support::endian::write(CB, Binary, llvm::endianness::little);282}283 284void LoongArchMCCodeEmitter::encodeInstruction(285    const MCInst &MI, SmallVectorImpl<char> &CB,286    SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {287  const MCInstrDesc &Desc = MCII.get(MI.getOpcode());288  // Get byte count of instruction.289  unsigned Size = Desc.getSize();290 291  switch (MI.getOpcode()) {292  default:293    break;294  case LoongArch::PseudoVREPLI_B:295  case LoongArch::PseudoVREPLI_H:296  case LoongArch::PseudoVREPLI_W:297  case LoongArch::PseudoVREPLI_D:298    return expandToVectorLDI<LoongArch::VLDI>(MI, CB, Fixups, STI);299  case LoongArch::PseudoXVREPLI_B:300  case LoongArch::PseudoXVREPLI_H:301  case LoongArch::PseudoXVREPLI_W:302  case LoongArch::PseudoXVREPLI_D:303    return expandToVectorLDI<LoongArch::XVLDI>(MI, CB, Fixups, STI);304  case LoongArch::PseudoAddTPRel_W:305  case LoongArch::PseudoAddTPRel_D:306    return expandAddTPRel(MI, CB, Fixups, STI);307  }308 309  switch (Size) {310  default:311    llvm_unreachable("Unhandled encodeInstruction length!");312  case 4: {313    uint32_t Bits = getBinaryCodeForInstr(MI, Fixups, STI);314    support::endian::write(CB, Bits, llvm::endianness::little);315    break;316  }317  }318}319 320MCCodeEmitter *llvm::createLoongArchMCCodeEmitter(const MCInstrInfo &MCII,321                                                  MCContext &Ctx) {322  return new LoongArchMCCodeEmitter(Ctx, MCII);323}324 325#include "LoongArchGenMCCodeEmitter.inc"326