LLVM 23.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 relaxed-atomics encoding (even if relaxed-atomics is
88 // enabled) because the original encoding is smaller.
89 if (P2AlignIdx > 0 && Desc.operands()[P2AlignIdx - 1].OperandType ==
91 Order = MI.getOperand(P2AlignIdx - 1).getImm();
92 if (Order != wasm::WASM_MEM_ORDER_SEQ_CST) {
93 assert(STI.getFeatureBits()[WebAssembly::FeatureRelaxedAtomics] &&
94 "Non-default atomic ordering but feature not enabled");
96 }
97 }
98
99 encodeULEB128(P2Align, OS);
100
101 // Memory index will go here once we support multi-memory.
102
103 if (P2Align & wasm::WASM_MEMARG_HAS_MEM_ORDER) {
105 getEncodedMemOrder(Order, MI.getOpcode()),
107 }
108}
109
110void WebAssemblyMCCodeEmitter::encodeInstruction(
111 const MCInst &MI, SmallVectorImpl<char> &CB,
112 SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const {
113 raw_svector_ostream OS(CB);
114 uint64_t Start = OS.tell();
115
116 uint64_t Binary = getBinaryCodeForInstr(MI, Fixups, STI);
117 if (Binary < (1 << 8)) {
118 OS << uint8_t(Binary);
119 } else if (Binary < (1 << 16)) {
120 OS << uint8_t(Binary >> 8);
121 encodeULEB128(uint8_t(Binary), OS);
122 } else if (Binary < (1 << 24)) {
123 OS << uint8_t(Binary >> 16);
124 encodeULEB128(uint16_t(Binary), OS);
125 } else {
126 llvm_unreachable("Very large (prefix + 3 byte) opcodes not supported");
127 }
128
129 // For br_table instructions, encode the size of the table. In the MCInst,
130 // there's an index operand (if not a stack instruction), one operand for
131 // each table entry, and the default operand.
132 unsigned Opcode = MI.getOpcode();
133 if (Opcode == WebAssembly::BR_TABLE_I32_S ||
134 Opcode == WebAssembly::BR_TABLE_I64_S)
135 encodeULEB128(MI.getNumOperands() - 1, OS);
136 if (Opcode == WebAssembly::BR_TABLE_I32 ||
137 Opcode == WebAssembly::BR_TABLE_I64)
138 encodeULEB128(MI.getNumOperands() - 2, OS);
139
140 const MCInstrDesc &Desc = MCII.get(Opcode);
141 for (unsigned I = 0, E = MI.getNumOperands(); I < E; ++I) {
142 const MCOperand &MO = MI.getOperand(I);
143 if (MO.isReg()) {
144 /* nothing to encode */
145
146 } else if (MO.isImm()) {
147 if (I < Desc.getNumOperands()) {
148 const MCOperandInfo &Info = Desc.operands()[I];
149 LLVM_DEBUG(dbgs() << "Encoding immediate: type="
150 << int(Info.OperandType) << "\n");
151 switch (Info.OperandType) {
153 encodeSLEB128(int32_t(MO.getImm()), OS);
154 break;
156 encodeP2AlignAndMemOrder(MI, I, Desc, STI, OS, Fixups, Start);
157 break;
159 encodeULEB128(uint32_t(MO.getImm()), OS);
160 break;
162 encodeSLEB128(MO.getImm(), OS);
163 break;
168 break;
170 // If there is a p2align operand (everything but fence) it is encoded
171 // together with the mem ordering (in the next iteration).
172 if (I + 1 < Desc.getNumOperands() &&
173 Desc.operands()[I + 1].OperandType ==
175 break;
176 uint8_t Val = getEncodedMemOrder(MO.getImm(), Opcode);
177 if (STI.getFeatureBits()[WebAssembly::FeatureRelaxedAtomics]) {
179 } else {
180 assert(Opcode == WebAssembly::ATOMIC_FENCE_S);
182 }
183 break;
184 }
188 break;
192 break;
196 break;
198 Ctx.reportError(
199 SMLoc(),
200 Twine("Wasm globals should only be accessed symbolically!"));
201 break;
202 default:
203 encodeULEB128(uint64_t(MO.getImm()), OS);
204 }
205 } else {
206 // Variadic immediate operands are br_table's destination operands or
207 // try_table's operands (# of catch clauses, catch sub-opcodes, or catch
208 // clause destinations)
210 Opcode == WebAssembly::TRY_TABLE_S);
211 encodeULEB128(uint32_t(MO.getImm()), OS);
212 }
213
214 } else if (MO.isSFPImm()) {
215 uint32_t F = MO.getSFPImm();
217 } else if (MO.isDFPImm()) {
218 uint64_t D = MO.getDFPImm();
220 } else if (MO.isExpr()) {
222 size_t PaddedSize = 5;
223 if (I < Desc.getNumOperands()) {
224 const MCOperandInfo &Info = Desc.operands()[I];
225 switch (Info.OperandType) {
228 break;
231 PaddedSize = 10;
232 break;
241 break;
244 PaddedSize = 10;
245 break;
246 default:
247 llvm_unreachable("unexpected symbolic operand kind");
248 }
249 } else {
250 // Variadic expr operands are try_table's catch/catch_ref clauses' tags.
251 assert(Opcode == WebAssembly::TRY_TABLE_S);
253 }
254 Fixups.push_back(
255 MCFixup::create(OS.tell() - Start, MO.getExpr(), FixupKind));
256 ++MCNumFixups;
257 encodeULEB128(0, OS, PaddedSize);
258 } else {
259 llvm_unreachable("unexpected operand kind");
260 }
261 }
262
263 ++MCNumEmitted; // Keep track of the # of mi's emitted.
264}
265
266#include "WebAssemblyGenMCCodeEmitter.inc"
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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:114
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:86
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:90
StringRef getName(unsigned Opcode) const
Returns the name for the instructions with the given opcode.
Definition MCInstrInfo.h:97
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...
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
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.
bool isBrTable(unsigned Opc)
@ OPERAND_OFFSET64
64-bit unsigned memory offsets.
@ OPERAND_MEMORDER
Memory ordering immediate for atomic instructions.
@ OPERAND_I32IMM
32-bit integer immediates.
@ OPERAND_P2ALIGN
p2align immediate for load and store address alignment.
@ OPERAND_TABLE
32-bit unsigned table number.
@ OPERAND_VEC_I64IMM
64-bit vector lane immediate
@ OPERAND_VEC_I16IMM
16-bit vector lane immediate
@ OPERAND_TYPEINDEX
type signature immediate for call_indirect.
@ OPERAND_FUNCTION32
32-bit unsigned function indices.
@ OPERAND_VEC_I32IMM
32-bit vector lane immediate
@ OPERAND_VEC_I8IMM
8-bit vector lane immediate
@ OPERAND_SIGNATURE
signature immediate for block/loop.
@ OPERAND_I64IMM
64-bit integer immediates.
@ OPERAND_OFFSET32
32-bit unsigned memory offsets.
void write(void *memory, value_type value, endianness endian)
Write a value to memory with a particular endianness.
Definition Endian.h:96
@ 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.
Definition Types.h:26
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:207
static Lanai::Fixups FixupKind(const MCExpr *Expr)
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