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: 5306c3fb27SDimitry Andric WebAssemblyMCCodeEmitter(const MCInstrInfo &MCII, MCContext &Ctx) 5406c3fb27SDimitry Andric : MCII(MCII), Ctx{Ctx} {} 550b57cec5SDimitry Andric }; 560b57cec5SDimitry Andric } // end anonymous namespace 570b57cec5SDimitry Andric 5806c3fb27SDimitry Andric MCCodeEmitter *llvm::createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII, 5906c3fb27SDimitry Andric MCContext &Ctx) { 6006c3fb27SDimitry Andric return new WebAssemblyMCCodeEmitter(MCII, Ctx); 610b57cec5SDimitry Andric } 620b57cec5SDimitry Andric 630b57cec5SDimitry 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