summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt8
-rwxr-xr-xcheck.py42
-rw-r--r--src/binaryen-c.cpp376
-rw-r--r--src/binaryen-c.h247
-rw-r--r--src/wasm-builder.h14
-rw-r--r--src/wasm.h10
-rw-r--r--test/example/c-api-hello-world.c29
-rw-r--r--test/example/c-api-hello-world.txt10
-rw-r--r--test/example/c-api-kitchen-sink.c213
-rw-r--r--test/example/c-api-kitchen-sink.txt318
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
diff --git a/check.py b/check.py
index 977da0764..a21c1c03d 100755
--- a/check.py
+++ b/check.py
@@ -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)
+ )
+ )
+)