/* * 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 #include "binaryen-c.h" #include "pass.h" #include "wasm.h" #include "wasm-binary.h" #include "wasm-builder.h" #include "wasm-interpreter.h" #include "wasm-printing.h" #include "wasm-validator.h" #include "cfg/Relooper.h" #include "shell-interface.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(); } } // Tracing support static int tracing = 0; void traceNameOrNULL(const char *name) { if (name) std::cout << "\"" << name << "\""; else std::cout << "NULL"; } std::map functionTypes; std::map expressions; std::map functions; std::map relooperBlocks; size_t noteExpression(BinaryenExpressionRef expression) { auto id = expressions.size(); assert(expressions.find(expression) == expressions.end()); expressions[expression] = id; return id; } 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(void) { if (tracing) { std::cout << " the_module = BinaryenModuleCreate();\n"; std::cout << " expressions[size_t(NULL)] = BinaryenExpressionRef(NULL);\n"; expressions[NULL] = 0; } return new Module(); } void BinaryenModuleDispose(BinaryenModuleRef module) { if (tracing) { std::cout << " BinaryenModuleDispose(the_module);\n"; std::cout << " functionTypes.clear();\n"; std::cout << " expressions.clear();\n"; std::cout << " functions.clear();\n"; std::cout << " relooperBlocks.clear();\n"; functionTypes.clear(); expressions.clear(); functions.clear(); relooperBlocks.clear(); } 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; if (name) ret->name = name; else ret->name = Name::fromInt(wasm->functionTypes.size()); ret->result = WasmType(result); for (BinaryenIndex i = 0; i < numParams; i++) { ret->params.push_back(WasmType(paramTypes[i])); } // Lock. This can be called from multiple threads at once, and is a // point where they all access and modify the module. static std::mutex BinaryenAddFunctionTypeMutex; { std::lock_guard lock(BinaryenAddFunctionTypeMutex); wasm->addFunctionType(ret); } if (tracing) { std::cout << " {\n"; std::cout << " BinaryenIndex paramTypes[] = { "; for (BinaryenIndex i = 0; i < numParams; i++) { if (i > 0) std::cout << ", "; std::cout << paramTypes[i]; } if (numParams == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS std::cout << " };\n"; size_t id = functionTypes.size(); std::cout << " functionTypes[" << id << "] = BinaryenAddFunctionType(the_module, "; functionTypes[ret] = id; traceNameOrNULL(name); std::cout << ", " << result << ", paramTypes, " << numParams << ");\n"; std::cout << " }\n"; } 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 BinaryenClzInt32(void) { return ClzInt32; } BinaryenOp BinaryenCtzInt32(void) { return CtzInt32; } BinaryenOp BinaryenPopcntInt32(void) { return PopcntInt32; } BinaryenOp BinaryenNegFloat32(void) { return NegFloat32; } BinaryenOp BinaryenAbsFloat32(void) { return AbsFloat32; } BinaryenOp BinaryenCeilFloat32(void) { return CeilFloat32; } BinaryenOp BinaryenFloorFloat32(void) { return FloorFloat32; } BinaryenOp BinaryenTruncFloat32(void) { return TruncFloat32; } BinaryenOp BinaryenNearestFloat32(void) { return NearestFloat32; } BinaryenOp BinaryenSqrtFloat32(void) { return SqrtFloat32; } BinaryenOp BinaryenEqZInt32(void) { return EqZInt32; } BinaryenOp BinaryenClzInt64(void) { return ClzInt64; } BinaryenOp BinaryenCtzInt64(void) { return CtzInt64; } BinaryenOp BinaryenPopcntInt64(void) { return PopcntInt64; } BinaryenOp BinaryenNegFloat64(void) { return NegFloat64; } BinaryenOp BinaryenAbsFloat64(void) { return AbsFloat64; } BinaryenOp BinaryenCeilFloat64(void) { return CeilFloat64; } BinaryenOp BinaryenFloorFloat64(void) { return FloorFloat64; } BinaryenOp BinaryenTruncFloat64(void) { return TruncFloat64; } BinaryenOp BinaryenNearestFloat64(void) { return NearestFloat64; } BinaryenOp BinaryenSqrtFloat64(void) { return SqrtFloat64; } BinaryenOp BinaryenEqZInt64(void) { return EqZInt64; } BinaryenOp BinaryenExtendSInt32(void) { return ExtendSInt32; } BinaryenOp BinaryenExtendUInt32(void) { return ExtendUInt32; } BinaryenOp BinaryenWrapInt64(void) { return WrapInt64; } BinaryenOp BinaryenTruncSFloat32ToInt32(void) { return TruncSFloat32ToInt32; } BinaryenOp BinaryenTruncSFloat32ToInt64(void) { return TruncSFloat32ToInt64; } BinaryenOp BinaryenTruncUFloat32ToInt32(void) { return TruncUFloat32ToInt32; } BinaryenOp BinaryenTruncUFloat32ToInt64(void) { return TruncUFloat32ToInt64; } BinaryenOp BinaryenTruncSFloat64ToInt32(void) { return TruncSFloat64ToInt32; } BinaryenOp BinaryenTruncSFloat64ToInt64(void) { return TruncSFloat64ToInt64; } BinaryenOp BinaryenTruncUFloat64ToInt32(void) { return TruncUFloat64ToInt32; } BinaryenOp BinaryenTruncUFloat64ToInt64(void) { return TruncUFloat64ToInt64; } BinaryenOp BinaryenReinterpretFloat32(void) { return ReinterpretFloat32; } BinaryenOp BinaryenReinterpretFloat64(void) { return ReinterpretFloat64; } BinaryenOp BinaryenConvertSInt32ToFloat32(void) { return ConvertSInt32ToFloat32; } BinaryenOp BinaryenConvertSInt32ToFloat64(void) { return ConvertSInt32ToFloat64; } BinaryenOp BinaryenConvertUInt32ToFloat32(void) { return ConvertUInt32ToFloat32; } BinaryenOp BinaryenConvertUInt32ToFloat64(void) { return ConvertUInt32ToFloat64; } BinaryenOp BinaryenConvertSInt64ToFloat32(void) { return ConvertSInt64ToFloat32; } BinaryenOp BinaryenConvertSInt64ToFloat64(void) { return ConvertSInt64ToFloat64; } BinaryenOp BinaryenConvertUInt64ToFloat32(void) { return ConvertUInt64ToFloat32; } BinaryenOp BinaryenConvertUInt64ToFloat64(void) { return ConvertUInt64ToFloat64; } BinaryenOp BinaryenPromoteFloat32(void) { return PromoteFloat32; } BinaryenOp BinaryenDemoteFloat64(void) { return DemoteFloat64; } BinaryenOp BinaryenReinterpretInt32(void) { return ReinterpretInt32; } BinaryenOp BinaryenReinterpretInt64(void) { return ReinterpretInt64; } BinaryenOp BinaryenAddInt32(void) { return AddInt32; } BinaryenOp BinaryenSubInt32(void) { return SubInt32; } BinaryenOp BinaryenMulInt32(void) { return MulInt32; } BinaryenOp BinaryenDivSInt32(void) { return DivSInt32; } BinaryenOp BinaryenDivUInt32(void) { return DivUInt32; } BinaryenOp BinaryenRemSInt32(void) { return RemSInt32; } BinaryenOp BinaryenRemUInt32(void) { return RemUInt32; } BinaryenOp BinaryenAndInt32(void) { return AndInt32; } BinaryenOp BinaryenOrInt32(void) { return OrInt32; } BinaryenOp BinaryenXorInt32(void) { return XorInt32; } BinaryenOp BinaryenShlInt32(void) { return ShlInt32; } BinaryenOp BinaryenShrUInt32(void) { return ShrUInt32; } BinaryenOp BinaryenShrSInt32(void) { return ShrSInt32; } BinaryenOp BinaryenRotLInt32(void) { return RotLInt32; } BinaryenOp BinaryenRotRInt32(void) { return RotRInt32; } BinaryenOp BinaryenEqInt32(void) { return EqInt32; } BinaryenOp BinaryenNeInt32(void) { return NeInt32; } BinaryenOp BinaryenLtSInt32(void) { return LtSInt32; } BinaryenOp BinaryenLtUInt32(void) { return LtUInt32; } BinaryenOp BinaryenLeSInt32(void) { return LeSInt32; } BinaryenOp BinaryenLeUInt32(void) { return LeUInt32; } BinaryenOp BinaryenGtSInt32(void) { return GtSInt32; } BinaryenOp BinaryenGtUInt32(void) { return GtUInt32; } BinaryenOp BinaryenGeSInt32(void) { return GeSInt32; } BinaryenOp BinaryenGeUInt32(void) { return GeUInt32; } BinaryenOp BinaryenAddInt64(void) { return AddInt64; } BinaryenOp BinaryenSubInt64(void) { return SubInt64; } BinaryenOp BinaryenMulInt64(void) { return MulInt64; } BinaryenOp BinaryenDivSInt64(void) { return DivSInt64; } BinaryenOp BinaryenDivUInt64(void) { return DivUInt64; } BinaryenOp BinaryenRemSInt64(void) { return RemSInt64; } BinaryenOp BinaryenRemUInt64(void) { return RemUInt64; } BinaryenOp BinaryenAndInt64(void) { return AndInt64; } BinaryenOp BinaryenOrInt64(void) { return OrInt64; } BinaryenOp BinaryenXorInt64(void) { return XorInt64; } BinaryenOp BinaryenShlInt64(void) { return ShlInt64; } BinaryenOp BinaryenShrUInt64(void) { return ShrUInt64; } BinaryenOp BinaryenShrSInt64(void) { return ShrSInt64; } BinaryenOp BinaryenRotLInt64(void) { return RotLInt64; } BinaryenOp BinaryenRotRInt64(void) { return RotRInt64; } BinaryenOp BinaryenEqInt64(void) { return EqInt64; } BinaryenOp BinaryenNeInt64(void) { return NeInt64; } BinaryenOp BinaryenLtSInt64(void) { return LtSInt64; } BinaryenOp BinaryenLtUInt64(void) { return LtUInt64; } BinaryenOp BinaryenLeSInt64(void) { return LeSInt64; } BinaryenOp BinaryenLeUInt64(void) { return LeUInt64; } BinaryenOp BinaryenGtSInt64(void) { return GtSInt64; } BinaryenOp BinaryenGtUInt64(void) { return GtUInt64; } BinaryenOp BinaryenGeSInt64(void) { return GeSInt64; } BinaryenOp BinaryenGeUInt64(void) { return GeUInt64; } BinaryenOp BinaryenAddFloat32(void) { return AddFloat32; } BinaryenOp BinaryenSubFloat32(void) { return SubFloat32; } BinaryenOp BinaryenMulFloat32(void) { return MulFloat32; } BinaryenOp BinaryenDivFloat32(void) { return DivFloat32; } BinaryenOp BinaryenCopySignFloat32(void) { return CopySignFloat32; } BinaryenOp BinaryenMinFloat32(void) { return MinFloat32; } BinaryenOp BinaryenMaxFloat32(void) { return MaxFloat32; } BinaryenOp BinaryenEqFloat32(void) { return EqFloat32; } BinaryenOp BinaryenNeFloat32(void) { return NeFloat32; } BinaryenOp BinaryenLtFloat32(void) { return LtFloat32; } BinaryenOp BinaryenLeFloat32(void) { return LeFloat32; } BinaryenOp BinaryenGtFloat32(void) { return GtFloat32; } BinaryenOp BinaryenGeFloat32(void) { return GeFloat32; } BinaryenOp BinaryenAddFloat64(void) { return AddFloat64; } BinaryenOp BinaryenSubFloat64(void) { return SubFloat64; } BinaryenOp BinaryenMulFloat64(void) { return MulFloat64; } BinaryenOp BinaryenDivFloat64(void) { return DivFloat64; } BinaryenOp BinaryenCopySignFloat64(void) { return CopySignFloat64; } BinaryenOp BinaryenMinFloat64(void) { return MinFloat64; } BinaryenOp BinaryenMaxFloat64(void) { return MaxFloat64; } BinaryenOp BinaryenEqFloat64(void) { return EqFloat64; } BinaryenOp BinaryenNeFloat64(void) { return NeFloat64; } BinaryenOp BinaryenLtFloat64(void) { return LtFloat64; } BinaryenOp BinaryenLeFloat64(void) { return LeFloat64; } BinaryenOp BinaryenGtFloat64(void) { return GtFloat64; } BinaryenOp BinaryenGeFloat64(void) { return GeFloat64; } 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(); if (name) ret->name = name; for (BinaryenIndex i = 0; i < numChildren; i++) { ret->list.push_back((Expression*)children[i]); } ret->finalize(); if (tracing) { std::cout << " {\n"; std::cout << " BinaryenExpressionRef children[] = { "; for (BinaryenIndex i = 0; i < numChildren; i++) { if (i > 0) std::cout << ", "; std::cout << "expressions[" << expressions[children[i]] << "]"; } if (numChildren == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS std::cout << " };\n"; auto id = noteExpression(ret); std::cout << " expressions[" << id << "] = BinaryenBlock(the_module, "; traceNameOrNULL(name); std::cout << ", children, " << numChildren << ");\n"; std::cout << " }\n"; } return static_cast(ret); } BinaryenExpressionRef BinaryenIf(BinaryenModuleRef module, BinaryenExpressionRef condition, BinaryenExpressionRef ifTrue, BinaryenExpressionRef ifFalse) { auto* ret = ((Module*)module)->allocator.alloc(); ret->condition = (Expression*)condition; ret->ifTrue = (Expression*)ifTrue; ret->ifFalse = (Expression*)ifFalse; ret->finalize(); if (tracing) { auto id = noteExpression(ret); std::cout << " expressions[" << id << "] = BinaryenIf(the_module, expressions[" << expressions[condition] << "], expressions[" << expressions[ifTrue] << "], expressions[" << expressions[ifFalse] << "]);\n"; } return static_cast(ret); } BinaryenExpressionRef BinaryenLoop(BinaryenModuleRef module, const char* name, BinaryenExpressionRef body) { auto* ret = Builder(*((Module*)module)).makeLoop(name ? Name(name) : Name(), (Expression*)body); if (tracing) { auto id = noteExpression(ret); std::cout << " expressions[" << id << "] = BinaryenLoop(the_module, "; traceNameOrNULL(name); std::cout << ", expressions[" << expressions[body] << "]);\n"; } return static_cast(ret); } BinaryenExpressionRef BinaryenBreak(BinaryenModuleRef module, const char* name, BinaryenExpressionRef condition, BinaryenExpressionRef value) { auto* ret = Builder(*((Module*)module)).makeBreak(name, (Expression*)value, (Expression*)condition); if (tracing) { auto id = noteExpression(ret); std::cout << " expressions[" << id << "] = BinaryenBreak(the_module, \"" << name << "\", expressions[" << expressions[condition] << "], expressions[" << expressions[value] << "]);\n"; } return static_cast(ret); } BinaryenExpressionRef BinaryenSwitch(BinaryenModuleRef module, const char **names, BinaryenIndex numNames, const char* defaultName, BinaryenExpressionRef condition, BinaryenExpressionRef value) { auto* ret = ((Module*)module)->allocator.alloc(); if (tracing) { std::cout << " {\n"; std::cout << " const char* names[] = { "; for (BinaryenIndex i = 0; i < numNames; i++) { if (i > 0) std::cout << ", "; std::cout << "\"" << names[i] << "\""; } if (numNames == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS std::cout << " };\n"; auto id = noteExpression(ret); std::cout << " expressions[" << id << "] = BinaryenSwitch(the_module, names, " << numNames << ", \"" << defaultName << "\", expressions[" << expressions[condition] << "], expressions[" << expressions[value] << "]);\n"; std::cout << " }\n"; } 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 static_cast(ret); } BinaryenExpressionRef BinaryenCall(BinaryenModuleRef module, const char *target, BinaryenExpressionRef* operands, BinaryenIndex numOperands, BinaryenType returnType) { auto* ret = ((Module*)module)->allocator.alloc(); if (tracing) { std::cout << " {\n"; std::cout << " BinaryenExpressionRef operands[] = { "; for (BinaryenIndex i = 0; i < numOperands; i++) { if (i > 0) std::cout << ", "; std::cout << "expressions[" << expressions[operands[i]] << "]"; } if (numOperands == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS std::cout << " };\n"; auto id = noteExpression(ret); std::cout << " expressions[" << id << "] = BinaryenCall(the_module, \"" << target << "\", operands, " << numOperands << ", " << returnType << ");\n"; std::cout << " }\n"; } ret->target = target; for (BinaryenIndex i = 0; i < numOperands; i++) { ret->operands.push_back((Expression*)operands[i]); } ret->type = WasmType(returnType); ret->finalize(); return static_cast(ret); } BinaryenExpressionRef BinaryenCallImport(BinaryenModuleRef module, const char *target, BinaryenExpressionRef* operands, BinaryenIndex numOperands, BinaryenType returnType) { auto* ret = ((Module*)module)->allocator.alloc(); if (tracing) { std::cout << " {\n"; std::cout << " BinaryenExpressionRef operands[] = { "; for (BinaryenIndex i = 0; i < numOperands; i++) { if (i > 0) std::cout << ", "; std::cout << "expressions[" << expressions[operands[i]] << "]"; } if (numOperands == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS std::cout << " };\n"; auto id = noteExpression(ret); std::cout << " expressions[" << id << "] = BinaryenCallImport(the_module, \"" << target << "\", operands, " << numOperands << ", " << returnType << ");\n"; std::cout << " }\n"; } ret->target = target; for (BinaryenIndex i = 0; i < numOperands; i++) { ret->operands.push_back((Expression*)operands[i]); } ret->type = WasmType(returnType); ret->finalize(); return static_cast(ret); } BinaryenExpressionRef BinaryenCallIndirect(BinaryenModuleRef module, BinaryenExpressionRef target, BinaryenExpressionRef* operands, BinaryenIndex numOperands, const char* type) { auto* wasm = (Module*)module; auto* ret = wasm->allocator.alloc(); if (tracing) { std::cout << " {\n"; std::cout << " BinaryenExpressionRef operands[] = { "; for (BinaryenIndex i = 0; i < numOperands; i++) { if (i > 0) std::cout << ", "; std::cout << "expressions[" << expressions[operands[i]] << "]"; } if (numOperands == 0) std::cout << "0"; // ensure the array is not empty, otherwise a compiler error on VS std::cout << " };\n"; auto id = noteExpression(ret); std::cout << " expressions[" << id << "] = BinaryenCallIndirect(the_module, expressions[" << expressions[target] << "], operands, " << numOperands << ", \"" << type << "\");\n"; std::cout << " }\n"; } ret->target = (Expression*)target; for (BinaryenIndex i = 0; i < numOperands; i++) { ret->operands.push_back((Expression*)operands[i]); } ret->fullType = type; ret->type = wasm->getFunctionType(ret->fullType)->result; return static_cast(ret); } BinaryenExpressionRef BinaryenGetLocal(BinaryenModuleRef module, BinaryenIndex index, BinaryenType type) { auto* ret = ((Module*)module)->allocator.alloc(); if (tracing) { auto id = noteExpression(ret); std::cout << " expressions[" << id << "] = BinaryenGetLocal(the_module, " << index << ", " << type << ");\n"; } ret->index = index; ret->type = WasmType(type); ret->finalize(); return static_cast(ret); } BinaryenExpressionRef BinaryenSetLocal(BinaryenModuleRef module, BinaryenIndex index, BinaryenExpressionRef value) { auto* ret = ((Module*)module)->allocator.alloc(); if (tracing) { auto id = noteExpression(ret); std::cout << " expressions[" << id << "] = BinaryenSetLocal(the_module, " << index << ", expressions[" << expressions[value] << "]);\n"; } ret->index = index; ret->value = (Expression*)value; ret->setTee(false); ret->finalize(); return static_cast(ret); } BinaryenExpressionRef BinaryenTeeLocal(BinaryenModuleRef module, BinaryenIndex index, BinaryenExpressionRef value) { auto* ret = ((Module*)module)->allocator.alloc(); if (tracing) { auto id = noteExpression(ret); std::cout << " expressions[" << id << "] = BinaryenTeeLocal(the_module, " << index << ", expressions[" << expressions[value] << "]);\n"; } ret->index = index; ret->value = (Expression*)value; ret->setTee(true); ret->finalize(); return static_cast(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(); if (tracing) { auto id = noteExpression(ret); std::cout << " expressions[" << id << "] = BinaryenLoad(the_module, " << bytes << ", " << int(signed_) << ", " << offset << ", " << align << ", " << type << ", expressions[" << expressions[ptr] << "]);\n"; } 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 static_cast(ret); } BinaryenExpressionRef BinaryenStore(BinaryenModuleRef module, uint32_t bytes, uint32_t offset, uint32_t align, BinaryenExpressionRef ptr, BinaryenExpressionRef value, BinaryenType type) { auto* ret = ((Module*)module)->allocator.alloc(); if (tracing) { auto id = noteExpression(ret); std::cout << " expressions[" << id << "] = BinaryenStore(the_module, " << bytes << ", " << offset << ", " << align << ", expressions[" << expressions[ptr] << "], expressions[" << expressions[value] << "], " << type << ");\n"; } ret->bytes = bytes; ret->offset = offset; ret->align = align ? align : bytes; ret->ptr = (Expression*)ptr; ret->value = (Expression*)value; ret->valueType = WasmType(type); ret->finalize(); return static_cast(ret); } BinaryenExpressionRef BinaryenConst(BinaryenModuleRef module, BinaryenLiteral value) { auto* ret = Builder(*((Module*)module)).makeConst(fromBinaryenLiteral(value)); if (tracing) { auto id = noteExpression(ret); switch (value.type) { case WasmType::i32: std::cout << " expressions[" << id << "] = BinaryenConst(the_module, BinaryenLiteralInt32(" << value.i32 << "));\n"; break; case WasmType::i64: std::cout << " expressions[" << id << "] = BinaryenConst(the_module, BinaryenLiteralInt64(" << value.i64 << "));\n"; break; case WasmType::f32: { std::cout << " expressions[" << id << "] = BinaryenConst(the_module, BinaryenLiteralFloat32("; if (std::isnan(value.f32)) std::cout << "NAN"; else std::cout << value.f32; std::cout << "));\n"; break; } case WasmType::f64: { std::cout << " expressions[" << id << "] = BinaryenConst(the_module, BinaryenLiteralFloat64("; if (std::isnan(value.f64)) std::cout << "NAN"; else std::cout << value.f64; std::cout << "));\n"; break; } default: WASM_UNREACHABLE(); } } return static_cast(ret); } BinaryenExpressionRef BinaryenUnary(BinaryenModuleRef module, BinaryenOp op, BinaryenExpressionRef value) { auto* ret = Builder(*((Module*)module)).makeUnary(UnaryOp(op), (Expression*)value); if (tracing) { auto id = noteExpression(ret); std::cout << " expressions[" << id << "] = BinaryenUnary(the_module, " << op << ", expressions[" << expressions[value] << "]);\n"; } return static_cast(ret); } BinaryenExpressionRef BinaryenBinary(BinaryenModuleRef module, BinaryenOp op, BinaryenExpressionRef left, BinaryenExpressionRef right) { auto* ret = Builder(*((Module*)module)).makeBinary(BinaryOp(op), (Expression*)left, (Expression*)right); if (tracing) { auto id = noteExpression(ret); std::cout << " expressions[" << id << "] = BinaryenBinary(the_module, " << op << ", expressions[" << expressions[left] << "], expressions[" << expressions[right] << "]);\n"; } return static_cast(ret); } BinaryenExpressionRef BinaryenSelect(BinaryenModuleRef module, BinaryenExpressionRef condition, BinaryenExpressionRef ifTrue, BinaryenExpressionRef ifFalse) { auto* ret = ((Module*)module)->allocator.alloc