1//===- WriterUtils.cpp ----------------------------------------------------===//
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#include "WriterUtils.h"
10#include "lld/Common/ErrorHandler.h"
11#include "llvm/ADT/StringExtras.h"
12#include "llvm/Support/Debug.h"
13#include "llvm/Support/EndianStream.h"
14#include "llvm/Support/LEB128.h"
15
16#define DEBUG_TYPE "lld"
17
18using namespace llvm;
19using namespace llvm::wasm;
20
21namespace lld {
22std::string toString(ValType type) {
23 switch (type) {
24 case ValType::I32:
25 return "i32";
26 case ValType::I64:
27 return "i64";
28 case ValType::F32:
29 return "f32";
30 case ValType::F64:
31 return "f64";
32 case ValType::V128:
33 return "v128";
34 case ValType::FUNCREF:
35 return "funcref";
36 case ValType::EXTERNREF:
37 return "externref";
38 case ValType::EXNREF:
39 return "exnref";
40 case ValType::OTHERREF:
41 return "otherref";
42 }
43 llvm_unreachable("Invalid wasm::ValType");
44}
45
46std::string toString(const WasmSignature &sig) {
47 SmallString<128> s("(");
48 for (ValType type : sig.Params) {
49 if (s.size() != 1)
50 s += ", ";
51 s += toString(type);
52 }
53 s += ") -> ";
54 if (sig.Returns.empty())
55 s += "void";
56 else
57 s += toString(type: sig.Returns[0]);
58 return std::string(s);
59}
60
61std::string toString(const WasmGlobalType &type) {
62 return (type.Mutable ? "var " : "const ") +
63 toString(type: static_cast<ValType>(type.Type));
64}
65
66static std::string toString(const llvm::wasm::WasmLimits &limits) {
67 std::string ret;
68 ret += "flags=0x" + std::to_string(val: limits.Flags);
69 ret += "; min=" + std::to_string(val: limits.Minimum);
70 if (limits.Flags & WASM_LIMITS_FLAG_HAS_MAX)
71 ret += "; max=" + std::to_string(val: limits.Maximum);
72 if (limits.Flags & WASM_LIMITS_FLAG_HAS_PAGE_SIZE)
73 ret += "; pagesize=" + std::to_string(val: limits.PageSize);
74 return ret;
75}
76
77std::string toString(const WasmTableType &type) {
78 return "type=" + toString(type: static_cast<ValType>(type.ElemType)) +
79 "; limits=[" + toString(limits: type.Limits) + "]";
80}
81
82namespace wasm {
83#ifdef LLVM_DEBUG
84void debugWrite(uint64_t offset, const Twine &msg) {
85 LLVM_DEBUG(dbgs() << format(" | %08lld: ", offset) << msg << "\n");
86}
87#endif
88
89void writeUleb128(raw_ostream &os, uint64_t number, const Twine &msg) {
90 debugWrite(offset: os.tell(), msg: msg + "[" + utohexstr(X: number) + "]");
91 encodeULEB128(Value: number, OS&: os);
92}
93
94void writeSleb128(raw_ostream &os, int64_t number, const Twine &msg) {
95 debugWrite(offset: os.tell(), msg: msg + "[" + utohexstr(X: number) + "]");
96 encodeSLEB128(Value: number, OS&: os);
97}
98
99void writeBytes(raw_ostream &os, const char *bytes, size_t count,
100 const Twine &msg) {
101 debugWrite(offset: os.tell(), msg: msg + " [data[" + Twine(count) + "]]");
102 os.write(Ptr: bytes, Size: count);
103}
104
105void writeStr(raw_ostream &os, StringRef string, const Twine &msg) {
106 debugWrite(offset: os.tell(),
107 msg: msg + " [str[" + Twine(string.size()) + "]: " + string + "]");
108 encodeULEB128(Value: string.size(), OS&: os);
109 os.write(Ptr: string.data(), Size: string.size());
110}
111
112void writeU8(raw_ostream &os, uint8_t byte, const Twine &msg) {
113 debugWrite(offset: os.tell(), msg: msg + " [0x" + utohexstr(X: byte) + "]");
114 os << byte;
115}
116
117void writeU32(raw_ostream &os, uint32_t number, const Twine &msg) {
118 debugWrite(offset: os.tell(), msg: msg + "[0x" + utohexstr(X: number) + "]");
119 support::endian::write(os, value: number, endian: llvm::endianness::little);
120}
121
122void writeU64(raw_ostream &os, uint64_t number, const Twine &msg) {
123 debugWrite(offset: os.tell(), msg: msg + "[0x" + utohexstr(X: number) + "]");
124 support::endian::write(os, value: number, endian: llvm::endianness::little);
125}
126
127void writeValueType(raw_ostream &os, ValType type, const Twine &msg) {
128 writeU8(os, byte: static_cast<uint8_t>(type),
129 msg: msg + "[type: " + toString(type) + "]");
130}
131
132void writeSig(raw_ostream &os, const WasmSignature &sig) {
133 writeU8(os, byte: WASM_TYPE_FUNC, msg: "signature type");
134 writeUleb128(os, number: sig.Params.size(), msg: "param Count");
135 for (ValType paramType : sig.Params) {
136 writeValueType(os, type: paramType, msg: "param type");
137 }
138 writeUleb128(os, number: sig.Returns.size(), msg: "result Count");
139 for (ValType returnType : sig.Returns) {
140 writeValueType(os, type: returnType, msg: "result type");
141 }
142}
143
144void writeI32Const(raw_ostream &os, int32_t number, const Twine &msg) {
145 writeU8(os, byte: WASM_OPCODE_I32_CONST, msg: "i32.const");
146 writeSleb128(os, number, msg);
147}
148
149void writeI64Const(raw_ostream &os, int64_t number, const Twine &msg) {
150 writeU8(os, byte: WASM_OPCODE_I64_CONST, msg: "i64.const");
151 writeSleb128(os, number, msg);
152}
153
154void writePtrConst(raw_ostream &os, int64_t number, bool is64,
155 const Twine &msg) {
156 if (is64)
157 writeI64Const(os, number, msg);
158 else
159 writeI32Const(os, number: static_cast<int32_t>(number), msg);
160}
161
162void writeMemArg(raw_ostream &os, uint32_t alignment, uint64_t offset) {
163 writeUleb128(os, number: alignment, msg: "alignment");
164 writeUleb128(os, number: offset, msg: "offset");
165}
166
167void writeInitExpr(raw_ostream &os, const WasmInitExpr &initExpr) {
168 assert(!initExpr.Extended);
169 writeInitExprMVP(os, initExpr: initExpr.Inst);
170}
171
172void writeInitExprMVP(raw_ostream &os, const WasmInitExprMVP &initExpr) {
173 writeU8(os, byte: initExpr.Opcode, msg: "opcode");
174 switch (initExpr.Opcode) {
175 case WASM_OPCODE_I32_CONST:
176 writeSleb128(os, number: initExpr.Value.Int32, msg: "literal (i32)");
177 break;
178 case WASM_OPCODE_I64_CONST:
179 writeSleb128(os, number: initExpr.Value.Int64, msg: "literal (i64)");
180 break;
181 case WASM_OPCODE_F32_CONST:
182 writeU32(os, number: initExpr.Value.Float32, msg: "literal (f32)");
183 break;
184 case WASM_OPCODE_F64_CONST:
185 writeU64(os, number: initExpr.Value.Float64, msg: "literal (f64)");
186 break;
187 case WASM_OPCODE_GLOBAL_GET:
188 writeUleb128(os, number: initExpr.Value.Global, msg: "literal (global index)");
189 break;
190 case WASM_OPCODE_REF_NULL:
191 writeValueType(os, type: ValType::EXTERNREF, msg: "literal (externref type)");
192 break;
193 default:
194 fatal(msg: "unknown opcode in init expr: " + Twine(initExpr.Opcode));
195 }
196 writeU8(os, byte: WASM_OPCODE_END, msg: "opcode:end");
197}
198
199void writeLimits(raw_ostream &os, const WasmLimits &limits) {
200 writeU8(os, byte: limits.Flags, msg: "limits flags");
201 writeUleb128(os, number: limits.Minimum, msg: "limits min");
202 if (limits.Flags & WASM_LIMITS_FLAG_HAS_MAX)
203 writeUleb128(os, number: limits.Maximum, msg: "limits max");
204 if (limits.Flags & WASM_LIMITS_FLAG_HAS_PAGE_SIZE)
205 writeUleb128(os, number: llvm::Log2_64(Value: limits.PageSize), msg: "page size");
206}
207
208void writeGlobalType(raw_ostream &os, const WasmGlobalType &type) {
209 // TODO: Update WasmGlobalType to use ValType and remove this cast.
210 writeValueType(os, type: ValType(type.Type), msg: "global type");
211 writeU8(os, byte: type.Mutable, msg: "global mutable");
212}
213
214void writeTableType(raw_ostream &os, const WasmTableType &type) {
215 writeValueType(os, type: ValType(type.ElemType), msg: "table type");
216 writeLimits(os, limits: type.Limits);
217}
218
219void writeImport(raw_ostream &os, const WasmImport &import) {
220 writeStr(os, string: import.Module, msg: "import module name");
221 writeStr(os, string: import.Field, msg: "import field name");
222 writeU8(os, byte: import.Kind, msg: "import kind");
223 switch (import.Kind) {
224 case WASM_EXTERNAL_FUNCTION:
225 writeUleb128(os, number: import.SigIndex, msg: "import sig index");
226 break;
227 case WASM_EXTERNAL_GLOBAL:
228 writeGlobalType(os, type: import.Global);
229 break;
230 case WASM_EXTERNAL_TAG:
231 writeUleb128(os, number: 0, msg: "tag attribute"); // Reserved "attribute" field
232 writeUleb128(os, number: import.SigIndex, msg: "import sig index");
233 break;
234 case WASM_EXTERNAL_MEMORY:
235 writeLimits(os, limits: import.Memory);
236 break;
237 case WASM_EXTERNAL_TABLE:
238 writeTableType(os, type: import.Table);
239 break;
240 default:
241 fatal(msg: "unsupported import type: " + Twine(import.Kind));
242 }
243}
244
245void writeExport(raw_ostream &os, const WasmExport &export_) {
246 writeStr(os, string: export_.Name, msg: "export name");
247 writeU8(os, byte: export_.Kind, msg: "export kind");
248 switch (export_.Kind) {
249 case WASM_EXTERNAL_FUNCTION:
250 writeUleb128(os, number: export_.Index, msg: "function index");
251 break;
252 case WASM_EXTERNAL_GLOBAL:
253 writeUleb128(os, number: export_.Index, msg: "global index");
254 break;
255 case WASM_EXTERNAL_TAG:
256 writeUleb128(os, number: export_.Index, msg: "tag index");
257 break;
258 case WASM_EXTERNAL_MEMORY:
259 writeUleb128(os, number: export_.Index, msg: "memory index");
260 break;
261 case WASM_EXTERNAL_TABLE:
262 writeUleb128(os, number: export_.Index, msg: "table index");
263 break;
264 default:
265 fatal(msg: "unsupported export type: " + Twine(export_.Kind));
266 }
267}
268
269} // namespace wasm
270} // namespace lld
271

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of lld/wasm/WriterUtils.cpp