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