diff options
-rw-r--r-- | src/wasm2asm.h | 277 | ||||
-rw-r--r-- | test/float-ops.2asm.js | 294 | ||||
-rw-r--r-- | test/wasm2asm/float-ops.wast | 84 |
3 files changed, 554 insertions, 101 deletions
diff --git a/src/wasm2asm.h b/src/wasm2asm.h index fd7a03234..346c1c677 100644 --- a/src/wasm2asm.h +++ b/src/wasm2asm.h @@ -1400,6 +1400,12 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) { visit(curr->value, EXPRESSION_RESULT) ); break; + case PromoteFloat32: + return makeAsmCoercion(visit(curr->value, EXPRESSION_RESULT), + ASM_DOUBLE); + case DemoteFloat64: + return makeAsmCoercion(visit(curr->value, EXPRESSION_RESULT), + ASM_FLOAT); // TODO: more complex unary conversions default: std::cerr << "Unhandled unary float operator: " << curr @@ -1438,112 +1444,181 @@ Ref Wasm2AsmBuilder::processFunctionBody(Function* func, IString result) { Ref left = visit(curr->left, EXPRESSION_RESULT); Ref right = visit(curr->right, EXPRESSION_RESULT); Ref ret; - switch (curr->op) { - case AddInt32: - ret = ValueBuilder::makeBinary(left, PLUS, right); - break; - case SubInt32: - ret = ValueBuilder::makeBinary(left, MINUS, right); - break; - case MulInt32: { - if (curr->type == i32) { - // TODO: when one operand is a small int, emit a multiply - return ValueBuilder::makeCall(MATH_IMUL, left, right); - } else { - return ValueBuilder::makeBinary(left, MUL, right); + switch (curr->type) { + case i32: { + switch (curr->op) { + case AddInt32: + ret = ValueBuilder::makeBinary(left, PLUS, right); + break; + case SubInt32: + ret = ValueBuilder::makeBinary(left, MINUS, right); + break; + case MulInt32: { + if (curr->type == i32) { + // TODO: when one operand is a small int, emit a multiply + return ValueBuilder::makeCall(MATH_IMUL, left, right); + } else { + return ValueBuilder::makeBinary(left, MUL, right); + } + } + case DivSInt32: + ret = ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), DIV, + makeSigning(right, ASM_SIGNED)); + break; + case DivUInt32: + ret = ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), DIV, + makeSigning(right, ASM_UNSIGNED)); + break; + case RemSInt32: + ret = ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), MOD, + makeSigning(right, ASM_SIGNED)); + break; + case RemUInt32: + ret = ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), MOD, + makeSigning(right, ASM_UNSIGNED)); + break; + case AndInt32: + ret = ValueBuilder::makeBinary(left, AND, right); + break; + case OrInt32: + ret = ValueBuilder::makeBinary(left, OR, right); + break; + case XorInt32: + ret = ValueBuilder::makeBinary(left, XOR, right); + break; + case ShlInt32: + ret = ValueBuilder::makeBinary(left, LSHIFT, right); + break; + case ShrUInt32: + ret = ValueBuilder::makeBinary(left, TRSHIFT, right); + break; + case ShrSInt32: + ret = ValueBuilder::makeBinary(left, RSHIFT, right); + break; + case EqInt32: { + // TODO: check if this condition is still valid/necessary + if (curr->left->type == i32) { + return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), EQ, + makeSigning(right, ASM_SIGNED)); + } else { + return ValueBuilder::makeBinary(left, EQ, right); + } + } + case NeInt32: { + if (curr->left->type == i32) { + return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), NE, + makeSigning(right, ASM_SIGNED)); + } else { + return ValueBuilder::makeBinary(left, NE, right); + } + } + case LtSInt32: + return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), LT, + makeSigning(right, ASM_SIGNED)); + case LtUInt32: + return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), LT, + makeSigning(right, ASM_UNSIGNED)); + case LeSInt32: + return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), LE, + makeSigning(right, ASM_SIGNED)); + case LeUInt32: + return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), LE, + makeSigning(right, ASM_UNSIGNED)); + case GtSInt32: + return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), GT, + makeSigning(right, ASM_SIGNED)); + case GtUInt32: + return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), GT, + makeSigning(right, ASM_UNSIGNED)); + case GeSInt32: + return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), GE, + makeSigning(right, ASM_SIGNED)); + case GeUInt32: + return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), GE, + makeSigning(right, ASM_UNSIGNED)); + case RotLInt32: + return makeSigning(ValueBuilder::makeCall(WASM_ROTL32, left, right), + ASM_SIGNED); + case RotRInt32: + return makeSigning(ValueBuilder::makeCall(WASM_ROTR32, left, right), + ASM_SIGNED); + case EqFloat32: + return makeAsmCoercion(ValueBuilder::makeBinary(left, EQ, right), + ASM_FLOAT); + case EqFloat64: + return ValueBuilder::makeBinary(left, EQ, right); + case NeFloat32: + return makeAsmCoercion(ValueBuilder::makeBinary(left, NE, right), + ASM_FLOAT); + case NeFloat64: + return ValueBuilder::makeBinary(left, NE, right); + case GeFloat32: + return makeAsmCoercion(ValueBuilder::makeBinary(left, GE, right), + ASM_FLOAT); + case GeFloat64: + return ValueBuilder::makeBinary(left, GE, right); + case GtFloat32: + return makeAsmCoercion(ValueBuilder::makeBinary(left, GT, right), + ASM_FLOAT); + case GtFloat64: + return ValueBuilder::makeBinary(left, GT, right); + case LeFloat32: + return makeAsmCoercion(ValueBuilder::makeBinary(left, LE, right), + ASM_FLOAT); + case LeFloat64: + return ValueBuilder::makeBinary(left, LE, right); + case LtFloat32: + return makeAsmCoercion(ValueBuilder::makeBinary(left, LT, right), + ASM_FLOAT); + case LtFloat64: + return ValueBuilder::makeBinary(left, LT, right); + default: { + std::cerr << "Unhandled i32 binary operator: " << curr << std::endl; + abort(); + } } - } - case DivSInt32: - ret = ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), DIV, - makeSigning(right, ASM_SIGNED)); - break; - case DivUInt32: - ret = ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), DIV, - makeSigning(right, ASM_UNSIGNED)); - break; - case RemSInt32: - ret = ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), MOD, - makeSigning(right, ASM_SIGNED)); - break; - case RemUInt32: - ret = ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), MOD, - makeSigning(right, ASM_UNSIGNED)); - break; - case AndInt32: - ret = ValueBuilder::makeBinary(left, AND, right); - break; - case OrInt32: - ret = ValueBuilder::makeBinary(left, OR, right); - break; - case XorInt32: - ret = ValueBuilder::makeBinary(left, XOR, right); - break; - case ShlInt32: - ret = ValueBuilder::makeBinary(left, LSHIFT, right); break; - case ShrUInt32: - ret = ValueBuilder::makeBinary(left, TRSHIFT, right); - break; - case ShrSInt32: - ret = ValueBuilder::makeBinary(left, RSHIFT, right); - break; - case MinFloat32: - ret = ValueBuilder::makeCall(MATH_MIN, left, right); - break; - case MaxFloat32: - ret = ValueBuilder::makeCall(MATH_MAX, left, right); - break; - case EqInt32: { - // TODO: check if this condition is still valid/necessary - if (curr->left->type == i32) { - return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), EQ, - makeSigning(right, ASM_SIGNED)); - } else { - return ValueBuilder::makeBinary(left, EQ, right); - } } - case NeInt32: { - if (curr->left->type == i32) { - return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), NE, - makeSigning(right, ASM_SIGNED)); - } else { - return ValueBuilder::makeBinary(left, NE, right); + case f32: + case f64: + switch (curr->op) { + case AddFloat32: + case AddFloat64: + ret = ValueBuilder::makeBinary(left, PLUS, right); + break; + case SubFloat32: + case SubFloat64: + ret = ValueBuilder::makeBinary(left, MINUS, right); + break; + case MulFloat32: + case MulFloat64: + ret = ValueBuilder::makeBinary(left, MUL, right); + break; + case DivFloat32: + case DivFloat64: + ret = ValueBuilder::makeBinary(left, DIV, right); + break; + case MinFloat32: + case MinFloat64: + ret = ValueBuilder::makeCall(MATH_MIN, left, right); + break; + case MaxFloat32: + case MaxFloat64: + ret = ValueBuilder::makeCall(MATH_MAX, left, right); + break; + case CopySignFloat32: + case CopySignFloat64: + default: + std::cerr << "Unhandled binary float operator: " << curr << std::endl; + abort(); } - } - case LtSInt32: - return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), LT, - makeSigning(right, ASM_SIGNED)); - case LtUInt32: - return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), LT, - makeSigning(right, ASM_UNSIGNED)); - case LeSInt32: - return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), LE, - makeSigning(right, ASM_SIGNED)); - case LeUInt32: - return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), LE, - makeSigning(right, ASM_UNSIGNED)); - case GtSInt32: - return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), GT, - makeSigning(right, ASM_SIGNED)); - case GtUInt32: - return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), GT, - makeSigning(right, ASM_UNSIGNED)); - case GeSInt32: - return ValueBuilder::makeBinary(makeSigning(left, ASM_SIGNED), GE, - makeSigning(right, ASM_SIGNED)); - case GeUInt32: - return ValueBuilder::makeBinary(makeSigning(left, ASM_UNSIGNED), GE, - makeSigning(right, ASM_UNSIGNED)); - case RotLInt32: - return makeSigning(ValueBuilder::makeCall(WASM_ROTL32, left, right), - ASM_SIGNED); - case RotRInt32: - return makeSigning(ValueBuilder::makeCall(WASM_ROTR32, left, right), - ASM_SIGNED); - default: { - std::cerr << "Unhandled binary operator: " << curr << std::endl; + if (curr->type == f32) { + return makeAsmCoercion(ret, ASM_FLOAT); + } + return ret; + default: + std::cerr << "Unhandled type in binary: " << curr << std::endl; abort(); - } } return makeAsmCoercion(ret, wasmToAsmType(curr->type)); } diff --git a/test/float-ops.2asm.js b/test/float-ops.2asm.js new file mode 100644 index 000000000..5cad310f9 --- /dev/null +++ b/test/float-ops.2asm.js @@ -0,0 +1,294 @@ +function asmFunc(global, env, buffer) { + "use asm"; + var HEAP8 = new global.Int8Array(buffer); + var HEAP16 = new global.Int16Array(buffer); + var HEAP32 = new global.Int32Array(buffer); + var HEAPU8 = new global.Uint8Array(buffer); + var HEAPU16 = new global.Uint16Array(buffer); + var HEAPU32 = new global.Uint32Array(buffer); + var HEAPF32 = new global.Float32Array(buffer); + var HEAPF64 = new global.Float64Array(buffer); + var Math_imul = global.Math.imul; + var Math_fround = global.Math.fround; + var Math_abs = global.Math.abs; + var Math_clz32 = global.Math.clz32; + function dummy() { + + } + + function $$1($$0, $$1) { + $$0 = Math_fround($$0); + $$1 = Math_fround($$1); + var $$2 = Math_fround(0), $$3 = Math_fround(0), $$4 = Math_fround(0), wasm2asm_f32$0 = Math_fround(0); + return Math_fround(Math_fround($$0 + $$1)); + return Math_fround(wasm2asm_f32$0); + } + + function $$2($$0, $$1) { + $$0 = Math_fround($$0); + $$1 = Math_fround($$1); + var $$2 = Math_fround(0), $$3 = Math_fround(0), $$4 = Math_fround(0), wasm2asm_f32$0 = Math_fround(0); + return Math_fround(Math_fround($$0 - $$1)); + return Math_fround(wasm2asm_f32$0); + } + + function $$3($$0, $$1) { + $$0 = Math_fround($$0); + $$1 = Math_fround($$1); + var $$2 = Math_fround(0), $$3 = Math_fround(0), $$4 = Math_fround(0), wasm2asm_f32$0 = Math_fround(0); + return Math_fround(Math_fround($$0 * $$1)); + return Math_fround(wasm2asm_f32$0); + } + + function $$4($$0, $$1) { + $$0 = Math_fround($$0); + $$1 = Math_fround($$1); + var $$2 = Math_fround(0), $$3 = Math_fround(0), $$4 = Math_fround(0), wasm2asm_f32$0 = Math_fround(0); + return Math_fround(Math_fround($$0 / $$1)); + return Math_fround(wasm2asm_f32$0); + } + + function $$5($$0, $$1) { + $$0 = +$$0; + $$1 = +$$1; + var $$2 = 0.0, $$3 = 0.0, $$4 = 0.0, wasm2asm_f64$0 = 0.0; + return +($$0 + $$1); + return +wasm2asm_f64$0; + } + + function $$6($$0, $$1) { + $$0 = +$$0; + $$1 = +$$1; + var $$2 = 0.0, $$3 = 0.0, $$4 = 0.0, wasm2asm_f64$0 = 0.0; + return +($$0 - $$1); + return +wasm2asm_f64$0; + } + + function $$7($$0, $$1) { + $$0 = +$$0; + $$1 = +$$1; + var $$2 = 0.0, $$3 = 0.0, $$4 = 0.0, wasm2asm_f64$0 = 0.0; + return +($$0 * $$1); + return +wasm2asm_f64$0; + } + + function $$8($$0, $$1) { + $$0 = +$$0; + $$1 = +$$1; + var $$2 = 0.0, $$3 = 0.0, $$4 = 0.0, wasm2asm_f64$0 = 0.0; + return +($$0 / $$1); + return +wasm2asm_f64$0; + } + + function $$9($$0, $$1) { + $$0 = Math_fround($$0); + $$1 = Math_fround($$1); + var $$2 = Math_fround(0), $$3 = Math_fround(0), $$4 = 0, wasm2asm_i32$0 = 0; + return Math_fround($$0 == $$1) | 0; + return wasm2asm_i32$0 | 0; + } + + function $$10($$0, $$1) { + $$0 = Math_fround($$0); + $$1 = Math_fround($$1); + var $$2 = Math_fround(0), $$3 = Math_fround(0), $$4 = 0, wasm2asm_i32$0 = 0; + return Math_fround($$0 != $$1) | 0; + return wasm2asm_i32$0 | 0; + } + + function $$11($$0, $$1) { + $$0 = Math_fround($$0); + $$1 = Math_fround($$1); + var $$2 = Math_fround(0), $$3 = Math_fround(0), $$4 = 0, wasm2asm_i32$0 = 0; + return Math_fround($$0 >= $$1) | 0; + return wasm2asm_i32$0 | 0; + } + + function $$12($$0, $$1) { + $$0 = Math_fround($$0); + $$1 = Math_fround($$1); + var $$2 = Math_fround(0), $$3 = Math_fround(0), $$4 = 0, wasm2asm_i32$0 = 0; + return Math_fround($$0 > $$1) | 0; + return wasm2asm_i32$0 | 0; + } + + function $$13($$0, $$1) { + $$0 = Math_fround($$0); + $$1 = Math_fround($$1); + var $$2 = Math_fround(0), $$3 = Math_fround(0), $$4 = 0, wasm2asm_i32$0 = 0; + return Math_fround($$0 <= $$1) | 0; + return wasm2asm_i32$0 | 0; + } + + function $$14($$0, $$1) { + $$0 = Math_fround($$0); + $$1 = Math_fround($$1); + var $$2 = Math_fround(0), $$3 = Math_fround(0), $$4 = 0, wasm2asm_i32$0 = 0; + return Math_fround($$0 < $$1) | 0; + return wasm2asm_i32$0 | 0; + } + + function $$15($$0, $$1) { + $$0 = +$$0; + $$1 = +$$1; + var $$2 = 0.0, $$3 = 0.0, $$4 = 0, wasm2asm_i32$0 = 0; + return $$0 == $$1 | 0; + return wasm2asm_i32$0 | 0; + } + + function $$16($$0, $$1) { + $$0 = +$$0; + $$1 = +$$1; + var $$2 = 0.0, $$3 = 0.0, $$4 = 0, wasm2asm_i32$0 = 0; + return $$0 != $$1 | 0; + return wasm2asm_i32$0 | 0; + } + + function $$17($$0, $$1) { + $$0 = +$$0; + $$1 = +$$1; + var $$2 = 0.0, $$3 = 0.0, $$4 = 0, wasm2asm_i32$0 = 0; + return $$0 >= $$1 | 0; + return wasm2asm_i32$0 | 0; + } + + function $$18($$0, $$1) { + $$0 = +$$0; + $$1 = +$$1; + var $$2 = 0.0, $$3 = 0.0, $$4 = 0, wasm2asm_i32$0 = 0; + return $$0 > $$1 | 0; + return wasm2asm_i32$0 | 0; + } + + function $$19($$0, $$1) { + $$0 = +$$0; + $$1 = +$$1; + var $$2 = 0.0, $$3 = 0.0, $$4 = 0, wasm2asm_i32$0 = 0; + return $$0 <= $$1 | 0; + return wasm2asm_i32$0 | 0; + } + + function $$20($$0, $$1) { + $$0 = +$$0; + $$1 = +$$1; + var $$2 = 0.0, $$3 = 0.0, $$4 = 0, wasm2asm_i32$0 = 0; + return $$0 < $$1 | 0; + return wasm2asm_i32$0 | 0; + } + + function $$21($$0, $$1) { + $$0 = Math_fround($$0); + $$1 = Math_fround($$1); + var $$2 = Math_fround(0), $$3 = Math_fround(0), $$4 = Math_fround(0), wasm2asm_f32$0 = Math_fround(0); + return Math_fround(Math_fround(Math_min($$0, $$1))); + return Math_fround(wasm2asm_f32$0); + } + + function $$22($$0, $$1) { + $$0 = Math_fround($$0); + $$1 = Math_fround($$1); + var $$2 = Math_fround(0), $$3 = Math_fround(0), $$4 = Math_fround(0), wasm2asm_f32$0 = Math_fround(0); + return Math_fround(Math_fround(Math_max($$0, $$1))); + return Math_fround(wasm2asm_f32$0); + } + + function $$23($$0, $$1) { + $$0 = +$$0; + $$1 = +$$1; + var $$2 = 0.0, $$3 = 0.0, $$4 = 0.0, wasm2asm_f64$0 = 0.0; + return +Math_min($$0, $$1); + return +wasm2asm_f64$0; + } + + function $$24($$0, $$1) { + $$0 = +$$0; + $$1 = +$$1; + var $$2 = 0.0, $$3 = 0.0, $$4 = 0.0, wasm2asm_f64$0 = 0.0; + return +Math_max($$0, $$1); + return +wasm2asm_f64$0; + } + + function $$25($$0) { + $$0 = Math_fround($$0); + var $$1 = Math_fround(0), $$2 = 0.0, wasm2asm_f64$0 = 0.0; + return +(+$$0); + return +wasm2asm_f64$0; + } + + function $$26($$0) { + $$0 = +$$0; + var $$1 = 0.0, $$2 = Math_fround(0), wasm2asm_f32$0 = Math_fround(0); + return Math_fround(Math_fround($$0)); + return Math_fround(wasm2asm_f32$0); + } + + function __wasm_ctz_i32(x) { + x = x | 0; + var $$1 = 0, $$2 = 0, $$3 = 0, $$4 = 0, $$5 = 0, $$6 = 0, $$7 = 0, $$8 = 0, $$9 = 0, $$10 = 0; + if ((x | 0) == (0 | 0)) $$9 = 32; else $$9 = 31 - Math_clz32(x ^ (x - 1 | 0) | 0) | 0; + return $$9 | 0; + } + + function __wasm_popcnt_i32(x) { + x = x | 0; + var count = 0, $$2 = 0, $$3 = 0, $$4 = 0, $$5 = 0, $$6 = 0, $$7 = 0, $$8 = 0, $$9 = 0, $$10 = 0, $$11 = 0, $$12 = 0, $$13 = 0, $$14 = 0, $$15 = 0; + count = 0; + b : { + l : do { + $$5 = count; + if ((x | 0) == (0 | 0)) break b; + x = x & (x - 1 | 0) | 0; + count = count + 1 | 0; + continue l; + break l; + } while (1); + }; + return $$5 | 0; + } + + function __wasm_rotl_i32(x, k) { + x = x | 0; + k = k | 0; + var $$2 = 0, $$3 = 0, $$4 = 0, $$5 = 0, $$6 = 0, $$7 = 0, $$8 = 0, $$9 = 0, $$10 = 0, $$11 = 0, $$12 = 0, $$13 = 0, $$14 = 0, $$15 = 0, $$16 = 0, $$17 = 0, $$18 = 0, $$19 = 0, $$20 = 0, wasm2asm_i32$0 = 0; + return ((4294967295 >>> (k & 31 | 0) | 0) & x | 0) << (k & 31 | 0) | 0 | (((4294967295 << (32 - (k & 31 | 0) | 0) | 0) & x | 0) >>> (32 - (k & 31 | 0) | 0) | 0) | 0 | 0; + return wasm2asm_i32$0 | 0; + } + + function __wasm_rotr_i32(x, k) { + x = x | 0; + k = k | 0; + var $$2 = 0, $$3 = 0, $$4 = 0, $$5 = 0, $$6 = 0, $$7 = 0, $$8 = 0, $$9 = 0, $$10 = 0, $$11 = 0, $$12 = 0, $$13 = 0, $$14 = 0, $$15 = 0, $$16 = 0, $$17 = 0, $$18 = 0, $$19 = 0, $$20 = 0, wasm2asm_i32$0 = 0; + return ((4294967295 << (k & 31 | 0) | 0) & x | 0) >>> (k & 31 | 0) | 0 | (((4294967295 >>> (32 - (k & 31 | 0) | 0) | 0) & x | 0) << (32 - (k & 31 | 0) | 0) | 0) | 0 | 0; + return wasm2asm_i32$0 | 0; + } + + return { + "f32.add": $$1, + "f32.sub": $$2, + "f32.mul": $$3, + "f32.div": $$4, + "f64.add": $$5, + "f64.sub": $$6, + "f64.mul": $$7, + "f64.div": $$8, + "f32.eq": $$9, + "f32.ne": $$10, + "f32.ge": $$11, + "f32.gt": $$12, + "f32.le": $$13, + "f32.lt": $$14, + "f64.eq": $$15, + "f64.ne": $$16, + "f64.ge": $$17, + "f64.gt": $$18, + "f64.le": $$19, + "f64.lt": $$20, + "f32.min": $$21, + "f32.max": $$22, + "f64.min": $$23, + "f64.max": $$24, + "f64.promote": $$25, + "f32.demote": $$26 + }; +} + diff --git a/test/wasm2asm/float-ops.wast b/test/wasm2asm/float-ops.wast new file mode 100644 index 000000000..ee8f899e8 --- /dev/null +++ b/test/wasm2asm/float-ops.wast @@ -0,0 +1,84 @@ +(module + (func $dummy) + + (func (export "f32.add") (param $0 f32) (param $1 f32) (result f32) + (f32.add (get_local $0) (get_local $1))) + + (func (export "f32.sub") (param $0 f32) (param $1 f32) (result f32) + (f32.sub (get_local $0) (get_local $1))) + + (func (export "f32.mul") (param $0 f32) (param $1 f32) (result f32) + (f32.mul (get_local $0) (get_local $1))) + + (func (export "f32.div") (param $0 f32) (param $1 f32) (result f32) + (f32.div (get_local $0) (get_local $1))) + + (func (export "f64.add") (param $0 f64) (param $1 f64) (result f64) + (f64.add (get_local $0) (get_local $1))) + + (func (export "f64.sub") (param $0 f64) (param $1 f64) (result f64) + (f64.sub (get_local $0) (get_local $1))) + + (func (export "f64.mul") (param $0 f64) (param $1 f64) (result f64) + (f64.mul (get_local $0) (get_local $1))) + + (func (export "f64.div") (param $0 f64) (param $1 f64) (result f64) + (f64.div (get_local $0) (get_local $1))) + + ;; comparisons + (func (export "f32.eq") (param $0 f32) (param $1 f32) (result i32) + (f32.eq (get_local $0) (get_local $1))) + + (func (export "f32.ne") (param $0 f32) (param $1 f32) (result i32) + (f32.ne (get_local $0) (get_local $1))) + + (func (export "f32.ge") (param $0 f32) (param $1 f32) (result i32) + (f32.ge (get_local $0) (get_local $1))) + + (func (export "f32.gt") (param $0 f32) (param $1 f32) (result i32) + (f32.gt (get_local $0) (get_local $1))) + + (func (export "f32.le") (param $0 f32) (param $1 f32) (result i32) + (f32.le (get_local $0) (get_local $1))) + + (func (export "f32.lt") (param $0 f32) (param $1 f32) (result i32) + (f32.lt (get_local $0) (get_local $1))) + + (func (export "f64.eq") (param $0 f64) (param $1 f64) (result i32) + (f64.eq (get_local $0) (get_local $1))) + + (func (export "f64.ne") (param $0 f64) (param $1 f64) (result i32) + (f64.ne (get_local $0) (get_local $1))) + + (func (export "f64.ge") (param $0 f64) (param $1 f64) (result i32) + (f64.ge (get_local $0) (get_local $1))) + + (func (export "f64.gt") (param $0 f64) (param $1 f64) (result i32) + (f64.gt (get_local $0) (get_local $1))) + + (func (export "f64.le") (param $0 f64) (param $1 f64) (result i32) + (f64.le (get_local $0) (get_local $1))) + + (func (export "f64.lt") (param $0 f64) (param $1 f64) (result i32) + (f64.lt (get_local $0) (get_local $1))) + + ;; min/max + (func (export "f32.min") (param $0 f32) (param $1 f32) (result f32) + (f32.min (get_local $0) (get_local $1))) + + (func (export "f32.max") (param $0 f32) (param $1 f32) (result f32) + (f32.max (get_local $0) (get_local $1))) + + (func (export "f64.min") (param $0 f64) (param $1 f64) (result f64) + (f64.min (get_local $0) (get_local $1))) + + (func (export "f64.max") (param $0 f64) (param $1 f64) (result f64) + (f64.max (get_local $0) (get_local $1))) + + ;; promotion/demotion + (func (export "f64.promote") (param $0 f32) (result f64) + (f64.promote/f32 (get_local $0))) + + (func (export "f32.demote") (param $0 f64) (result f32) + (f32.demote/f64 (get_local $0))) +) |