diff --git a/src/asm2wasm.h b/src/asm2wasm.h index e2b1802b53f..9abfe7432b3 100644 --- a/src/asm2wasm.h +++ b/src/asm2wasm.h @@ -675,6 +675,19 @@ class Asm2WasmBuilder { return ret; } + // converts an f32 to an f64 if necessary + Expression* ensureDouble(Expression* expr) { + if (expr->type == f32) { + auto conv = allocator.alloc(); + conv->op = PromoteFloat32; + conv->value = expr; + conv->type = WasmType::f64; + return conv; + } + assert(expr->type == f64); + return expr; + } + // Some binary opts might trap, so emit them safely if necessary Expression* makeTrappingI32Binary(BinaryOp op, Expression* left, Expression* right) { if (trapMode == TrapMode::Allow) return builder.makeBinary(op, left, right); @@ -803,14 +816,7 @@ class Asm2WasmBuilder { } // WebAssembly traps on float-to-int overflows, but asm.js wouldn't, so we must do something // First, normalize input to f64 - auto input = value; - if (input->type == f32) { - auto conv = allocator.alloc(); - conv->op = PromoteFloat32; - conv->value = input; - conv->type = WasmType::f64; - input = conv; - } + auto input = ensureDouble(value); // We can handle this in one of two ways: clamping, which is fast, or JS, which // is precisely like JS but in order to do that we do a slow ffi if (trapMode == TrapMode::JS) { @@ -894,14 +900,7 @@ class Asm2WasmBuilder { } // WebAssembly traps on float-to-int overflows, but asm.js wouldn't, so we must do something // First, normalize input to f64 - auto input = value; - if (input->type == f32) { - auto conv = allocator.alloc(); - conv->op = PromoteFloat32; - conv->value = input; - conv->type = WasmType::f64; - input = conv; - } + auto input = ensureDouble(value); // There is no "JS" way to handle this, as no i64s in JS, so always clamp if we don't allow traps Call *ret = allocator.alloc(); ret->target = F64_TO_INT64; @@ -1795,11 +1794,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { conv->type = WasmType::f32; ret->value = conv; } else if (ret->valueType == f64 && ret->value->type == f32) { - auto conv = allocator.alloc(); - conv->op = PromoteFloat32; - conv->value = ret->value; - conv->type = WasmType::f64; - ret->value = conv; + ret->value = ensureDouble(ret->value); } else { abort_on("bad sub[] types", ast); } @@ -1822,8 +1817,8 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { // WebAssembly does not have floating-point remainder, we have to emit a call to a special import of ours CallImport *call = allocator.alloc(); call->target = F64_REM; - call->operands.push_back(ret->left); - call->operands.push_back(ret->right); + call->operands.push_back(ensureDouble(ret->left)); + call->operands.push_back(ensureDouble(ret->right)); call->type = f64; static bool addedImport = false; if (!addedImport) { @@ -1873,11 +1868,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { return conv; } if (ret->type == f32) { - auto conv = allocator.alloc(); - conv->op = PromoteFloat32; - conv->value = ret; - conv->type = WasmType::f64; - return conv; + return ensureDouble(ret); } fixCallType(ret, f64); return ret; @@ -2485,11 +2476,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { conv->value = process(writtenValue); conv->type = WasmType::f32; if (readType == ASM_DOUBLE) { - auto promote = allocator.alloc(); - promote->op = PromoteFloat32; - promote->value = conv; - promote->type = WasmType::f64; - return promote; + return ensureDouble(conv); } return conv; } else if (writeType == ASM_FLOAT && readType == ASM_INT) { diff --git a/test/unit.asm.js b/test/unit.asm.js index 22e18007848..0655120119a 100644 --- a/test/unit.asm.js +++ b/test/unit.asm.js @@ -137,6 +137,9 @@ function asm(global, env, buffer) { function frem() { return +(5.5 % 1.2); } + function frem_float() { + return Math_fround(Math_fround(5.5) % Math_fround(1.2)); + } function big_uint_div_u() { var x = 0; x = (4294967295 / 2)&-1; @@ -740,6 +743,6 @@ function asm(global, env, buffer) { var FUNCTION_TABLE_vi = [ vi, vi, vi, vi, vi, vi, vi, vi ]; var FUNCTION_TABLE_ii = [ ii ]; - return { big_negative: big_negative, pick: forgetMe, pick: exportMe, doubleCompares: doubleCompares, intOps: intOps, conversions: conversions, switcher: switcher, frem: frem, big_uint_div_u: big_uint_div_u, fr: fr, negZero: negZero, neg: neg, smallCompare: smallCompare, cneg_nosemicolon: cneg_nosemicolon, forLoop: forLoop, ceiling_32_64: ceiling_32_64, aborts: aborts, continues: continues, bitcasts: bitcasts, recursiveBlockMerging: recursiveBlockMerging, lb: lb, zeroInit: zeroInit, phi: phi, smallIf: smallIf, dropCall: dropCall, useSetGlobal: useSetGlobal, usesSetGlobal2: usesSetGlobal2, breakThroughMany: breakThroughMany, ifChainEmpty: ifChainEmpty, heap8NoShift: heap8NoShift, conditionalTypeFun: conditionalTypeFun, loadSigned: loadSigned, globalOpts: globalOpts, dropCallImport: dropCallImport, loophi: loophi, loophi2: loophi2, relooperJumpThreading: relooperJumpThreading, relooperJumpThreading__ZN4game14preloadweaponsEv: relooperJumpThreading__ZN4game14preloadweaponsEv, __Z12multi_varargiz: __Z12multi_varargiz, jumpThreadDrop: jumpThreadDrop, dropIgnoredImportInIf: dropIgnoredImportInIf, dropIgnoredImportsInIf: dropIgnoredImportsInIf, relooperJumpThreading_irreducible: relooperJumpThreading_irreducible, store_fround: store_fround, exportedNumber: 42, relocatableAndModules: relocatableAndModules, exported_f32_user: exported_f32_user, keepAlive: keepAlive }; + return { big_negative: big_negative, pick: forgetMe, pick: exportMe, doubleCompares: doubleCompares, intOps: intOps, conversions: conversions, switcher: switcher, frem: frem, frem_float: frem_float, big_uint_div_u: big_uint_div_u, fr: fr, negZero: negZero, neg: neg, smallCompare: smallCompare, cneg_nosemicolon: cneg_nosemicolon, forLoop: forLoop, ceiling_32_64: ceiling_32_64, aborts: aborts, continues: continues, bitcasts: bitcasts, recursiveBlockMerging: recursiveBlockMerging, lb: lb, zeroInit: zeroInit, phi: phi, smallIf: smallIf, dropCall: dropCall, useSetGlobal: useSetGlobal, usesSetGlobal2: usesSetGlobal2, breakThroughMany: breakThroughMany, ifChainEmpty: ifChainEmpty, heap8NoShift: heap8NoShift, conditionalTypeFun: conditionalTypeFun, loadSigned: loadSigned, globalOpts: globalOpts, dropCallImport: dropCallImport, loophi: loophi, loophi2: loophi2, relooperJumpThreading: relooperJumpThreading, relooperJumpThreading__ZN4game14preloadweaponsEv: relooperJumpThreading__ZN4game14preloadweaponsEv, __Z12multi_varargiz: __Z12multi_varargiz, jumpThreadDrop: jumpThreadDrop, dropIgnoredImportInIf: dropIgnoredImportInIf, dropIgnoredImportsInIf: dropIgnoredImportsInIf, relooperJumpThreading_irreducible: relooperJumpThreading_irreducible, store_fround: store_fround, exportedNumber: 42, relocatableAndModules: relocatableAndModules, exported_f32_user: exported_f32_user, keepAlive: keepAlive }; } diff --git a/test/unit.fromasm b/test/unit.fromasm index 68f5920ee34..020ded16322 100644 --- a/test/unit.fromasm +++ b/test/unit.fromasm @@ -33,6 +33,7 @@ (export "conversions" (func $conversions)) (export "switcher" (func $switcher)) (export "frem" (func $frem)) + (export "frem_float" (func $legalstub$frem_float)) (export "big_uint_div_u" (func $big_uint_div_u)) (export "fr" (func $legalstub$fr)) (export "negZero" (func $negZero)) @@ -245,6 +246,14 @@ (f64.const 1.2) ) ) + (func $frem_float (result f32) + (f32.demote/f64 + (call $f64-rem + (f64.const 5.5) + (f64.const 1.2000000476837158) + ) + ) + ) (func $i32u-div (param $0 i32) (param $1 i32) (result i32) (if (result i32) (get_local $1) @@ -1217,6 +1226,11 @@ (func $ii (param $0 i32) (result i32) (get_local $0) ) + (func $legalstub$frem_float (result f64) + (f64.promote/f32 + (call $frem_float) + ) + ) (func $legalstub$fr (param $0 f64) (call $fr (f32.demote/f64 diff --git a/test/unit.fromasm.clamp b/test/unit.fromasm.clamp index 1442ea94788..06c57775367 100644 --- a/test/unit.fromasm.clamp +++ b/test/unit.fromasm.clamp @@ -31,6 +31,7 @@ (export "conversions" (func $conversions)) (export "switcher" (func $switcher)) (export "frem" (func $frem)) + (export "frem_float" (func $legalstub$frem_float)) (export "big_uint_div_u" (func $big_uint_div_u)) (export "fr" (func $legalstub$fr)) (export "negZero" (func $negZero)) @@ -269,6 +270,14 @@ (f64.const 1.2) ) ) + (func $frem_float (result f32) + (f32.demote/f64 + (call $f64-rem + (f64.const 5.5) + (f64.const 1.2000000476837158) + ) + ) + ) (func $i32u-div (param $0 i32) (param $1 i32) (result i32) (if (result i32) (get_local $1) @@ -1241,6 +1250,11 @@ (func $ii (param $0 i32) (result i32) (get_local $0) ) + (func $legalstub$frem_float (result f64) + (f64.promote/f32 + (call $frem_float) + ) + ) (func $legalstub$fr (param $0 f64) (call $fr (f32.demote/f64 diff --git a/test/unit.fromasm.clamp.no-opts b/test/unit.fromasm.clamp.no-opts index 37456128f5d..393147603fd 100644 --- a/test/unit.fromasm.clamp.no-opts +++ b/test/unit.fromasm.clamp.no-opts @@ -38,6 +38,7 @@ (export "conversions" (func $conversions)) (export "switcher" (func $switcher)) (export "frem" (func $frem)) + (export "frem_float" (func $legalstub$frem_float)) (export "big_uint_div_u" (func $big_uint_div_u)) (export "fr" (func $legalstub$fr)) (export "negZero" (func $negZero)) @@ -407,6 +408,20 @@ ) ) ) + (func $frem_float (result f32) + (return + (f32.demote/f64 + (call $f64-rem + (f64.promote/f32 + (f32.const 5.5) + ) + (f64.promote/f32 + (f32.const 1.2000000476837158) + ) + ) + ) + ) + ) (func $i32u-div (param $0 i32) (param $1 i32) (result i32) (if (result i32) (i32.eqz @@ -2030,6 +2045,11 @@ (get_local $x) ) ) + (func $legalstub$frem_float (result f64) + (f64.promote/f32 + (call $frem_float) + ) + ) (func $legalstub$fr (param $0 f64) (call $fr (f32.demote/f64 diff --git a/test/unit.fromasm.imprecise b/test/unit.fromasm.imprecise index ea664d5f017..8ee0b073f59 100644 --- a/test/unit.fromasm.imprecise +++ b/test/unit.fromasm.imprecise @@ -30,6 +30,7 @@ (export "conversions" (func $big_negative)) (export "switcher" (func $switcher)) (export "frem" (func $frem)) + (export "frem_float" (func $legalstub$frem_float)) (export "big_uint_div_u" (func $big_uint_div_u)) (export "fr" (func $legalstub$fr)) (export "negZero" (func $negZero)) @@ -226,6 +227,14 @@ (f64.const 1.2) ) ) + (func $frem_float (result f32) + (f32.demote/f64 + (call $f64-rem + (f64.const 5.5) + (f64.const 1.2000000476837158) + ) + ) + ) (func $big_uint_div_u (result i32) (i32.const 2147483647) ) @@ -1190,6 +1199,11 @@ (func $ii (param $0 i32) (result i32) (get_local $0) ) + (func $legalstub$frem_float (result f64) + (f64.promote/f32 + (call $frem_float) + ) + ) (func $legalstub$fr (param $0 f64) (call $fr (f32.demote/f64 diff --git a/test/unit.fromasm.imprecise.no-opts b/test/unit.fromasm.imprecise.no-opts index 227cf5e793b..70eece97df4 100644 --- a/test/unit.fromasm.imprecise.no-opts +++ b/test/unit.fromasm.imprecise.no-opts @@ -38,6 +38,7 @@ (export "conversions" (func $conversions)) (export "switcher" (func $switcher)) (export "frem" (func $frem)) + (export "frem_float" (func $legalstub$frem_float)) (export "big_uint_div_u" (func $big_uint_div_u)) (export "fr" (func $legalstub$fr)) (export "negZero" (func $negZero)) @@ -379,6 +380,20 @@ ) ) ) + (func $frem_float (result f32) + (return + (f32.demote/f64 + (call $f64-rem + (f64.promote/f32 + (f32.const 5.5) + ) + (f64.promote/f32 + (f32.const 1.2000000476837158) + ) + ) + ) + ) + ) (func $big_uint_div_u (result i32) (local $x i32) (set_local $x @@ -1990,6 +2005,11 @@ (get_local $x) ) ) + (func $legalstub$frem_float (result f64) + (f64.promote/f32 + (call $frem_float) + ) + ) (func $legalstub$fr (param $0 f64) (call $fr (f32.demote/f64 diff --git a/test/unit.fromasm.no-opts b/test/unit.fromasm.no-opts index 878011cefd2..511e310a399 100644 --- a/test/unit.fromasm.no-opts +++ b/test/unit.fromasm.no-opts @@ -40,6 +40,7 @@ (export "conversions" (func $conversions)) (export "switcher" (func $switcher)) (export "frem" (func $frem)) + (export "frem_float" (func $legalstub$frem_float)) (export "big_uint_div_u" (func $big_uint_div_u)) (export "fr" (func $legalstub$fr)) (export "negZero" (func $negZero)) @@ -383,6 +384,20 @@ ) ) ) + (func $frem_float (result f32) + (return + (f32.demote/f64 + (call $f64-rem + (f64.promote/f32 + (f32.const 5.5) + ) + (f64.promote/f32 + (f32.const 1.2000000476837158) + ) + ) + ) + ) + ) (func $i32u-div (param $0 i32) (param $1 i32) (result i32) (if (result i32) (i32.eqz @@ -2006,6 +2021,11 @@ (get_local $x) ) ) + (func $legalstub$frem_float (result f64) + (f64.promote/f32 + (call $frem_float) + ) + ) (func $legalstub$fr (param $0 f64) (call $fr (f32.demote/f64