Path: blob/main/contrib/llvm-project/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
35294 views
//=- WebAssemblyMCCodeEmitter.cpp - Convert WebAssembly code to machine code -//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9/// This file implements the WebAssemblyMCCodeEmitter class.10///11//===----------------------------------------------------------------------===//1213#include "MCTargetDesc/WebAssemblyFixupKinds.h"14#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"15#include "llvm/ADT/STLExtras.h"16#include "llvm/ADT/Statistic.h"17#include "llvm/MC/MCCodeEmitter.h"18#include "llvm/MC/MCContext.h"19#include "llvm/MC/MCFixup.h"20#include "llvm/MC/MCInst.h"21#include "llvm/MC/MCInstrInfo.h"22#include "llvm/MC/MCRegisterInfo.h"23#include "llvm/MC/MCSubtargetInfo.h"24#include "llvm/MC/MCSymbol.h"25#include "llvm/Support/Debug.h"26#include "llvm/Support/EndianStream.h"27#include "llvm/Support/LEB128.h"28#include "llvm/Support/SMLoc.h"29#include "llvm/Support/raw_ostream.h"3031using namespace llvm;3233#define DEBUG_TYPE "mccodeemitter"3435STATISTIC(MCNumEmitted, "Number of MC instructions emitted.");36STATISTIC(MCNumFixups, "Number of MC fixups created.");3738namespace {39class WebAssemblyMCCodeEmitter final : public MCCodeEmitter {40const MCInstrInfo &MCII;41MCContext &Ctx;42// Implementation generated by tablegen.43uint64_t getBinaryCodeForInstr(const MCInst &MI,44SmallVectorImpl<MCFixup> &Fixups,45const MCSubtargetInfo &STI) const;4647void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,48SmallVectorImpl<MCFixup> &Fixups,49const MCSubtargetInfo &STI) const override;5051public:52WebAssemblyMCCodeEmitter(const MCInstrInfo &MCII, MCContext &Ctx)53: MCII(MCII), Ctx{Ctx} {}54};55} // end anonymous namespace5657MCCodeEmitter *llvm::createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII,58MCContext &Ctx) {59return new WebAssemblyMCCodeEmitter(MCII, Ctx);60}6162void WebAssemblyMCCodeEmitter::encodeInstruction(63const MCInst &MI, SmallVectorImpl<char> &CB,64SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {65raw_svector_ostream OS(CB);66uint64_t Start = OS.tell();6768uint64_t Binary = getBinaryCodeForInstr(MI, Fixups, STI);69if (Binary < (1 << 8)) {70OS << uint8_t(Binary);71} else if (Binary < (1 << 16)) {72OS << uint8_t(Binary >> 8);73encodeULEB128(uint8_t(Binary), OS);74} else if (Binary < (1 << 24)) {75OS << uint8_t(Binary >> 16);76encodeULEB128(uint16_t(Binary), OS);77} else {78llvm_unreachable("Very large (prefix + 3 byte) opcodes not supported");79}8081// For br_table instructions, encode the size of the table. In the MCInst,82// there's an index operand (if not a stack instruction), one operand for83// each table entry, and the default operand.84if (MI.getOpcode() == WebAssembly::BR_TABLE_I32_S ||85MI.getOpcode() == WebAssembly::BR_TABLE_I64_S)86encodeULEB128(MI.getNumOperands() - 1, OS);87if (MI.getOpcode() == WebAssembly::BR_TABLE_I32 ||88MI.getOpcode() == WebAssembly::BR_TABLE_I64)89encodeULEB128(MI.getNumOperands() - 2, OS);9091const MCInstrDesc &Desc = MCII.get(MI.getOpcode());92for (unsigned I = 0, E = MI.getNumOperands(); I < E; ++I) {93const MCOperand &MO = MI.getOperand(I);94if (MO.isReg()) {95/* nothing to encode */9697} else if (MO.isImm()) {98if (I < Desc.getNumOperands()) {99const MCOperandInfo &Info = Desc.operands()[I];100LLVM_DEBUG(dbgs() << "Encoding immediate: type="101<< int(Info.OperandType) << "\n");102switch (Info.OperandType) {103case WebAssembly::OPERAND_I32IMM:104encodeSLEB128(int32_t(MO.getImm()), OS);105break;106case WebAssembly::OPERAND_OFFSET32:107encodeULEB128(uint32_t(MO.getImm()), OS);108break;109case WebAssembly::OPERAND_I64IMM:110encodeSLEB128(int64_t(MO.getImm()), OS);111break;112case WebAssembly::OPERAND_SIGNATURE:113case WebAssembly::OPERAND_VEC_I8IMM:114support::endian::write<uint8_t>(OS, MO.getImm(),115llvm::endianness::little);116break;117case WebAssembly::OPERAND_VEC_I16IMM:118support::endian::write<uint16_t>(OS, MO.getImm(),119llvm::endianness::little);120break;121case WebAssembly::OPERAND_VEC_I32IMM:122support::endian::write<uint32_t>(OS, MO.getImm(),123llvm::endianness::little);124break;125case WebAssembly::OPERAND_VEC_I64IMM:126support::endian::write<uint64_t>(OS, MO.getImm(),127llvm::endianness::little);128break;129case WebAssembly::OPERAND_GLOBAL:130Ctx.reportError(131SMLoc(),132Twine("Wasm globals should only be accessed symbolically!"));133break;134default:135encodeULEB128(uint64_t(MO.getImm()), OS);136}137} else {138encodeULEB128(uint64_t(MO.getImm()), OS);139}140141} else if (MO.isSFPImm()) {142uint32_t F = MO.getSFPImm();143support::endian::write<uint32_t>(OS, F, llvm::endianness::little);144} else if (MO.isDFPImm()) {145uint64_t D = MO.getDFPImm();146support::endian::write<uint64_t>(OS, D, llvm::endianness::little);147} else if (MO.isExpr()) {148const MCOperandInfo &Info = Desc.operands()[I];149llvm::MCFixupKind FixupKind;150size_t PaddedSize = 5;151switch (Info.OperandType) {152case WebAssembly::OPERAND_I32IMM:153FixupKind = MCFixupKind(WebAssembly::fixup_sleb128_i32);154break;155case WebAssembly::OPERAND_I64IMM:156FixupKind = MCFixupKind(WebAssembly::fixup_sleb128_i64);157PaddedSize = 10;158break;159case WebAssembly::OPERAND_FUNCTION32:160case WebAssembly::OPERAND_TABLE:161case WebAssembly::OPERAND_OFFSET32:162case WebAssembly::OPERAND_SIGNATURE:163case WebAssembly::OPERAND_TYPEINDEX:164case WebAssembly::OPERAND_GLOBAL:165case WebAssembly::OPERAND_TAG:166FixupKind = MCFixupKind(WebAssembly::fixup_uleb128_i32);167break;168case WebAssembly::OPERAND_OFFSET64:169FixupKind = MCFixupKind(WebAssembly::fixup_uleb128_i64);170PaddedSize = 10;171break;172default:173llvm_unreachable("unexpected symbolic operand kind");174}175Fixups.push_back(MCFixup::create(OS.tell() - Start, MO.getExpr(),176FixupKind, MI.getLoc()));177++MCNumFixups;178encodeULEB128(0, OS, PaddedSize);179} else {180llvm_unreachable("unexpected operand kind");181}182}183184++MCNumEmitted; // Keep track of the # of mi's emitted.185}186187#include "WebAssemblyGenMCCodeEmitter.inc"188189190