brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.3 KiB · 7096104 Raw
199 lines · cpp
1//=- WebAssemblyMCCodeEmitter.cpp - Convert WebAssembly 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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file implements the WebAssemblyMCCodeEmitter class.11///12//===----------------------------------------------------------------------===//13 14#include "MCTargetDesc/WebAssemblyFixupKinds.h"15#include "MCTargetDesc/WebAssemblyMCTargetDesc.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/MCSubtargetInfo.h"23#include "llvm/MC/MCSymbol.h"24#include "llvm/Support/Debug.h"25#include "llvm/Support/EndianStream.h"26#include "llvm/Support/LEB128.h"27#include "llvm/Support/SMLoc.h"28#include "llvm/Support/raw_ostream.h"29 30using namespace llvm;31 32#define DEBUG_TYPE "mccodeemitter"33 34STATISTIC(MCNumEmitted, "Number of MC instructions emitted.");35STATISTIC(MCNumFixups, "Number of MC fixups created.");36 37namespace {38class WebAssemblyMCCodeEmitter final : public MCCodeEmitter {39  const MCInstrInfo &MCII;40  MCContext &Ctx;41  // Implementation generated by tablegen.42  uint64_t getBinaryCodeForInstr(const MCInst &MI,43                                 SmallVectorImpl<MCFixup> &Fixups,44                                 const MCSubtargetInfo &STI) const;45 46  void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,47                         SmallVectorImpl<MCFixup> &Fixups,48                         const MCSubtargetInfo &STI) const override;49 50public:51  WebAssemblyMCCodeEmitter(const MCInstrInfo &MCII, MCContext &Ctx)52      : MCII(MCII), Ctx{Ctx} {}53};54} // end anonymous namespace55 56MCCodeEmitter *llvm::createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII,57                                                    MCContext &Ctx) {58  return new WebAssemblyMCCodeEmitter(MCII, Ctx);59}60 61void WebAssemblyMCCodeEmitter::encodeInstruction(62    const MCInst &MI, SmallVectorImpl<char> &CB,63    SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {64  raw_svector_ostream OS(CB);65  uint64_t Start = OS.tell();66 67  uint64_t Binary = getBinaryCodeForInstr(MI, Fixups, STI);68  if (Binary < (1 << 8)) {69    OS << uint8_t(Binary);70  } else if (Binary < (1 << 16)) {71    OS << uint8_t(Binary >> 8);72    encodeULEB128(uint8_t(Binary), OS);73  } else if (Binary < (1 << 24)) {74    OS << uint8_t(Binary >> 16);75    encodeULEB128(uint16_t(Binary), OS);76  } else {77    llvm_unreachable("Very large (prefix + 3 byte) opcodes not supported");78  }79 80  // For br_table instructions, encode the size of the table. In the MCInst,81  // there's an index operand (if not a stack instruction), one operand for82  // each table entry, and the default operand.83  unsigned Opcode = MI.getOpcode();84  if (Opcode == WebAssembly::BR_TABLE_I32_S ||85      Opcode == WebAssembly::BR_TABLE_I64_S)86    encodeULEB128(MI.getNumOperands() - 1, OS);87  if (Opcode == WebAssembly::BR_TABLE_I32 ||88      Opcode == WebAssembly::BR_TABLE_I64)89    encodeULEB128(MI.getNumOperands() - 2, OS);90 91  const MCInstrDesc &Desc = MCII.get(Opcode);92  for (unsigned I = 0, E = MI.getNumOperands(); I < E; ++I) {93    const MCOperand &MO = MI.getOperand(I);94    if (MO.isReg()) {95      /* nothing to encode */96 97    } else if (MO.isImm()) {98      if (I < Desc.getNumOperands()) {99        const MCOperandInfo &Info = Desc.operands()[I];100        LLVM_DEBUG(dbgs() << "Encoding immediate: type="101                          << int(Info.OperandType) << "\n");102        switch (Info.OperandType) {103        case WebAssembly::OPERAND_I32IMM:104          encodeSLEB128(int32_t(MO.getImm()), OS);105          break;106        case WebAssembly::OPERAND_OFFSET32:107          encodeULEB128(uint32_t(MO.getImm()), OS);108          break;109        case WebAssembly::OPERAND_I64IMM:110          encodeSLEB128(MO.getImm(), OS);111          break;112        case WebAssembly::OPERAND_SIGNATURE:113        case WebAssembly::OPERAND_VEC_I8IMM:114          support::endian::write<uint8_t>(OS, MO.getImm(),115                                          llvm::endianness::little);116          break;117        case WebAssembly::OPERAND_VEC_I16IMM:118          support::endian::write<uint16_t>(OS, MO.getImm(),119                                           llvm::endianness::little);120          break;121        case WebAssembly::OPERAND_VEC_I32IMM:122          support::endian::write<uint32_t>(OS, MO.getImm(),123                                           llvm::endianness::little);124          break;125        case WebAssembly::OPERAND_VEC_I64IMM:126          support::endian::write<uint64_t>(OS, MO.getImm(),127                                           llvm::endianness::little);128          break;129        case WebAssembly::OPERAND_GLOBAL:130          Ctx.reportError(131              SMLoc(),132              Twine("Wasm globals should only be accessed symbolically!"));133          break;134        default:135          encodeULEB128(uint64_t(MO.getImm()), OS);136        }137      } else {138        // Variadic immediate operands are br_table's destination operands or139        // try_table's operands (# of catch clauses, catch sub-opcodes, or catch140        // clause destinations)141        assert(WebAssembly::isBrTable(Opcode) ||142               Opcode == WebAssembly::TRY_TABLE_S);143        encodeULEB128(uint32_t(MO.getImm()), OS);144      }145 146    } else if (MO.isSFPImm()) {147      uint32_t F = MO.getSFPImm();148      support::endian::write<uint32_t>(OS, F, llvm::endianness::little);149    } else if (MO.isDFPImm()) {150      uint64_t D = MO.getDFPImm();151      support::endian::write<uint64_t>(OS, D, llvm::endianness::little);152    } else if (MO.isExpr()) {153      llvm::MCFixupKind FixupKind;154      size_t PaddedSize = 5;155      if (I < Desc.getNumOperands()) {156        const MCOperandInfo &Info = Desc.operands()[I];157        switch (Info.OperandType) {158        case WebAssembly::OPERAND_I32IMM:159          FixupKind = WebAssembly::fixup_sleb128_i32;160          break;161        case WebAssembly::OPERAND_I64IMM:162          FixupKind = WebAssembly::fixup_sleb128_i64;163          PaddedSize = 10;164          break;165        case WebAssembly::OPERAND_FUNCTION32:166        case WebAssembly::OPERAND_TABLE:167        case WebAssembly::OPERAND_OFFSET32:168        case WebAssembly::OPERAND_SIGNATURE:169        case WebAssembly::OPERAND_TYPEINDEX:170        case WebAssembly::OPERAND_GLOBAL:171        case WebAssembly::OPERAND_TAG:172          FixupKind = WebAssembly::fixup_uleb128_i32;173          break;174        case WebAssembly::OPERAND_OFFSET64:175          FixupKind = WebAssembly::fixup_uleb128_i64;176          PaddedSize = 10;177          break;178        default:179          llvm_unreachable("unexpected symbolic operand kind");180        }181      } else {182        // Variadic expr operands are try_table's catch/catch_ref clauses' tags.183        assert(Opcode == WebAssembly::TRY_TABLE_S);184        FixupKind = WebAssembly::fixup_uleb128_i32;185      }186      Fixups.push_back(187          MCFixup::create(OS.tell() - Start, MO.getExpr(), FixupKind));188      ++MCNumFixups;189      encodeULEB128(0, OS, PaddedSize);190    } else {191      llvm_unreachable("unexpected operand kind");192    }193  }194 195  ++MCNumEmitted; // Keep track of the # of mi's emitted.196}197 198#include "WebAssemblyGenMCCodeEmitter.inc"199