]>
Commit | Line | Data |
---|---|---|
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 | ||
37 | using namespace wasm; | |
38 | ||
39 | // Literal utilities | |
40 | ||
41 | static_assert(sizeof(BinaryenLiteral) == sizeof(Literal), "Binaryen C API literal must match wasm.h"); | |
42 | ||
43 | BinaryenLiteral 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 | ||
56 | Literal 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 | ||
70 | static std::mutex BinaryenFunctionMutex; | |
71 | static std::mutex BinaryenFunctionTypeMutex; | |
72 | ||
73 | // Tracing support | |
74 | ||
75 | static int tracing = 0; | |
76 | ||
77 | void traceNameOrNULL(const char *name) { | |
78 | if (name) std::cout << "\"" << name << "\""; | |
79 | else std::cout << "NULL"; | |
80 | } | |
81 | ||
82 | std::map<BinaryenFunctionTypeRef, size_t> functionTypes; | |
83 | std::map<BinaryenExpressionRef, size_t> expressions; | |
84 | std::map<BinaryenFunctionRef, size_t> functions; | |
85 | std::map<RelooperBlockRef, size_t> relooperBlocks; | |
86 | ||
87 | size_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 | ||
94 | extern "C" { | |
95 | ||
96 | // | |
97 | // ========== Module Creation ========== | |
98 | // | |
99 | ||
100 | // Core types | |
101 | ||
102 | BinaryenType BinaryenNone(void) { return none; } | |
103 | BinaryenType BinaryenInt32(void) { return i32; } | |
104 | BinaryenType BinaryenInt64(void) { return i64; } | |
105 | BinaryenType BinaryenFloat32(void) { return f32; } | |
106 | BinaryenType BinaryenFloat64(void) { return f64; } | |
107 | BinaryenType BinaryenUndefined(void) { return uint32_t(-1); } | |
108 | ||
109 | // Expression ids | |
110 | ||
111 | BinaryenExpressionId BinaryenInvalidId(void) { return Expression::Id::InvalidId; } | |
112 | BinaryenExpressionId BinaryenBlockId(void) { return Expression::Id::BlockId; } | |
113 | BinaryenExpressionId BinaryenIfId(void) { return Expression::Id::IfId; } | |
114 | BinaryenExpressionId BinaryenLoopId(void) { return Expression::Id::LoopId; } | |
115 | BinaryenExpressionId BinaryenBreakId(void) { return Expression::Id::BreakId; } | |
116 | BinaryenExpressionId BinaryenSwitchId(void) { return Expression::Id::SwitchId; } | |
117 | BinaryenExpressionId BinaryenCallId(void) { return Expression::Id::CallId; } | |
118 | BinaryenExpressionId BinaryenCallImportId(void) { return Expression::Id::CallImportId; } | |
119 | BinaryenExpressionId BinaryenCallIndirectId(void) { return Expression::Id::CallIndirectId; } | |
120 | BinaryenExpressionId BinaryenGetLocalId(void) { return Expression::Id::GetLocalId; } | |
121 | BinaryenExpressionId BinaryenSetLocalId(void) { return Expression::Id::SetLocalId; } | |
122 | BinaryenExpressionId BinaryenGetGlobalId(void) { return Expression::Id::GetGlobalId; } | |
123 | BinaryenExpressionId BinaryenSetGlobalId(void) { return Expression::Id::SetGlobalId; } | |
124 | BinaryenExpressionId BinaryenLoadId(void) { return Expression::Id::LoadId; } | |
125 | BinaryenExpressionId BinaryenStoreId(void) { return Expression::Id::StoreId; } | |
126 | BinaryenExpressionId BinaryenConstId(void) { return Expression::Id::ConstId; } | |
127 | BinaryenExpressionId BinaryenUnaryId(void) { return Expression::Id::UnaryId; } | |
128 | BinaryenExpressionId BinaryenBinaryId(void) { return Expression::Id::BinaryId; } | |
129 | BinaryenExpressionId BinaryenSelectId(void) { return Expression::Id::SelectId; } | |
130 | BinaryenExpressionId BinaryenDropId(void) { return Expression::Id::DropId; } | |
131 | BinaryenExpressionId BinaryenReturnId(void) { return Expression::Id::ReturnId; } | |
132 | BinaryenExpressionId BinaryenHostId(void) { return Expression::Id::HostId; } | |
133 | BinaryenExpressionId BinaryenNopId(void) { return Expression::Id::NopId; } | |
134 | BinaryenExpressionId BinaryenUnreachableId(void) { return Expression::Id::UnreachableId; } | |
135 | BinaryenExpressionId BinaryenAtomicCmpxchgId(void) { return Expression::Id::AtomicCmpxchgId; } | |
136 | BinaryenExpressionId BinaryenAtomicRMWId(void) { return Expression::Id::AtomicRMWId; } | |
137 | BinaryenExpressionId BinaryenAtomicWaitId(void) { return Expression::Id::AtomicWaitId; } | |
138 | BinaryenExpressionId BinaryenAtomicWakeId(void) { return Expression::Id::AtomicWakeId; } | |
139 | ||
140 | // Modules | |
141 | ||
142 | BinaryenModuleRef 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 | } | |
151 | void 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 | ||
169 | BinaryenFunctionTypeRef 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 | ||
206 | BinaryenLiteral BinaryenLiteralInt32(int32_t x) { return toBinaryenLiteral(Literal(x)); } | |
207 | BinaryenLiteral BinaryenLiteralInt64(int64_t x) { return toBinaryenLiteral(Literal(x)); } | |
208 | BinaryenLiteral BinaryenLiteralFloat32(float x) { return toBinaryenLiteral(Literal(x)); } | |
209 | BinaryenLiteral BinaryenLiteralFloat64(double x) { return toBinaryenLiteral(Literal(x)); } | |
210 | BinaryenLiteral BinaryenLiteralFloat32Bits(int32_t x) { return toBinaryenLiteral(Literal(x).castToF32()); } | |
211 | BinaryenLiteral BinaryenLiteralFloat64Bits(int64_t x) { return toBinaryenLiteral(Literal(x).castToF64()); } | |
212 | ||
213 | // Expressions | |
214 | ||
215 | BinaryenOp BinaryenClzInt32(void) { return ClzInt32; } | |
216 | BinaryenOp BinaryenCtzInt32(void) { return CtzInt32; } | |
217 | BinaryenOp BinaryenPopcntInt32(void) { return PopcntInt32; } | |
218 | BinaryenOp BinaryenNegFloat32(void) { return NegFloat32; } | |
219 | BinaryenOp BinaryenAbsFloat32(void) { return AbsFloat32; } | |
220 | BinaryenOp BinaryenCeilFloat32(void) { return CeilFloat32; } | |
221 | BinaryenOp BinaryenFloorFloat32(void) { return FloorFloat32; } | |
222 | BinaryenOp BinaryenTruncFloat32(void) { return TruncFloat32; } | |
223 | BinaryenOp BinaryenNearestFloat32(void) { return NearestFloat32; } | |
224 | BinaryenOp BinaryenSqrtFloat32(void) { return SqrtFloat32; } | |
225 | BinaryenOp BinaryenEqZInt32(void) { return EqZInt32; } | |
226 | BinaryenOp BinaryenClzInt64(void) { return ClzInt64; } | |
227 | BinaryenOp BinaryenCtzInt64(void) { return CtzInt64; } | |
228 | BinaryenOp BinaryenPopcntInt64(void) { return PopcntInt64; } | |
229 | BinaryenOp BinaryenNegFloat64(void) { return NegFloat64; } | |
230 | BinaryenOp BinaryenAbsFloat64(void) { return AbsFloat64; } | |
231 | BinaryenOp BinaryenCeilFloat64(void) { return CeilFloat64; } | |
232 | BinaryenOp BinaryenFloorFloat64(void) { return FloorFloat64; } | |
233 | BinaryenOp BinaryenTruncFloat64(void) { return TruncFloat64; } | |
234 | BinaryenOp BinaryenNearestFloat64(void) { return NearestFloat64; } | |
235 | BinaryenOp BinaryenSqrtFloat64(void) { return SqrtFloat64; } | |
236 | BinaryenOp BinaryenEqZInt64(void) { return EqZInt64; } | |
237 | BinaryenOp BinaryenExtendSInt32(void) { return ExtendSInt32; } | |
238 | BinaryenOp BinaryenExtendUInt32(void) { return ExtendUInt32; } | |
239 | BinaryenOp BinaryenWrapInt64(void) { return WrapInt64; } | |
240 | BinaryenOp BinaryenTruncSFloat32ToInt32(void) { return TruncSFloat32ToInt32; } | |
241 | BinaryenOp BinaryenTruncSFloat32ToInt64(void) { return TruncSFloat32ToInt64; } | |
242 | BinaryenOp BinaryenTruncUFloat32ToInt32(void) { return TruncUFloat32ToInt32; } | |
243 | BinaryenOp BinaryenTruncUFloat32ToInt64(void) { return TruncUFloat32ToInt64; } | |
244 | BinaryenOp BinaryenTruncSFloat64ToInt32(void) { return TruncSFloat64ToInt32; } | |
245 | BinaryenOp BinaryenTruncSFloat64ToInt64(void) { return TruncSFloat64ToInt64; } | |
246 | BinaryenOp BinaryenTruncUFloat64ToInt32(void) { return TruncUFloat64ToInt32; } | |
247 | BinaryenOp BinaryenTruncUFloat64ToInt64(void) { return TruncUFloat64ToInt64; } | |
248 | BinaryenOp BinaryenReinterpretFloat32(void) { return ReinterpretFloat32; } | |
249 | BinaryenOp BinaryenReinterpretFloat64(void) { return ReinterpretFloat64; } | |
250 | BinaryenOp BinaryenConvertSInt32ToFloat32(void) { return ConvertSInt32ToFloat32; } | |
251 | BinaryenOp BinaryenConvertSInt32ToFloat64(void) { return ConvertSInt32ToFloat64; } | |
252 | BinaryenOp BinaryenConvertUInt32ToFloat32(void) { return ConvertUInt32ToFloat32; } | |
253 | BinaryenOp BinaryenConvertUInt32ToFloat64(void) { return ConvertUInt32ToFloat64; } | |
254 | BinaryenOp BinaryenConvertSInt64ToFloat32(void) { return ConvertSInt64ToFloat32; } | |
255 | BinaryenOp BinaryenConvertSInt64ToFloat64(void) { return ConvertSInt64ToFloat64; } | |
256 | BinaryenOp BinaryenConvertUInt64ToFloat32(void) { return ConvertUInt64ToFloat32; } | |
257 | BinaryenOp BinaryenConvertUInt64ToFloat64(void) { return ConvertUInt64ToFloat64; } | |
258 | BinaryenOp BinaryenPromoteFloat32(void) { return PromoteFloat32; } | |
259 | BinaryenOp BinaryenDemoteFloat64(void) { return DemoteFloat64; } | |
260 | BinaryenOp BinaryenReinterpretInt32(void) { return ReinterpretInt32; } | |
261 | BinaryenOp BinaryenReinterpretInt64(void) { return ReinterpretInt64; } | |
262 | BinaryenOp BinaryenAddInt32(void) { return AddInt32; } | |
263 | BinaryenOp BinaryenSubInt32(void) { return SubInt32; } | |
264 | BinaryenOp BinaryenMulInt32(void) { return MulInt32; } | |
265 | BinaryenOp BinaryenDivSInt32(void) { return DivSInt32; } | |
266 | BinaryenOp BinaryenDivUInt32(void) { return DivUInt32; } | |
267 | BinaryenOp BinaryenRemSInt32(void) { return RemSInt32; } | |
268 | BinaryenOp BinaryenRemUInt32(void) { return RemUInt32; } | |
269 | BinaryenOp BinaryenAndInt32(void) { return AndInt32; } | |
270 | BinaryenOp BinaryenOrInt32(void) { return OrInt32; } | |
271 | BinaryenOp BinaryenXorInt32(void) { return XorInt32; } | |
272 | BinaryenOp BinaryenShlInt32(void) { return ShlInt32; } | |
273 | BinaryenOp BinaryenShrUInt32(void) { return ShrUInt32; } | |
274 | BinaryenOp BinaryenShrSInt32(void) { return ShrSInt32; } | |
275 | BinaryenOp BinaryenRotLInt32(void) { return RotLInt32; } | |
276 | BinaryenOp BinaryenRotRInt32(void) { return RotRInt32; } | |
277 | BinaryenOp BinaryenEqInt32(void) { return EqInt32; } | |
278 | BinaryenOp BinaryenNeInt32(void) { return NeInt32; } | |
279 | BinaryenOp BinaryenLtSInt32(void) { return LtSInt32; } | |
280 | BinaryenOp BinaryenLtUInt32(void) { return LtUInt32; } | |
281 | BinaryenOp BinaryenLeSInt32(void) { return LeSInt32; } | |
282 | BinaryenOp BinaryenLeUInt32(void) { return LeUInt32; } | |
283 | BinaryenOp BinaryenGtSInt32(void) { return GtSInt32; } | |
284 | BinaryenOp BinaryenGtUInt32(void) { return GtUInt32; } | |
285 | BinaryenOp BinaryenGeSInt32(void) { return GeSInt32; } | |
286 | BinaryenOp BinaryenGeUInt32(void) { return GeUInt32; } | |
287 | BinaryenOp BinaryenAddInt64(void) { return AddInt64; } | |
288 | BinaryenOp BinaryenSubInt64(void) { return SubInt64; } | |
289 | BinaryenOp BinaryenMulInt64(void) { return MulInt64; } | |
290 | BinaryenOp BinaryenDivSInt64(void) { return DivSInt64; } | |
291 | BinaryenOp BinaryenDivUInt64(void) { return DivUInt64; } | |
292 | BinaryenOp BinaryenRemSInt64(void) { return RemSInt64; } | |
293 | BinaryenOp BinaryenRemUInt64(void) { return RemUInt64; } | |
294 | BinaryenOp BinaryenAndInt64(void) { return AndInt64; } | |
295 | BinaryenOp BinaryenOrInt64(void) { return OrInt64; } | |
296 | BinaryenOp BinaryenXorInt64(void) { return XorInt64; } | |
297 | BinaryenOp BinaryenShlInt64(void) { return ShlInt64; } | |
298 | BinaryenOp BinaryenShrUInt64(void) { return ShrUInt64; } | |
299 | BinaryenOp BinaryenShrSInt64(void) { return ShrSInt64; } | |
300 | BinaryenOp BinaryenRotLInt64(void) { return RotLInt64; } | |
301 | BinaryenOp BinaryenRotRInt64(void) { return RotRInt64; } | |
302 | BinaryenOp BinaryenEqInt64(void) { return EqInt64; } | |
303 | BinaryenOp BinaryenNeInt64(void) { return NeInt64; } | |
304 | BinaryenOp BinaryenLtSInt64(void) { return LtSInt64; } | |
305 | BinaryenOp BinaryenLtUInt64(void) { return LtUInt64; } | |
306 | BinaryenOp BinaryenLeSInt64(void) { return LeSInt64; } | |
307 | BinaryenOp BinaryenLeUInt64(void) { return LeUInt64; } | |
308 | BinaryenOp BinaryenGtSInt64(void) { return GtSInt64; } | |
309 | BinaryenOp BinaryenGtUInt64(void) { return GtUInt64; } | |
310 | BinaryenOp BinaryenGeSInt64(void) { return GeSInt64; } | |
311 | BinaryenOp BinaryenGeUInt64(void) { return GeUInt64; } | |
312 | BinaryenOp BinaryenAddFloat32(void) { return AddFloat32; } | |
313 | BinaryenOp BinaryenSubFloat32(void) { return SubFloat32; } | |
314 | BinaryenOp BinaryenMulFloat32(void) { return MulFloat32; } | |
315 | BinaryenOp BinaryenDivFloat32(void) { return DivFloat32; } | |
316 | BinaryenOp BinaryenCopySignFloat32(void) { return CopySignFloat32; } | |
317 | BinaryenOp BinaryenMinFloat32(void) { return MinFloat32; } | |
318 | BinaryenOp BinaryenMaxFloat32(void) { return MaxFloat32; } | |
319 | BinaryenOp BinaryenEqFloat32(void) { return EqFloat32; } | |
320 | BinaryenOp BinaryenNeFloat32(void) { return NeFloat32; } | |
321 | BinaryenOp BinaryenLtFloat32(void) { return LtFloat32; } | |
322 | BinaryenOp BinaryenLeFloat32(void) { return LeFloat32; } | |
323 | BinaryenOp BinaryenGtFloat32(void) { return GtFloat32; } | |
324 | BinaryenOp BinaryenGeFloat32(void) { return GeFloat32; } | |
325 | BinaryenOp BinaryenAddFloat64(void) { return AddFloat64; } | |
326 | BinaryenOp BinaryenSubFloat64(void) { return SubFloat64; } | |
327 | BinaryenOp BinaryenMulFloat64(void) { return MulFloat64; } | |
328 | BinaryenOp BinaryenDivFloat64(void) { return DivFloat64; } | |
329 | BinaryenOp BinaryenCopySignFloat64(void) { return CopySignFloat64; } | |
330 | BinaryenOp BinaryenMinFloat64(void) { return MinFloat64; } | |
331 | BinaryenOp BinaryenMaxFloat64(void) { return MaxFloat64; } | |
332 | BinaryenOp BinaryenEqFloat64(void) { return EqFloat64; } | |
333 | BinaryenOp BinaryenNeFloat64(void) { return NeFloat64; } | |
334 | BinaryenOp BinaryenLtFloat64(void) { return LtFloat64; } | |
335 | BinaryenOp BinaryenLeFloat64(void) { return LeFloat64; } | |
336 | BinaryenOp BinaryenGtFloat64(void) { return GtFloat64; } | |
337 | BinaryenOp BinaryenGeFloat64(void) { return GeFloat64; } | |
338 | BinaryenOp BinaryenPageSize(void) { return PageSize; } | |
339 | BinaryenOp BinaryenCurrentMemory(void) { return CurrentMemory; } | |
340 | BinaryenOp BinaryenGrowMemory(void) { return GrowMemory; } | |
341 | BinaryenOp BinaryenHasFeature(void) { return HasFeature; } | |
342 | BinaryenOp BinaryenAtomicRMWAdd(void) { return AtomicRMWOp::Add; } | |
343 | BinaryenOp BinaryenAtomicRMWSub(void) { return AtomicRMWOp::Sub; } | |
344 | BinaryenOp BinaryenAtomicRMWAnd(void) { return AtomicRMWOp::And; } | |
345 | BinaryenOp BinaryenAtomicRMWOr(void) { return AtomicRMWOp::Or; } | |
346 | BinaryenOp BinaryenAtomicRMWXor(void) { return AtomicRMWOp::Xor; } | |
347 | BinaryenOp BinaryenAtomicRMWXchg(void) { return AtomicRMWOp::Xchg; } | |
348 | ||
349 | BinaryenExpressionRef 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 | } | |
379 | BinaryenExpressionRef 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 | } | |
393 | BinaryenExpressionRef 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 | } | |
405 | BinaryenExpressionRef 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 | } | |
415 | BinaryenExpressionRef 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 | } | |
441 | BinaryenExpressionRef 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 | } | |
466 | BinaryenExpressionRef 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 | } | |
491 | BinaryenExpressionRef 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 | } | |
518 | BinaryenExpressionRef 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 | } | |
531 | BinaryenExpressionRef 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 | } | |
545 | BinaryenExpressionRef 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 | } | |
559 | BinaryenExpressionRef 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 | } | |
572 | BinaryenExpressionRef 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 | } | |
585 | BinaryenExpressionRef 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 | } | |
602 | BinaryenExpressionRef 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 | } | |
619 | BinaryenExpressionRef 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 | } | |
645 | BinaryenExpressionRef 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 | } | |
655 | BinaryenExpressionRef 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 | } | |
665 | BinaryenExpressionRef 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 | } | |
679 | BinaryenExpressionRef 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 | } | |
691 | BinaryenExpressionRef 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 | } | |
701 | BinaryenExpressionRef 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 | } | |
715 | BinaryenExpressionRef 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 | } | |
725 | BinaryenExpressionRef 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 | } | |
735 | BinaryenExpressionRef 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 | } | |
745 | BinaryenExpressionRef 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 | } | |
755 | BinaryenExpressionRef 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 | } | |
765 | BinaryenExpressionRef 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 | ||
778 | BinaryenExpressionId BinaryenExpressionGetId(BinaryenExpressionRef expr) { | |
779 | if (tracing) { | |
780 | std::cout << " BinaryenExpressionGetId(expressions[" << expressions[expr] << "]);\n"; | |
781 | } | |
782 | ||
783 | return ((Expression*)expr)->_id; | |
784 | } | |
785 | BinaryenType BinaryenExpressionGetType(BinaryenExpressionRef expr) { | |
786 | if (tracing) { | |
787 | std::cout << " BinaryenExpressionGetType(expressions[" << expressions[expr] << "]);\n"; | |
788 | } | |
789 | ||
790 | return ((Expression*)expr)->type; | |
791 | } | |
792 | void 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 | } | |
800 | int32_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 | } | |
809 | int64_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 | } | |
818 | int32_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 | } | |
827 | int32_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 | } | |
836 | float 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 | } | |
845 | double 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 | ||
857 | BinaryenFunctionRef 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 | ||
896 | BinaryenGlobalRef 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 | ||
913 | BinaryenImportRef 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 | ||
929 | void 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 | ||
940 | BinaryenExportRef 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 | ||
953 | void 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 | ||
964 | void 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 | ||
990 | void 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 | ||
1046 | void 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 | ||
1059 | BinaryenModuleRef 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 | ||
1076 | void BinaryenModulePrint(BinaryenModuleRef module) { | |
1077 | if (tracing) { | |
1078 | std::cout << " BinaryenModulePrint(the_module);\n"; | |
1079 | } | |
1080 | ||
1081 | WasmPrinter::printModule((Module*)module); | |
1082 | } | |
1083 | ||
1084 | void 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 | ||
1099 | int 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 | ||
1108 | void 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 | ||
1119 | void 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 | ||
1140 | void 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 | ||
1151 | size_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 | ||
1165 | BinaryenModuleRef 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 | ||
1184 | void 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 | ||
1198 | RelooperRef RelooperCreate(void) { | |
1199 | if (tracing) { | |
1200 | std::cout << " the_relooper = RelooperCreate();\n"; | |
1201 | } | |
1202 | ||
1203 | return RelooperRef(new CFG::Relooper()); | |
1204 | } | |
1205 | ||
1206 | RelooperBlockRef 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 | ||
1220 | void 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 | ||
1230 | RelooperBlockRef 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 | ||
1242 | void 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 | ||
1265 | BinaryenExpressionRef 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 | ||
1285 | void 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 | ||
1310 | BinaryenFunctionTypeRef 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" |