]> git.proxmox.com Git - rustc.git/blame - src/binaryen/src/binaryen-c.cpp
New upstream version 1.25.0+dfsg1
[rustc.git] / src / binaryen / src / binaryen-c.cpp
CommitLineData
abe05a73
XL
1/*
2 * Copyright 2016 WebAssembly Community Group participants
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//===============================
18// Binaryen C API implementation
19//===============================
20
21#include <mutex>
22
23#include "binaryen-c.h"
24#include "pass.h"
25#include "wasm.h"
26#include "wasm-binary.h"
27#include "wasm-builder.h"
28#include "wasm-interpreter.h"
29#include "wasm-printing.h"
30#include "wasm-s-parser.h"
31#include "wasm-validator.h"
32#include "wasm2asm.h"
33#include "cfg/Relooper.h"
34#include "ir/utils.h"
35#include "shell-interface.h"
36
37using namespace wasm;
38
39// Literal utilities
40
41static_assert(sizeof(BinaryenLiteral) == sizeof(Literal), "Binaryen C API literal must match wasm.h");
42
43BinaryenLiteral toBinaryenLiteral(Literal x) {
44 BinaryenLiteral ret;
45 ret.type = x.type;
46 switch (x.type) {
47 case WasmType::i32: ret.i32 = x.geti32(); break;
48 case WasmType::i64: ret.i64 = x.geti64(); break;
49 case WasmType::f32: ret.i32 = x.reinterpreti32(); break;
50 case WasmType::f64: ret.i64 = x.reinterpreti64(); break;
51 default: abort();
52 }
53 return ret;
54}
55
56Literal fromBinaryenLiteral(BinaryenLiteral x) {
57 switch (x.type) {
58 case WasmType::i32: return Literal(x.i32);
59 case WasmType::i64: return Literal(x.i64);
60 case WasmType::f32: return Literal(x.i32).castToF32();
61 case WasmType::f64: return Literal(x.i64).castToF64();
62 default: abort();
63 }
64}
65
66// Mutexes (global for now; in theory if multiple modules
67// are used at once this should be optimized to be per-
68// module, but likely it doesn't matter)
69
70static std::mutex BinaryenFunctionMutex;
71static std::mutex BinaryenFunctionTypeMutex;
72
73// Tracing support
74
75static int tracing = 0;
76
77void traceNameOrNULL(const char *name) {
78 if (name) std::cout << "\"" << name << "\"";
79 else std::cout << "NULL";
80}
81
82std::map<BinaryenFunctionTypeRef, size_t> functionTypes;
83std::map<BinaryenExpressionRef, size_t> expressions;
84std::map<BinaryenFunctionRef, size_t> functions;
85std::map<RelooperBlockRef, size_t> relooperBlocks;
86
87size_t noteExpression(BinaryenExpressionRef expression) {
88 auto id = expressions.size();
89 assert(expressions.find(expression) == expressions.end());
90 expressions[expression] = id;
91 return id;
92}
93
94extern "C" {
95
96//
97// ========== Module Creation ==========
98//
99
100// Core types
101
102BinaryenType BinaryenNone(void) { return none; }
103BinaryenType BinaryenInt32(void) { return i32; }
104BinaryenType BinaryenInt64(void) { return i64; }
105BinaryenType BinaryenFloat32(void) { return f32; }
106BinaryenType BinaryenFloat64(void) { return f64; }
107BinaryenType BinaryenUndefined(void) { return uint32_t(-1); }
108
109// Expression ids
110
111BinaryenExpressionId BinaryenInvalidId(void) { return Expression::Id::InvalidId; }
112BinaryenExpressionId BinaryenBlockId(void) { return Expression::Id::BlockId; }
113BinaryenExpressionId BinaryenIfId(void) { return Expression::Id::IfId; }
114BinaryenExpressionId BinaryenLoopId(void) { return Expression::Id::LoopId; }
115BinaryenExpressionId BinaryenBreakId(void) { return Expression::Id::BreakId; }
116BinaryenExpressionId BinaryenSwitchId(void) { return Expression::Id::SwitchId; }
117BinaryenExpressionId BinaryenCallId(void) { return Expression::Id::CallId; }
118BinaryenExpressionId BinaryenCallImportId(void) { return Expression::Id::CallImportId; }
119BinaryenExpressionId BinaryenCallIndirectId(void) { return Expression::Id::CallIndirectId; }
120BinaryenExpressionId BinaryenGetLocalId(void) { return Expression::Id::GetLocalId; }
121BinaryenExpressionId BinaryenSetLocalId(void) { return Expression::Id::SetLocalId; }
122BinaryenExpressionId BinaryenGetGlobalId(void) { return Expression::Id::GetGlobalId; }
123BinaryenExpressionId BinaryenSetGlobalId(void) { return Expression::Id::SetGlobalId; }
124BinaryenExpressionId BinaryenLoadId(void) { return Expression::Id::LoadId; }
125BinaryenExpressionId BinaryenStoreId(void) { return Expression::Id::StoreId; }
126BinaryenExpressionId BinaryenConstId(void) { return Expression::Id::ConstId; }
127BinaryenExpressionId BinaryenUnaryId(void) { return Expression::Id::UnaryId; }
128BinaryenExpressionId BinaryenBinaryId(void) { return Expression::Id::BinaryId; }
129BinaryenExpressionId BinaryenSelectId(void) { return Expression::Id::SelectId; }
130BinaryenExpressionId BinaryenDropId(void) { return Expression::Id::DropId; }
131BinaryenExpressionId BinaryenReturnId(void) { return Expression::Id::ReturnId; }
132BinaryenExpressionId BinaryenHostId(void) { return Expression::Id::HostId; }
133BinaryenExpressionId BinaryenNopId(void) { return Expression::Id::NopId; }
134BinaryenExpressionId BinaryenUnreachableId(void) { return Expression::Id::UnreachableId; }
135BinaryenExpressionId BinaryenAtomicCmpxchgId(void) { return Expression::Id::AtomicCmpxchgId; }
136BinaryenExpressionId BinaryenAtomicRMWId(void) { return Expression::Id::AtomicRMWId; }
137BinaryenExpressionId BinaryenAtomicWaitId(void) { return Expression::Id::AtomicWaitId; }
138BinaryenExpressionId BinaryenAtomicWakeId(void) { return Expression::Id::AtomicWakeId; }
139
140// Modules
141
142BinaryenModuleRef BinaryenModuleCreate(void) {
143 if (tracing) {
144 std::cout << " the_module = BinaryenModuleCreate();\n";
145 std::cout << " expressions[size_t(NULL)] = BinaryenExpressionRef(NULL);\n";
146 expressions[NULL] = 0;
147 }
148
149 return new Module();
150}
151void BinaryenModuleDispose(BinaryenModuleRef module) {
152 if (tracing) {
153 std::cout << " BinaryenModuleDispose(the_module);\n";
154 std::cout << " functionTypes.clear();\n";
155 std::cout << " expressions.clear();\n";
156 std::cout << " functions.clear();\n";
157 std::cout << " relooperBlocks.clear();\n";
158 functionTypes.clear();
159 expressions.clear();
160 functions.clear();
161 relooperBlocks.clear();
162 }
163
164 delete (Module*)module;
165}
166
167// Function types
168
169BinaryenFunctionTypeRef BinaryenAddFunctionType(BinaryenModuleRef module, const char* name, BinaryenType result, BinaryenType* paramTypes, BinaryenIndex numParams) {
170 auto* wasm = (Module*)module;
171 auto* ret = new FunctionType;
172 if (name) ret->name = name;
173 else ret->name = Name::fromInt(wasm->functionTypes.size());
174 ret->result = WasmType(result);
175 for (BinaryenIndex i = 0; i < numParams; i++) {
176 ret->params.push_back(WasmType(paramTypes[i]));
177 }
178
179 // Lock. This can be called from multiple threads at once, and is a
180 // point where they all access and modify the module.
181 {
182 std::lock_guard<std::mutex> lock(BinaryenFunctionTypeMutex);
183 wasm->addFunctionType(ret);
184 }
185
186 if (tracing) {
187 std::cout << " {\n";
188 std::cout << " BinaryenType paramTypes[] = { ";
189 for (BinaryenIndex i = 0; i < numParams; i++) {
190 if (i > 0) std::cout << ", ";
191 std::cout << paramTypes[i];
192 }
193 if (numParams == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
194 std::cout << " };\n";
195 size_t id = functionTypes.size();
196 std::cout << " functionTypes[" << id << "] = BinaryenAddFunctionType(the_module, ";
197 functionTypes[ret] = id;
198 traceNameOrNULL(name);
199 std::cout << ", " << result << ", paramTypes, " << numParams << ");\n";
200 std::cout << " }\n";
201 }
202
203 return ret;
204}
205
206BinaryenLiteral BinaryenLiteralInt32(int32_t x) { return toBinaryenLiteral(Literal(x)); }
207BinaryenLiteral BinaryenLiteralInt64(int64_t x) { return toBinaryenLiteral(Literal(x)); }
208BinaryenLiteral BinaryenLiteralFloat32(float x) { return toBinaryenLiteral(Literal(x)); }
209BinaryenLiteral BinaryenLiteralFloat64(double x) { return toBinaryenLiteral(Literal(x)); }
210BinaryenLiteral BinaryenLiteralFloat32Bits(int32_t x) { return toBinaryenLiteral(Literal(x).castToF32()); }
211BinaryenLiteral BinaryenLiteralFloat64Bits(int64_t x) { return toBinaryenLiteral(Literal(x).castToF64()); }
212
213// Expressions
214
215BinaryenOp BinaryenClzInt32(void) { return ClzInt32; }
216BinaryenOp BinaryenCtzInt32(void) { return CtzInt32; }
217BinaryenOp BinaryenPopcntInt32(void) { return PopcntInt32; }
218BinaryenOp BinaryenNegFloat32(void) { return NegFloat32; }
219BinaryenOp BinaryenAbsFloat32(void) { return AbsFloat32; }
220BinaryenOp BinaryenCeilFloat32(void) { return CeilFloat32; }
221BinaryenOp BinaryenFloorFloat32(void) { return FloorFloat32; }
222BinaryenOp BinaryenTruncFloat32(void) { return TruncFloat32; }
223BinaryenOp BinaryenNearestFloat32(void) { return NearestFloat32; }
224BinaryenOp BinaryenSqrtFloat32(void) { return SqrtFloat32; }
225BinaryenOp BinaryenEqZInt32(void) { return EqZInt32; }
226BinaryenOp BinaryenClzInt64(void) { return ClzInt64; }
227BinaryenOp BinaryenCtzInt64(void) { return CtzInt64; }
228BinaryenOp BinaryenPopcntInt64(void) { return PopcntInt64; }
229BinaryenOp BinaryenNegFloat64(void) { return NegFloat64; }
230BinaryenOp BinaryenAbsFloat64(void) { return AbsFloat64; }
231BinaryenOp BinaryenCeilFloat64(void) { return CeilFloat64; }
232BinaryenOp BinaryenFloorFloat64(void) { return FloorFloat64; }
233BinaryenOp BinaryenTruncFloat64(void) { return TruncFloat64; }
234BinaryenOp BinaryenNearestFloat64(void) { return NearestFloat64; }
235BinaryenOp BinaryenSqrtFloat64(void) { return SqrtFloat64; }
236BinaryenOp BinaryenEqZInt64(void) { return EqZInt64; }
237BinaryenOp BinaryenExtendSInt32(void) { return ExtendSInt32; }
238BinaryenOp BinaryenExtendUInt32(void) { return ExtendUInt32; }
239BinaryenOp BinaryenWrapInt64(void) { return WrapInt64; }
240BinaryenOp BinaryenTruncSFloat32ToInt32(void) { return TruncSFloat32ToInt32; }
241BinaryenOp BinaryenTruncSFloat32ToInt64(void) { return TruncSFloat32ToInt64; }
242BinaryenOp BinaryenTruncUFloat32ToInt32(void) { return TruncUFloat32ToInt32; }
243BinaryenOp BinaryenTruncUFloat32ToInt64(void) { return TruncUFloat32ToInt64; }
244BinaryenOp BinaryenTruncSFloat64ToInt32(void) { return TruncSFloat64ToInt32; }
245BinaryenOp BinaryenTruncSFloat64ToInt64(void) { return TruncSFloat64ToInt64; }
246BinaryenOp BinaryenTruncUFloat64ToInt32(void) { return TruncUFloat64ToInt32; }
247BinaryenOp BinaryenTruncUFloat64ToInt64(void) { return TruncUFloat64ToInt64; }
248BinaryenOp BinaryenReinterpretFloat32(void) { return ReinterpretFloat32; }
249BinaryenOp BinaryenReinterpretFloat64(void) { return ReinterpretFloat64; }
250BinaryenOp BinaryenConvertSInt32ToFloat32(void) { return ConvertSInt32ToFloat32; }
251BinaryenOp BinaryenConvertSInt32ToFloat64(void) { return ConvertSInt32ToFloat64; }
252BinaryenOp BinaryenConvertUInt32ToFloat32(void) { return ConvertUInt32ToFloat32; }
253BinaryenOp BinaryenConvertUInt32ToFloat64(void) { return ConvertUInt32ToFloat64; }
254BinaryenOp BinaryenConvertSInt64ToFloat32(void) { return ConvertSInt64ToFloat32; }
255BinaryenOp BinaryenConvertSInt64ToFloat64(void) { return ConvertSInt64ToFloat64; }
256BinaryenOp BinaryenConvertUInt64ToFloat32(void) { return ConvertUInt64ToFloat32; }
257BinaryenOp BinaryenConvertUInt64ToFloat64(void) { return ConvertUInt64ToFloat64; }
258BinaryenOp BinaryenPromoteFloat32(void) { return PromoteFloat32; }
259BinaryenOp BinaryenDemoteFloat64(void) { return DemoteFloat64; }
260BinaryenOp BinaryenReinterpretInt32(void) { return ReinterpretInt32; }
261BinaryenOp BinaryenReinterpretInt64(void) { return ReinterpretInt64; }
262BinaryenOp BinaryenAddInt32(void) { return AddInt32; }
263BinaryenOp BinaryenSubInt32(void) { return SubInt32; }
264BinaryenOp BinaryenMulInt32(void) { return MulInt32; }
265BinaryenOp BinaryenDivSInt32(void) { return DivSInt32; }
266BinaryenOp BinaryenDivUInt32(void) { return DivUInt32; }
267BinaryenOp BinaryenRemSInt32(void) { return RemSInt32; }
268BinaryenOp BinaryenRemUInt32(void) { return RemUInt32; }
269BinaryenOp BinaryenAndInt32(void) { return AndInt32; }
270BinaryenOp BinaryenOrInt32(void) { return OrInt32; }
271BinaryenOp BinaryenXorInt32(void) { return XorInt32; }
272BinaryenOp BinaryenShlInt32(void) { return ShlInt32; }
273BinaryenOp BinaryenShrUInt32(void) { return ShrUInt32; }
274BinaryenOp BinaryenShrSInt32(void) { return ShrSInt32; }
275BinaryenOp BinaryenRotLInt32(void) { return RotLInt32; }
276BinaryenOp BinaryenRotRInt32(void) { return RotRInt32; }
277BinaryenOp BinaryenEqInt32(void) { return EqInt32; }
278BinaryenOp BinaryenNeInt32(void) { return NeInt32; }
279BinaryenOp BinaryenLtSInt32(void) { return LtSInt32; }
280BinaryenOp BinaryenLtUInt32(void) { return LtUInt32; }
281BinaryenOp BinaryenLeSInt32(void) { return LeSInt32; }
282BinaryenOp BinaryenLeUInt32(void) { return LeUInt32; }
283BinaryenOp BinaryenGtSInt32(void) { return GtSInt32; }
284BinaryenOp BinaryenGtUInt32(void) { return GtUInt32; }
285BinaryenOp BinaryenGeSInt32(void) { return GeSInt32; }
286BinaryenOp BinaryenGeUInt32(void) { return GeUInt32; }
287BinaryenOp BinaryenAddInt64(void) { return AddInt64; }
288BinaryenOp BinaryenSubInt64(void) { return SubInt64; }
289BinaryenOp BinaryenMulInt64(void) { return MulInt64; }
290BinaryenOp BinaryenDivSInt64(void) { return DivSInt64; }
291BinaryenOp BinaryenDivUInt64(void) { return DivUInt64; }
292BinaryenOp BinaryenRemSInt64(void) { return RemSInt64; }
293BinaryenOp BinaryenRemUInt64(void) { return RemUInt64; }
294BinaryenOp BinaryenAndInt64(void) { return AndInt64; }
295BinaryenOp BinaryenOrInt64(void) { return OrInt64; }
296BinaryenOp BinaryenXorInt64(void) { return XorInt64; }
297BinaryenOp BinaryenShlInt64(void) { return ShlInt64; }
298BinaryenOp BinaryenShrUInt64(void) { return ShrUInt64; }
299BinaryenOp BinaryenShrSInt64(void) { return ShrSInt64; }
300BinaryenOp BinaryenRotLInt64(void) { return RotLInt64; }
301BinaryenOp BinaryenRotRInt64(void) { return RotRInt64; }
302BinaryenOp BinaryenEqInt64(void) { return EqInt64; }
303BinaryenOp BinaryenNeInt64(void) { return NeInt64; }
304BinaryenOp BinaryenLtSInt64(void) { return LtSInt64; }
305BinaryenOp BinaryenLtUInt64(void) { return LtUInt64; }
306BinaryenOp BinaryenLeSInt64(void) { return LeSInt64; }
307BinaryenOp BinaryenLeUInt64(void) { return LeUInt64; }
308BinaryenOp BinaryenGtSInt64(void) { return GtSInt64; }
309BinaryenOp BinaryenGtUInt64(void) { return GtUInt64; }
310BinaryenOp BinaryenGeSInt64(void) { return GeSInt64; }
311BinaryenOp BinaryenGeUInt64(void) { return GeUInt64; }
312BinaryenOp BinaryenAddFloat32(void) { return AddFloat32; }
313BinaryenOp BinaryenSubFloat32(void) { return SubFloat32; }
314BinaryenOp BinaryenMulFloat32(void) { return MulFloat32; }
315BinaryenOp BinaryenDivFloat32(void) { return DivFloat32; }
316BinaryenOp BinaryenCopySignFloat32(void) { return CopySignFloat32; }
317BinaryenOp BinaryenMinFloat32(void) { return MinFloat32; }
318BinaryenOp BinaryenMaxFloat32(void) { return MaxFloat32; }
319BinaryenOp BinaryenEqFloat32(void) { return EqFloat32; }
320BinaryenOp BinaryenNeFloat32(void) { return NeFloat32; }
321BinaryenOp BinaryenLtFloat32(void) { return LtFloat32; }
322BinaryenOp BinaryenLeFloat32(void) { return LeFloat32; }
323BinaryenOp BinaryenGtFloat32(void) { return GtFloat32; }
324BinaryenOp BinaryenGeFloat32(void) { return GeFloat32; }
325BinaryenOp BinaryenAddFloat64(void) { return AddFloat64; }
326BinaryenOp BinaryenSubFloat64(void) { return SubFloat64; }
327BinaryenOp BinaryenMulFloat64(void) { return MulFloat64; }
328BinaryenOp BinaryenDivFloat64(void) { return DivFloat64; }
329BinaryenOp BinaryenCopySignFloat64(void) { return CopySignFloat64; }
330BinaryenOp BinaryenMinFloat64(void) { return MinFloat64; }
331BinaryenOp BinaryenMaxFloat64(void) { return MaxFloat64; }
332BinaryenOp BinaryenEqFloat64(void) { return EqFloat64; }
333BinaryenOp BinaryenNeFloat64(void) { return NeFloat64; }
334BinaryenOp BinaryenLtFloat64(void) { return LtFloat64; }
335BinaryenOp BinaryenLeFloat64(void) { return LeFloat64; }
336BinaryenOp BinaryenGtFloat64(void) { return GtFloat64; }
337BinaryenOp BinaryenGeFloat64(void) { return GeFloat64; }
338BinaryenOp BinaryenPageSize(void) { return PageSize; }
339BinaryenOp BinaryenCurrentMemory(void) { return CurrentMemory; }
340BinaryenOp BinaryenGrowMemory(void) { return GrowMemory; }
341BinaryenOp BinaryenHasFeature(void) { return HasFeature; }
342BinaryenOp BinaryenAtomicRMWAdd(void) { return AtomicRMWOp::Add; }
343BinaryenOp BinaryenAtomicRMWSub(void) { return AtomicRMWOp::Sub; }
344BinaryenOp BinaryenAtomicRMWAnd(void) { return AtomicRMWOp::And; }
345BinaryenOp BinaryenAtomicRMWOr(void) { return AtomicRMWOp::Or; }
346BinaryenOp BinaryenAtomicRMWXor(void) { return AtomicRMWOp::Xor; }
347BinaryenOp BinaryenAtomicRMWXchg(void) { return AtomicRMWOp::Xchg; }
348
349BinaryenExpressionRef BinaryenBlock(BinaryenModuleRef module, const char* name, BinaryenExpressionRef* children, BinaryenIndex numChildren, BinaryenType type) {
350 auto* ret = ((Module*)module)->allocator.alloc<Block>();
351 if (name) ret->name = name;
352 for (BinaryenIndex i = 0; i < numChildren; i++) {
353 ret->list.push_back((Expression*)children[i]);
354 }
355 if (type != BinaryenUndefined()) ret->finalize(WasmType(type));
356 else ret->finalize();
357
358 if (tracing) {
359 std::cout << " {\n";
360 std::cout << " BinaryenExpressionRef children[] = { ";
361 for (BinaryenIndex i = 0; i < numChildren; i++) {
362 if (i > 0) std::cout << ", ";
363 std::cout << "expressions[" << expressions[children[i]] << "]";
364 }
365 if (numChildren == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
366 std::cout << " };\n";
367 auto id = noteExpression(ret);
368 std::cout << " expressions[" << id << "] = BinaryenBlock(the_module, ";
369 traceNameOrNULL(name);
370 std::cout << ", children, " << numChildren << ", ";
371 if (type == BinaryenUndefined()) std::cout << "BinaryenUndefined()";
372 else std::cout << type;
373 std::cout << ");\n";
374 std::cout << " }\n";
375 }
376
377 return static_cast<Expression*>(ret);
378}
379BinaryenExpressionRef BinaryenIf(BinaryenModuleRef module, BinaryenExpressionRef condition, BinaryenExpressionRef ifTrue, BinaryenExpressionRef ifFalse) {
380 auto* ret = ((Module*)module)->allocator.alloc<If>();
381 ret->condition = (Expression*)condition;
382 ret->ifTrue = (Expression*)ifTrue;
383 ret->ifFalse = (Expression*)ifFalse;
384 ret->finalize();
385
386 if (tracing) {
387 auto id = noteExpression(ret);
388 std::cout << " expressions[" << id << "] = BinaryenIf(the_module, expressions[" << expressions[condition] << "], expressions[" << expressions[ifTrue] << "], expressions[" << expressions[ifFalse] << "]);\n";
389 }
390
391 return static_cast<Expression*>(ret);
392}
393BinaryenExpressionRef BinaryenLoop(BinaryenModuleRef module, const char* name, BinaryenExpressionRef body) {
394 auto* ret = Builder(*((Module*)module)).makeLoop(name ? Name(name) : Name(), (Expression*)body);
395
396 if (tracing) {
397 auto id = noteExpression(ret);
398 std::cout << " expressions[" << id << "] = BinaryenLoop(the_module, ";
399 traceNameOrNULL(name);
400 std::cout << ", expressions[" << expressions[body] << "]);\n";
401 }
402
403 return static_cast<Expression*>(ret);
404}
405BinaryenExpressionRef BinaryenBreak(BinaryenModuleRef module, const char* name, BinaryenExpressionRef condition, BinaryenExpressionRef value) {
406 auto* ret = Builder(*((Module*)module)).makeBreak(name, (Expression*)value, (Expression*)condition);
407
408 if (tracing) {
409 auto id = noteExpression(ret);
410 std::cout << " expressions[" << id << "] = BinaryenBreak(the_module, \"" << name << "\", expressions[" << expressions[condition] << "], expressions[" << expressions[value] << "]);\n";
411 }
412
413 return static_cast<Expression*>(ret);
414}
415BinaryenExpressionRef BinaryenSwitch(BinaryenModuleRef module, const char **names, BinaryenIndex numNames, const char* defaultName, BinaryenExpressionRef condition, BinaryenExpressionRef value) {
416 auto* ret = ((Module*)module)->allocator.alloc<Switch>();
417
418 if (tracing) {
419 std::cout << " {\n";
420 std::cout << " const char* names[] = { ";
421 for (BinaryenIndex i = 0; i < numNames; i++) {
422 if (i > 0) std::cout << ", ";
423 std::cout << "\"" << names[i] << "\"";
424 }
425 if (numNames == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
426 std::cout << " };\n";
427 auto id = noteExpression(ret);
428 std::cout << " expressions[" << id << "] = BinaryenSwitch(the_module, names, " << numNames << ", \"" << defaultName << "\", expressions[" << expressions[condition] << "], expressions[" << expressions[value] << "]);\n";
429 std::cout << " }\n";
430 }
431
432 for (BinaryenIndex i = 0; i < numNames; i++) {
433 ret->targets.push_back(names[i]);
434 }
435 ret->default_ = defaultName;
436 ret->condition = (Expression*)condition;
437 ret->value = (Expression*)value;
438 ret->finalize();
439 return static_cast<Expression*>(ret);
440}
441BinaryenExpressionRef BinaryenCall(BinaryenModuleRef module, const char *target, BinaryenExpressionRef* operands, BinaryenIndex numOperands, BinaryenType returnType) {
442 auto* ret = ((Module*)module)->allocator.alloc<Call>();
443
444 if (tracing) {
445 std::cout << " {\n";
446 std::cout << " BinaryenExpressionRef operands[] = { ";
447 for (BinaryenIndex i = 0; i < numOperands; i++) {
448 if (i > 0) std::cout << ", ";
449 std::cout << "expressions[" << expressions[operands[i]] << "]";
450 }
451 if (numOperands == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
452 std::cout << " };\n";
453 auto id = noteExpression(ret);
454 std::cout << " expressions[" << id << "] = BinaryenCall(the_module, \"" << target << "\", operands, " << numOperands << ", " << returnType << ");\n";
455 std::cout << " }\n";
456 }
457
458 ret->target = target;
459 for (BinaryenIndex i = 0; i < numOperands; i++) {
460 ret->operands.push_back((Expression*)operands[i]);
461 }
462 ret->type = WasmType(returnType);
463 ret->finalize();
464 return static_cast<Expression*>(ret);
465}
466BinaryenExpressionRef BinaryenCallImport(BinaryenModuleRef module, const char *target, BinaryenExpressionRef* operands, BinaryenIndex numOperands, BinaryenType returnType) {
467 auto* ret = ((Module*)module)->allocator.alloc<CallImport>();
468
469 if (tracing) {
470 std::cout << " {\n";
471 std::cout << " BinaryenExpressionRef operands[] = { ";
472 for (BinaryenIndex i = 0; i < numOperands; i++) {
473 if (i > 0) std::cout << ", ";
474 std::cout << "expressions[" << expressions[operands[i]] << "]";
475 }
476 if (numOperands == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
477 std::cout << " };\n";
478 auto id = noteExpression(ret);
479 std::cout << " expressions[" << id << "] = BinaryenCallImport(the_module, \"" << target << "\", operands, " << numOperands << ", " << returnType << ");\n";
480 std::cout << " }\n";
481 }
482
483 ret->target = target;
484 for (BinaryenIndex i = 0; i < numOperands; i++) {
485 ret->operands.push_back((Expression*)operands[i]);
486 }
487 ret->type = WasmType(returnType);
488 ret->finalize();
489 return static_cast<Expression*>(ret);
490}
491BinaryenExpressionRef BinaryenCallIndirect(BinaryenModuleRef module, BinaryenExpressionRef target, BinaryenExpressionRef* operands, BinaryenIndex numOperands, const char* type) {
492 auto* wasm = (Module*)module;
493 auto* ret = wasm->allocator.alloc<CallIndirect>();
494
495 if (tracing) {
496 std::cout << " {\n";
497 std::cout << " BinaryenExpressionRef operands[] = { ";
498 for (BinaryenIndex i = 0; i < numOperands; i++) {
499 if (i > 0) std::cout << ", ";
500 std::cout << "expressions[" << expressions[operands[i]] << "]";
501 }
502 if (numOperands == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
503 std::cout << " };\n";
504 auto id = noteExpression(ret);
505 std::cout << " expressions[" << id << "] = BinaryenCallIndirect(the_module, expressions[" << expressions[target] << "], operands, " << numOperands << ", \"" << type << "\");\n";
506 std::cout << " }\n";
507 }
508
509 ret->target = (Expression*)target;
510 for (BinaryenIndex i = 0; i < numOperands; i++) {
511 ret->operands.push_back((Expression*)operands[i]);
512 }
513 ret->fullType = type;
514 ret->type = wasm->getFunctionType(ret->fullType)->result;
515 ret->finalize();
516 return static_cast<Expression*>(ret);
517}
518BinaryenExpressionRef BinaryenGetLocal(BinaryenModuleRef module, BinaryenIndex index, BinaryenType type) {
519 auto* ret = ((Module*)module)->allocator.alloc<GetLocal>();
520
521 if (tracing) {
522 auto id = noteExpression(ret);
523 std::cout << " expressions[" << id << "] = BinaryenGetLocal(the_module, " << index << ", " << type << ");\n";
524 }
525
526 ret->index = index;
527 ret->type = WasmType(type);
528 ret->finalize();
529 return static_cast<Expression*>(ret);
530}
531BinaryenExpressionRef BinaryenSetLocal(BinaryenModuleRef module, BinaryenIndex index, BinaryenExpressionRef value) {
532 auto* ret = ((Module*)module)->allocator.alloc<SetLocal>();
533
534 if (tracing) {
535 auto id = noteExpression(ret);
536 std::cout << " expressions[" << id << "] = BinaryenSetLocal(the_module, " << index << ", expressions[" << expressions[value] << "]);\n";
537 }
538
539 ret->index = index;
540 ret->value = (Expression*)value;
541 ret->setTee(false);
542 ret->finalize();
543 return static_cast<Expression*>(ret);
544}
545BinaryenExpressionRef BinaryenTeeLocal(BinaryenModuleRef module, BinaryenIndex index, BinaryenExpressionRef value) {
546 auto* ret = ((Module*)module)->allocator.alloc<SetLocal>();
547
548 if (tracing) {
549 auto id = noteExpression(ret);
550 std::cout << " expressions[" << id << "] = BinaryenTeeLocal(the_module, " << index << ", expressions[" << expressions[value] << "]);\n";
551 }
552
553 ret->index = index;
554 ret->value = (Expression*)value;
555 ret->setTee(true);
556 ret->finalize();
557 return static_cast<Expression*>(ret);
558}
559BinaryenExpressionRef BinaryenGetGlobal(BinaryenModuleRef module, const char *name, BinaryenType type) {
560 auto* ret = ((Module*)module)->allocator.alloc<GetGlobal>();
561
562 if (tracing) {
563 auto id = noteExpression(ret);
564 std::cout << " expressions[" << id << "] = BinaryenGetGlobal(the_module, \"" << name << "\", " << type << ");\n";
565 }
566
567 ret->name = name;
568 ret->type = WasmType(type);
569 ret->finalize();
570 return static_cast<Expression*>(ret);
571}
572BinaryenExpressionRef BinaryenSetGlobal(BinaryenModuleRef module, const char *name, BinaryenExpressionRef value) {
573 auto* ret = ((Module*)module)->allocator.alloc<SetGlobal>();
574
575 if (tracing) {
576 auto id = noteExpression(ret);
577 std::cout << " expressions[" << id << "] = BinaryenSetGlobal(the_module, \"" << name << "\", expressions[" << expressions[value] << "]);\n";
578 }
579
580 ret->name = name;
581 ret->value = (Expression*)value;
582 ret->finalize();
583 return static_cast<Expression*>(ret);
584}
585BinaryenExpressionRef BinaryenLoad(BinaryenModuleRef module, uint32_t bytes, int8_t signed_, uint32_t offset, uint32_t align, BinaryenType type, BinaryenExpressionRef ptr) {
586 auto* ret = ((Module*)module)->allocator.alloc<Load>();
587
588 if (tracing) {
589 auto id = noteExpression(ret);
590 std::cout << " expressions[" << id << "] = BinaryenLoad(the_module, " << bytes << ", " << int(signed_) << ", " << offset << ", " << align << ", " << type << ", expressions[" << expressions[ptr] << "]);\n";
591 }
592 ret->isAtomic = false;
593 ret->bytes = bytes;
594 ret->signed_ = !!signed_;
595 ret->offset = offset;
596 ret->align = align ? align : bytes;
597 ret->type = WasmType(type);
598 ret->ptr = (Expression*)ptr;
599 ret->finalize();
600 return static_cast<Expression*>(ret);
601}
602BinaryenExpressionRef BinaryenStore(BinaryenModuleRef module, uint32_t bytes, uint32_t offset, uint32_t align, BinaryenExpressionRef ptr, BinaryenExpressionRef value, BinaryenType type) {
603 auto* ret = ((Module*)module)->allocator.alloc<Store>();
604
605 if (tracing) {
606 auto id = noteExpression(ret);
607 std::cout << " expressions[" << id << "] = BinaryenStore(the_module, " << bytes << ", " << offset << ", " << align << ", expressions[" << expressions[ptr] << "], expressions[" << expressions[value] << "], " << type << ");\n";
608 }
609 ret->isAtomic = false;
610 ret->bytes = bytes;
611 ret->offset = offset;
612 ret->align = align ? align : bytes;
613 ret->ptr = (Expression*)ptr;
614 ret->value = (Expression*)value;
615 ret->valueType = WasmType(type);
616 ret->finalize();
617 return static_cast<Expression*>(ret);
618}
619BinaryenExpressionRef BinaryenConst(BinaryenModuleRef module, BinaryenLiteral value) {
620 auto* ret = Builder(*((Module*)module)).makeConst(fromBinaryenLiteral(value));
621 if (tracing) {
622 auto id = noteExpression(ret);
623 switch (value.type) {
624 case WasmType::i32: std::cout << " expressions[" << id << "] = BinaryenConst(the_module, BinaryenLiteralInt32(" << value.i32 << "));\n"; break;
625 case WasmType::i64: std::cout << " expressions[" << id << "] = BinaryenConst(the_module, BinaryenLiteralInt64(" << value.i64 << "));\n"; break;
626 case WasmType::f32: {
627 std::cout << " expressions[" << id << "] = BinaryenConst(the_module, BinaryenLiteralFloat32(";
628 if (std::isnan(value.f32)) std::cout << "NAN";
629 else std::cout << value.f32;
630 std::cout << "));\n";
631 break;
632 }
633 case WasmType::f64: {
634 std::cout << " expressions[" << id << "] = BinaryenConst(the_module, BinaryenLiteralFloat64(";
635 if (std::isnan(value.f64)) std::cout << "NAN";
636 else std::cout << value.f64;
637 std::cout << "));\n";
638 break;
639 }
640 default: WASM_UNREACHABLE();
641 }
642 }
643 return static_cast<Expression*>(ret);
644}
645BinaryenExpressionRef BinaryenUnary(BinaryenModuleRef module, BinaryenOp op, BinaryenExpressionRef value) {
646 auto* ret = Builder(*((Module*)module)).makeUnary(UnaryOp(op), (Expression*)value);
647
648 if (tracing) {
649 auto id = noteExpression(ret);
650 std::cout << " expressions[" << id << "] = BinaryenUnary(the_module, " << op << ", expressions[" << expressions[value] << "]);\n";
651 }
652
653 return static_cast<Expression*>(ret);
654}
655BinaryenExpressionRef BinaryenBinary(BinaryenModuleRef module, BinaryenOp op, BinaryenExpressionRef left, BinaryenExpressionRef right) {
656 auto* ret = Builder(*((Module*)module)).makeBinary(BinaryOp(op), (Expression*)left, (Expression*)right);
657
658 if (tracing) {
659 auto id = noteExpression(ret);
660 std::cout << " expressions[" << id << "] = BinaryenBinary(the_module, " << op << ", expressions[" << expressions[left] << "], expressions[" << expressions[right] << "]);\n";
661 }
662
663 return static_cast<Expression*>(ret);
664}
665BinaryenExpressionRef BinaryenSelect(BinaryenModuleRef module, BinaryenExpressionRef condition, BinaryenExpressionRef ifTrue, BinaryenExpressionRef ifFalse) {
666 auto* ret = ((Module*)module)->allocator.alloc<Select>();
667
668 if (tracing) {
669 auto id = noteExpression(ret);
670 std::cout << " expressions[" << id << "] = BinaryenSelect(the_module, expressions[" << expressions[condition] << "], expressions[" << expressions[ifTrue] << "], expressions[" << expressions[ifFalse] << "]);\n";
671 }
672
673 ret->condition = (Expression*)condition;
674 ret->ifTrue = (Expression*)ifTrue;
675 ret->ifFalse = (Expression*)ifFalse;
676 ret->finalize();
677 return static_cast<Expression*>(ret);
678}
679BinaryenExpressionRef BinaryenDrop(BinaryenModuleRef module, BinaryenExpressionRef value) {
680 auto* ret = ((Module*)module)->allocator.alloc<Drop>();
681
682 if (tracing) {
683 auto id = noteExpression(ret);
684 std::cout << " expressions[" << id << "] = BinaryenDrop(the_module, expressions[" << expressions[value] << "]);\n";
685 }
686
687 ret->value = (Expression*)value;
688 ret->finalize();
689 return static_cast<Expression*>(ret);
690}
691BinaryenExpressionRef BinaryenReturn(BinaryenModuleRef module, BinaryenExpressionRef value) {
692 auto* ret = Builder(*((Module*)module)).makeReturn((Expression*)value);
693
694 if (tracing) {
695 auto id = noteExpression(ret);
696 std::cout << " expressions[" << id << "] = BinaryenReturn(the_module, expressions[" << expressions[value] << "]);\n";
697 }
698
699 return static_cast<Expression*>(ret);
700}
701BinaryenExpressionRef BinaryenHost(BinaryenModuleRef module, BinaryenOp op, const char* name, BinaryenExpressionRef* operands, BinaryenIndex numOperands) {
702 if (tracing) {
703 std::cout << " TODO: host...\n";
704 }
705
706 auto* ret = ((Module*)module)->allocator.alloc<Host>();
707 ret->op = HostOp(op);
708 if (name) ret->nameOperand = name;
709 for (BinaryenIndex i = 0; i < numOperands; i++) {
710 ret->operands.push_back((Expression*)operands[i]);
711 }
712 ret->finalize();
713 return static_cast<Expression*>(ret);
714}
715BinaryenExpressionRef BinaryenNop(BinaryenModuleRef module) {
716 auto* ret = ((Module*)module)->allocator.alloc<Nop>();
717
718 if (tracing) {
719 auto id = noteExpression(ret);
720 std::cout << " expressions[" << id << "] = BinaryenNop(the_module);\n";
721 }
722
723 return static_cast<Expression*>(ret);
724}
725BinaryenExpressionRef BinaryenUnreachable(BinaryenModuleRef module) {
726 auto* ret = ((Module*)module)->allocator.alloc<Unreachable>();
727
728 if (tracing) {
729 auto id = noteExpression(ret);
730 std::cout << " expressions[" << id << "] = BinaryenUnreachable(the_module);\n";
731 }
732
733 return static_cast<Expression*>(ret);
734}
735BinaryenExpressionRef BinaryenAtomicRMW(BinaryenModuleRef module, BinaryenOp op, BinaryenIndex bytes, BinaryenIndex offset, BinaryenExpressionRef ptr, BinaryenExpressionRef value, BinaryenType type) {
736 auto* ret = Builder(*((Module*)module)).makeAtomicRMW(AtomicRMWOp(op), bytes, offset, (Expression*)ptr, (Expression*)value, WasmType(type));
737
738 if (tracing) {
739 auto id = noteExpression(ret);
740 std::cout << " expressions[" << id << "] = BinaryenAtomicRMW(the_module, " << op << ", " << bytes << ", " << offset << ", expressions[" << expressions[ptr] << "], expressions[" << expressions[value] << "], " << type << ");\n";
741 }
742
743 return static_cast<Expression*>(ret);
744}
745BinaryenExpressionRef BinaryenAtomicCmpxchg(BinaryenModuleRef module, BinaryenIndex bytes, BinaryenIndex offset, BinaryenExpressionRef ptr, BinaryenExpressionRef expected, BinaryenExpressionRef replacement, BinaryenType type) {
746 auto* ret = Builder(*((Module*)module)).makeAtomicCmpxchg(bytes, offset, (Expression*)ptr, (Expression*)expected, (Expression*)replacement, WasmType(type));
747
748 if (tracing) {
749 auto id = noteExpression(ret);
750 std::cout << " expressions[" << id << "] = BinaryenAtomicCmpxchg(the_module, " << bytes << ", " << offset << ", expressions[" << expressions[ptr] << "], expressions[" << expressions[expected] << "], expressions[" << expressions[replacement] << "], " << type << ");\n";
751 }
752
753 return static_cast<Expression*>(ret);
754}
755BinaryenExpressionRef BinaryenAtomicWait(BinaryenModuleRef module, BinaryenExpressionRef ptr, BinaryenExpressionRef expected, BinaryenExpressionRef timeout, BinaryenType expectedType) {
756 auto* ret = Builder(*((Module*)module)).makeAtomicWait((Expression*)ptr, (Expression*)expected, (Expression*)timeout, WasmType(expectedType));
757
758 if (tracing) {
759 auto id = noteExpression(ret);
760 std::cout << " expressions[" << id << "] = BinaryenAtomicWait(the_module, expressions[" << expressions[ptr] << "], expressions[" << expressions[expected] << "], expressions[" << expressions[timeout] << "], " << expectedType << ");\n";
761 }
762
763 return static_cast<Expression*>(ret);
764}
765BinaryenExpressionRef BinaryenAtomicWake(BinaryenModuleRef module, BinaryenExpressionRef ptr, BinaryenExpressionRef wakeCount) {
766 auto* ret = Builder(*((Module*)module)).makeAtomicWake((Expression*)ptr, (Expression*)wakeCount);
767
768 if (tracing) {
769 auto id = noteExpression(ret);
770 std::cout << " expressions[" << id << "] = BinaryenAtomicWake(the_module, expressions[" << expressions[ptr] << "], expressions[" << expressions[wakeCount] << "]);\n";
771 }
772
773 return static_cast<Expression*>(ret);
774}
775
776// Expression utility
777
778BinaryenExpressionId BinaryenExpressionGetId(BinaryenExpressionRef expr) {
779 if (tracing) {
780 std::cout << " BinaryenExpressionGetId(expressions[" << expressions[expr] << "]);\n";
781 }
782
783 return ((Expression*)expr)->_id;
784}
785BinaryenType BinaryenExpressionGetType(BinaryenExpressionRef expr) {
786 if (tracing) {
787 std::cout << " BinaryenExpressionGetType(expressions[" << expressions[expr] << "]);\n";
788 }
789
790 return ((Expression*)expr)->type;
791}
792void BinaryenExpressionPrint(BinaryenExpressionRef expr) {
793 if (tracing) {
794 std::cout << " BinaryenExpressionPrint(expressions[" << expressions[expr] << "]);\n";
795 }
796
797 WasmPrinter::printExpression((Expression*)expr, std::cout);
798 std::cout << '\n';
799}
800int32_t BinaryenConstGetValueI32(BinaryenExpressionRef expr) {
801 if (tracing) {
802 std::cout << " BinaryenConstGetValueI32(expressions[" << expressions[expr] << "]);\n";
803 }
804
805 auto* expression = (Expression*)expr;
806 assert(expression->is<Const>());
807 return static_cast<Const*>(expression)->value.geti32();
808}
809int64_t BinaryenConstGetValueI64(BinaryenExpressionRef expr) {
810 if (tracing) {
811 std::cout << " BinaryenConstGetValueI64(expressions[" << expressions[expr] << "]);\n";
812 }
813
814 auto* expression = (Expression*)expr;
815 assert(expression->is<Const>());
816 return static_cast<Const*>(expression)->value.geti64();
817}
818int32_t BinaryenConstGetValueI64Low(BinaryenExpressionRef expr) {
819 if (tracing) {
820 std::cout << " BinaryenConstGetValueI64Low(expressions[" << expressions[expr] << "]);\n";
821 }
822
823 auto* expression = (Expression*)expr;
824 assert(expression->is<Const>());
825 return (int32_t)(static_cast<Const*>(expression)->value.geti64() & 0xffffffff);
826}
827int32_t BinaryenConstGetValueI64High(BinaryenExpressionRef expr) {
828 if (tracing) {
829 std::cout << " BinaryenConstGetValueI64High(expressions[" << expressions[expr] << "]);\n";
830 }
831
832 auto* expression = (Expression*)expr;
833 assert(expression->is<Const>());
834 return (int32_t)(static_cast<Const*>(expression)->value.geti64() >> 32);
835}
836float BinaryenConstGetValueF32(BinaryenExpressionRef expr) {
837 if (tracing) {
838 std::cout << " BinaryenConstGetValueF32(expressions[" << expressions[expr] << "]);\n";
839 }
840
841 auto* expression = (Expression*)expr;
842 assert(expression->is<Const>());
843 return static_cast<Const*>(expression)->value.getf32();
844}
845double BinaryenConstGetValueF64(BinaryenExpressionRef expr) {
846 if (tracing) {
847 std::cout << " BinaryenConstGetValueF64(expressions[" << expressions[expr] << "]);\n";
848 }
849
850 auto* expression = (Expression*)expr;
851 assert(expression->is<Const>());
852 return static_cast<Const*>(expression)->value.getf64();
853}
854
855// Functions
856
857BinaryenFunctionRef BinaryenAddFunction(BinaryenModuleRef module, const char* name, BinaryenFunctionTypeRef type, BinaryenType* varTypes, BinaryenIndex numVarTypes, BinaryenExpressionRef body) {
858 auto* wasm = (Module*)module;
859 auto* ret = new Function;
860
861 if (tracing) {
862 std::cout << " {\n";
863 std::cout << " BinaryenType varTypes[] = { ";
864 for (BinaryenIndex i = 0; i < numVarTypes; i++) {
865 if (i > 0) std::cout << ", ";
866 std::cout << varTypes[i];
867 }
868 if (numVarTypes == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
869 std::cout << " };\n";
870 auto id = functions.size();
871 functions[ret] = id;
872 std::cout << " functions[" << id << "] = BinaryenAddFunction(the_module, \"" << name << "\", functionTypes[" << functionTypes[type] << "], varTypes, " << numVarTypes << ", expressions[" << expressions[body] << "]);\n";
873 std::cout << " }\n";
874 }
875
876 ret->name = name;
877 ret->type = ((FunctionType*)type)->name;
878 auto* functionType = wasm->getFunctionType(ret->type);
879 ret->result = functionType->result;
880 ret->params = functionType->params;
881 for (BinaryenIndex i = 0; i < numVarTypes; i++) {
882 ret->vars.push_back(WasmType(varTypes[i]));
883 }
884 ret->body = (Expression*)body;
885
886 // Lock. This can be called from multiple threads at once, and is a
887 // point where they all access and modify the module.
888 {
889 std::lock_guard<std::mutex> lock(BinaryenFunctionMutex);
890 wasm->addFunction(ret);
891 }
892
893 return ret;
894}
895
896BinaryenGlobalRef BinaryenAddGlobal(BinaryenModuleRef module, const char* name, BinaryenType type, int8_t mutable_, BinaryenExpressionRef init) {
897 if (tracing) {
898 std::cout << " BinaryenAddGlobal(the_module, \"" << name << "\", " << type << ", " << int(mutable_) << ", expressions[" << expressions[init] << "]);\n";
899 }
900
901 auto* wasm = (Module*)module;
902 auto* ret = new Global();
903 ret->name = name;
904 ret->type = WasmType(type);
905 ret->mutable_ = !!mutable_;
906 ret->init = (Expression*)init;
907 wasm->addGlobal(ret);
908 return ret;
909}
910
911// Imports
912
913BinaryenImportRef BinaryenAddImport(BinaryenModuleRef module, const char* internalName, const char* externalModuleName, const char *externalBaseName, BinaryenFunctionTypeRef type) {
914 if (tracing) {
915 std::cout << " BinaryenAddImport(the_module, \"" << internalName << "\", \"" << externalModuleName << "\", \"" << externalBaseName << "\", functionTypes[" << functionTypes[type] << "]);\n";
916 }
917
918 auto* wasm = (Module*)module;
919 auto* ret = new Import();
920 ret->name = internalName;
921 ret->module = externalModuleName;
922 ret->base = externalBaseName;
923 ret->functionType = ((FunctionType*)type)->name;
924 ret->kind = ExternalKind::Function;
925 wasm->addImport(ret);
926 return ret;
927}
928
929void BinaryenRemoveImport(BinaryenModuleRef module, const char* internalName) {
930 if (tracing) {
931 std::cout << " BinaryenRemoveImport(the_module, \"" << internalName << "\");\n";
932 }
933
934 auto* wasm = (Module*)module;
935 wasm->removeImport(internalName);
936}
937
938// Exports
939
940BinaryenExportRef BinaryenAddExport(BinaryenModuleRef module, const char* internalName, const char* externalName) {
941 if (tracing) {
942 std::cout << " BinaryenAddExport(the_module, \"" << internalName << "\", \"" << externalName << "\");\n";
943 }
944
945 auto* wasm = (Module*)module;
946 auto* ret = new Export();
947 ret->value = internalName;
948 ret->name = externalName;
949 wasm->addExport(ret);
950 return ret;
951}
952
953void BinaryenRemoveExport(BinaryenModuleRef module, const char* externalName) {
954 if (tracing) {
955 std::cout << " BinaryenRemoveExport(the_module, \"" << externalName << "\");\n";
956 }
957
958 auto* wasm = (Module*)module;
959 wasm->removeExport(externalName);
960}
961
962// Function table. One per module
963
964void BinaryenSetFunctionTable(BinaryenModuleRef module, BinaryenFunctionRef* funcs, BinaryenIndex numFuncs) {
965 if (tracing) {
966 std::cout << " {\n";
967 std::cout << " BinaryenFunctionRef funcs[] = { ";
968 for (BinaryenIndex i = 0; i < numFuncs; i++) {
969 if (i > 0) std::cout << ", ";
970 std::cout << "functions[" << functions[funcs[i]] << "]";
971 }
972 if (numFuncs == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
973 std::cout << " };\n";
974 std::cout << " BinaryenSetFunctionTable(the_module, funcs, " << numFuncs << ");\n";
975 std::cout << " }\n";
976 }
977
978 auto* wasm = (Module*)module;
979 wasm->table.exists = true;
980 Table::Segment segment(wasm->allocator.alloc<Const>()->set(Literal(int32_t(0))));
981 for (BinaryenIndex i = 0; i < numFuncs; i++) {
982 segment.data.push_back(((Function*)funcs[i])->name);
983 }
984 wasm->table.segments.push_back(segment);
985 wasm->table.initial = wasm->table.max = numFuncs;
986}
987
988// Memory. One per module
989
990void BinaryenSetMemory(BinaryenModuleRef module, BinaryenIndex initial, BinaryenIndex maximum, const char* exportName, const char **segments, BinaryenExpressionRef* segmentOffsets, BinaryenIndex* segmentSizes, BinaryenIndex numSegments) {
991 if (tracing) {
992 std::cout << " {\n";
993 for (BinaryenIndex i = 0; i < numSegments; i++) {
994 std::cout << " const char segment" << i << "[] = { ";
995 for (BinaryenIndex j = 0; j < segmentSizes[i]; j++) {
996 if (j > 0) std::cout << ", ";
997 std::cout << int(segments[i][j]);
998 }
999 std::cout << " };\n";
1000 }
1001 std::cout << " const char* segments[] = { ";
1002 for (BinaryenIndex i = 0; i < numSegments; i++) {
1003 if (i > 0) std::cout << ", ";
1004 std::cout << "segment" << i;
1005 }
1006 if (numSegments == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
1007 std::cout << " };\n";
1008 std::cout << " BinaryenExpressionRef segmentOffsets[] = { ";
1009 for (BinaryenIndex i = 0; i < numSegments; i++) {
1010 if (i > 0) std::cout << ", ";
1011 std::cout << "expressions[" << expressions[segmentOffsets[i]] << "]";
1012 }
1013 if (numSegments == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
1014 std::cout << " };\n";
1015 std::cout << " BinaryenIndex segmentSizes[] = { ";
1016 for (BinaryenIndex i = 0; i < numSegments; i++) {
1017 if (i > 0) std::cout << ", ";
1018 std::cout << segmentSizes[i];
1019 }
1020 if (numSegments == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
1021 std::cout << " };\n";
1022 std::cout << " BinaryenSetMemory(the_module, " << initial << ", " << maximum << ", ";
1023 traceNameOrNULL(exportName);
1024 std::cout << ", segments, segmentOffsets, segmentSizes, " << numSegments << ");\n";
1025 std::cout << " }\n";
1026 }
1027
1028 auto* wasm = (Module*)module;
1029 wasm->memory.initial = initial;
1030 wasm->memory.max = maximum;
1031 wasm->memory.exists = true;
1032 if (exportName) {
1033 auto memoryExport = make_unique<Export>();
1034 memoryExport->name = exportName;
1035 memoryExport->value = Name::fromInt(0);
1036 memoryExport->kind = ExternalKind::Memory;
1037 wasm->addExport(memoryExport.release());
1038 }
1039 for (BinaryenIndex i = 0; i < numSegments; i++) {
1040 wasm->memory.segments.emplace_back((Expression*)segmentOffsets[i], segments[i], segmentSizes[i]);
1041 }
1042}
1043
1044// Start function. One per module
1045
1046void BinaryenSetStart(BinaryenModuleRef module, BinaryenFunctionRef start) {
1047 if (tracing) {
1048 std::cout << " BinaryenSetStart(the_module, functions[" << functions[start] << "]);\n";
1049 }
1050
1051 auto* wasm = (Module*)module;
1052 wasm->addStart(((Function*)start)->name);
1053}
1054
1055//
1056// ========== Module Operations ==========
1057//
1058
1059BinaryenModuleRef BinaryenModuleParse(const char* text) {
1060 if (tracing) {
1061 std::cout << " // BinaryenModuleRead\n";
1062 }
1063
1064 auto* wasm = new Module;
1065 try {
1066 SExpressionParser parser(const_cast<char*>(text));
1067 Element& root = *parser.root;
1068 SExpressionWasmBuilder builder(*wasm, *root[0]);
1069 } catch (ParseException& p) {
1070 p.dump(std::cerr);
1071 Fatal() << "error in parsing wasm text";
1072 }
1073 return wasm;
1074}
1075
1076void BinaryenModulePrint(BinaryenModuleRef module) {
1077 if (tracing) {
1078 std::cout << " BinaryenModulePrint(the_module);\n";
1079 }
1080
1081 WasmPrinter::printModule((Module*)module);
1082}
1083
1084void BinaryenModulePrintAsmjs(BinaryenModuleRef module) {
1085 if (tracing) {
1086 std::cout << " BinaryenModulePrintAsmjs(the_module);\n";
1087 }
1088
1089 Module* wasm = (Module*)module;
1090 Wasm2AsmBuilder::Flags builderFlags;
1091 Wasm2AsmBuilder wasm2asm(builderFlags);
1092 Ref asmjs = wasm2asm.processWasm(wasm);
1093 JSPrinter jser(true, true, asmjs);
1094 jser.printAst();
1095
1096 std::cout << jser.buffer;
1097}
1098
1099int BinaryenModuleValidate(BinaryenModuleRef module) {
1100 if (tracing) {
1101 std::cout << " BinaryenModuleValidate(the_module);\n";
1102 }
1103
1104 Module* wasm = (Module*)module;
1105 return WasmValidator().validate(*wasm) ? 1 : 0;
1106}
1107
1108void BinaryenModuleOptimize(BinaryenModuleRef module) {
1109 if (tracing) {
1110 std::cout << " BinaryenModuleOptimize(the_module);\n";
1111 }
1112
1113 Module* wasm = (Module*)module;
1114 PassRunner passRunner(wasm);
1115 passRunner.addDefaultOptimizationPasses();
1116 passRunner.run();
1117}
1118
1119void BinaryenModuleRunPasses(BinaryenModuleRef module, const char **passes, BinaryenIndex numPasses) {
1120 if (tracing) {
1121 std::cout << " {\n";
1122 std::cout << " const char* passes[] = { ";
1123 for (BinaryenIndex i = 0; i < numPasses; i++) {
1124 if (i > 0) std::cout << ", ";
1125 std::cout << "\"" << passes[i] << "\"";
1126 }
1127 std::cout << " };\n";
1128 std::cout << " BinaryenModuleRunPasses(the_module, passes, " << numPasses << ");\n";
1129 std::cout << " }\n";
1130 }
1131
1132 Module* wasm = (Module*)module;
1133 PassRunner passRunner(wasm);
1134 for (BinaryenIndex i = 0; i < numPasses; i++) {
1135 passRunner.add(passes[i]);
1136 }
1137 passRunner.run();
1138}
1139
1140void BinaryenModuleAutoDrop(BinaryenModuleRef module) {
1141 if (tracing) {
1142 std::cout << " BinaryenModuleAutoDrop(the_module);\n";
1143 }
1144
1145 Module* wasm = (Module*)module;
1146 PassRunner passRunner(wasm);
1147 passRunner.add<AutoDrop>();
1148 passRunner.run();
1149}
1150
1151size_t BinaryenModuleWrite(BinaryenModuleRef module, char* output, size_t outputSize) {
1152 if (tracing) {
1153 std::cout << " // BinaryenModuleWrite\n";
1154 }
1155
1156 Module* wasm = (Module*)module;
1157 BufferWithRandomAccess buffer(false);
1158 WasmBinaryWriter writer(wasm, buffer, false);
1159 writer.write();
1160 size_t bytes = std::min(buffer.size(), outputSize);
1161 std::copy_n(buffer.begin(), bytes, output);
1162 return bytes;
1163}
1164
1165BinaryenModuleRef BinaryenModuleRead(char* input, size_t inputSize) {
1166 if (tracing) {
1167 std::cout << " // BinaryenModuleRead\n";
1168 }
1169
1170 auto* wasm = new Module;
1171 std::vector<char> buffer(false);
1172 buffer.resize(inputSize);
1173 std::copy_n(input, inputSize, buffer.begin());
1174 try {
1175 WasmBinaryBuilder parser(*wasm, buffer, false);
1176 parser.read();
1177 } catch (ParseException& p) {
1178 p.dump(std::cerr);
1179 Fatal() << "error in parsing wasm binary";
1180 }
1181 return wasm;
1182}
1183
1184void BinaryenModuleInterpret(BinaryenModuleRef module) {
1185 if (tracing) {
1186 std::cout << " BinaryenModuleInterpret(the_module);\n";
1187 }
1188
1189 Module* wasm = (Module*)module;
1190 ShellExternalInterface interface;
1191 ModuleInstance instance(*wasm, &interface);
1192}
1193
1194//
1195// ========== CFG / Relooper ==========
1196//
1197
1198RelooperRef RelooperCreate(void) {
1199 if (tracing) {
1200 std::cout << " the_relooper = RelooperCreate();\n";
1201 }
1202
1203 return RelooperRef(new CFG::Relooper());
1204}
1205
1206RelooperBlockRef RelooperAddBlock(RelooperRef relooper, BinaryenExpressionRef code) {
1207 auto* R = (CFG::Relooper*)relooper;
1208 auto* ret = new CFG::Block((Expression*)code);
1209
1210 if (tracing) {
1211 auto id = relooperBlocks.size();
1212 relooperBlocks[ret] = id;
1213 std::cout << " relooperBlocks[" << id << "] = RelooperAddBlock(the_relooper, expressions[" << expressions[code] << "]);\n";
1214 }
1215
1216 R->AddBlock(ret);
1217 return RelooperRef(ret);
1218}
1219
1220void RelooperAddBranch(RelooperBlockRef from, RelooperBlockRef to, BinaryenExpressionRef condition, BinaryenExpressionRef code) {
1221 if (tracing) {
1222 std::cout << " RelooperAddBranch(relooperBlocks[" << relooperBlocks[from] << "], relooperBlocks[" << relooperBlocks[to] << "], expressions[" << expressions[condition] << "], expressions[" << expressions[code] << "]);\n";
1223 }
1224
1225 auto* fromBlock = (CFG::Block*)from;
1226 auto* toBlock = (CFG::Block*)to;
1227 fromBlock->AddBranchTo(toBlock, (Expression*)condition, (Expression*)code);
1228}
1229
1230RelooperBlockRef RelooperAddBlockWithSwitch(RelooperRef relooper, BinaryenExpressionRef code, BinaryenExpressionRef condition) {
1231 auto* R = (CFG::Relooper*)relooper;
1232 auto* ret = new CFG::Block((Expression*)code, (Expression*)condition);
1233
1234 if (tracing) {
1235 std::cout << " relooperBlocks[" << relooperBlocks[ret] << "] = RelooperAddBlockWithSwitch(the_relooper, expressions[" << expressions[code] << "], expressions[" << expressions[condition] << "]);\n";
1236 }
1237
1238 R->AddBlock(ret);
1239 return RelooperRef(ret);
1240}
1241
1242void RelooperAddBranchForSwitch(RelooperBlockRef from, RelooperBlockRef to, BinaryenIndex* indexes, BinaryenIndex numIndexes, BinaryenExpressionRef code) {
1243 if (tracing) {
1244 std::cout << " {\n";
1245 std::cout << " BinaryenIndex indexes[] = { ";
1246 for (BinaryenIndex i = 0; i < numIndexes; i++) {
1247 if (i > 0) std::cout << ", ";
1248 std::cout << indexes[i];
1249 }
1250 if (numIndexes == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS
1251 std::cout << " };\n";
1252 std::cout << " RelooperAddBranchForSwitch(relooperBlocks[" << relooperBlocks[from] << "], relooperBlocks[" << relooperBlocks[to] << "], indexes, " << numIndexes << ", expressions[" << expressions[code] << "]);\n";
1253 std::cout << " }\n";
1254 }
1255
1256 auto* fromBlock = (CFG::Block*)from;
1257 auto* toBlock = (CFG::Block*)to;
1258 std::vector<Index> values;
1259 for (Index i = 0; i < numIndexes; i++) {
1260 values.push_back(indexes[i]);
1261 }
1262 fromBlock->AddSwitchBranchTo(toBlock, std::move(values), (Expression*)code);
1263}
1264
1265BinaryenExpressionRef RelooperRenderAndDispose(RelooperRef relooper, RelooperBlockRef entry, BinaryenIndex labelHelper, BinaryenModuleRef module) {
1266 auto* R = (CFG::Relooper*)relooper;
1267 R->Calculate((CFG::Block*)entry);
1268 CFG::RelooperBuilder builder(*(Module*)module, labelHelper);
1269 auto* ret = R->Render(builder);
1270
1271 if (tracing) {
1272 auto id = noteExpression(ret);
1273 std::cout << " expressions[" << id << "] = RelooperRenderAndDispose(the_relooper, relooperBlocks[" << relooperBlocks[entry] << "], " << labelHelper << ", the_module);\n";
1274 relooperBlocks.clear();
1275 }
1276
1277 delete R;
1278 return BinaryenExpressionRef(ret);
1279}
1280
1281//
1282// ========= Other APIs =========
1283//
1284
1285void BinaryenSetAPITracing(int on) {
1286 tracing = on;
1287
1288 if (tracing) {
1289 std::cout << "// beginning a Binaryen API trace\n"
1290 "#include <math.h>\n"
1291 "#include <map>\n"
1292 "#include \"src/binaryen-c.h\"\n"
1293 "int main() {\n"
1294 " std::map<size_t, BinaryenFunctionTypeRef> functionTypes;\n"
1295 " std::map<size_t, BinaryenExpressionRef> expressions;\n"
1296 " std::map<size_t, BinaryenFunctionRef> functions;\n"
1297 " std::map<size_t, RelooperBlockRef> relooperBlocks;\n"
1298 " BinaryenModuleRef the_module = NULL;\n"
1299 " RelooperRef the_relooper = NULL;\n";
1300 } else {
1301 std::cout << " return 0;\n";
1302 std::cout << "}\n";
1303 }
1304}
1305
1306//
1307// ========= Utilities =========
1308//
1309
1310BinaryenFunctionTypeRef BinaryenGetFunctionTypeBySignature(BinaryenModuleRef module, BinaryenType result, BinaryenType* paramTypes, BinaryenIndex numParams) {
1311 if (tracing) {
1312 std::cout << " // BinaryenGetFunctionTypeBySignature\n";
1313 }
1314
1315 auto* wasm = (Module*)module;
1316 FunctionType test;
1317 test.result = WasmType(result);
1318 for (BinaryenIndex i = 0; i < numParams; i++) {
1319 test.params.push_back(WasmType(paramTypes[i]));
1320 }
1321
1322 // Lock. Guard against reading the list while types are being added.
1323 {
1324 std::lock_guard<std::mutex> lock(BinaryenFunctionTypeMutex);
1325 for (BinaryenIndex i = 0; i < wasm->functionTypes.size(); i++) {
1326 FunctionType* curr = wasm->functionTypes[i].get();
1327 if (curr->structuralComparison(test)) {
1328 return curr;
1329 }
1330 }
1331 }
1332
1333 return NULL;
1334}
1335
1336} // extern "C"