1 //===- WriterUtils.cpp ----------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "WriterUtils.h"
10 #include "lld/Common/ErrorHandler.h"
11 #include "llvm/Support/Debug.h"
12 #include "llvm/Support/EndianStream.h"
13 #include "llvm/Support/LEB128.h"
15 #define DEBUG_TYPE "lld"
18 using namespace llvm::wasm
;
21 std::string
toString(ValType type
) {
33 case ValType::FUNCREF
:
35 case ValType::EXTERNREF
:
38 llvm_unreachable("Invalid wasm::ValType");
41 std::string
toString(const WasmSignature
&sig
) {
42 SmallString
<128> s("(");
43 for (ValType type
: sig
.Params
) {
49 if (sig
.Returns
.empty())
52 s
+= toString(sig
.Returns
[0]);
53 return std::string(s
.str());
56 std::string
toString(const WasmGlobalType
&type
) {
57 return (type
.Mutable
? "var " : "const ") +
58 toString(static_cast<ValType
>(type
.Type
));
61 std::string
toString(const WasmTagType
&type
) {
62 if (type
.Attribute
== WASM_TAG_ATTRIBUTE_EXCEPTION
)
67 static std::string
toString(const llvm::wasm::WasmLimits
&limits
) {
69 ret
+= "flags=0x" + std::to_string(limits
.Flags
);
70 ret
+= "; min=" + std::to_string(limits
.Minimum
);
71 if (limits
.Flags
& WASM_LIMITS_FLAG_HAS_MAX
)
72 ret
+= "; max=" + std::to_string(limits
.Maximum
);
76 std::string
toString(const WasmTableType
&type
) {
77 SmallString
<128> ret("");
78 return "type=" + toString(static_cast<ValType
>(type
.ElemType
)) +
79 "; limits=[" + toString(type
.Limits
) + "]";
83 void debugWrite(uint64_t offset
, const Twine
&msg
) {
84 LLVM_DEBUG(dbgs() << format(" | %08lld: ", offset
) << msg
<< "\n");
87 void writeUleb128(raw_ostream
&os
, uint64_t number
, const Twine
&msg
) {
88 debugWrite(os
.tell(), msg
+ "[" + utohexstr(number
) + "]");
89 encodeULEB128(number
, os
);
92 void writeSleb128(raw_ostream
&os
, int64_t number
, const Twine
&msg
) {
93 debugWrite(os
.tell(), msg
+ "[" + utohexstr(number
) + "]");
94 encodeSLEB128(number
, os
);
97 void writeBytes(raw_ostream
&os
, const char *bytes
, size_t count
,
99 debugWrite(os
.tell(), msg
+ " [data[" + Twine(count
) + "]]");
100 os
.write(bytes
, count
);
103 void writeStr(raw_ostream
&os
, StringRef string
, const Twine
&msg
) {
104 debugWrite(os
.tell(),
105 msg
+ " [str[" + Twine(string
.size()) + "]: " + string
+ "]");
106 encodeULEB128(string
.size(), os
);
107 os
.write(string
.data(), string
.size());
110 void writeU8(raw_ostream
&os
, uint8_t byte
, const Twine
&msg
) {
111 debugWrite(os
.tell(), msg
+ " [0x" + utohexstr(byte
) + "]");
115 void writeU32(raw_ostream
&os
, uint32_t number
, const Twine
&msg
) {
116 debugWrite(os
.tell(), msg
+ "[0x" + utohexstr(number
) + "]");
117 support::endian::write(os
, number
, support::little
);
120 void writeU64(raw_ostream
&os
, uint64_t number
, const Twine
&msg
) {
121 debugWrite(os
.tell(), msg
+ "[0x" + utohexstr(number
) + "]");
122 support::endian::write(os
, number
, support::little
);
125 void writeValueType(raw_ostream
&os
, ValType type
, const Twine
&msg
) {
126 writeU8(os
, static_cast<uint8_t>(type
),
127 msg
+ "[type: " + toString(type
) + "]");
130 void writeSig(raw_ostream
&os
, const WasmSignature
&sig
) {
131 writeU8(os
, WASM_TYPE_FUNC
, "signature type");
132 writeUleb128(os
, sig
.Params
.size(), "param Count");
133 for (ValType paramType
: sig
.Params
) {
134 writeValueType(os
, paramType
, "param type");
136 writeUleb128(os
, sig
.Returns
.size(), "result Count");
137 for (ValType returnType
: sig
.Returns
) {
138 writeValueType(os
, returnType
, "result type");
142 void writeI32Const(raw_ostream
&os
, int32_t number
, const Twine
&msg
) {
143 writeU8(os
, WASM_OPCODE_I32_CONST
, "i32.const");
144 writeSleb128(os
, number
, msg
);
147 void writeI64Const(raw_ostream
&os
, int64_t number
, const Twine
&msg
) {
148 writeU8(os
, WASM_OPCODE_I64_CONST
, "i64.const");
149 writeSleb128(os
, number
, msg
);
152 void writePtrConst(raw_ostream
&os
, int64_t number
, bool is64
,
155 writeI64Const(os
, number
, msg
);
157 writeI32Const(os
, static_cast<int32_t>(number
), msg
);
160 void writeMemArg(raw_ostream
&os
, uint32_t alignment
, uint64_t offset
) {
161 writeUleb128(os
, alignment
, "alignment");
162 writeUleb128(os
, offset
, "offset");
165 void writeInitExpr(raw_ostream
&os
, const WasmInitExpr
&initExpr
) {
166 writeU8(os
, initExpr
.Opcode
, "opcode");
167 switch (initExpr
.Opcode
) {
168 case WASM_OPCODE_I32_CONST
:
169 writeSleb128(os
, initExpr
.Value
.Int32
, "literal (i32)");
171 case WASM_OPCODE_I64_CONST
:
172 writeSleb128(os
, initExpr
.Value
.Int64
, "literal (i64)");
174 case WASM_OPCODE_F32_CONST
:
175 writeU32(os
, initExpr
.Value
.Float32
, "literal (f32)");
177 case WASM_OPCODE_F64_CONST
:
178 writeU64(os
, initExpr
.Value
.Float64
, "literal (f64)");
180 case WASM_OPCODE_GLOBAL_GET
:
181 writeUleb128(os
, initExpr
.Value
.Global
, "literal (global index)");
183 case WASM_OPCODE_REF_NULL
:
184 writeValueType(os
, ValType::EXTERNREF
, "literal (externref type)");
187 fatal("unknown opcode in init expr: " + Twine(initExpr
.Opcode
));
189 writeU8(os
, WASM_OPCODE_END
, "opcode:end");
192 void writeLimits(raw_ostream
&os
, const WasmLimits
&limits
) {
193 writeU8(os
, limits
.Flags
, "limits flags");
194 writeUleb128(os
, limits
.Minimum
, "limits min");
195 if (limits
.Flags
& WASM_LIMITS_FLAG_HAS_MAX
)
196 writeUleb128(os
, limits
.Maximum
, "limits max");
199 void writeGlobalType(raw_ostream
&os
, const WasmGlobalType
&type
) {
200 // TODO: Update WasmGlobalType to use ValType and remove this cast.
201 writeValueType(os
, ValType(type
.Type
), "global type");
202 writeU8(os
, type
.Mutable
, "global mutable");
205 void writeTagType(raw_ostream
&os
, const WasmTagType
&type
) {
206 writeUleb128(os
, type
.Attribute
, "tag attribute");
207 writeUleb128(os
, type
.SigIndex
, "sig index");
210 void writeTag(raw_ostream
&os
, const WasmTag
&tag
) {
211 writeTagType(os
, tag
.Type
);
214 void writeTableType(raw_ostream
&os
, const WasmTableType
&type
) {
215 writeValueType(os
, ValType(type
.ElemType
), "table type");
216 writeLimits(os
, type
.Limits
);
219 void writeImport(raw_ostream
&os
, const WasmImport
&import
) {
220 writeStr(os
, import
.Module
, "import module name");
221 writeStr(os
, import
.Field
, "import field name");
222 writeU8(os
, import
.Kind
, "import kind");
223 switch (import
.Kind
) {
224 case WASM_EXTERNAL_FUNCTION
:
225 writeUleb128(os
, import
.SigIndex
, "import sig index");
227 case WASM_EXTERNAL_GLOBAL
:
228 writeGlobalType(os
, import
.Global
);
230 case WASM_EXTERNAL_TAG
:
231 writeTagType(os
, import
.Tag
);
233 case WASM_EXTERNAL_MEMORY
:
234 writeLimits(os
, import
.Memory
);
236 case WASM_EXTERNAL_TABLE
:
237 writeTableType(os
, import
.Table
);
240 fatal("unsupported import type: " + Twine(import
.Kind
));
244 void writeExport(raw_ostream
&os
, const WasmExport
&export_
) {
245 writeStr(os
, export_
.Name
, "export name");
246 writeU8(os
, export_
.Kind
, "export kind");
247 switch (export_
.Kind
) {
248 case WASM_EXTERNAL_FUNCTION
:
249 writeUleb128(os
, export_
.Index
, "function index");
251 case WASM_EXTERNAL_GLOBAL
:
252 writeUleb128(os
, export_
.Index
, "global index");
254 case WASM_EXTERNAL_TAG
:
255 writeUleb128(os
, export_
.Index
, "tag index");
257 case WASM_EXTERNAL_MEMORY
:
258 writeUleb128(os
, export_
.Index
, "memory index");
260 case WASM_EXTERNAL_TABLE
:
261 writeUleb128(os
, export_
.Index
, "table index");
264 fatal("unsupported export type: " + Twine(export_
.Kind
));