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 | |
26 | using namespace llvm; |
27 | |
28 | #define DEBUG_TYPE "mccodeemitter" |
29 | |
30 | namespace { |
31 | class LoongArchMCCodeEmitter : public MCCodeEmitter { |
32 | LoongArchMCCodeEmitter(const LoongArchMCCodeEmitter &) = delete; |
33 | void operator=(const LoongArchMCCodeEmitter &) = delete; |
34 | MCContext &Ctx; |
35 | MCInstrInfo const &MCII; |
36 | |
37 | public: |
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 | |
100 | unsigned |
101 | LoongArchMCCodeEmitter::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 | |
116 | unsigned |
117 | LoongArchMCCodeEmitter::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 | |
123 | unsigned |
124 | LoongArchMCCodeEmitter::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 | |
209 | template <unsigned Opc> |
210 | void 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 | |
236 | void 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 | |
267 | void 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 | |
303 | MCCodeEmitter *llvm::createLoongArchMCCodeEmitter(const MCInstrInfo &MCII, |
304 | MCContext &Ctx) { |
305 | return new LoongArchMCCodeEmitter(Ctx, MCII); |
306 | } |
307 | |
308 | #include "LoongArchGenMCCodeEmitter.inc" |
309 | |