Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
Line
Count
Source (jump to first uncovered line)
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-exception
6
//
7
//===----------------------------------------------------------------------===//
8
///
9
/// \file
10
/// This file implements the WebAssemblyMCCodeEmitter class.
11
///
12
//===----------------------------------------------------------------------===//
13
14
#include "MCTargetDesc/WebAssemblyFixupKinds.h"
15
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
16
#include "llvm/ADT/STLExtras.h"
17
#include "llvm/ADT/Statistic.h"
18
#include "llvm/MC/MCCodeEmitter.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/raw_ostream.h"
29
30
using namespace llvm;
31
32
#define DEBUG_TYPE "mccodeemitter"
33
34
STATISTIC(MCNumEmitted, "Number of MC instructions emitted.");
35
STATISTIC(MCNumFixups, "Number of MC fixups created.");
36
37
namespace {
38
class WebAssemblyMCCodeEmitter final : public MCCodeEmitter {
39
  const MCInstrInfo &MCII;
40
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, raw_ostream &OS,
47
                         SmallVectorImpl<MCFixup> &Fixups,
48
                         const MCSubtargetInfo &STI) const override;
49
50
public:
51
213
  WebAssemblyMCCodeEmitter(const MCInstrInfo &MCII) : MCII(MCII) {}
52
};
53
} // end anonymous namespace
54
55
213
MCCodeEmitter *llvm::createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII) {
56
213
  return new WebAssemblyMCCodeEmitter(MCII);
57
213
}
58
59
void WebAssemblyMCCodeEmitter::encodeInstruction(
60
    const MCInst &MI, raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups,
61
1.62k
    const MCSubtargetInfo &STI) const {
62
1.62k
  uint64_t Start = OS.tell();
63
1.62k
64
1.62k
  uint64_t Binary = getBinaryCodeForInstr(MI, Fixups, STI);
65
1.62k
  if (Binary <= UINT8_MAX) {
66
1.41k
    OS << uint8_t(Binary);
67
1.41k
  } else {
68
216
    assert(Binary <= UINT16_MAX && "Several-byte opcodes not supported yet");
69
216
    OS << uint8_t(Binary >> 8);
70
216
    encodeULEB128(uint8_t(Binary), OS);
71
216
  }
72
1.62k
73
1.62k
  // For br_table instructions, encode the size of the table. In the MCInst,
74
1.62k
  // there's an index operand (if not a stack instruction), one operand for
75
1.62k
  // each table entry, and the default operand.
76
1.62k
  if (MI.getOpcode() == WebAssembly::BR_TABLE_I32_S ||
77
1.62k
      MI.getOpcode() == WebAssembly::BR_TABLE_I64_S)
78
1
    encodeULEB128(MI.getNumOperands() - 1, OS);
79
1.62k
  if (MI.getOpcode() == WebAssembly::BR_TABLE_I32 ||
80
1.62k
      MI.getOpcode() == WebAssembly::BR_TABLE_I64)
81
0
    encodeULEB128(MI.getNumOperands() - 2, OS);
82
1.62k
83
1.62k
  const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
84
2.89k
  for (unsigned I = 0, E = MI.getNumOperands(); I < E; 
++I1.26k
) {
85
1.26k
    const MCOperand &MO = MI.getOperand(I);
86
1.26k
    if (MO.isReg()) {
87
33
      /* nothing to encode */
88
33
89
1.23k
    } else if (MO.isImm()) {
90
815
      if (I < Desc.getNumOperands()) {
91
813
        const MCOperandInfo &Info = Desc.OpInfo[I];
92
813
        LLVM_DEBUG(dbgs() << "Encoding immediate: type="
93
813
                          << int(Info.OperandType) << "\n");
94
813
        switch (Info.OperandType) {
95
813
        case WebAssembly::OPERAND_I32IMM:
96
277
          encodeSLEB128(int32_t(MO.getImm()), OS);
97
277
          break;
98
813
        case WebAssembly::OPERAND_OFFSET32:
99
87
          encodeULEB128(uint32_t(MO.getImm()), OS);
100
87
          break;
101
813
        case WebAssembly::OPERAND_I64IMM:
102
11
          encodeSLEB128(int64_t(MO.getImm()), OS);
103
11
          break;
104
813
        case WebAssembly::OPERAND_SIGNATURE:
105
20
          OS << uint8_t(MO.getImm());
106
20
          break;
107
813
        case WebAssembly::OPERAND_VEC_I8IMM:
108
62
          support::endian::write<uint8_t>(OS, MO.getImm(), support::little);
109
62
          break;
110
813
        case WebAssembly::OPERAND_VEC_I16IMM:
111
16
          support::endian::write<uint16_t>(OS, MO.getImm(), support::little);
112
16
          break;
113
813
        case WebAssembly::OPERAND_VEC_I32IMM:
114
0
          support::endian::write<uint32_t>(OS, MO.getImm(), support::little);
115
0
          break;
116
813
        case WebAssembly::OPERAND_VEC_I64IMM:
117
0
          support::endian::write<uint64_t>(OS, MO.getImm(), support::little);
118
0
          break;
119
813
        case WebAssembly::OPERAND_GLOBAL:
120
0
          llvm_unreachable("wasm globals should only be accessed symbolicly");
121
813
        default:
122
340
          encodeULEB128(uint64_t(MO.getImm()), OS);
123
813
        }
124
813
      } else {
125
2
        encodeULEB128(uint64_t(MO.getImm()), OS);
126
2
      }
127
815
128
815
    } else 
if (416
MO.isFPImm()416
) {
129
15
      const MCOperandInfo &Info = Desc.OpInfo[I];
130
15
      if (Info.OperandType == WebAssembly::OPERAND_F32IMM) {
131
12
        // TODO: MC converts all floating point immediate operands to double.
132
12
        // This is fine for numeric values, but may cause NaNs to change bits.
133
12
        auto F = float(MO.getFPImm());
134
12
        support::endian::write<float>(OS, F, support::little);
135
12
      } else {
136
3
        assert(Info.OperandType == WebAssembly::OPERAND_F64IMM);
137
3
        double D = MO.getFPImm();
138
3
        support::endian::write<double>(OS, D, support::little);
139
3
      }
140
15
141
401
    } else if (MO.isExpr()) {
142
401
      const MCOperandInfo &Info = Desc.OpInfo[I];
143
401
      llvm::MCFixupKind FixupKind;
144
401
      size_t PaddedSize = 5;
145
401
      switch (Info.OperandType) {
146
401
      case WebAssembly::OPERAND_I32IMM:
147
66
        FixupKind = MCFixupKind(WebAssembly::fixup_sleb128_i32);
148
66
        break;
149
401
      case WebAssembly::OPERAND_I64IMM:
150
0
        FixupKind = MCFixupKind(WebAssembly::fixup_sleb128_i64);
151
0
        PaddedSize = 10;
152
0
        break;
153
401
      case WebAssembly::OPERAND_FUNCTION32:
154
335
      case WebAssembly::OPERAND_OFFSET32:
155
335
      case WebAssembly::OPERAND_TYPEINDEX:
156
335
      case WebAssembly::OPERAND_GLOBAL:
157
335
      case WebAssembly::OPERAND_EVENT:
158
335
        FixupKind = MCFixupKind(WebAssembly::fixup_uleb128_i32);
159
335
        break;
160
335
      default:
161
0
        llvm_unreachable("unexpected symbolic operand kind");
162
401
      }
163
401
      Fixups.push_back(MCFixup::create(OS.tell() - Start, MO.getExpr(),
164
401
                                       FixupKind, MI.getLoc()));
165
401
      ++MCNumFixups;
166
401
      encodeULEB128(0, OS, PaddedSize);
167
401
    } else {
168
0
      llvm_unreachable("unexpected operand kind");
169
0
    }
170
1.26k
  }
171
1.62k
172
1.62k
  ++MCNumEmitted; // Keep track of the # of mi's emitted.
173
1.62k
}
174
175
#include "WebAssemblyGenMCCodeEmitter.inc"