357 lines
13 KiB
C++
357 lines
13 KiB
C++
//=- LoongArchMCCodeEmitter.cpp - Convert LoongArch code to machine code --===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements the LoongArchMCCodeEmitter class.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "LoongArchFixupKinds.h"
|
|
#include "MCTargetDesc/LoongArchBaseInfo.h"
|
|
#include "MCTargetDesc/LoongArchMCExpr.h"
|
|
#include "MCTargetDesc/LoongArchMCTargetDesc.h"
|
|
#include "llvm/MC/MCCodeEmitter.h"
|
|
#include "llvm/MC/MCContext.h"
|
|
#include "llvm/MC/MCInstBuilder.h"
|
|
#include "llvm/MC/MCInstrInfo.h"
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
|
#include "llvm/MC/MCSubtargetInfo.h"
|
|
#include "llvm/Support/Casting.h"
|
|
#include "llvm/Support/EndianStream.h"
|
|
|
|
using namespace llvm;
|
|
|
|
#define DEBUG_TYPE "mccodeemitter"
|
|
|
|
namespace {
|
|
class LoongArchMCCodeEmitter : public MCCodeEmitter {
|
|
LoongArchMCCodeEmitter(const LoongArchMCCodeEmitter &) = delete;
|
|
void operator=(const LoongArchMCCodeEmitter &) = delete;
|
|
MCContext &Ctx;
|
|
MCInstrInfo const &MCII;
|
|
|
|
public:
|
|
LoongArchMCCodeEmitter(MCContext &ctx, MCInstrInfo const &MCII)
|
|
: Ctx(ctx), MCII(MCII) {}
|
|
|
|
~LoongArchMCCodeEmitter() override {}
|
|
|
|
void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
const MCSubtargetInfo &STI) const override;
|
|
|
|
template <unsigned Opc>
|
|
void expandToVectorLDI(const MCInst &MI, SmallVectorImpl<char> &CB,
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
const MCSubtargetInfo &STI) const;
|
|
|
|
/// TableGen'erated function for getting the binary encoding for an
|
|
/// instruction.
|
|
uint64_t getBinaryCodeForInstr(const MCInst &MI,
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
const MCSubtargetInfo &STI) const;
|
|
|
|
/// Return binary encoding of operand. If the machine operand requires
|
|
/// relocation, record the relocation and return zero.
|
|
unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
const MCSubtargetInfo &STI) const;
|
|
|
|
/// Return binary encoding of an immediate operand specified by OpNo.
|
|
/// The value returned is the value of the immediate minus 1.
|
|
/// Note that this function is dedicated to specific immediate types,
|
|
/// e.g. uimm2_plus1.
|
|
unsigned getImmOpValueSub1(const MCInst &MI, unsigned OpNo,
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
const MCSubtargetInfo &STI) const;
|
|
|
|
/// Return binary encoding of an immediate operand specified by OpNo.
|
|
/// The value returned is the value of the immediate shifted right
|
|
// arithmetically by N.
|
|
/// Note that this function is dedicated to specific immediate types,
|
|
/// e.g. simm14_lsl2, simm16_lsl2, simm21_lsl2 and simm26_lsl2.
|
|
template <unsigned N>
|
|
unsigned getImmOpValueAsr(const MCInst &MI, unsigned OpNo,
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
const MCSubtargetInfo &STI) const {
|
|
const MCOperand &MO = MI.getOperand(OpNo);
|
|
if (MO.isImm()) {
|
|
unsigned Res = MI.getOperand(OpNo).getImm();
|
|
assert((Res & ((1U << N) - 1U)) == 0 && "lowest N bits are non-zero");
|
|
return Res >> N;
|
|
}
|
|
return getExprOpValue(MI, MO, Fixups, STI);
|
|
}
|
|
|
|
unsigned getExprOpValue(const MCInst &MI, const MCOperand &MO,
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
const MCSubtargetInfo &STI) const;
|
|
};
|
|
} // end namespace
|
|
|
|
unsigned
|
|
LoongArchMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO,
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
const MCSubtargetInfo &STI) const {
|
|
|
|
if (MO.isReg())
|
|
return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg());
|
|
|
|
if (MO.isImm())
|
|
return static_cast<unsigned>(MO.getImm());
|
|
|
|
// MO must be an Expr.
|
|
assert(MO.isExpr());
|
|
return getExprOpValue(MI, MO, Fixups, STI);
|
|
}
|
|
|
|
unsigned
|
|
LoongArchMCCodeEmitter::getImmOpValueSub1(const MCInst &MI, unsigned OpNo,
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
const MCSubtargetInfo &STI) const {
|
|
return MI.getOperand(OpNo).getImm() - 1;
|
|
}
|
|
|
|
unsigned
|
|
LoongArchMCCodeEmitter::getExprOpValue(const MCInst &MI, const MCOperand &MO,
|
|
SmallVectorImpl<MCFixup> &Fixups,
|
|
const MCSubtargetInfo &STI) const {
|
|
assert(MO.isExpr() && "getExprOpValue expects only expressions");
|
|
bool RelaxCandidate = false;
|
|
bool EnableRelax = STI.hasFeature(LoongArch::FeatureRelax);
|
|
const MCExpr *Expr = MO.getExpr();
|
|
MCExpr::ExprKind Kind = Expr->getKind();
|
|
LoongArch::Fixups FixupKind = LoongArch::fixup_loongarch_invalid;
|
|
if (Kind == MCExpr::Target) {
|
|
const LoongArchMCExpr *LAExpr = cast<LoongArchMCExpr>(Expr);
|
|
|
|
RelaxCandidate = LAExpr->getRelaxHint();
|
|
switch (LAExpr->getKind()) {
|
|
case LoongArchMCExpr::VK_LoongArch_None:
|
|
case LoongArchMCExpr::VK_LoongArch_Invalid:
|
|
llvm_unreachable("Unhandled fixup kind!");
|
|
case LoongArchMCExpr::VK_LoongArch_B16:
|
|
FixupKind = LoongArch::fixup_loongarch_b16;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_B21:
|
|
FixupKind = LoongArch::fixup_loongarch_b21;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_B26:
|
|
case LoongArchMCExpr::VK_LoongArch_CALL:
|
|
case LoongArchMCExpr::VK_LoongArch_CALL_PLT:
|
|
FixupKind = LoongArch::fixup_loongarch_b26;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_ABS_HI20:
|
|
FixupKind = LoongArch::fixup_loongarch_abs_hi20;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_ABS_LO12:
|
|
FixupKind = LoongArch::fixup_loongarch_abs_lo12;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_ABS64_LO20:
|
|
FixupKind = LoongArch::fixup_loongarch_abs64_lo20;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_ABS64_HI12:
|
|
FixupKind = LoongArch::fixup_loongarch_abs64_hi12;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_PCALA_HI20:
|
|
FixupKind = LoongArch::fixup_loongarch_pcala_hi20;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_PCALA_LO12:
|
|
FixupKind = LoongArch::fixup_loongarch_pcala_lo12;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_PCALA64_LO20:
|
|
FixupKind = LoongArch::fixup_loongarch_pcala64_lo20;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_PCALA64_HI12:
|
|
FixupKind = LoongArch::fixup_loongarch_pcala64_hi12;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_GOT_PC_HI20:
|
|
FixupKind = LoongArch::fixup_loongarch_got_pc_hi20;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_GOT_PC_LO12:
|
|
FixupKind = LoongArch::fixup_loongarch_got_pc_lo12;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_GOT64_PC_LO20:
|
|
FixupKind = LoongArch::fixup_loongarch_got64_pc_lo20;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_GOT64_PC_HI12:
|
|
FixupKind = LoongArch::fixup_loongarch_got64_pc_hi12;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_GOT_HI20:
|
|
FixupKind = LoongArch::fixup_loongarch_got_hi20;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_GOT_LO12:
|
|
FixupKind = LoongArch::fixup_loongarch_got_lo12;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_GOT64_LO20:
|
|
FixupKind = LoongArch::fixup_loongarch_got64_lo20;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_GOT64_HI12:
|
|
FixupKind = LoongArch::fixup_loongarch_got64_hi12;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_TLS_LE_HI20:
|
|
FixupKind = LoongArch::fixup_loongarch_tls_le_hi20;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_TLS_LE_LO12:
|
|
FixupKind = LoongArch::fixup_loongarch_tls_le_lo12;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_TLS_LE64_LO20:
|
|
FixupKind = LoongArch::fixup_loongarch_tls_le64_lo20;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_TLS_LE64_HI12:
|
|
FixupKind = LoongArch::fixup_loongarch_tls_le64_hi12;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_HI20:
|
|
FixupKind = LoongArch::fixup_loongarch_tls_ie_pc_hi20;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_TLS_IE_PC_LO12:
|
|
FixupKind = LoongArch::fixup_loongarch_tls_ie_pc_lo12;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_LO20:
|
|
FixupKind = LoongArch::fixup_loongarch_tls_ie64_pc_lo20;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_TLS_IE64_PC_HI12:
|
|
FixupKind = LoongArch::fixup_loongarch_tls_ie64_pc_hi12;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_TLS_IE_HI20:
|
|
FixupKind = LoongArch::fixup_loongarch_tls_ie_hi20;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_TLS_IE_LO12:
|
|
FixupKind = LoongArch::fixup_loongarch_tls_ie_lo12;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_TLS_IE64_LO20:
|
|
FixupKind = LoongArch::fixup_loongarch_tls_ie64_lo20;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_TLS_IE64_HI12:
|
|
FixupKind = LoongArch::fixup_loongarch_tls_ie64_hi12;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_TLS_LD_PC_HI20:
|
|
FixupKind = LoongArch::fixup_loongarch_tls_ld_pc_hi20;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_TLS_LD_HI20:
|
|
FixupKind = LoongArch::fixup_loongarch_tls_ld_hi20;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_TLS_GD_PC_HI20:
|
|
FixupKind = LoongArch::fixup_loongarch_tls_gd_pc_hi20;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_TLS_GD_HI20:
|
|
FixupKind = LoongArch::fixup_loongarch_tls_gd_hi20;
|
|
break;
|
|
case LoongArchMCExpr::VK_LoongArch_CALL36:
|
|
FixupKind = LoongArch::fixup_loongarch_call36;
|
|
break;
|
|
}
|
|
} else if (Kind == MCExpr::SymbolRef &&
|
|
cast<MCSymbolRefExpr>(Expr)->getKind() ==
|
|
MCSymbolRefExpr::VK_None) {
|
|
switch (MI.getOpcode()) {
|
|
default:
|
|
break;
|
|
case LoongArch::BEQ:
|
|
case LoongArch::BNE:
|
|
case LoongArch::BLT:
|
|
case LoongArch::BGE:
|
|
case LoongArch::BLTU:
|
|
case LoongArch::BGEU:
|
|
FixupKind = LoongArch::fixup_loongarch_b16;
|
|
break;
|
|
case LoongArch::BEQZ:
|
|
case LoongArch::BNEZ:
|
|
case LoongArch::BCEQZ:
|
|
case LoongArch::BCNEZ:
|
|
FixupKind = LoongArch::fixup_loongarch_b21;
|
|
break;
|
|
case LoongArch::B:
|
|
case LoongArch::BL:
|
|
FixupKind = LoongArch::fixup_loongarch_b26;
|
|
break;
|
|
}
|
|
}
|
|
|
|
assert(FixupKind != LoongArch::fixup_loongarch_invalid &&
|
|
"Unhandled expression!");
|
|
|
|
Fixups.push_back(
|
|
MCFixup::create(0, Expr, MCFixupKind(FixupKind), MI.getLoc()));
|
|
|
|
// Emit an R_LARCH_RELAX if linker relaxation is enabled and LAExpr has relax
|
|
// hint.
|
|
if (EnableRelax && RelaxCandidate) {
|
|
const MCConstantExpr *Dummy = MCConstantExpr::create(0, Ctx);
|
|
Fixups.push_back(MCFixup::create(
|
|
0, Dummy, MCFixupKind(LoongArch::fixup_loongarch_relax), MI.getLoc()));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
template <unsigned Opc>
|
|
void LoongArchMCCodeEmitter::expandToVectorLDI(
|
|
const MCInst &MI, SmallVectorImpl<char> &CB,
|
|
SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
|
|
int64_t Imm = MI.getOperand(1).getImm() & 0x3FF;
|
|
switch (MI.getOpcode()) {
|
|
case LoongArch::PseudoVREPLI_B:
|
|
case LoongArch::PseudoXVREPLI_B:
|
|
break;
|
|
case LoongArch::PseudoVREPLI_H:
|
|
case LoongArch::PseudoXVREPLI_H:
|
|
Imm |= 0x400;
|
|
break;
|
|
case LoongArch::PseudoVREPLI_W:
|
|
case LoongArch::PseudoXVREPLI_W:
|
|
Imm |= 0x800;
|
|
break;
|
|
case LoongArch::PseudoVREPLI_D:
|
|
case LoongArch::PseudoXVREPLI_D:
|
|
Imm |= 0xC00;
|
|
break;
|
|
}
|
|
MCInst TmpInst = MCInstBuilder(Opc).addOperand(MI.getOperand(0)).addImm(Imm);
|
|
uint32_t Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI);
|
|
support::endian::write(CB, Binary, llvm::endianness::little);
|
|
}
|
|
|
|
void LoongArchMCCodeEmitter::encodeInstruction(
|
|
const MCInst &MI, SmallVectorImpl<char> &CB,
|
|
SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
|
|
const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
|
|
// Get byte count of instruction.
|
|
unsigned Size = Desc.getSize();
|
|
|
|
switch (MI.getOpcode()) {
|
|
default:
|
|
break;
|
|
case LoongArch::PseudoVREPLI_B:
|
|
case LoongArch::PseudoVREPLI_H:
|
|
case LoongArch::PseudoVREPLI_W:
|
|
case LoongArch::PseudoVREPLI_D:
|
|
return expandToVectorLDI<LoongArch::VLDI>(MI, CB, Fixups, STI);
|
|
case LoongArch::PseudoXVREPLI_B:
|
|
case LoongArch::PseudoXVREPLI_H:
|
|
case LoongArch::PseudoXVREPLI_W:
|
|
case LoongArch::PseudoXVREPLI_D:
|
|
return expandToVectorLDI<LoongArch::XVLDI>(MI, CB, Fixups, STI);
|
|
}
|
|
|
|
switch (Size) {
|
|
default:
|
|
llvm_unreachable("Unhandled encodeInstruction length!");
|
|
case 4: {
|
|
uint32_t Bits = getBinaryCodeForInstr(MI, Fixups, STI);
|
|
support::endian::write(CB, Bits, llvm::endianness::little);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
MCCodeEmitter *llvm::createLoongArchMCCodeEmitter(const MCInstrInfo &MCII,
|
|
MCContext &Ctx) {
|
|
return new LoongArchMCCodeEmitter(Ctx, MCII);
|
|
}
|
|
|
|
#include "LoongArchGenMCCodeEmitter.inc"
|