| 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 | |