blob: 44b6d6a968a9d1d518628c39448c4b0a963fe458 [file] [log] [blame]
Dan Gohman05ac43f2015-12-17 01:39:00 +00001//=- WebAssemblyMCCodeEmitter.cpp - Convert WebAssembly code to machine code -//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Dan Gohman05ac43f2015-12-17 01:39:00 +00006//
7//===----------------------------------------------------------------------===//
8///
9/// \file
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000010/// This file implements the WebAssemblyMCCodeEmitter class.
Dan Gohman05ac43f2015-12-17 01:39:00 +000011///
12//===----------------------------------------------------------------------===//
13
Dan Gohmand934cb82017-02-24 23:18:00 +000014#include "MCTargetDesc/WebAssemblyFixupKinds.h"
Chandler Carruth6bda14b2017-06-06 11:49:48 +000015#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
Dan Gohman1a427282016-01-12 03:32:29 +000016#include "llvm/ADT/STLExtras.h"
Dan Gohman05ac43f2015-12-17 01:39:00 +000017#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"
Sam Clegg685c5e82018-04-04 22:27:58 +000025#include "llvm/Support/Debug.h"
Reid Kleckner8f4bd1f2016-06-23 18:12:31 +000026#include "llvm/Support/EndianStream.h"
Dan Gohman4fc4e422016-10-24 19:49:43 +000027#include "llvm/Support/LEB128.h"
Dan Gohman05ac43f2015-12-17 01:39:00 +000028#include "llvm/Support/raw_ostream.h"
Sam Clegg685c5e82018-04-04 22:27:58 +000029
Dan Gohman05ac43f2015-12-17 01:39:00 +000030using namespace llvm;
31
32#define DEBUG_TYPE "mccodeemitter"
33
Dan Gohman1a427282016-01-12 03:32:29 +000034STATISTIC(MCNumEmitted, "Number of MC instructions emitted.");
35STATISTIC(MCNumFixups, "Number of MC fixups created.");
36
Dan Gohman05ac43f2015-12-17 01:39:00 +000037namespace {
38class WebAssemblyMCCodeEmitter final : public MCCodeEmitter {
Dan Gohman1a427282016-01-12 03:32:29 +000039 const MCInstrInfo &MCII;
Dan Gohman05ac43f2015-12-17 01:39:00 +000040
Dan Gohman1a427282016-01-12 03:32:29 +000041 // Implementation generated by tablegen.
Dan Gohman05ac43f2015-12-17 01:39:00 +000042 uint64_t getBinaryCodeForInstr(const MCInst &MI,
43 SmallVectorImpl<MCFixup> &Fixups,
44 const MCSubtargetInfo &STI) const;
45
Dan Gohman05ac43f2015-12-17 01:39:00 +000046 void encodeInstruction(const MCInst &MI, raw_ostream &OS,
47 SmallVectorImpl<MCFixup> &Fixups,
48 const MCSubtargetInfo &STI) const override;
Dan Gohman1a427282016-01-12 03:32:29 +000049
50public:
Heejin Ahn18c56a02019-02-04 19:13:39 +000051 WebAssemblyMCCodeEmitter(const MCInstrInfo &MCII) : MCII(MCII) {}
Dan Gohman05ac43f2015-12-17 01:39:00 +000052};
53} // end anonymous namespace
54
Sam Clegg9d24fb72017-06-16 23:59:10 +000055MCCodeEmitter *llvm::createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII) {
56 return new WebAssemblyMCCodeEmitter(MCII);
Dan Gohman05ac43f2015-12-17 01:39:00 +000057}
58
59void WebAssemblyMCCodeEmitter::encodeInstruction(
60 const MCInst &MI, raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups,
61 const MCSubtargetInfo &STI) const {
Dan Gohman4fc4e422016-10-24 19:49:43 +000062 uint64_t Start = OS.tell();
63
64 uint64_t Binary = getBinaryCodeForInstr(MI, Fixups, STI);
Dan Gohmancdd48b82017-11-28 01:13:40 +000065 if (Binary <= UINT8_MAX) {
66 OS << uint8_t(Binary);
67 } else {
68 assert(Binary <= UINT16_MAX && "Several-byte opcodes not supported yet");
Thomas Lively299d2142018-11-09 01:45:56 +000069 OS << uint8_t(Binary >> 8);
70 encodeULEB128(uint8_t(Binary), OS);
Dan Gohmancdd48b82017-11-28 01:13:40 +000071 }
Dan Gohman4fc4e422016-10-24 19:49:43 +000072
Dan Gohmand934cb82017-02-24 23:18:00 +000073 // For br_table instructions, encode the size of the table. In the MCInst,
Wouter van Oortmerssen8a9cb242018-08-27 15:45:51 +000074 // there's an index operand (if not a stack instruction), one operand for
75 // each table entry, and the default operand.
76 if (MI.getOpcode() == WebAssembly::BR_TABLE_I32_S ||
77 MI.getOpcode() == WebAssembly::BR_TABLE_I64_S)
78 encodeULEB128(MI.getNumOperands() - 1, OS);
Dan Gohmand934cb82017-02-24 23:18:00 +000079 if (MI.getOpcode() == WebAssembly::BR_TABLE_I32 ||
80 MI.getOpcode() == WebAssembly::BR_TABLE_I64)
81 encodeULEB128(MI.getNumOperands() - 2, OS);
82
Dan Gohman1a427282016-01-12 03:32:29 +000083 const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
Heejin Ahn18c56a02019-02-04 19:13:39 +000084 for (unsigned I = 0, E = MI.getNumOperands(); I < E; ++I) {
85 const MCOperand &MO = MI.getOperand(I);
Dan Gohman1a427282016-01-12 03:32:29 +000086 if (MO.isReg()) {
Dan Gohman4fc4e422016-10-24 19:49:43 +000087 /* nothing to encode */
Heejin Ahnda419bd2018-11-14 02:46:21 +000088
Dan Gohman1a427282016-01-12 03:32:29 +000089 } else if (MO.isImm()) {
Heejin Ahn18c56a02019-02-04 19:13:39 +000090 if (I < Desc.getNumOperands()) {
91 const MCOperandInfo &Info = Desc.OpInfo[I];
Nicola Zaghend34e60c2018-05-14 12:53:11 +000092 LLVM_DEBUG(dbgs() << "Encoding immediate: type="
93 << int(Info.OperandType) << "\n");
Thomas Lively22442922018-08-21 21:03:18 +000094 switch (Info.OperandType) {
95 case WebAssembly::OPERAND_I32IMM:
Dan Gohman3acb1872016-10-24 23:27:49 +000096 encodeSLEB128(int32_t(MO.getImm()), OS);
Thomas Lively22442922018-08-21 21:03:18 +000097 break;
98 case WebAssembly::OPERAND_OFFSET32:
Sam Clegg685c5e82018-04-04 22:27:58 +000099 encodeULEB128(uint32_t(MO.getImm()), OS);
Thomas Lively22442922018-08-21 21:03:18 +0000100 break;
101 case WebAssembly::OPERAND_I64IMM:
Dan Gohman3acb1872016-10-24 23:27:49 +0000102 encodeSLEB128(int64_t(MO.getImm()), OS);
Thomas Lively22442922018-08-21 21:03:18 +0000103 break;
104 case WebAssembly::OPERAND_SIGNATURE:
Heejin Ahn0c69a3e2018-03-02 20:52:59 +0000105 OS << uint8_t(MO.getImm());
Thomas Lively22442922018-08-21 21:03:18 +0000106 break;
107 case WebAssembly::OPERAND_VEC_I8IMM:
108 support::endian::write<uint8_t>(OS, MO.getImm(), support::little);
109 break;
110 case WebAssembly::OPERAND_VEC_I16IMM:
111 support::endian::write<uint16_t>(OS, MO.getImm(), support::little);
112 break;
113 case WebAssembly::OPERAND_VEC_I32IMM:
114 support::endian::write<uint32_t>(OS, MO.getImm(), support::little);
115 break;
116 case WebAssembly::OPERAND_VEC_I64IMM:
117 support::endian::write<uint64_t>(OS, MO.getImm(), support::little);
118 break;
119 case WebAssembly::OPERAND_GLOBAL:
120 llvm_unreachable("wasm globals should only be accessed symbolicly");
121 default:
Dan Gohman3acb1872016-10-24 23:27:49 +0000122 encodeULEB128(uint64_t(MO.getImm()), OS);
123 }
Dan Gohman4fc4e422016-10-24 19:49:43 +0000124 } else {
125 encodeULEB128(uint64_t(MO.getImm()), OS);
126 }
Heejin Ahnda419bd2018-11-14 02:46:21 +0000127
Dan Gohman1a427282016-01-12 03:32:29 +0000128 } else if (MO.isFPImm()) {
Heejin Ahn18c56a02019-02-04 19:13:39 +0000129 const MCOperandInfo &Info = Desc.OpInfo[I];
Dan Gohman4fc4e422016-10-24 19:49:43 +0000130 if (Info.OperandType == WebAssembly::OPERAND_F32IMM) {
131 // TODO: MC converts all floating point immediate operands to double.
132 // This is fine for numeric values, but may cause NaNs to change bits.
Heejin Ahn18c56a02019-02-04 19:13:39 +0000133 auto F = float(MO.getFPImm());
134 support::endian::write<float>(OS, F, support::little);
Dan Gohman4fc4e422016-10-24 19:49:43 +0000135 } else {
136 assert(Info.OperandType == WebAssembly::OPERAND_F64IMM);
Heejin Ahn18c56a02019-02-04 19:13:39 +0000137 double D = MO.getFPImm();
138 support::endian::write<double>(OS, D, support::little);
Dan Gohman4fc4e422016-10-24 19:49:43 +0000139 }
Heejin Ahnda419bd2018-11-14 02:46:21 +0000140
Dan Gohman1a427282016-01-12 03:32:29 +0000141 } else if (MO.isExpr()) {
Heejin Ahn18c56a02019-02-04 19:13:39 +0000142 const MCOperandInfo &Info = Desc.OpInfo[I];
Dan Gohmand934cb82017-02-24 23:18:00 +0000143 llvm::MCFixupKind FixupKind;
Sam Clegg66a99e42017-09-15 20:34:47 +0000144 size_t PaddedSize = 5;
Heejin Ahnda419bd2018-11-14 02:46:21 +0000145 switch (Info.OperandType) {
146 case WebAssembly::OPERAND_I32IMM:
Sam Clegga5e175c2019-03-28 02:07:28 +0000147 FixupKind = MCFixupKind(WebAssembly::fixup_sleb128_i32);
Heejin Ahnda419bd2018-11-14 02:46:21 +0000148 break;
149 case WebAssembly::OPERAND_I64IMM:
Sam Clegga5e175c2019-03-28 02:07:28 +0000150 FixupKind = MCFixupKind(WebAssembly::fixup_sleb128_i64);
Dan Gohmand934cb82017-02-24 23:18:00 +0000151 PaddedSize = 10;
Heejin Ahnda419bd2018-11-14 02:46:21 +0000152 break;
153 case WebAssembly::OPERAND_FUNCTION32:
154 case WebAssembly::OPERAND_OFFSET32:
155 case WebAssembly::OPERAND_TYPEINDEX:
156 case WebAssembly::OPERAND_GLOBAL:
157 case WebAssembly::OPERAND_EVENT:
Sam Clegga5e175c2019-03-28 02:07:28 +0000158 FixupKind = MCFixupKind(WebAssembly::fixup_uleb128_i32);
Heejin Ahnda419bd2018-11-14 02:46:21 +0000159 break;
160 default:
Dan Gohmand934cb82017-02-24 23:18:00 +0000161 llvm_unreachable("unexpected symbolic operand kind");
162 }
Heejin Ahnf208f632018-09-05 01:27:38 +0000163 Fixups.push_back(MCFixup::create(OS.tell() - Start, MO.getExpr(),
164 FixupKind, MI.getLoc()));
Dan Gohman1a427282016-01-12 03:32:29 +0000165 ++MCNumFixups;
Sam Clegg66a99e42017-09-15 20:34:47 +0000166 encodeULEB128(0, OS, PaddedSize);
Dan Gohman1a427282016-01-12 03:32:29 +0000167 } else {
168 llvm_unreachable("unexpected operand kind");
169 }
170 }
Dan Gohman05ac43f2015-12-17 01:39:00 +0000171
Dan Gohman1a427282016-01-12 03:32:29 +0000172 ++MCNumEmitted; // Keep track of the # of mi's emitted.
Dan Gohman05ac43f2015-12-17 01:39:00 +0000173}
174
175#include "WebAssemblyGenMCCodeEmitter.inc"