diff options
-rw-r--r-- | CMakeLists.txt | 8 | ||||
-rwxr-xr-x | check.py | 42 | ||||
-rw-r--r-- | src/binaryen-c.cpp | 376 | ||||
-rw-r--r-- | src/binaryen-c.h | 247 | ||||
-rw-r--r-- | src/wasm-builder.h | 14 | ||||
-rw-r--r-- | src/wasm.h | 10 | ||||
-rw-r--r-- | test/example/c-api-hello-world.c | 29 | ||||
-rw-r--r-- | test/example/c-api-hello-world.txt | 10 | ||||
-rw-r--r-- | test/example/c-api-kitchen-sink.c | 213 | ||||
-rw-r--r-- | test/example/c-api-kitchen-sink.txt | 318 |
10 files changed, 1249 insertions, 18 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index b948328f1..c952df396 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -90,6 +90,14 @@ SET(support_SOURCES ) ADD_LIBRARY(support STATIC ${support_SOURCES}) +SET(binaryen_c_SOURCES + src/binaryen-c.cpp + src/pass.cpp + src/passes/Print.cpp + src/wasm.cpp +) +ADD_LIBRARY(binaryen-c STATIC ${binaryen_c_SOURCES}) + SET(binaryen-shell_SOURCES src/binaryen-shell.cpp src/pass.cpp @@ -569,21 +569,33 @@ if has_vanilla_emcc and has_vanilla_llvm: print '\n[ checking example testcases... ]\n' -cmd = [os.environ.get('CXX') or 'g++', '-std=c++11', - os.path.join('test', 'example', 'find_div0s.cpp'), - os.path.join('src', 'pass.cpp'), - os.path.join('src', 'wasm.cpp'), - os.path.join('src', 'passes', 'Print.cpp'), - '-Isrc', '-g', '-lasmjs', '-lsupport', '-Llib/.', '-pthread'] -if os.environ.get('COMPILER_FLAGS'): - for f in os.environ.get('COMPILER_FLAGS').split(' '): - cmd.append(f) -print ' '.join(cmd) -subprocess.check_call(cmd) -actual = subprocess.Popen(['./a.out'], stdout=subprocess.PIPE).communicate()[0] -expected = open(os.path.join('test', 'example', 'find_div0s.txt')).read() -if actual != expected: - fail(actual, expected) +for t in sorted(os.listdir(os.path.join('test', 'example'))): + cmd = ['-Isrc', '-g', '-lasmjs', '-lsupport', '-Llib/.', '-pthread'] + if t.endswith('.cpp'): + cmd = [os.path.join('test', 'example', t), + os.path.join('src', 'pass.cpp'), + os.path.join('src', 'wasm.cpp'), + os.path.join('src', 'passes', 'Print.cpp')] + cmd + elif t.endswith('.c'): + # build the C file separately + extra = [os.environ.get('CC') or 'gcc', + os.path.join('test', 'example', t), '-c', '-o', 'example.o', + '-Isrc', '-g', '-lasmjs', '-lsupport', '-Llib/.', '-pthread'] + print ' '.join(extra) + subprocess.check_call(extra) + cmd = ['example.o', '-lbinaryen-c'] + cmd + else: + continue + if os.environ.get('COMPILER_FLAGS'): + for f in os.environ.get('COMPILER_FLAGS').split(' '): + cmd.append(f) + cmd = [os.environ.get('CXX') or 'g++', '-std=c++11'] + cmd + print ' '.join(cmd) + subprocess.check_call(cmd) + actual = subprocess.Popen(['./a.out'], stdout=subprocess.PIPE).communicate()[0] + expected = open(os.path.join('test', 'example', '.'.join(t.split('.')[:-1]) + '.txt')).read() + if actual != expected: + fail(actual, expected) if has_emcc: diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp new file mode 100644 index 000000000..f80c2be50 --- /dev/null +++ b/src/binaryen-c.cpp @@ -0,0 +1,376 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//=============================== +// Binaryen C API implementation +//=============================== + +#include "binaryen-c.h" +#include "wasm.h" +#include "wasm-builder.h" +#include "wasm-printing.h" + +using namespace wasm; + +// Literal utilities + +static_assert(sizeof(BinaryenLiteral) == sizeof(Literal), "Binaryen C API literal must match wasm.h"); + +BinaryenLiteral toBinaryenLiteral(Literal x) { + BinaryenLiteral ret; + ret.type = x.type; + switch (x.type) { + case WasmType::i32: ret.i32 = x.geti32(); break; + case WasmType::i64: ret.i64 = x.geti64(); break; + case WasmType::f32: ret.i32 = x.reinterpreti32(); break; + case WasmType::f64: ret.i64 = x.reinterpreti64(); break; + default: abort(); + } + return ret; +} + +Literal fromBinaryenLiteral(BinaryenLiteral x) { + switch (x.type) { + case WasmType::i32: return Literal(x.i32); + case WasmType::i64: return Literal(x.i64); + case WasmType::f32: return Literal(x.i32).castToF32(); + case WasmType::f64: return Literal(x.i64).castToF64(); + default: abort(); + } +} + +extern "C" { + +// +// ========== Module Creation ========== +// + +// Core types + +BinaryenType BinaryenNone(void) { return none; } +BinaryenType BinaryenInt32(void) { return i32; } +BinaryenType BinaryenInt64(void) { return i64; } +BinaryenType BinaryenFloat32(void) { return f32; } +BinaryenType BinaryenFloat64(void) { return f64; } + +// Modules + +BinaryenModuleRef BinaryenModuleCreate() { return new Module(); } +void BinaryenModuleDispose(BinaryenModuleRef module) { delete (Module*)module; } + +// Function types + +BinaryenFunctionTypeRef BinaryenAddFunctionType(BinaryenModuleRef module, const char* name, BinaryenType result, BinaryenType* paramTypes, BinaryenIndex numParams) { + auto* wasm = (Module*)module; + auto* ret = new FunctionType; + ret->name = name; + ret->result = WasmType(result); + for (BinaryenIndex i = 0; i < numParams; i++) { + ret->params.push_back(WasmType(paramTypes[i])); + } + wasm->addFunctionType(ret); + return ret; +} + +BinaryenLiteral BinaryenLiteralInt32(int32_t x) { return toBinaryenLiteral(Literal(x)); } +BinaryenLiteral BinaryenLiteralInt64(int64_t x) { return toBinaryenLiteral(Literal(x)); } +BinaryenLiteral BinaryenLiteralFloat32(float x) { return toBinaryenLiteral(Literal(x)); } +BinaryenLiteral BinaryenLiteralFloat64(double x) { return toBinaryenLiteral(Literal(x)); } +BinaryenLiteral BinaryenLiteralFloat32Bits(int32_t x) { return toBinaryenLiteral(Literal(x).castToF32()); } +BinaryenLiteral BinaryenLiteralFloat64Bits(int64_t x) { return toBinaryenLiteral(Literal(x).castToF64()); } + +// Expressions + +BinaryenOp BinaryenClz(void) { return Clz; } +BinaryenOp BinaryenCtz(void) { return Ctz; } +BinaryenOp BinaryenPopcnt(void) { return Popcnt; } +BinaryenOp BinaryenNeg(void) { return Neg; } +BinaryenOp BinaryenAbs(void) { return Abs; } +BinaryenOp BinaryenCeil(void) { return Ceil; } +BinaryenOp BinaryenFloor(void) { return Floor; } +BinaryenOp BinaryenTrunc(void) { return Trunc; } +BinaryenOp BinaryenNearest(void) { return Nearest; } +BinaryenOp BinaryenSqrt(void) { return Sqrt; } +BinaryenOp BinaryenEqZ(void) { return EqZ; } +BinaryenOp BinaryenExtendSInt32(void) { return ExtendSInt32; } +BinaryenOp BinaryenExtentUInt32(void) { return ExtendUInt32; } +BinaryenOp BinaryenWrapInt64(void) { return WrapInt64; } +BinaryenOp BinaryenTruncSFloat32(void) { return TruncSFloat32; } +BinaryenOp BinaryenTruncUFloat32(void) { return TruncUFloat32; } +BinaryenOp BinaryenTruncSFloat64(void) { return TruncSFloat64; } +BinaryenOp BinaryenTruncUFloat64(void) { return TruncUFloat64; } +BinaryenOp BinaryenReinterpretFloat(void) { return ReinterpretFloat; } +BinaryenOp BinaryenConvertSInt32(void) { return ConvertSInt32; } +BinaryenOp BinaryenConvertUInt32(void) { return ConvertUInt32; } +BinaryenOp BinaryenConvertSInt64(void) { return ConvertSInt64; } +BinaryenOp BinaryenConvertUInt64(void) { return ConvertUInt64; } +BinaryenOp BinaryenPromoteFloat32(void) { return PromoteFloat32; } +BinaryenOp BinaryenDemoteFloat64(void) { return DemoteFloat64; } +BinaryenOp BinaryenReinterpretInt(void) { return ReinterpretInt; } +BinaryenOp BinaryenAdd(void) { return Add; } +BinaryenOp BinaryenSub(void) { return Sub; } +BinaryenOp BinaryenMul(void) { return Mul; } +BinaryenOp BinaryenDivS(void) { return DivS; } +BinaryenOp BinaryenDivU(void) { return DivU; } +BinaryenOp BinaryenRemS(void) { return RemS; } +BinaryenOp BinaryenRemU(void) { return RemU; } +BinaryenOp BinaryenAnd(void) { return And; } +BinaryenOp BinaryenOr(void) { return Or; } +BinaryenOp BinaryenXor(void) { return Xor; } +BinaryenOp BinaryenShl(void) { return Shl; } +BinaryenOp BinaryenShrU(void) { return ShrU; } +BinaryenOp BinaryenShrS(void) { return ShrS; } +BinaryenOp BinaryenRotL(void) { return RotL; } +BinaryenOp BinaryenRotR(void) { return RotR; } +BinaryenOp BinaryenDiv(void) { return Div; } +BinaryenOp BinaryenCopySign(void) { return CopySign; } +BinaryenOp BinaryenMin(void) { return Min; } +BinaryenOp BinaryenMax(void) { return Max; } +BinaryenOp BinaryenEq(void) { return Eq; } +BinaryenOp BinaryenNe(void) { return Ne; } +BinaryenOp BinaryenLtS(void) { return LtS; } +BinaryenOp BinaryenLtU(void) { return LtU; } +BinaryenOp BinaryenLeS(void) { return LeS; } +BinaryenOp BinaryenLeU(void) { return LeU; } +BinaryenOp BinaryenGtS(void) { return GtS; } +BinaryenOp BinaryenGtU(void) { return GtU; } +BinaryenOp BinaryenGeS(void) { return GeS; } +BinaryenOp BinaryenGeU(void) { return GeU; } +BinaryenOp BinaryenLt(void) { return Lt; } +BinaryenOp BinaryenLe(void) { return Le; } +BinaryenOp BinaryenGt(void) { return Gt; } +BinaryenOp BinaryenGe(void) { return Ge; } +BinaryenOp BinaryenPageSize(void) { return PageSize; } +BinaryenOp BinaryenCurrentMemory(void) { return CurrentMemory; } +BinaryenOp BinaryenGrowMemory(void) { return GrowMemory; } +BinaryenOp BinaryenHasFeature(void) { return HasFeature; } + +BinaryenExpressionRef BinaryenBlock(BinaryenModuleRef module, const char* name, BinaryenExpressionRef* children, BinaryenIndex numChildren) { + auto* ret = ((Module*)module)->allocator.alloc<Block>(); + if (name) { + ret->name = name; + } + for (BinaryenIndex i = 0; i < numChildren; i++) { + ret->list.push_back((Expression*)children[i]); + } + ret->finalize(); + return ret; +} +BinaryenExpressionRef BinaryenIf(BinaryenModuleRef module, BinaryenExpressionRef condition, BinaryenExpressionRef ifTrue, BinaryenExpressionRef ifFalse) { + auto* ret = ((Module*)module)->allocator.alloc<If>(); + ret->condition = (Expression*)condition; + ret->ifTrue = (Expression*)ifTrue; + ret->ifFalse = (Expression*)ifFalse; + ret->finalize(); + return ret; +} +BinaryenExpressionRef BinaryenLoop(BinaryenModuleRef module, const char* out, const char* in, BinaryenExpressionRef body) { + if (out && !in) abort(); + return Builder(*((Module*)module)).makeLoop(out ? Name(out) : Name(), in ? Name(in) : Name(), (Expression*)body); +} +BinaryenExpressionRef BinaryenBreak(BinaryenModuleRef module, const char* name, BinaryenExpressionRef value, BinaryenExpressionRef condition) { + return Builder(*((Module*)module)).makeBreak(name, (Expression*)value, (Expression*)condition); +} +BinaryenExpressionRef BinaryenSwitch(BinaryenModuleRef module, const char **names, BinaryenIndex numNames, const char* defaultName, BinaryenExpressionRef condition, BinaryenExpressionRef value) { + auto* ret = ((Module*)module)->allocator.alloc<Switch>(); + for (BinaryenIndex i = 0; i < numNames; i++) { + ret->targets.push_back(names[i]); + } + ret->default_ = defaultName; + ret->condition = (Expression*)condition; + ret->value = (Expression*)value; + ret->finalize(); + return ret; +} +BinaryenExpressionRef BinaryenCall(BinaryenModuleRef module, const char *target, BinaryenExpressionRef* operands, BinaryenIndex numOperands) { + auto* ret = ((Module*)module)->allocator.alloc<Call>(); + ret->target = target; + for (BinaryenIndex i = 0; i < numOperands; i++) { + ret->operands.push_back((Expression*)operands[i]); + } + ret->finalize(); + return ret; +} +BinaryenExpressionRef BinaryenCallImport(BinaryenModuleRef module, const char *target, BinaryenExpressionRef* operands, BinaryenIndex numOperands) { + auto* ret = ((Module*)module)->allocator.alloc<CallImport>(); + ret->target = target; + for (BinaryenIndex i = 0; i < numOperands; i++) { + ret->operands.push_back((Expression*)operands[i]); + } + ret->finalize(); + return ret; +} +BinaryenExpressionRef BinaryenCallIndirect(BinaryenModuleRef module, BinaryenExpressionRef target, BinaryenExpressionRef* operands, BinaryenIndex numOperands, BinaryenFunctionTypeRef type) { + auto* ret = ((Module*)module)->allocator.alloc<CallIndirect>(); + ret->target = (Expression*)target; + for (BinaryenIndex i = 0; i < numOperands; i++) { + ret->operands.push_back((Expression*)operands[i]); + } + ret->fullType = (FunctionType*)type; + ret->finalize(); + return ret; +} +BinaryenExpressionRef BinaryenGetLocal(BinaryenModuleRef module, BinaryenIndex index, BinaryenType type) { + auto* ret = ((Module*)module)->allocator.alloc<GetLocal>(); + ret->index = index; + ret->type = WasmType(type); + ret->finalize(); + return ret; +} +BinaryenExpressionRef BinaryenSetLocal(BinaryenModuleRef module, BinaryenIndex index, BinaryenExpressionRef value) { + auto* ret = ((Module*)module)->allocator.alloc<SetLocal>(); + ret->index = index; + ret->value = (Expression*)value; + ret->finalize(); + return ret; +} +BinaryenExpressionRef BinaryenLoad(BinaryenModuleRef module, uint32_t bytes, int8_t signed_, uint32_t offset, uint32_t align, BinaryenType type, BinaryenExpressionRef ptr) { + auto* ret = ((Module*)module)->allocator.alloc<Load>(); + ret->bytes = bytes; + ret->signed_ = signed_; + ret->offset = offset; + ret->align = align ? align : bytes; + ret->type = WasmType(type); + ret->ptr = (Expression*)ptr; + ret->finalize(); + return ret; +} +BinaryenExpressionRef BinaryenStore(BinaryenModuleRef module, uint32_t bytes, uint32_t offset, uint32_t align, BinaryenExpressionRef ptr, BinaryenExpressionRef value) { + auto* ret = ((Module*)module)->allocator.alloc<Store>(); + ret->bytes = bytes; + ret->offset = offset; + ret->align = align ? align : bytes; + ret->ptr = (Expression*)ptr; + ret->value = (Expression*)value; + ret->finalize(); + return ret; +} +BinaryenExpressionRef BinaryenConst(BinaryenModuleRef module, BinaryenLiteral value) { + return Builder(*((Module*)module)).makeConst(fromBinaryenLiteral(value)); +} +BinaryenExpressionRef BinaryenUnary(BinaryenModuleRef module, BinaryenOp op, BinaryenExpressionRef value, BinaryenType type) { + return Builder(*((Module*)module)).makeUnary(UnaryOp(op), (Expression*)value, WasmType(type)); +} +BinaryenExpressionRef BinaryenBinary(BinaryenModuleRef module, BinaryenOp op, BinaryenExpressionRef left, BinaryenExpressionRef right) { + return Builder(*((Module*)module)).makeBinary(BinaryOp(op), (Expression*)left, (Expression*)right); +} +BinaryenExpressionRef BinaryenSelect(BinaryenModuleRef module, BinaryenExpressionRef condition, BinaryenExpressionRef ifTrue, BinaryenExpressionRef ifFalse) { + auto* ret = ((Module*)module)->allocator.alloc<Select>(); + ret->condition = (Expression*)condition; + ret->ifTrue = (Expression*)ifTrue; + ret->ifFalse = (Expression*)ifFalse; + ret->finalize(); + return ret; +} +BinaryenExpressionRef BinaryenReturn(BinaryenModuleRef module, BinaryenExpressionRef value) { + return Builder(*((Module*)module)).makeReturn((Expression*)value); +} +BinaryenExpressionRef BinaryenHost(BinaryenModuleRef module, BinaryenOp op, const char* name, BinaryenExpressionRef* operands, BinaryenIndex numOperands) { + auto* ret = ((Module*)module)->allocator.alloc<Host>(); + ret->op = HostOp(op); + if (name) ret->nameOperand = name; + for (BinaryenIndex i = 0; i < numOperands; i++) { + ret->operands.push_back((Expression*)operands[i]); + } + ret->finalize(); + return ret; +} +BinaryenExpressionRef BinaryenNop(BinaryenModuleRef module) { + return ((Module*)module)->allocator.alloc<Nop>(); +} +BinaryenExpressionRef BinaryenUnreachable(BinaryenModuleRef module) { + return ((Module*)module)->allocator.alloc<Unreachable>(); +} + +// Functions + +BinaryenFunctionRef BinaryenAddFunction(BinaryenModuleRef module, const char* name, BinaryenFunctionTypeRef type, BinaryenType* localTypes, BinaryenIndex numLocalTypes, BinaryenExpressionRef body) { + auto* wasm = (Module*)module; + auto* ret = new Function; + ret->name = name; + ret->type = ((FunctionType*)type)->name; + auto* functionType = wasm->getFunctionType(ret->type); + ret->result = functionType->result; + ret->params = functionType->params; + for (BinaryenIndex i = 0; i < numLocalTypes; i++) { + ret->vars.push_back(WasmType(localTypes[i])); + } + ret->body = (Expression*)body; + wasm->addFunction(ret); + return ret; +} + +// Imports + +BinaryenImportRef BinaryenAddImport(BinaryenModuleRef module, const char* internalName, const char* externalModuleName, const char *externalBaseName, BinaryenFunctionTypeRef type) { + auto* wasm = (Module*)module; + auto* ret = new Import(); + ret->name = internalName; + ret->module = externalModuleName; + ret->base = externalBaseName; + ret->type = (FunctionType*)type; + wasm->addImport(ret); + return ret; +} + +// Exports + +BinaryenExportRef BinaryenAddExport(BinaryenModuleRef module, const char* internalName, const char* externalName) { + auto* wasm = (Module*)module; + auto* ret = new Export(); + ret->value = internalName; + ret->name = externalName; + wasm->addExport(ret); + return ret; +} + +// Function table. One per module + +void BinaryenSetFunctionTable(BinaryenModuleRef module, BinaryenFunctionRef* functions, BinaryenIndex numFunctions) { + auto* wasm = (Module*)module; + for (BinaryenIndex i = 0; i < numFunctions; i++) { + wasm->table.names.push_back(((Function*)functions[i])->name); + } +} + +// Memory. One per module + +void BinaryenSetMemory(BinaryenModuleRef module, BinaryenIndex initial, BinaryenIndex maximum, const char* exportName, const char **segments, BinaryenIndex* segmentOffsets, BinaryenIndex* segmentSizes, BinaryenIndex numSegments) { + auto* wasm = (Module*)module; + wasm->memory.initial = initial; + wasm->memory.max = maximum; + if (exportName) wasm->memory.exportName = exportName; + for (BinaryenIndex i = 0; i < numSegments; i++) { + wasm->memory.segments.emplace_back(segmentOffsets[i], segments[i], segmentSizes[i]); + } +} + +// Start function. One per module + +void BinaryenSetStart(BinaryenModuleRef module, const char* name) { + auto* wasm = (Module*)module; + wasm->addStart(name); +} + +// +// ========== Module Operations ========== +// + +void BinaryenModulePrint(BinaryenModuleRef module) { + WasmPrinter::printModule((Module*)module); +} + +} // extern "C" diff --git a/src/binaryen-c.h b/src/binaryen-c.h new file mode 100644 index 000000000..475c65613 --- /dev/null +++ b/src/binaryen-c.h @@ -0,0 +1,247 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//================ +// Binaryen C API +// +// The first part of the API lets you create modules and their parts. +// The second part of the API lets you perform operations on modules. +//================ + +#ifndef binaryen_h +#define binaryen_h + +#include <stddef.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +// +// ========== Module Creation ========== +// + +// BinaryenIndex +// +// Used for internal indexes and list sizes. + +typedef uint32_t BinaryenIndex; + +// Core types (call to get the value of each; you can cache them, they +// never change) + +typedef uint32_t BinaryenType; + +BinaryenType BinaryenNone(void); +BinaryenType BinaryenInt32(void); +BinaryenType BinaryenInt64(void); +BinaryenType BinaryenFloat32(void); +BinaryenType BinaryenFloat64(void); + +// Modules +// +// Modules contain lists of functions, imports, exports, function types. The +// Add* methods create them on a module. The module owns them and will free their +// memory when the module is disposed of. +// +// Expressions are also allocated inside modules, and freed with the module. They +// are not created by Add* methods, since they are not added directly on the +// module, instead, they are arguments to other expressions (and then they are +// the children of that AST node), or to a function (and then they are the body +// of that function). +// +// A module can also contain a function table for indirect calls, a memory, +// and a start method. + +typedef void* BinaryenModuleRef; + +BinaryenModuleRef BinaryenModuleCreate(); +void BinaryenModuleDispose(BinaryenModuleRef module); + +// Function types + +typedef void* BinaryenFunctionTypeRef; + +BinaryenFunctionTypeRef BinaryenAddFunctionType(BinaryenModuleRef module, const char* name, BinaryenType result, BinaryenType* paramTypes, BinaryenIndex numParams); + +// Literals. These are passed by value. + +struct BinaryenLiteral { + int type; // size of enum in c++ + union { + int32_t i32; + int64_t i64; + float f32; + double f64; + }; +}; + +struct BinaryenLiteral BinaryenLiteralInt32(int32_t x); +struct BinaryenLiteral BinaryenLiteralInt64(int64_t x); +struct BinaryenLiteral BinaryenLiteralFloat32(float x); +struct BinaryenLiteral BinaryenLiteralFloat64(double x); +struct BinaryenLiteral BinaryenLiteralFloat32Bits(int32_t x); +struct BinaryenLiteral BinaryenLiteralFloat64Bits(int64_t x); + +// Expressions +// +// Some expressions have a BinaryenOp, which is the more +// specific operation/opcode. +// +// Some expressions have optional parameters, like Return may not +// return a value. You can supply a NULL pointer in those cases. + +typedef int32_t BinaryenOp; + +BinaryenOp BinaryenClz(void); +BinaryenOp BinaryenCtz(void); +BinaryenOp BinaryenPopcnt(void); +BinaryenOp BinaryenNeg(void); +BinaryenOp BinaryenAbs(void); +BinaryenOp BinaryenCeil(void); +BinaryenOp BinaryenFloor(void); +BinaryenOp BinaryenTrunc(void); +BinaryenOp BinaryenNearest(void); +BinaryenOp BinaryenSqrt(void); +BinaryenOp BinaryenEqZ(void); +BinaryenOp BinaryenExtendSInt32(void); +BinaryenOp BinaryenExtentUInt32(void); +BinaryenOp BinaryenWrapInt64(void); +BinaryenOp BinaryenTruncSFloat32(void); +BinaryenOp BinaryenTruncUFloat32(void); +BinaryenOp BinaryenTruncSFloat64(void); +BinaryenOp BinaryenTruncUFloat64(void); +BinaryenOp BinaryenReinterpretFloat(void); +BinaryenOp BinaryenConvertSInt32(void); +BinaryenOp BinaryenConvertUInt32(void); +BinaryenOp BinaryenConvertSInt64(void); +BinaryenOp BinaryenConvertUInt64(void); +BinaryenOp BinaryenPromoteFloat32(void); +BinaryenOp BinaryenDemoteFloat64(void); +BinaryenOp BinaryenReinterpretInt(void); +BinaryenOp BinaryenAdd(void); +BinaryenOp BinaryenSub(void); +BinaryenOp BinaryenMul(void); +BinaryenOp BinaryenDivS(void); +BinaryenOp BinaryenDivU(void); +BinaryenOp BinaryenRemS(void); +BinaryenOp BinaryenRemU(void); +BinaryenOp BinaryenAnd(void); +BinaryenOp BinaryenOr(void); +BinaryenOp BinaryenXor(void); +BinaryenOp BinaryenShl(void); +BinaryenOp BinaryenShrU(void); +BinaryenOp BinaryenShrS(void); +BinaryenOp BinaryenRotL(void); +BinaryenOp BinaryenRotR(void); +BinaryenOp BinaryenDiv(void); +BinaryenOp BinaryenCopySign(void); +BinaryenOp BinaryenMin(void); +BinaryenOp BinaryenMax(void); +BinaryenOp BinaryenEq(void); +BinaryenOp BinaryenNe(void); +BinaryenOp BinaryenLtS(void); +BinaryenOp BinaryenLtU(void); +BinaryenOp BinaryenLeS(void); +BinaryenOp BinaryenLeU(void); +BinaryenOp BinaryenGtS(void); +BinaryenOp BinaryenGtU(void); +BinaryenOp BinaryenGeS(void); +BinaryenOp BinaryenGeU(void); +BinaryenOp BinaryenLt(void); +BinaryenOp BinaryenLe(void); +BinaryenOp BinaryenGt(void); +BinaryenOp BinaryenGe(void); +BinaryenOp BinaryenPageSize(void); +BinaryenOp BinaryenCurrentMemory(void); +BinaryenOp BinaryenGrowMemory(void); +BinaryenOp BinaryenHasFeature(void); + +typedef void* BinaryenExpressionRef; + +// Block: name can be NULL +BinaryenExpressionRef BinaryenBlock(BinaryenModuleRef module, const char* name, BinaryenExpressionRef* children, BinaryenIndex numChildren); +// If: ifFalse can be NULL +BinaryenExpressionRef BinaryenIf(BinaryenModuleRef module, BinaryenExpressionRef condition, BinaryenExpressionRef ifTrue, BinaryenExpressionRef ifFalse); +// Loop: both out and in can be NULL, or just out can be NULL +BinaryenExpressionRef BinaryenLoop(BinaryenModuleRef module, const char* out, const char* in, BinaryenExpressionRef body); +// Break: value and condition can be NULL +BinaryenExpressionRef BinaryenBreak(BinaryenModuleRef module, const char* name, BinaryenExpressionRef value, BinaryenExpressionRef condition); +// Switch: value can be NULL +BinaryenExpressionRef BinaryenSwitch(BinaryenModuleRef module, const char **names, BinaryenIndex numNames, const char* defaultName, BinaryenExpressionRef condition, BinaryenExpressionRef value); +BinaryenExpressionRef BinaryenCall(BinaryenModuleRef module, const char *target, BinaryenExpressionRef* operands, BinaryenIndex numOperands); +BinaryenExpressionRef BinaryenCallImport(BinaryenModuleRef module, const char *target, BinaryenExpressionRef* operands, BinaryenIndex numOperands); +BinaryenExpressionRef BinaryenCallIndirect(BinaryenModuleRef module, BinaryenExpressionRef target, BinaryenExpressionRef* operands, BinaryenIndex numOperands, BinaryenFunctionTypeRef type); +BinaryenExpressionRef BinaryenGetLocal(BinaryenModuleRef module, BinaryenIndex index, BinaryenType type); +BinaryenExpressionRef BinaryenSetLocal(BinaryenModuleRef module, BinaryenIndex index, BinaryenExpressionRef value); +BinaryenExpressionRef BinaryenLoad(BinaryenModuleRef module, uint32_t bytes, int8_t signed_, uint32_t offset, uint32_t align, BinaryenType type, BinaryenExpressionRef ptr); +BinaryenExpressionRef BinaryenStore(BinaryenModuleRef module, uint32_t bytes, uint32_t offset, uint32_t align, BinaryenExpressionRef ptr, BinaryenExpressionRef value); +BinaryenExpressionRef BinaryenConst(BinaryenModuleRef module, struct BinaryenLiteral value); +BinaryenExpressionRef BinaryenUnary(BinaryenModuleRef module, BinaryenOp op, BinaryenExpressionRef value, BinaryenType type); +BinaryenExpressionRef BinaryenBinary(BinaryenModuleRef module, BinaryenOp op, BinaryenExpressionRef left, BinaryenExpressionRef right); +BinaryenExpressionRef BinaryenSelect(BinaryenModuleRef module, BinaryenExpressionRef condition, BinaryenExpressionRef ifTrue, BinaryenExpressionRef ifFalse); +// Return: value can be NULL +BinaryenExpressionRef BinaryenReturn(BinaryenModuleRef module, BinaryenExpressionRef value); +// Host: name may be NULL +BinaryenExpressionRef BinaryenHost(BinaryenModuleRef module, BinaryenOp op, const char* name, BinaryenExpressionRef* operands, BinaryenIndex numOperands); +BinaryenExpressionRef BinaryenNop(BinaryenModuleRef module); +BinaryenExpressionRef BinaryenUnreachable(BinaryenModuleRef module); + +// Functions + +typedef void* BinaryenFunctionRef; + +BinaryenFunctionRef BinaryenAddFunction(BinaryenModuleRef module, const char* name, BinaryenFunctionTypeRef type, BinaryenType* localTypes, BinaryenIndex numLocalTypes, BinaryenExpressionRef body); + +// Imports + +typedef void* BinaryenImportRef; + +BinaryenImportRef BinaryenAddImport(BinaryenModuleRef module, const char* internalName, const char* externalModuleName, const char *externalBaseName, BinaryenFunctionTypeRef type); + +// Exports + +typedef void* BinaryenExportRef; + +BinaryenExportRef BinaryenAddExport(BinaryenModuleRef module, const char* internalName, const char* externalName); + +// Function table. One per module + +void BinaryenSetFunctionTable(BinaryenModuleRef module, BinaryenFunctionRef* functions, BinaryenIndex numFunctions); + +// Memory. One per module + +// Each segment has data in segments, a start offset in segmentOffsets, and a size in segmentSizes. +// exportName can be NULL +void BinaryenSetMemory(BinaryenModuleRef module, BinaryenIndex initial, BinaryenIndex maximum, const char* exportName, const char **segments, BinaryenIndex* segmentOffsets, BinaryenIndex* segmentSizes, BinaryenIndex numSegments); + +// Start function. One per module + +void BinaryenSetStart(BinaryenModuleRef module, const char* name); + +// +// ========== Module Operations ========== +// + +// Print a module to stdout. +void BinaryenModulePrint(BinaryenModuleRef module); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // binaryen_h diff --git a/src/wasm-builder.h b/src/wasm-builder.h index 5d4c90840..0dc3e41b1 100644 --- a/src/wasm-builder.h +++ b/src/wasm-builder.h @@ -79,8 +79,18 @@ public: ret->finalize(); return ret; } - // Loop - // Break + Loop* makeLoop(Name out, Name in, Expression* body) { + auto* ret = allocator.alloc<Loop>(); + ret->out = out; ret->in = in; ret->body = body; + ret->finalize(); + return ret; + } + Break* makeBreak(Name name, Expression* value=nullptr, Expression* condition=nullptr) { + auto* ret = allocator.alloc<Break>(); + ret->name = name; ret->value = value; ret->condition = condition; + ret->finalize(); + return ret; + } // Switch // CallBase // Call diff --git a/src/wasm.h b/src/wasm.h index fabc702c5..e3c8ea7d9 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -801,7 +801,9 @@ public: WasmType type; // the type of the expression: its *output*, not necessarily its input(s) Expression(Id id) : _id(id), type(none) {} - + + void finalize() {} + template<class T> bool is() { return int(_id) == int(T::SpecificId); @@ -1011,6 +1013,8 @@ public: uint32_t offset; uint32_t align; Expression *ptr; + + // type must be set during creation, cannot be inferred }; class Store : public SpecificExpression<Expression::StoreId> { @@ -1022,6 +1026,10 @@ public: uint32_t offset; unsigned align; Expression *ptr, *value; + + void finalize() { + type = value->type; + } }; class Const : public SpecificExpression<Expression::ConstId> { diff --git a/test/example/c-api-hello-world.c b/test/example/c-api-hello-world.c new file mode 100644 index 000000000..016c2404b --- /dev/null +++ b/test/example/c-api-hello-world.c @@ -0,0 +1,29 @@ + +#include <binaryen-c.h> + +// "hello world" type example: create a function that adds two i32s and returns the result + +int main() { + BinaryenModuleRef module = BinaryenModuleCreate(); + + // Creation a function type for i32 (i32, i32) + BinaryenType params[2] = { BinaryenInt32(), BinaryenInt32() }; + BinaryenFunctionTypeRef iii = BinaryenAddFunctionType(module, "iii", BinaryenInt32(), params, 2); + + // Get the 0 and 1 arguments, and add them + BinaryenExpressionRef x = BinaryenGetLocal(module, 0, BinaryenInt32()), + y = BinaryenGetLocal(module, 1, BinaryenInt32()); + BinaryenExpressionRef add = BinaryenBinary(module, BinaryenAdd(), x, y); + + // Create the add function + // Note: no additional local variables + // Note: no basic blocks here, we are an AST. The function body is just an expression node. + BinaryenFunctionRef adder = BinaryenAddFunction(module, "adder", iii, NULL, 0, add); + + // Print it out + BinaryenModulePrint(module); + + // Clean up the module, which owns all the objects we created above + BinaryenModuleDispose(module); +} + diff --git a/test/example/c-api-hello-world.txt b/test/example/c-api-hello-world.txt new file mode 100644 index 000000000..4360107d3 --- /dev/null +++ b/test/example/c-api-hello-world.txt @@ -0,0 +1,10 @@ +(module + (memory 0) + (type $iii (func (param i32 i32) (result i32))) + (func $adder (type $iii) (param $0 i32) (param $1 i32) (result i32) + (i32.add + (get_local $0) + (get_local $1) + ) + ) +) diff --git a/test/example/c-api-kitchen-sink.c b/test/example/c-api-kitchen-sink.c new file mode 100644 index 000000000..f7dc5c341 --- /dev/null +++ b/test/example/c-api-kitchen-sink.c @@ -0,0 +1,213 @@ + +#include <stdio.h> +#include <stdlib.h> + +#include <binaryen-c.h> + + +// kitchen sink, tests the full API + + +// helpers + +BinaryenExpressionRef makeUnary(BinaryenModuleRef module, BinaryenOp op, BinaryenType inputType, BinaryenType outputType) { + if (inputType == BinaryenInt32()) return BinaryenUnary(module, op, BinaryenConst(module, BinaryenLiteralInt32(-10)), outputType); + if (inputType == BinaryenInt64()) return BinaryenUnary(module, op, BinaryenConst(module, BinaryenLiteralInt64(-22)), outputType); + if (inputType == BinaryenFloat32()) return BinaryenUnary(module, op, BinaryenConst(module, BinaryenLiteralFloat32(-33.612)), outputType); + if (inputType == BinaryenFloat64()) return BinaryenUnary(module, op, BinaryenConst(module, BinaryenLiteralFloat64(-9005.841)), outputType); + abort(); +} + +BinaryenExpressionRef makeBinary(BinaryenModuleRef module, BinaryenOp op, BinaryenType type) { + if (type == BinaryenInt32()) return BinaryenBinary(module, op, BinaryenConst(module, BinaryenLiteralInt32(-10)), BinaryenConst(module, BinaryenLiteralInt32(-11))); + if (type == BinaryenInt64()) return BinaryenBinary(module, op, BinaryenConst(module, BinaryenLiteralInt64(-22)), BinaryenConst(module, BinaryenLiteralInt64(-23))); + if (type == BinaryenFloat32()) return BinaryenBinary(module, op, BinaryenConst(module, BinaryenLiteralFloat32(-33.612)), BinaryenConst(module, BinaryenLiteralFloat32(-62.5))); + if (type == BinaryenFloat64()) return BinaryenBinary(module, op, BinaryenConst(module, BinaryenLiteralFloat64(-9005.841)), BinaryenConst(module, BinaryenLiteralFloat64(-9007.333))); + abort(); +} + +BinaryenExpressionRef makeInt32(BinaryenModuleRef module, int x) { + return BinaryenConst(module, BinaryenLiteralInt32(x)); +} + +BinaryenExpressionRef makeFloat32(BinaryenModuleRef module, float x) { + return BinaryenConst(module, BinaryenLiteralFloat32(x)); +} + +BinaryenExpressionRef makeInt64(BinaryenModuleRef module, int64_t x) { + return BinaryenConst(module, BinaryenLiteralInt64(x)); +} + +BinaryenExpressionRef makeFloat64(BinaryenModuleRef module, double x) { + return BinaryenConst(module, BinaryenLiteralFloat64(x)); +} + +BinaryenExpressionRef makeSomething(BinaryenModuleRef module) { + return makeInt32(module, 1337); +} + +// main + +int main() { + + // Core types + + printf("BinaryenNone: %d\n", BinaryenNone()); + printf("BinaryenInt32: %d\n", BinaryenInt32()); + printf("BinaryenInt64: %d\n", BinaryenInt64()); + printf("BinaryenFloat32: %d\n", BinaryenFloat32()); + printf("BinaryenFloat64: %d\n", BinaryenFloat64()); + + // Module creation + + BinaryenModuleRef module = BinaryenModuleCreate(); + + // Literals and consts + + BinaryenExpressionRef constI32 = BinaryenConst(module, BinaryenLiteralInt32(1)), + constI64 = BinaryenConst(module, BinaryenLiteralInt64(2)), + constF32 = BinaryenConst(module, BinaryenLiteralFloat32(3.14)), + constF64 = BinaryenConst(module, BinaryenLiteralFloat64(2.1828)), + constF32Bits = BinaryenConst(module, BinaryenLiteralFloat32Bits(0xffff1234)), + constF64Bits = BinaryenConst(module, BinaryenLiteralFloat64Bits(0xffff12345678abcdLL)); + + const char* switchNames[] = { "the-body" }; + + BinaryenExpressionRef callOperands2[] = { makeInt32(module, 13), makeFloat64(module, 3.7) }; + BinaryenExpressionRef callOperands4[] = { makeInt32(module, 13), makeInt64(module, 37), makeFloat32(module, 1.3), makeFloat64(module, 3.7) }; + + BinaryenType params[4] = { BinaryenInt32(), BinaryenInt64(), BinaryenFloat32(), BinaryenFloat64() }; + BinaryenFunctionTypeRef iiIfF = BinaryenAddFunctionType(module, "iiIfF", BinaryenInt32(), params, 4); + + BinaryenExpressionRef bodyList[] = { + // Unary + makeUnary(module, BinaryenClz(), 1, 1), + makeUnary(module, BinaryenCtz(), 2, 2), + makeUnary(module, BinaryenPopcnt(), 1, 1), + makeUnary(module, BinaryenNeg(), 3, 3), + makeUnary(module, BinaryenAbs(), 4, 3), + makeUnary(module, BinaryenCeil(), 3, 3), + makeUnary(module, BinaryenFloor(), 4, 4), + makeUnary(module, BinaryenTrunc(), 3, 3), + makeUnary(module, BinaryenNearest(), 3, 3), + makeUnary(module, BinaryenSqrt(), 4, 4), + makeUnary(module, BinaryenEqZ(), 1, 1), + makeUnary(module, BinaryenExtendSInt32(), 1, 2), + makeUnary(module, BinaryenExtentUInt32(), 1, 2), + makeUnary(module, BinaryenWrapInt64(), 2, 1), + makeUnary(module, BinaryenTruncSFloat32(), 3, 1), + makeUnary(module, BinaryenTruncUFloat32(), 3, 2), + makeUnary(module, BinaryenTruncSFloat64(), 4, 2), + makeUnary(module, BinaryenTruncUFloat64(), 4, 1), + makeUnary(module, BinaryenReinterpretFloat(), 3, 1), + makeUnary(module, BinaryenConvertSInt32(), 1, 3), + makeUnary(module, BinaryenConvertUInt32(), 1, 4), + makeUnary(module, BinaryenConvertSInt64(), 2, 3), + makeUnary(module, BinaryenConvertUInt64(), 2, 4), + makeUnary(module, BinaryenPromoteFloat32(), 3, 4), + makeUnary(module, BinaryenDemoteFloat64(), 4, 3), + makeUnary(module, BinaryenReinterpretInt(), 1, 3), + // Binary + makeBinary(module, BinaryenAdd(), 1), + makeBinary(module, BinaryenSub(), 4), + makeBinary(module, BinaryenDivS(), 1), + makeBinary(module, BinaryenDivU(), 2), + makeBinary(module, BinaryenRemS(), 2), + makeBinary(module, BinaryenRemU(), 1), + makeBinary(module, BinaryenAnd(), 1), + makeBinary(module, BinaryenOr(), 2), + makeBinary(module, BinaryenXor(), 1), + makeBinary(module, BinaryenShl(), 2), + makeBinary(module, BinaryenShrU(), 2), + makeBinary(module, BinaryenShrS(), 1), + makeBinary(module, BinaryenRotL(), 1), + makeBinary(module, BinaryenRotR(), 2), + makeBinary(module, BinaryenDiv(), 3), + makeBinary(module, BinaryenCopySign(), 4), + makeBinary(module, BinaryenMin(), 3), + makeBinary(module, BinaryenMax(), 4), + makeBinary(module, BinaryenEq(), 1), + makeBinary(module, BinaryenNe(), 3), + makeBinary(module, BinaryenLtS(), 1), + makeBinary(module, BinaryenLtU(), 2), + makeBinary(module, BinaryenLeS(), 2), + makeBinary(module, BinaryenLeU(), 1), + makeBinary(module, BinaryenGtS(), 2), + makeBinary(module, BinaryenGtU(), 1), + makeBinary(module, BinaryenGeS(), 1), + makeBinary(module, BinaryenGeU(), 2), + makeBinary(module, BinaryenLt(), 3), + makeBinary(module, BinaryenLe(), 4), + makeBinary(module, BinaryenGt(), 4), + makeBinary(module, BinaryenGe(), 3), + // All the rest + BinaryenBlock(module, NULL, NULL, 0), // block with no name + BinaryenIf(module, makeInt32(module, 1), makeInt32(module, 2), makeInt32(module, 3)), + BinaryenIf(module, makeInt32(module, 4), makeInt32(module, 5), NULL), + BinaryenLoop(module, "out", "in", makeInt32(module, 0)), + BinaryenLoop(module, NULL, "in2", makeInt32(module, 0)), + BinaryenLoop(module, NULL, NULL, makeInt32(module, 0)), + BinaryenBreak(module, "the-body", makeInt32(module, 0), makeInt32(module, 1)), + BinaryenBreak(module, "the-body", makeInt32(module, 2), NULL), + BinaryenBreak(module, "the-body", NULL, makeInt32(module, 3)), + BinaryenBreak(module, "the-body", NULL, NULL), + BinaryenSwitch(module, switchNames, 1, "the-body", makeInt32(module, 0), makeInt32(module, 1)), + BinaryenSwitch(module, switchNames, 1, "the-body", makeInt32(module, 2), NULL), + BinaryenCall(module, "kitchen-sinker", callOperands4, 4), + BinaryenCallImport(module, "an-imported", callOperands2, 2), + BinaryenCallIndirect(module, makeInt32(module, 2449), callOperands4, 4, iiIfF), + BinaryenGetLocal(module, 0, BinaryenInt32()), + BinaryenSetLocal(module, 0, makeInt32(module, 101)), + BinaryenLoad(module, 4, 0, 0, 0, BinaryenInt32(), makeInt32(module, 1)), + BinaryenLoad(module, 1, 1, 2, 4, BinaryenInt64(), makeInt32(module, 8)), + BinaryenLoad(module, 4, 0, 0, 0, BinaryenFloat32(), makeInt32(module, 2)), + BinaryenLoad(module, 8, 0, 2, 8, BinaryenFloat64(), makeInt32(module, 9)), + BinaryenStore(module, 4, 0, 0, makeInt32(module, 10), makeInt32(module, 11)), + BinaryenStore(module, 8, 2, 4, makeInt32(module, 110), makeInt64(module, 111)), + BinaryenSelect(module, makeInt32(module, 1), makeInt32(module, 3), makeInt32(module, 5)), + BinaryenReturn(module, NULL), + BinaryenReturn(module, makeFloat32(module, 1)), + // TODO: Host + BinaryenNop(module), + BinaryenUnreachable(module), + }; + + // Make the main body of the function + BinaryenExpressionRef body = BinaryenBlock(module, "the-body", bodyList, sizeof(bodyList) / sizeof(BinaryenExpressionRef)); + + // Create the function + BinaryenType localTypes[] = { BinaryenInt32() }; + BinaryenFunctionRef sinker = BinaryenAddFunction(module, "kitchen-sinker", iiIfF, localTypes, 1, body); + + // Imports + + BinaryenType iparams[2] = { BinaryenInt32(), BinaryenFloat64() }; + BinaryenFunctionTypeRef viF = BinaryenAddFunctionType(module, "viF", BinaryenNone(), iparams, 2); + BinaryenAddImport(module, "an-imported", "module", "base", viF); + + // Exports + + BinaryenAddExport(module, "kitchen-sinker", "kitchen_sinker"); + + // Function table. One per module + BinaryenFunctionRef functions[] = { sinker }; + BinaryenSetFunctionTable(module, functions, 1); + + // Memory. One per module + + const char *segments[] = { "hello, world" }; + BinaryenIndex segmentOffsets[] = { 10 }; + BinaryenIndex segmentSizes[] = { 12 }; + BinaryenSetMemory(module, 1, 256, "mem", segments, segmentOffsets, segmentSizes, 1); + + // Start function. One per module + + BinaryenSetStart(module, "sinker"); + + // Print it out + BinaryenModulePrint(module); + + // Clean up the module, which owns all the objects we created above + BinaryenModuleDispose(module); +} + diff --git a/test/example/c-api-kitchen-sink.txt b/test/example/c-api-kitchen-sink.txt new file mode 100644 index 000000000..2c80d8706 --- /dev/null +++ b/test/example/c-api-kitchen-sink.txt @@ -0,0 +1,318 @@ +BinaryenNone: 0 +BinaryenInt32: 1 +BinaryenInt64: 2 +BinaryenFloat32: 3 +BinaryenFloat64: 4 +(module + (memory 1 256 + (segment 10 "hello, world") + ) + (export "mem" memory) + (start $sinker) + (type $iiIfF (func (param i32 i64 f32 f64) (result i32))) + (type $viF (func (param i32 f64))) + (import $an-imported "module" "base" (param i32 f64)) + (export "kitchen_sinker" $kitchen-sinker) + (table $kitchen-sinker) + (func $kitchen-sinker (type $iiIfF) (param $0 i32) (param $1 i64) (param $2 f32) (param $3 f64) (result i32) + (local $4 i32) + (block $the-body + (i32.clz + (i32.const -10) + ) + (i64.ctz + (i64.const -22) + ) + (i32.popcnt + (i32.const -10) + ) + (f32.neg + (f32.const -33.61199951171875) + ) + (f32.abs + (f64.const -9005.841) + ) + (f32.ceil + (f32.const -33.61199951171875) + ) + (f64.floor + (f64.const -9005.841) + ) + (f32.trunc + (f32.const -33.61199951171875) + ) + (f32.nearest + (f32.const -33.61199951171875) + ) + (f64.sqrt + (f64.const -9005.841) + ) + (i32.eqz + (i32.const -10) + ) + (i64.extend_s/i32 + (i32.const -10) + ) + (i64.extend_u/i32 + (i32.const -10) + ) + (i32.wrap/i64 + (i64.const -22) + ) + (i32.trunc_s/f32 + (f32.const -33.61199951171875) + ) + (i64.trunc_u/f32 + (f32.const -33.61199951171875) + ) + (i64.trunc_s/f64 + (f64.const -9005.841) + ) + (i32.trunc_u/f64 + (f64.const -9005.841) + ) + (i32.reinterpret/f32 + (f32.const -33.61199951171875) + ) + (f32.convert_s/i32 + (i32.const -10) + ) + (f64.convert_u/i32 + (i32.const -10) + ) + (f32.convert_s/i64 + (i64.const -22) + ) + (f64.convert_u/i64 + (i64.const -22) + ) + (f64.promote/f32 + (f32.const -33.61199951171875) + ) + (f32.demote/f64 + (f64.const -9005.841) + ) + (f32.reinterpret/i32 + (i32.const -10) + ) + (i32.add + (i32.const -10) + (i32.const -11) + ) + (f64.sub + (f64.const -9005.841) + (f64.const -9007.333) + ) + (i32.div_s + (i32.const -10) + (i32.const -11) + ) + (i64.div_u + (i64.const -22) + (i64.const -23) + ) + (i64.rem_s + (i64.const -22) + (i64.const -23) + ) + (i32.rem_u + (i32.const -10) + (i32.const -11) + ) + (i32.and + (i32.const -10) + (i32.const -11) + ) + (i64.or + (i64.const -22) + (i64.const -23) + ) + (i32.xor + (i32.const -10) + (i32.const -11) + ) + (i64.shl + (i64.const -22) + (i64.const -23) + ) + (i64.shr_u + (i64.const -22) + (i64.const -23) + ) + (i32.shr_s + (i32.const -10) + (i32.const -11) + ) + (i32.rotl + (i32.const -10) + (i32.const -11) + ) + (i64.rotr + (i64.const -22) + (i64.const -23) + ) + (f32.div + (f32.const -33.61199951171875) + (f32.const -62.5) + ) + (f64.copysign + (f64.const -9005.841) + (f64.const -9007.333) + ) + (f32.min + (f32.const -33.61199951171875) + (f32.const -62.5) + ) + (f64.max + (f64.const -9005.841) + (f64.const -9007.333) + ) + (i32.eq + (i32.const -10) + (i32.const -11) + ) + (f32.ne + (f32.const -33.61199951171875) + (f32.const -62.5) + ) + (i32.lt_s + (i32.const -10) + (i32.const -11) + ) + (i64.lt_u + (i64.const -22) + (i64.const -23) + ) + (i64.le_s + (i64.const -22) + (i64.const -23) + ) + (i32.le_u + (i32.const -10) + (i32.const -11) + ) + (i64.gt_s + (i64.const -22) + (i64.const -23) + ) + (i32.gt_u + (i32.const -10) + (i32.const -11) + ) + (i32.ge_s + (i32.const -10) + (i32.const -11) + ) + (i64.ge_u + (i64.const -22) + (i64.const -23) + ) + (f32.lt + (f32.const -33.61199951171875) + (f32.const -62.5) + ) + (f64.le + (f64.const -9005.841) + (f64.const -9007.333) + ) + (f64.gt + (f64.const -9005.841) + (f64.const -9007.333) + ) + (f32.ge + (f32.const -33.61199951171875) + (f32.const -62.5) + ) + (block + ) + (if + (i32.const 1) + (i32.const 2) + (i32.const 3) + ) + (if + (i32.const 4) + (i32.const 5) + ) + (loop $out $in + (i32.const 0) + ) + (loop $in2 + (i32.const 0) + ) + (loop + (i32.const 0) + ) + (br_if $the-body + (i32.const 0) + (i32.const 1) + ) + (br $the-body + (i32.const 2) + ) + (br_if $the-body + (i32.const 3) + ) + (br $the-body) + (br_table $the-body $the-body + (i32.const 1) + (i32.const 0) + ) + (br_table $the-body $the-body + (i32.const 2) + ) + (call $kitchen-sinker + (i32.const 13) + (i64.const 37) + (f32.const 1.2999999523162842) + (f64.const 3.7) + ) + (call_import $an-imported + (i32.const 13) + (f64.const 3.7) + ) + (call_indirect $iiIfF + (i32.const 2449) + (i32.const 13) + (i64.const 37) + (f32.const 1.2999999523162842) + (f64.const 3.7) + ) + (get_local $0) + (set_local $0 + (i32.const 101) + ) + (i32.load + (i32.const 1) + ) + (i64.load8_s offset=2 align=4 + (i32.const 8) + ) + (f32.load + (i32.const 2) + ) + (f64.load offset=2 + (i32.const 9) + ) + (i32.store + (i32.const 10) + (i32.const 11) + ) + (i64.store offset=2 align=4 + (i32.const 110) + (i64.const 111) + ) + (select + (i32.const 3) + (i32.const 5) + (i32.const 1) + ) + (return) + (return + (f32.const 1) + ) + (nop) + (unreachable) + ) + ) +) |