LLVM 24.0.0git
WebAssemblyMCCodeEmitter.cpp
Go to the documentation of this file.
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
16#include "llvm/ADT/Statistic.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"
23#include "llvm/MC/MCSymbol.h"
24#include "llvm/Support/Debug.h"
26#include "llvm/Support/LEB128.h"
27#include "llvm/Support/SMLoc.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,
44 const MCSubtargetInfo &STI) const;
45
46 void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,
48 const MCSubtargetInfo &STI) const override;
49
50 void encodeP2AlignAndMemOrder(const MCInst &MI, unsigned P2AlignIdx,
51 const MCInstrDesc &Desc,
52 const MCSubtargetInfo &STI, raw_ostream &OS,
54 uint64_t Start) const;
55
56 uint8_t getEncodedMemOrder(uint8_t Order, unsigned Opcode) const;
57
58public:
59 WebAssemblyMCCodeEmitter(const MCInstrInfo &MCII, MCContext &Ctx)
60 : MCII(MCII), Ctx{Ctx} {}
61};
62} // end anonymous namespace
63
65 MCContext &Ctx) {
66 return new WebAssemblyMCCodeEmitter(MCII, Ctx);
67}
68
69uint8_t WebAssemblyMCCodeEmitter::getEncodedMemOrder(uint8_t Order,
70 unsigned Opcode) const {
71 if (Order == wasm::WASM_MEM_ORDER_ACQ_REL) {
72 StringRef Name = MCII.getName(Opcode);
73 if (Name.contains("RMW") || Name.contains("CMPXCHG"))
75 }
76 return Order;
77}
78
79void WebAssemblyMCCodeEmitter::encodeP2AlignAndMemOrder(
80 const MCInst &MI, unsigned P2AlignIdx, const MCInstrDesc &Desc,
81 const MCSubtargetInfo &STI, raw_ostream &OS,
82 SmallVectorImpl<MCFixup> &Fixups, uint64_t Start) const {
83 uint64_t P2Align = MI.getOperand(P2AlignIdx).getImm();
84 uint8_t Order = wasm::WASM_MEM_ORDER_SEQ_CST;
85
86 // Atomic instructions always have an ordering, but if it's SEQ_CST then we
87 // don't use the acquire-release-atomics encoding (even if
88 // acquire-release-atomics is enabled) because the original encoding is
89 // smaller.
90 if (P2AlignIdx > 0 && Desc.operands()[P2AlignIdx - 1].OperandType ==
91 WebAssembly::OPERAND_MEMORDER) {
92 Order = MI.getOperand(P2AlignIdx - 1).getImm();
93 if (Order != wasm::WASM_MEM_ORDER_SEQ_CST) {
94 assert(STI.getFeatureBits()[WebAssembly::FeatureAcquireReleaseAtomics] &&
95 "Non-default atomic ordering but feature not enabled");
97 }
98 }
99
100 encodeULEB128(P2Align, OS);
101
102 // Memory index will go here once we support multi-memory.
103
104 if (P2Align & wasm::WASM_MEMARG_HAS_MEM_ORDER) {
106 getEncodedMemOrder(Order, MI.getOpcode()),
108 }
109}
110
111void WebAssemblyMCCodeEmitter::encodeInstruction(
112 const MCInst &MI, SmallVectorImpl<char> &CB,
113 SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
114 raw_svector_ostream OS(CB);
115 uint64_t Start = OS.tell();
116
117 uint64_t Binary = getBinaryCodeForInstr(MI, Fixups, STI);
118 if (Binary < (1 << 8)) {
119 OS << uint8_t(Binary);
120 } else if (Binary < (1 << 16)) {
121 OS << uint8_t(Binary >> 8);
122 encodeULEB128(uint8_t(Binary), OS);
123 } else if (Binary < (1 << 24)) {
124 OS << uint8_t(Binary >> 16);
125 encodeULEB128(uint16_t(Binary), OS);
126 } else {
127 llvm_unreachable("Very large (prefix + 3 byte) opcodes not supported");
128 }
129
130 // For br_table instructions, encode the size of the table. In the MCInst,
131 // there's an index operand (if not a stack instruction), one operand for
132 // each table entry, and the default operand.
133 unsigned Opcode = MI.getOpcode();
134 if (Opcode == WebAssembly::BR_TABLE_I32_S ||
135 Opcode == WebAssembly::BR_TABLE_I64_S)
136 encodeULEB128(MI.getNumOperands() - 1, OS);
137 if (Opcode == WebAssembly::BR_TABLE_I32 ||
138 Opcode == WebAssembly::BR_TABLE_I64)
139 encodeULEB128(MI.getNumOperands() - 2, OS);
140
141 const MCInstrDesc &Desc = MCII.get(Opcode);
142 for (unsigned I = 0, E = MI.getNumOperands(); I < E; ++I) {
143 const MCOperand &MO = MI.getOperand(I);
144 if (MO.isReg()) {
145 /* nothing to encode */
146
147 } else if (MO.isImm()) {
148 if (I < Desc.getNumOperands()) {
149 const MCOperandInfo &Info = Desc.operands()[I];
150 LLVM_DEBUG(dbgs() << "Encoding immediate: type="
151 << int(Info.OperandType) << "\n");
152 switch (Info.OperandType) {
153 case WebAssembly::OPERAND_I32IMM:
154 encodeSLEB128(int32_t(MO.getImm()), OS);
155 break;
156 case WebAssembly::OPERAND_P2ALIGN:
157 encodeP2AlignAndMemOrder(MI, I, Desc, STI, OS, Fixups, Start);
158 break;
159 case WebAssembly::OPERAND_OFFSET32:
160 encodeULEB128(uint32_t(MO.getImm()), OS);
161 break;
162 case WebAssembly::OPERAND_I64IMM:
163 encodeSLEB128(MO.getImm(), OS);
164 break;
165 case WebAssembly::OPERAND_SIGNATURE:
166 case WebAssembly::OPERAND_VEC_I8IMM:
169 break;
170 case WebAssembly::OPERAND_VALTYPE_LIST: {
171 // A vec of valtypes: emit the ULEB count followed by that many
172 // single-byte value types. The count lives in this MCOperand;
173 // subsequent MCOperands hold the valtype bytes and are consumed here.
175 if (Count > uint64_t(E - I - 1))
177 "select t* operand count exceeds MCInst operand count");
178 encodeULEB128(Count, OS);
179 for (uint64_t K = 0; K < Count; ++K) {
180 ++I;
181 int64_t Val = MI.getOperand(I).getImm();
182 assert(isUInt<8>(Val) && "select t* valtype out of byte range");
184 }
185 break;
186 }
187 case WebAssembly::OPERAND_MEMORDER: {
188 // If there is a p2align operand (everything but fence) it is encoded
189 // together with the mem ordering (in the next iteration).
190 if (I + 1 < Desc.getNumOperands() &&
191 Desc.operands()[I + 1].OperandType ==
192 WebAssembly::OPERAND_P2ALIGN)
193 break;
194 uint8_t Val = getEncodedMemOrder(MO.getImm(), Opcode);
195 if (STI.getFeatureBits()[WebAssembly::FeatureAcquireReleaseAtomics]) {
197 } else {
198 assert(Opcode == WebAssembly::ATOMIC_FENCE_S);
200 }
201 break;
202 }
203 case WebAssembly::OPERAND_VEC_I16IMM:
206 break;
207 case WebAssembly::OPERAND_VEC_I32IMM:
210 break;
211 case WebAssembly::OPERAND_VEC_I64IMM:
214 break;
215 case WebAssembly::OPERAND_GLOBAL:
216 Ctx.reportError(
217 SMLoc(),
218 Twine("Wasm globals should only be accessed symbolically!"));
219 break;
220 default:
221 encodeULEB128(uint64_t(MO.getImm()), OS);
222 }
223 } else {
224 // Variadic immediate operands are br_table's destination operands or
225 // try_table's operands (# of catch clauses, catch sub-opcodes, or catch
226 // clause destinations)
227 assert(WebAssembly::isBrTable(Opcode) ||
228 Opcode == WebAssembly::TRY_TABLE_S);
229 encodeULEB128(uint32_t(MO.getImm()), OS);
230 }
231
232 } else if (MO.isSFPImm()) {
233 uint32_t F = MO.getSFPImm();
235 } else if (MO.isDFPImm()) {
236 uint64_t D = MO.getDFPImm();
238 } else if (MO.isExpr()) {
240 size_t PaddedSize = 5;
241 if (I < Desc.getNumOperands()) {
242 const MCOperandInfo &Info = Desc.operands()[I];
243 switch (Info.OperandType) {
244 case WebAssembly::OPERAND_I32IMM:
245 FixupKind = WebAssembly::fixup_sleb128_i32;
246 break;
247 case WebAssembly::OPERAND_I64IMM:
248 FixupKind = WebAssembly::fixup_sleb128_i64;
249 PaddedSize = 10;
250 break;
251 case WebAssembly::OPERAND_FUNCTION32:
252 case WebAssembly::OPERAND_TABLE:
253 case WebAssembly::OPERAND_OFFSET32:
254 case WebAssembly::OPERAND_SIGNATURE:
255 case WebAssembly::OPERAND_TYPEINDEX:
256 case WebAssembly::OPERAND_GLOBAL:
257 case WebAssembly::OPERAND_TAG:
258 FixupKind = WebAssembly::fixup_uleb128_i32;
259 break;
260 case WebAssembly::OPERAND_OFFSET64:
261 FixupKind = WebAssembly::fixup_uleb128_i64;
262 PaddedSize = 10;
263 break;
264 default:
265 llvm_unreachable("unexpected symbolic operand kind");
266 }
267 } else {
268 // Variadic expr operands are try_table's catch/catch_ref clauses' tags.
269 assert(Opcode == WebAssembly::TRY_TABLE_S);
270 FixupKind = WebAssembly::fixup_uleb128_i32;
271 }
272 Fixups.push_back(
273 MCFixup::create(OS.tell() - Start, MO.getExpr(), FixupKind));
274 ++MCNumFixups;
275 encodeULEB128(0, OS, PaddedSize);
276 } else {
277 llvm_unreachable("unexpected operand kind");
278 }
279 }
280
281 ++MCNumEmitted; // Keep track of the # of mi's emitted.
282}
283
284#include "WebAssemblyGenMCCodeEmitter.inc"
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
#define LLVM_DEBUG(...)
Definition Debug.h:119
This file provides WebAssembly-specific target descriptions.
MCCodeEmitter - Generic instruction encoding interface.
Context object for machine code objects.
Definition MCContext.h:83
LLVM_ABI void reportError(SMLoc L, const Twine &Msg)
static MCFixup create(uint32_t Offset, const MCExpr *Value, MCFixupKind Kind, bool PCRel=false)
Consider bit fields if we need more flags.
Definition MCFixup.h:90
Instances of this class represent a single low-level machine instruction.
Definition MCInst.h:188
Describe properties that are true of each instruction in the target description file.
Interface to description of machine instruction set.
Definition MCInstrInfo.h:27
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
Definition MCInstrInfo.h:89
StringRef getName(unsigned Opcode) const
Returns the name for the instructions with the given opcode.
Definition MCInstrInfo.h:96
bool isSFPImm() const
Definition MCInst.h:67
int64_t getImm() const
Definition MCInst.h:84
bool isImm() const
Definition MCInst.h:66
bool isReg() const
Definition MCInst.h:65
bool isDFPImm() const
Definition MCInst.h:68
const MCExpr * getExpr() const
Definition MCInst.h:118
uint32_t getSFPImm() const
Definition MCInst.h:94
uint64_t getDFPImm() const
Definition MCInst.h:104
bool isExpr() const
Definition MCInst.h:69
Generic base class for all target subtargets.
const FeatureBitset & getFeatureBits() const
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
uint64_t tell() const
tell - Return the current offset with the file.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
void write(void *memory, value_type value, endianness endian)
Write a value to memory with a particular endianness.
Definition Endian.h:82
@ WASM_MEM_ORDER_SEQ_CST
Definition Wasm.h:86
@ WASM_MEM_ORDER_RMW_ACQ_REL
Definition Wasm.h:89
@ WASM_MEM_ORDER_ACQ_REL
Definition Wasm.h:87
const unsigned WASM_MEMARG_HAS_MEM_ORDER
Definition Wasm.h:91
This is an optimization pass for GlobalISel generic memory operations.
MCCodeEmitter * createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII, MCContext &Ctx)
Op::Description Desc
uint16_t MCFixupKind
Extensible enumeration to represent the type of a fixup.
Definition MCFixup.h:22
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
static Lanai::Fixups FixupKind(const MCExpr *Expr)
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:190
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
Definition InstrProf.h:145
unsigned encodeSLEB128(int64_t Value, raw_ostream &OS, unsigned PadTo=0)
Utility function to encode a SLEB128 value to an output stream.
Definition LEB128.h:24
unsigned encodeULEB128(uint64_t Value, raw_ostream &OS, unsigned PadTo=0)
Utility function to encode a ULEB128 value to an output stream.
Definition LEB128.h:79