10b57cec5SDimitry Andric //=- WebAssemblyMCCodeEmitter.cpp - Convert WebAssembly code to machine code -//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// This file implements the WebAssemblyMCCodeEmitter class.
110b57cec5SDimitry Andric ///
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
140b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyFixupKinds.h"
150b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
160b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
170b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
180b57cec5SDimitry Andric #include "llvm/MC/MCCodeEmitter.h"
1906c3fb27SDimitry Andric #include "llvm/MC/MCContext.h"
200b57cec5SDimitry Andric #include "llvm/MC/MCFixup.h"
210b57cec5SDimitry Andric #include "llvm/MC/MCInst.h"
220b57cec5SDimitry Andric #include "llvm/MC/MCInstrInfo.h"
230b57cec5SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
240b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
250b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h"
260b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
270b57cec5SDimitry Andric #include "llvm/Support/EndianStream.h"
280b57cec5SDimitry Andric #include "llvm/Support/LEB128.h"
2906c3fb27SDimitry Andric #include "llvm/Support/SMLoc.h"
300b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
310b57cec5SDimitry Andric
320b57cec5SDimitry Andric using namespace llvm;
330b57cec5SDimitry Andric
340b57cec5SDimitry Andric #define DEBUG_TYPE "mccodeemitter"
350b57cec5SDimitry Andric
360b57cec5SDimitry Andric STATISTIC(MCNumEmitted, "Number of MC instructions emitted.");
370b57cec5SDimitry Andric STATISTIC(MCNumFixups, "Number of MC fixups created.");
380b57cec5SDimitry Andric
390b57cec5SDimitry Andric namespace {
400b57cec5SDimitry Andric class WebAssemblyMCCodeEmitter final : public MCCodeEmitter {
410b57cec5SDimitry Andric const MCInstrInfo &MCII;
4206c3fb27SDimitry Andric MCContext &Ctx;
430b57cec5SDimitry Andric // Implementation generated by tablegen.
440b57cec5SDimitry Andric uint64_t getBinaryCodeForInstr(const MCInst &MI,
450b57cec5SDimitry Andric SmallVectorImpl<MCFixup> &Fixups,
460b57cec5SDimitry Andric const MCSubtargetInfo &STI) const;
470b57cec5SDimitry Andric
4806c3fb27SDimitry Andric void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,
490b57cec5SDimitry Andric SmallVectorImpl<MCFixup> &Fixups,
500b57cec5SDimitry Andric const MCSubtargetInfo &STI) const override;
510b57cec5SDimitry Andric
520b57cec5SDimitry Andric public:
WebAssemblyMCCodeEmitter(const MCInstrInfo & MCII,MCContext & Ctx)5306c3fb27SDimitry Andric WebAssemblyMCCodeEmitter(const MCInstrInfo &MCII, MCContext &Ctx)
5406c3fb27SDimitry Andric : MCII(MCII), Ctx{Ctx} {}
550b57cec5SDimitry Andric };
560b57cec5SDimitry Andric } // end anonymous namespace
570b57cec5SDimitry Andric
createWebAssemblyMCCodeEmitter(const MCInstrInfo & MCII,MCContext & Ctx)5806c3fb27SDimitry Andric MCCodeEmitter *llvm::createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII,
5906c3fb27SDimitry Andric MCContext &Ctx) {
6006c3fb27SDimitry Andric return new WebAssemblyMCCodeEmitter(MCII, Ctx);
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric
encodeInstruction(const MCInst & MI,SmallVectorImpl<char> & CB,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const630b57cec5SDimitry Andric void WebAssemblyMCCodeEmitter::encodeInstruction(
6406c3fb27SDimitry Andric const MCInst &MI, SmallVectorImpl<char> &CB,
6506c3fb27SDimitry Andric SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
6606c3fb27SDimitry Andric raw_svector_ostream OS(CB);
670b57cec5SDimitry Andric uint64_t Start = OS.tell();
680b57cec5SDimitry Andric
690b57cec5SDimitry Andric uint64_t Binary = getBinaryCodeForInstr(MI, Fixups, STI);
70e8d8bef9SDimitry Andric if (Binary < (1 << 8)) {
710b57cec5SDimitry Andric OS << uint8_t(Binary);
72e8d8bef9SDimitry Andric } else if (Binary < (1 << 16)) {
730b57cec5SDimitry Andric OS << uint8_t(Binary >> 8);
740b57cec5SDimitry Andric encodeULEB128(uint8_t(Binary), OS);
75e8d8bef9SDimitry Andric } else if (Binary < (1 << 24)) {
76e8d8bef9SDimitry Andric OS << uint8_t(Binary >> 16);
77e8d8bef9SDimitry Andric encodeULEB128(uint16_t(Binary), OS);
78e8d8bef9SDimitry Andric } else {
79e8d8bef9SDimitry Andric llvm_unreachable("Very large (prefix + 3 byte) opcodes not supported");
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric
820b57cec5SDimitry Andric // For br_table instructions, encode the size of the table. In the MCInst,
830b57cec5SDimitry Andric // there's an index operand (if not a stack instruction), one operand for
840b57cec5SDimitry Andric // each table entry, and the default operand.
850b57cec5SDimitry Andric if (MI.getOpcode() == WebAssembly::BR_TABLE_I32_S ||
860b57cec5SDimitry Andric MI.getOpcode() == WebAssembly::BR_TABLE_I64_S)
870b57cec5SDimitry Andric encodeULEB128(MI.getNumOperands() - 1, OS);
880b57cec5SDimitry Andric if (MI.getOpcode() == WebAssembly::BR_TABLE_I32 ||
890b57cec5SDimitry Andric MI.getOpcode() == WebAssembly::BR_TABLE_I64)
900b57cec5SDimitry Andric encodeULEB128(MI.getNumOperands() - 2, OS);
910b57cec5SDimitry Andric
920b57cec5SDimitry Andric const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
930b57cec5SDimitry Andric for (unsigned I = 0, E = MI.getNumOperands(); I < E; ++I) {
940b57cec5SDimitry Andric const MCOperand &MO = MI.getOperand(I);
950b57cec5SDimitry Andric if (MO.isReg()) {
960b57cec5SDimitry Andric /* nothing to encode */
970b57cec5SDimitry Andric
980b57cec5SDimitry Andric } else if (MO.isImm()) {
990b57cec5SDimitry Andric if (I < Desc.getNumOperands()) {
100bdd1243dSDimitry Andric const MCOperandInfo &Info = Desc.operands()[I];
1010b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Encoding immediate: type="
1020b57cec5SDimitry Andric << int(Info.OperandType) << "\n");
1030b57cec5SDimitry Andric switch (Info.OperandType) {
1040b57cec5SDimitry Andric case WebAssembly::OPERAND_I32IMM:
1050b57cec5SDimitry Andric encodeSLEB128(int32_t(MO.getImm()), OS);
1060b57cec5SDimitry Andric break;
1070b57cec5SDimitry Andric case WebAssembly::OPERAND_OFFSET32:
1080b57cec5SDimitry Andric encodeULEB128(uint32_t(MO.getImm()), OS);
1090b57cec5SDimitry Andric break;
1100b57cec5SDimitry Andric case WebAssembly::OPERAND_I64IMM:
1110b57cec5SDimitry Andric encodeSLEB128(int64_t(MO.getImm()), OS);
1120b57cec5SDimitry Andric break;
1130b57cec5SDimitry Andric case WebAssembly::OPERAND_SIGNATURE:
1140b57cec5SDimitry Andric case WebAssembly::OPERAND_VEC_I8IMM:
115*5f757f3fSDimitry Andric support::endian::write<uint8_t>(OS, MO.getImm(),
116*5f757f3fSDimitry Andric llvm::endianness::little);
1170b57cec5SDimitry Andric break;
1180b57cec5SDimitry Andric case WebAssembly::OPERAND_VEC_I16IMM:
119*5f757f3fSDimitry Andric support::endian::write<uint16_t>(OS, MO.getImm(),
120*5f757f3fSDimitry Andric llvm::endianness::little);
1210b57cec5SDimitry Andric break;
1220b57cec5SDimitry Andric case WebAssembly::OPERAND_VEC_I32IMM:
123*5f757f3fSDimitry Andric support::endian::write<uint32_t>(OS, MO.getImm(),
124*5f757f3fSDimitry Andric llvm::endianness::little);
1250b57cec5SDimitry Andric break;
1260b57cec5SDimitry Andric case WebAssembly::OPERAND_VEC_I64IMM:
127*5f757f3fSDimitry Andric support::endian::write<uint64_t>(OS, MO.getImm(),
128*5f757f3fSDimitry Andric llvm::endianness::little);
1290b57cec5SDimitry Andric break;
1300b57cec5SDimitry Andric case WebAssembly::OPERAND_GLOBAL:
13106c3fb27SDimitry Andric Ctx.reportError(
13206c3fb27SDimitry Andric SMLoc(),
13306c3fb27SDimitry Andric Twine("Wasm globals should only be accessed symbolically!"));
13406c3fb27SDimitry Andric break;
1350b57cec5SDimitry Andric default:
1360b57cec5SDimitry Andric encodeULEB128(uint64_t(MO.getImm()), OS);
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric } else {
1390b57cec5SDimitry Andric encodeULEB128(uint64_t(MO.getImm()), OS);
1400b57cec5SDimitry Andric }
1410b57cec5SDimitry Andric
142fe6060f1SDimitry Andric } else if (MO.isSFPImm()) {
143fe6060f1SDimitry Andric uint32_t F = MO.getSFPImm();
144*5f757f3fSDimitry Andric support::endian::write<uint32_t>(OS, F, llvm::endianness::little);
145fe6060f1SDimitry Andric } else if (MO.isDFPImm()) {
146fe6060f1SDimitry Andric uint64_t D = MO.getDFPImm();
147*5f757f3fSDimitry Andric support::endian::write<uint64_t>(OS, D, llvm::endianness::little);
1480b57cec5SDimitry Andric } else if (MO.isExpr()) {
149bdd1243dSDimitry Andric const MCOperandInfo &Info = Desc.operands()[I];
1500b57cec5SDimitry Andric llvm::MCFixupKind FixupKind;
1510b57cec5SDimitry Andric size_t PaddedSize = 5;
1520b57cec5SDimitry Andric switch (Info.OperandType) {
1530b57cec5SDimitry Andric case WebAssembly::OPERAND_I32IMM:
1540b57cec5SDimitry Andric FixupKind = MCFixupKind(WebAssembly::fixup_sleb128_i32);
1550b57cec5SDimitry Andric break;
1560b57cec5SDimitry Andric case WebAssembly::OPERAND_I64IMM:
1570b57cec5SDimitry Andric FixupKind = MCFixupKind(WebAssembly::fixup_sleb128_i64);
1580b57cec5SDimitry Andric PaddedSize = 10;
1590b57cec5SDimitry Andric break;
1600b57cec5SDimitry Andric case WebAssembly::OPERAND_FUNCTION32:
161e8d8bef9SDimitry Andric case WebAssembly::OPERAND_TABLE:
1620b57cec5SDimitry Andric case WebAssembly::OPERAND_OFFSET32:
1638bcb0991SDimitry Andric case WebAssembly::OPERAND_SIGNATURE:
1640b57cec5SDimitry Andric case WebAssembly::OPERAND_TYPEINDEX:
1650b57cec5SDimitry Andric case WebAssembly::OPERAND_GLOBAL:
166fe6060f1SDimitry Andric case WebAssembly::OPERAND_TAG:
1670b57cec5SDimitry Andric FixupKind = MCFixupKind(WebAssembly::fixup_uleb128_i32);
1680b57cec5SDimitry Andric break;
1695ffd83dbSDimitry Andric case WebAssembly::OPERAND_OFFSET64:
1705ffd83dbSDimitry Andric FixupKind = MCFixupKind(WebAssembly::fixup_uleb128_i64);
1715ffd83dbSDimitry Andric PaddedSize = 10;
1725ffd83dbSDimitry Andric break;
1730b57cec5SDimitry Andric default:
1740b57cec5SDimitry Andric llvm_unreachable("unexpected symbolic operand kind");
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric Fixups.push_back(MCFixup::create(OS.tell() - Start, MO.getExpr(),
1770b57cec5SDimitry Andric FixupKind, MI.getLoc()));
1780b57cec5SDimitry Andric ++MCNumFixups;
1790b57cec5SDimitry Andric encodeULEB128(0, OS, PaddedSize);
1800b57cec5SDimitry Andric } else {
1810b57cec5SDimitry Andric llvm_unreachable("unexpected operand kind");
1820b57cec5SDimitry Andric }
1830b57cec5SDimitry Andric }
1840b57cec5SDimitry Andric
1850b57cec5SDimitry Andric ++MCNumEmitted; // Keep track of the # of mi's emitted.
1860b57cec5SDimitry Andric }
1870b57cec5SDimitry Andric
1880b57cec5SDimitry Andric #include "WebAssemblyGenMCCodeEmitter.inc"
189