LCOV - code coverage report
Current view: top level - lib/Target/WebAssembly/MCTargetDesc - WebAssemblyMCCodeEmitter.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 52 63 82.5 %
Date: 2018-10-20 13:21:21 Functions: 2 2 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //=- WebAssemblyMCCodeEmitter.cpp - Convert WebAssembly code to machine code -//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : ///
      10             : /// \file
      11             : /// This file implements the WebAssemblyMCCodeEmitter class.
      12             : ///
      13             : //===----------------------------------------------------------------------===//
      14             : 
      15             : #include "MCTargetDesc/WebAssemblyFixupKinds.h"
      16             : #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
      17             : #include "llvm/ADT/STLExtras.h"
      18             : #include "llvm/ADT/Statistic.h"
      19             : #include "llvm/MC/MCCodeEmitter.h"
      20             : #include "llvm/MC/MCFixup.h"
      21             : #include "llvm/MC/MCInst.h"
      22             : #include "llvm/MC/MCInstrInfo.h"
      23             : #include "llvm/MC/MCRegisterInfo.h"
      24             : #include "llvm/MC/MCSubtargetInfo.h"
      25             : #include "llvm/MC/MCSymbol.h"
      26             : #include "llvm/Support/Debug.h"
      27             : #include "llvm/Support/EndianStream.h"
      28             : #include "llvm/Support/LEB128.h"
      29             : #include "llvm/Support/raw_ostream.h"
      30             : 
      31             : using namespace llvm;
      32             : 
      33             : #define DEBUG_TYPE "mccodeemitter"
      34             : 
      35             : STATISTIC(MCNumEmitted, "Number of MC instructions emitted.");
      36             : STATISTIC(MCNumFixups, "Number of MC fixups created.");
      37             : 
      38             : namespace {
      39             : class WebAssemblyMCCodeEmitter final : public MCCodeEmitter {
      40             :   const MCInstrInfo &MCII;
      41             : 
      42             :   // Implementation generated by tablegen.
      43             :   uint64_t getBinaryCodeForInstr(const MCInst &MI,
      44             :                                  SmallVectorImpl<MCFixup> &Fixups,
      45             :                                  const MCSubtargetInfo &STI) const;
      46             : 
      47             :   void encodeInstruction(const MCInst &MI, raw_ostream &OS,
      48             :                          SmallVectorImpl<MCFixup> &Fixups,
      49             :                          const MCSubtargetInfo &STI) const override;
      50             : 
      51             : public:
      52         154 :   WebAssemblyMCCodeEmitter(const MCInstrInfo &mcii) : MCII(mcii) {}
      53             : };
      54             : } // end anonymous namespace
      55             : 
      56         154 : MCCodeEmitter *llvm::createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII) {
      57         154 :   return new WebAssemblyMCCodeEmitter(MCII);
      58             : }
      59             : 
      60        4087 : void WebAssemblyMCCodeEmitter::encodeInstruction(
      61             :     const MCInst &MI, raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups,
      62             :     const MCSubtargetInfo &STI) const {
      63             :   uint64_t Start = OS.tell();
      64             : 
      65        4087 :   uint64_t Binary = getBinaryCodeForInstr(MI, Fixups, STI);
      66        4087 :   if (Binary <= UINT8_MAX) {
      67        3782 :     OS << uint8_t(Binary);
      68             :   } else {
      69             :     assert(Binary <= UINT16_MAX && "Several-byte opcodes not supported yet");
      70         610 :     OS << uint8_t(Binary >> 8) << uint8_t(Binary);
      71             :   }
      72             : 
      73             :   // For br_table instructions, encode the size of the table. In the MCInst,
      74             :   // there's an index operand (if not a stack instruction), one operand for
      75             :   // each table entry, and the default operand.
      76        4087 :   if (MI.getOpcode() == WebAssembly::BR_TABLE_I32_S ||
      77             :       MI.getOpcode() == WebAssembly::BR_TABLE_I64_S)
      78           0 :     encodeULEB128(MI.getNumOperands() - 1, OS);
      79        4087 :   if (MI.getOpcode() == WebAssembly::BR_TABLE_I32 ||
      80             :       MI.getOpcode() == WebAssembly::BR_TABLE_I64)
      81           0 :     encodeULEB128(MI.getNumOperands() - 2, OS);
      82             : 
      83        4087 :   const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
      84       11834 :   for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) {
      85             :     const MCOperand &MO = MI.getOperand(i);
      86        7747 :     if (MO.isReg()) {
      87             :       /* nothing to encode */
      88        1661 :     } else if (MO.isImm()) {
      89        2674 :       if (i < Desc.getNumOperands()) {
      90             :         assert(Desc.TSFlags == 0 &&
      91             :                "WebAssembly non-variable_ops don't use TSFlags");
      92        1337 :         const MCOperandInfo &Info = Desc.OpInfo[i];
      93             :         LLVM_DEBUG(dbgs() << "Encoding immediate: type="
      94             :                           << int(Info.OperandType) << "\n");
      95        1337 :         switch (Info.OperandType) {
      96         872 :         case WebAssembly::OPERAND_I32IMM:
      97         872 :           encodeSLEB128(int32_t(MO.getImm()), OS);
      98         872 :           break;
      99          93 :         case WebAssembly::OPERAND_OFFSET32:
     100          93 :           encodeULEB128(uint32_t(MO.getImm()), OS);
     101          93 :           break;
     102          13 :         case WebAssembly::OPERAND_I64IMM:
     103          13 :           encodeSLEB128(int64_t(MO.getImm()), OS);
     104          13 :           break;
     105           9 :         case WebAssembly::OPERAND_SIGNATURE:
     106           9 :           OS << uint8_t(MO.getImm());
     107             :           break;
     108          46 :         case WebAssembly::OPERAND_VEC_I8IMM:
     109          46 :           support::endian::write<uint8_t>(OS, MO.getImm(), support::little);
     110          46 :           break;
     111           8 :         case WebAssembly::OPERAND_VEC_I16IMM:
     112           8 :           support::endian::write<uint16_t>(OS, MO.getImm(), support::little);
     113           8 :           break;
     114           0 :         case WebAssembly::OPERAND_VEC_I32IMM:
     115           0 :           support::endian::write<uint32_t>(OS, MO.getImm(), support::little);
     116           0 :           break;
     117           0 :         case WebAssembly::OPERAND_VEC_I64IMM:
     118           0 :           support::endian::write<uint64_t>(OS, MO.getImm(), support::little);
     119           0 :           break;
     120             :         case WebAssembly::OPERAND_GLOBAL:
     121             :           llvm_unreachable("wasm globals should only be accessed symbolicly");
     122         296 :         default:
     123         296 :           encodeULEB128(uint64_t(MO.getImm()), OS);
     124             :         }
     125             :       } else {
     126             :         assert(Desc.TSFlags == (WebAssemblyII::VariableOpIsImmediate |
     127             :                                 WebAssemblyII::VariableOpImmediateIsLabel));
     128           0 :         encodeULEB128(uint64_t(MO.getImm()), OS);
     129             :       }
     130         324 :     } else if (MO.isFPImm()) {
     131             :       assert(i < Desc.getNumOperands() &&
     132             :              "Unexpected floating-point immediate as a non-fixed operand");
     133             :       assert(Desc.TSFlags == 0 &&
     134             :              "WebAssembly variable_ops floating point ops don't use TSFlags");
     135           8 :       const MCOperandInfo &Info = Desc.OpInfo[i];
     136           8 :       if (Info.OperandType == WebAssembly::OPERAND_F32IMM) {
     137             :         // TODO: MC converts all floating point immediate operands to double.
     138             :         // This is fine for numeric values, but may cause NaNs to change bits.
     139           6 :         float f = float(MO.getFPImm());
     140             :         support::endian::write<float>(OS, f, support::little);
     141             :       } else {
     142             :         assert(Info.OperandType == WebAssembly::OPERAND_F64IMM);
     143           2 :         double d = MO.getFPImm();
     144             :         support::endian::write<double>(OS, d, support::little);
     145             :       }
     146         316 :     } else if (MO.isExpr()) {
     147         316 :       const MCOperandInfo &Info = Desc.OpInfo[i];
     148             :       llvm::MCFixupKind FixupKind;
     149             :       size_t PaddedSize = 5;
     150         316 :       if (Info.OperandType == WebAssembly::OPERAND_I32IMM) {
     151             :         FixupKind = MCFixupKind(WebAssembly::fixup_code_sleb128_i32);
     152         267 :       } else if (Info.OperandType == WebAssembly::OPERAND_I64IMM) {
     153             :         FixupKind = MCFixupKind(WebAssembly::fixup_code_sleb128_i64);
     154             :         PaddedSize = 10;
     155         267 :       } else if (Info.OperandType == WebAssembly::OPERAND_FUNCTION32 ||
     156         267 :                  Info.OperandType == WebAssembly::OPERAND_OFFSET32 ||
     157             :                  Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
     158             :         FixupKind = MCFixupKind(WebAssembly::fixup_code_uleb128_i32);
     159          20 :       } else if (Info.OperandType == WebAssembly::OPERAND_GLOBAL) {
     160             :         FixupKind = MCFixupKind(WebAssembly::fixup_code_uleb128_i32);
     161             :       } else {
     162           0 :         llvm_unreachable("unexpected symbolic operand kind");
     163             :       }
     164         316 :       Fixups.push_back(MCFixup::create(OS.tell() - Start, MO.getExpr(),
     165         316 :                                        FixupKind, MI.getLoc()));
     166             :       ++MCNumFixups;
     167         316 :       encodeULEB128(0, OS, PaddedSize);
     168             :     } else {
     169           0 :       llvm_unreachable("unexpected operand kind");
     170             :     }
     171             :   }
     172             : 
     173             :   ++MCNumEmitted; // Keep track of the # of mi's emitted.
     174        4087 : }
     175             : 
     176             : #include "WebAssemblyGenMCCodeEmitter.inc"

Generated by: LCOV version 1.13