xref: /openbsd-src/gnu/llvm/lld/wasm/WriterUtils.cpp (revision dfe94b169149f14cc1aee2cf6dad58a8d9a1860c)
1ece8a530Spatrick //===- WriterUtils.cpp ----------------------------------------------------===//
2ece8a530Spatrick //
3ece8a530Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ece8a530Spatrick // See https://llvm.org/LICENSE.txt for license information.
5ece8a530Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ece8a530Spatrick //
7ece8a530Spatrick //===----------------------------------------------------------------------===//
8ece8a530Spatrick 
9ece8a530Spatrick #include "WriterUtils.h"
10ece8a530Spatrick #include "lld/Common/ErrorHandler.h"
11ece8a530Spatrick #include "llvm/Support/Debug.h"
12ece8a530Spatrick #include "llvm/Support/EndianStream.h"
13ece8a530Spatrick #include "llvm/Support/LEB128.h"
14ece8a530Spatrick 
15ece8a530Spatrick #define DEBUG_TYPE "lld"
16ece8a530Spatrick 
17ece8a530Spatrick using namespace llvm;
18ece8a530Spatrick using namespace llvm::wasm;
19ece8a530Spatrick 
20ece8a530Spatrick namespace lld {
toString(ValType type)21ece8a530Spatrick std::string toString(ValType type) {
22ece8a530Spatrick   switch (type) {
23ece8a530Spatrick   case ValType::I32:
24ece8a530Spatrick     return "i32";
25ece8a530Spatrick   case ValType::I64:
26ece8a530Spatrick     return "i64";
27ece8a530Spatrick   case ValType::F32:
28ece8a530Spatrick     return "f32";
29ece8a530Spatrick   case ValType::F64:
30ece8a530Spatrick     return "f64";
31ece8a530Spatrick   case ValType::V128:
32ece8a530Spatrick     return "v128";
331cf9926bSpatrick   case ValType::FUNCREF:
341cf9926bSpatrick     return "funcref";
35bb684c34Spatrick   case ValType::EXTERNREF:
36bb684c34Spatrick     return "externref";
37ece8a530Spatrick   }
38ece8a530Spatrick   llvm_unreachable("Invalid wasm::ValType");
39ece8a530Spatrick }
40ece8a530Spatrick 
toString(const WasmSignature & sig)41ece8a530Spatrick std::string toString(const WasmSignature &sig) {
42ece8a530Spatrick   SmallString<128> s("(");
43ece8a530Spatrick   for (ValType type : sig.Params) {
44ece8a530Spatrick     if (s.size() != 1)
45ece8a530Spatrick       s += ", ";
46ece8a530Spatrick     s += toString(type);
47ece8a530Spatrick   }
48ece8a530Spatrick   s += ") -> ";
49ece8a530Spatrick   if (sig.Returns.empty())
50ece8a530Spatrick     s += "void";
51ece8a530Spatrick   else
52ece8a530Spatrick     s += toString(sig.Returns[0]);
53bb684c34Spatrick   return std::string(s.str());
54ece8a530Spatrick }
55ece8a530Spatrick 
toString(const WasmGlobalType & type)56ece8a530Spatrick std::string toString(const WasmGlobalType &type) {
57ece8a530Spatrick   return (type.Mutable ? "var " : "const ") +
58ece8a530Spatrick          toString(static_cast<ValType>(type.Type));
59ece8a530Spatrick }
60ece8a530Spatrick 
toString(const llvm::wasm::WasmLimits & limits)611cf9926bSpatrick static std::string toString(const llvm::wasm::WasmLimits &limits) {
621cf9926bSpatrick   std::string ret;
631cf9926bSpatrick   ret += "flags=0x" + std::to_string(limits.Flags);
641cf9926bSpatrick   ret += "; min=" + std::to_string(limits.Minimum);
651cf9926bSpatrick   if (limits.Flags & WASM_LIMITS_FLAG_HAS_MAX)
661cf9926bSpatrick     ret += "; max=" + std::to_string(limits.Maximum);
671cf9926bSpatrick   return ret;
681cf9926bSpatrick }
691cf9926bSpatrick 
toString(const WasmTableType & type)701cf9926bSpatrick std::string toString(const WasmTableType &type) {
711cf9926bSpatrick   SmallString<128> ret("");
721cf9926bSpatrick   return "type=" + toString(static_cast<ValType>(type.ElemType)) +
731cf9926bSpatrick          "; limits=[" + toString(type.Limits) + "]";
741cf9926bSpatrick }
751cf9926bSpatrick 
76ece8a530Spatrick namespace wasm {
77*dfe94b16Srobert #ifdef LLVM_DEBUG
debugWrite(uint64_t offset,const Twine & msg)78ece8a530Spatrick void debugWrite(uint64_t offset, const Twine &msg) {
79ece8a530Spatrick   LLVM_DEBUG(dbgs() << format("  | %08lld: ", offset) << msg << "\n");
80ece8a530Spatrick }
81*dfe94b16Srobert #endif
82ece8a530Spatrick 
writeUleb128(raw_ostream & os,uint64_t number,const Twine & msg)83bb684c34Spatrick void writeUleb128(raw_ostream &os, uint64_t number, const Twine &msg) {
84ece8a530Spatrick   debugWrite(os.tell(), msg + "[" + utohexstr(number) + "]");
85ece8a530Spatrick   encodeULEB128(number, os);
86ece8a530Spatrick }
87ece8a530Spatrick 
writeSleb128(raw_ostream & os,int64_t number,const Twine & msg)88bb684c34Spatrick void writeSleb128(raw_ostream &os, int64_t number, const Twine &msg) {
89ece8a530Spatrick   debugWrite(os.tell(), msg + "[" + utohexstr(number) + "]");
90ece8a530Spatrick   encodeSLEB128(number, os);
91ece8a530Spatrick }
92ece8a530Spatrick 
writeBytes(raw_ostream & os,const char * bytes,size_t count,const Twine & msg)93ece8a530Spatrick void writeBytes(raw_ostream &os, const char *bytes, size_t count,
94ece8a530Spatrick                       const Twine &msg) {
95ece8a530Spatrick   debugWrite(os.tell(), msg + " [data[" + Twine(count) + "]]");
96ece8a530Spatrick   os.write(bytes, count);
97ece8a530Spatrick }
98ece8a530Spatrick 
writeStr(raw_ostream & os,StringRef string,const Twine & msg)99ece8a530Spatrick void writeStr(raw_ostream &os, StringRef string, const Twine &msg) {
100ece8a530Spatrick   debugWrite(os.tell(),
101ece8a530Spatrick              msg + " [str[" + Twine(string.size()) + "]: " + string + "]");
102ece8a530Spatrick   encodeULEB128(string.size(), os);
103ece8a530Spatrick   os.write(string.data(), string.size());
104ece8a530Spatrick }
105ece8a530Spatrick 
writeU8(raw_ostream & os,uint8_t byte,const Twine & msg)106ece8a530Spatrick void writeU8(raw_ostream &os, uint8_t byte, const Twine &msg) {
107ece8a530Spatrick   debugWrite(os.tell(), msg + " [0x" + utohexstr(byte) + "]");
108ece8a530Spatrick   os << byte;
109ece8a530Spatrick }
110ece8a530Spatrick 
writeU32(raw_ostream & os,uint32_t number,const Twine & msg)111ece8a530Spatrick void writeU32(raw_ostream &os, uint32_t number, const Twine &msg) {
112ece8a530Spatrick   debugWrite(os.tell(), msg + "[0x" + utohexstr(number) + "]");
113ece8a530Spatrick   support::endian::write(os, number, support::little);
114ece8a530Spatrick }
115ece8a530Spatrick 
writeU64(raw_ostream & os,uint64_t number,const Twine & msg)116bb684c34Spatrick void writeU64(raw_ostream &os, uint64_t number, const Twine &msg) {
117bb684c34Spatrick   debugWrite(os.tell(), msg + "[0x" + utohexstr(number) + "]");
118bb684c34Spatrick   support::endian::write(os, number, support::little);
119bb684c34Spatrick }
120bb684c34Spatrick 
writeValueType(raw_ostream & os,ValType type,const Twine & msg)121ece8a530Spatrick void writeValueType(raw_ostream &os, ValType type, const Twine &msg) {
122ece8a530Spatrick   writeU8(os, static_cast<uint8_t>(type),
123ece8a530Spatrick           msg + "[type: " + toString(type) + "]");
124ece8a530Spatrick }
125ece8a530Spatrick 
writeSig(raw_ostream & os,const WasmSignature & sig)126ece8a530Spatrick void writeSig(raw_ostream &os, const WasmSignature &sig) {
127ece8a530Spatrick   writeU8(os, WASM_TYPE_FUNC, "signature type");
128ece8a530Spatrick   writeUleb128(os, sig.Params.size(), "param Count");
129ece8a530Spatrick   for (ValType paramType : sig.Params) {
130ece8a530Spatrick     writeValueType(os, paramType, "param type");
131ece8a530Spatrick   }
132ece8a530Spatrick   writeUleb128(os, sig.Returns.size(), "result Count");
1331cf9926bSpatrick   for (ValType returnType : sig.Returns) {
1341cf9926bSpatrick     writeValueType(os, returnType, "result type");
135ece8a530Spatrick   }
136ece8a530Spatrick }
137ece8a530Spatrick 
writeI32Const(raw_ostream & os,int32_t number,const Twine & msg)138ece8a530Spatrick void writeI32Const(raw_ostream &os, int32_t number, const Twine &msg) {
139ece8a530Spatrick   writeU8(os, WASM_OPCODE_I32_CONST, "i32.const");
140ece8a530Spatrick   writeSleb128(os, number, msg);
141ece8a530Spatrick }
142ece8a530Spatrick 
writeI64Const(raw_ostream & os,int64_t number,const Twine & msg)143bb684c34Spatrick void writeI64Const(raw_ostream &os, int64_t number, const Twine &msg) {
144ece8a530Spatrick   writeU8(os, WASM_OPCODE_I64_CONST, "i64.const");
145ece8a530Spatrick   writeSleb128(os, number, msg);
146ece8a530Spatrick }
147ece8a530Spatrick 
writePtrConst(raw_ostream & os,int64_t number,bool is64,const Twine & msg)1481cf9926bSpatrick void writePtrConst(raw_ostream &os, int64_t number, bool is64,
1491cf9926bSpatrick                    const Twine &msg) {
1501cf9926bSpatrick   if (is64)
1511cf9926bSpatrick     writeI64Const(os, number, msg);
1521cf9926bSpatrick   else
1531cf9926bSpatrick     writeI32Const(os, static_cast<int32_t>(number), msg);
1541cf9926bSpatrick }
1551cf9926bSpatrick 
writeMemArg(raw_ostream & os,uint32_t alignment,uint64_t offset)156bb684c34Spatrick void writeMemArg(raw_ostream &os, uint32_t alignment, uint64_t offset) {
157ece8a530Spatrick   writeUleb128(os, alignment, "alignment");
158ece8a530Spatrick   writeUleb128(os, offset, "offset");
159ece8a530Spatrick }
160ece8a530Spatrick 
writeInitExpr(raw_ostream & os,const WasmInitExpr & initExpr)161ece8a530Spatrick void writeInitExpr(raw_ostream &os, const WasmInitExpr &initExpr) {
162*dfe94b16Srobert   assert(!initExpr.Extended);
163*dfe94b16Srobert   writeInitExprMVP(os, initExpr.Inst);
164*dfe94b16Srobert }
165*dfe94b16Srobert 
writeInitExprMVP(raw_ostream & os,const WasmInitExprMVP & initExpr)166*dfe94b16Srobert void writeInitExprMVP(raw_ostream &os, const WasmInitExprMVP &initExpr) {
167ece8a530Spatrick   writeU8(os, initExpr.Opcode, "opcode");
168ece8a530Spatrick   switch (initExpr.Opcode) {
169ece8a530Spatrick   case WASM_OPCODE_I32_CONST:
170ece8a530Spatrick     writeSleb128(os, initExpr.Value.Int32, "literal (i32)");
171ece8a530Spatrick     break;
172ece8a530Spatrick   case WASM_OPCODE_I64_CONST:
173ece8a530Spatrick     writeSleb128(os, initExpr.Value.Int64, "literal (i64)");
174ece8a530Spatrick     break;
175bb684c34Spatrick   case WASM_OPCODE_F32_CONST:
176bb684c34Spatrick     writeU32(os, initExpr.Value.Float32, "literal (f32)");
177bb684c34Spatrick     break;
178bb684c34Spatrick   case WASM_OPCODE_F64_CONST:
179bb684c34Spatrick     writeU64(os, initExpr.Value.Float64, "literal (f64)");
180bb684c34Spatrick     break;
181ece8a530Spatrick   case WASM_OPCODE_GLOBAL_GET:
182ece8a530Spatrick     writeUleb128(os, initExpr.Value.Global, "literal (global index)");
183ece8a530Spatrick     break;
184bb684c34Spatrick   case WASM_OPCODE_REF_NULL:
185bb684c34Spatrick     writeValueType(os, ValType::EXTERNREF, "literal (externref type)");
186bb684c34Spatrick     break;
187ece8a530Spatrick   default:
188ece8a530Spatrick     fatal("unknown opcode in init expr: " + Twine(initExpr.Opcode));
189ece8a530Spatrick   }
190ece8a530Spatrick   writeU8(os, WASM_OPCODE_END, "opcode:end");
191ece8a530Spatrick }
192ece8a530Spatrick 
writeLimits(raw_ostream & os,const WasmLimits & limits)193ece8a530Spatrick void writeLimits(raw_ostream &os, const WasmLimits &limits) {
194ece8a530Spatrick   writeU8(os, limits.Flags, "limits flags");
1951cf9926bSpatrick   writeUleb128(os, limits.Minimum, "limits min");
196ece8a530Spatrick   if (limits.Flags & WASM_LIMITS_FLAG_HAS_MAX)
197ece8a530Spatrick     writeUleb128(os, limits.Maximum, "limits max");
198ece8a530Spatrick }
199ece8a530Spatrick 
writeGlobalType(raw_ostream & os,const WasmGlobalType & type)200ece8a530Spatrick void writeGlobalType(raw_ostream &os, const WasmGlobalType &type) {
201ece8a530Spatrick   // TODO: Update WasmGlobalType to use ValType and remove this cast.
202ece8a530Spatrick   writeValueType(os, ValType(type.Type), "global type");
203ece8a530Spatrick   writeU8(os, type.Mutable, "global mutable");
204ece8a530Spatrick }
205ece8a530Spatrick 
writeTableType(raw_ostream & os,const WasmTableType & type)2061cf9926bSpatrick void writeTableType(raw_ostream &os, const WasmTableType &type) {
2071cf9926bSpatrick   writeValueType(os, ValType(type.ElemType), "table type");
208ece8a530Spatrick   writeLimits(os, type.Limits);
209ece8a530Spatrick }
210ece8a530Spatrick 
writeImport(raw_ostream & os,const WasmImport & import)211ece8a530Spatrick void writeImport(raw_ostream &os, const WasmImport &import) {
212ece8a530Spatrick   writeStr(os, import.Module, "import module name");
213ece8a530Spatrick   writeStr(os, import.Field, "import field name");
214ece8a530Spatrick   writeU8(os, import.Kind, "import kind");
215ece8a530Spatrick   switch (import.Kind) {
216ece8a530Spatrick   case WASM_EXTERNAL_FUNCTION:
217ece8a530Spatrick     writeUleb128(os, import.SigIndex, "import sig index");
218ece8a530Spatrick     break;
219ece8a530Spatrick   case WASM_EXTERNAL_GLOBAL:
220ece8a530Spatrick     writeGlobalType(os, import.Global);
221ece8a530Spatrick     break;
2221cf9926bSpatrick   case WASM_EXTERNAL_TAG:
223*dfe94b16Srobert     writeUleb128(os, 0, "tag attribute"); // Reserved "attribute" field
224*dfe94b16Srobert     writeUleb128(os, import.SigIndex, "import sig index");
225ece8a530Spatrick     break;
226ece8a530Spatrick   case WASM_EXTERNAL_MEMORY:
227ece8a530Spatrick     writeLimits(os, import.Memory);
228ece8a530Spatrick     break;
229ece8a530Spatrick   case WASM_EXTERNAL_TABLE:
230ece8a530Spatrick     writeTableType(os, import.Table);
231ece8a530Spatrick     break;
232ece8a530Spatrick   default:
233ece8a530Spatrick     fatal("unsupported import type: " + Twine(import.Kind));
234ece8a530Spatrick   }
235ece8a530Spatrick }
236ece8a530Spatrick 
writeExport(raw_ostream & os,const WasmExport & export_)237ece8a530Spatrick void writeExport(raw_ostream &os, const WasmExport &export_) {
238ece8a530Spatrick   writeStr(os, export_.Name, "export name");
239ece8a530Spatrick   writeU8(os, export_.Kind, "export kind");
240ece8a530Spatrick   switch (export_.Kind) {
241ece8a530Spatrick   case WASM_EXTERNAL_FUNCTION:
242ece8a530Spatrick     writeUleb128(os, export_.Index, "function index");
243ece8a530Spatrick     break;
244ece8a530Spatrick   case WASM_EXTERNAL_GLOBAL:
245ece8a530Spatrick     writeUleb128(os, export_.Index, "global index");
246ece8a530Spatrick     break;
2471cf9926bSpatrick   case WASM_EXTERNAL_TAG:
2481cf9926bSpatrick     writeUleb128(os, export_.Index, "tag index");
249bb684c34Spatrick     break;
250ece8a530Spatrick   case WASM_EXTERNAL_MEMORY:
251ece8a530Spatrick     writeUleb128(os, export_.Index, "memory index");
252ece8a530Spatrick     break;
253ece8a530Spatrick   case WASM_EXTERNAL_TABLE:
254ece8a530Spatrick     writeUleb128(os, export_.Index, "table index");
255ece8a530Spatrick     break;
256ece8a530Spatrick   default:
257ece8a530Spatrick     fatal("unsupported export type: " + Twine(export_.Kind));
258ece8a530Spatrick   }
259ece8a530Spatrick }
260ece8a530Spatrick 
261ece8a530Spatrick } // namespace wasm
262ece8a530Spatrick } // namespace lld
263