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-exception
6//
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 {}
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 an
57 /// 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 requires
63 /// 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 right
78 // 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(i: OpNo);
86 if (MO.isImm()) {
87 unsigned Res = MI.getOperand(i: 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 namespace
99
100unsigned
101LoongArchMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO,
102 SmallVectorImpl<MCFixup> &Fixups,
103 const MCSubtargetInfo &STI) const {
104
105 if (MO.isReg())
106 return Ctx.getRegisterInfo()->getEncodingValue(Reg: MO.getReg());
107
108 if (MO.isImm())
109 return static_cast<unsigned>(MO.getImm());
110
111 // MO must be an Expr.
112 assert(MO.isExpr());
113 return getExprOpValue(MI, MO, Fixups, STI);
114}
115
116unsigned
117LoongArchMCCodeEmitter::getImmOpValueSub1(const MCInst &MI, unsigned OpNo,
118 SmallVectorImpl<MCFixup> &Fixups,
119 const MCSubtargetInfo &STI) const {
120 return MI.getOperand(i: OpNo).getImm() - 1;
121}
122
123unsigned
124LoongArchMCCodeEmitter::getExprOpValue(const MCInst &MI, const MCOperand &MO,
125 SmallVectorImpl<MCFixup> &Fixups,
126 const MCSubtargetInfo &STI) const {
127 assert(MO.isExpr() && "getExprOpValue expects only expressions");
128 bool RelaxCandidate = false;
129 bool EnableRelax = STI.hasFeature(Feature: LoongArch::FeatureRelax);
130 const MCExpr *Expr = MO.getExpr();
131 MCExpr::ExprKind Kind = Expr->getKind();
132 unsigned FixupKind = LoongArch::fixup_loongarch_invalid;
133 if (Kind == MCExpr::Specifier) {
134 const LoongArchMCExpr *LAExpr = cast<LoongArchMCExpr>(Val: Expr);
135 FixupKind = LAExpr->getSpecifier();
136 RelaxCandidate = LAExpr->getRelaxHint();
137 switch (uint16_t(LAExpr->getSpecifier())) {
138 case LoongArchMCExpr::VK_None:
139 llvm_unreachable("Unhandled fixup kind!");
140 case ELF::R_LARCH_TLS_LE_ADD_R:
141 llvm_unreachable("ELF::R_LARCH_TLS_LE_ADD_R should not represent an "
142 "instruction operand");
143 case ELF::R_LARCH_B16:
144 FixupKind = LoongArch::fixup_loongarch_b16;
145 break;
146 case ELF::R_LARCH_B21:
147 FixupKind = LoongArch::fixup_loongarch_b21;
148 break;
149 case ELF::R_LARCH_B26:
150 FixupKind = LoongArch::fixup_loongarch_b26;
151 break;
152 case ELF::R_LARCH_ABS_HI20:
153 FixupKind = LoongArch::fixup_loongarch_abs_hi20;
154 break;
155 case ELF::R_LARCH_ABS_LO12:
156 FixupKind = LoongArch::fixup_loongarch_abs_lo12;
157 break;
158 case ELF::R_LARCH_ABS64_LO20:
159 FixupKind = LoongArch::fixup_loongarch_abs64_lo20;
160 break;
161 case ELF::R_LARCH_ABS64_HI12:
162 FixupKind = LoongArch::fixup_loongarch_abs64_hi12;
163 break;
164 case ELF::R_LARCH_CALL36:
165 case ELF::R_LARCH_TLS_LE_HI20_R:
166 case ELF::R_LARCH_TLS_LE_LO12_R:
167 RelaxCandidate = true;
168 break;
169 }
170 } else if (Kind == MCExpr::SymbolRef) {
171 switch (MI.getOpcode()) {
172 default:
173 break;
174 case LoongArch::BEQ:
175 case LoongArch::BNE:
176 case LoongArch::BLT:
177 case LoongArch::BGE:
178 case LoongArch::BLTU:
179 case LoongArch::BGEU:
180 FixupKind = LoongArch::fixup_loongarch_b16;
181 break;
182 case LoongArch::BEQZ:
183 case LoongArch::BNEZ:
184 case LoongArch::BCEQZ:
185 case LoongArch::BCNEZ:
186 FixupKind = LoongArch::fixup_loongarch_b21;
187 break;
188 case LoongArch::B:
189 case LoongArch::BL:
190 FixupKind = LoongArch::fixup_loongarch_b26;
191 break;
192 }
193 }
194
195 assert(FixupKind != LoongArch::fixup_loongarch_invalid &&
196 "Unhandled expression!");
197
198 Fixups.push_back(
199 Elt: MCFixup::create(Offset: 0, Value: Expr, Kind: MCFixupKind(FixupKind), Loc: MI.getLoc()));
200 // If linker relaxation is enabled and supported by this relocation, set
201 // a bit so that if fixup is unresolved, a R_LARCH_RELAX relocation will be
202 // appended.
203 if (EnableRelax && RelaxCandidate)
204 Fixups.back().setLinkerRelaxable();
205
206 return 0;
207}
208
209template <unsigned Opc>
210void LoongArchMCCodeEmitter::expandToVectorLDI(
211 const MCInst &MI, SmallVectorImpl<char> &CB,
212 SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
213 int64_t Imm = MI.getOperand(i: 1).getImm() & 0x3FF;
214 switch (MI.getOpcode()) {
215 case LoongArch::PseudoVREPLI_B:
216 case LoongArch::PseudoXVREPLI_B:
217 break;
218 case LoongArch::PseudoVREPLI_H:
219 case LoongArch::PseudoXVREPLI_H:
220 Imm |= 0x400;
221 break;
222 case LoongArch::PseudoVREPLI_W:
223 case LoongArch::PseudoXVREPLI_W:
224 Imm |= 0x800;
225 break;
226 case LoongArch::PseudoVREPLI_D:
227 case LoongArch::PseudoXVREPLI_D:
228 Imm |= 0xC00;
229 break;
230 }
231 MCInst TmpInst = MCInstBuilder(Opc).addOperand(Op: MI.getOperand(i: 0)).addImm(Val: Imm);
232 uint32_t Binary = getBinaryCodeForInstr(MI: TmpInst, Fixups, STI);
233 support::endian::write(Out&: CB, V: Binary, E: llvm::endianness::little);
234}
235
236void LoongArchMCCodeEmitter::expandAddTPRel(const MCInst &MI,
237 SmallVectorImpl<char> &CB,
238 SmallVectorImpl<MCFixup> &Fixups,
239 const MCSubtargetInfo &STI) const {
240 MCOperand Rd = MI.getOperand(i: 0);
241 MCOperand Rj = MI.getOperand(i: 1);
242 MCOperand Rk = MI.getOperand(i: 2);
243 MCOperand Symbol = MI.getOperand(i: 3);
244 assert(Symbol.isExpr() &&
245 "Expected expression as third input to TP-relative add");
246
247 const LoongArchMCExpr *Expr = dyn_cast<LoongArchMCExpr>(Val: Symbol.getExpr());
248 assert(Expr && Expr->getSpecifier() == ELF::R_LARCH_TLS_LE_ADD_R &&
249 "Expected %le_add_r relocation on TP-relative symbol");
250
251 // Emit the correct %le_add_r relocation for the symbol.
252 Fixups.push_back(
253 Elt: MCFixup::create(Offset: 0, Value: Expr, Kind: ELF::R_LARCH_TLS_LE_ADD_R, Loc: MI.getLoc()));
254 if (STI.hasFeature(Feature: LoongArch::FeatureRelax))
255 Fixups.back().setLinkerRelaxable();
256
257 // Emit a normal ADD instruction with the given operands.
258 unsigned ADD = MI.getOpcode() == LoongArch::PseudoAddTPRel_D
259 ? LoongArch::ADD_D
260 : LoongArch::ADD_W;
261 MCInst TmpInst =
262 MCInstBuilder(ADD).addOperand(Op: Rd).addOperand(Op: Rj).addOperand(Op: Rk);
263 uint32_t Binary = getBinaryCodeForInstr(MI: TmpInst, Fixups, STI);
264 support::endian::write(Out&: CB, V: Binary, E: llvm::endianness::little);
265}
266
267void LoongArchMCCodeEmitter::encodeInstruction(
268 const MCInst &MI, SmallVectorImpl<char> &CB,
269 SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
270 const MCInstrDesc &Desc = MCII.get(Opcode: MI.getOpcode());
271 // Get byte count of instruction.
272 unsigned Size = Desc.getSize();
273
274 switch (MI.getOpcode()) {
275 default:
276 break;
277 case LoongArch::PseudoVREPLI_B:
278 case LoongArch::PseudoVREPLI_H:
279 case LoongArch::PseudoVREPLI_W:
280 case LoongArch::PseudoVREPLI_D:
281 return expandToVectorLDI<LoongArch::VLDI>(MI, CB, Fixups, STI);
282 case LoongArch::PseudoXVREPLI_B:
283 case LoongArch::PseudoXVREPLI_H:
284 case LoongArch::PseudoXVREPLI_W:
285 case LoongArch::PseudoXVREPLI_D:
286 return expandToVectorLDI<LoongArch::XVLDI>(MI, CB, Fixups, STI);
287 case LoongArch::PseudoAddTPRel_W:
288 case LoongArch::PseudoAddTPRel_D:
289 return expandAddTPRel(MI, CB, Fixups, STI);
290 }
291
292 switch (Size) {
293 default:
294 llvm_unreachable("Unhandled encodeInstruction length!");
295 case 4: {
296 uint32_t Bits = getBinaryCodeForInstr(MI, Fixups, STI);
297 support::endian::write(Out&: CB, V: Bits, E: llvm::endianness::little);
298 break;
299 }
300 }
301}
302
303MCCodeEmitter *llvm::createLoongArchMCCodeEmitter(const MCInstrInfo &MCII,
304 MCContext &Ctx) {
305 return new LoongArchMCCodeEmitter(Ctx, MCII);
306}
307
308#include "LoongArchGenMCCodeEmitter.inc"
309