diff options
-rw-r--r-- | src/asm2wasm.h | 90 | ||||
-rw-r--r-- | src/asmjs/shared-constants.cpp | 1 | ||||
-rw-r--r-- | src/asmjs/shared-constants.h | 1 | ||||
-rw-r--r-- | test/unit.fromasm | 2 | ||||
-rw-r--r-- | test/unit.fromasm.clamp | 2 | ||||
-rw-r--r-- | test/unit.fromasm.clamp.no-opts | 2 | ||||
-rw-r--r-- | test/unit.fromasm.no-opts | 2 | ||||
-rw-r--r-- | test/wasm-only.fromasm | 88 | ||||
-rw-r--r-- | test/wasm-only.fromasm.clamp | 88 | ||||
-rw-r--r-- | test/wasm-only.fromasm.clamp.no-opts | 42 | ||||
-rw-r--r-- | test/wasm-only.fromasm.no-opts | 42 |
11 files changed, 305 insertions, 55 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h index f6d0443ec..90e258c54 100644 --- a/src/asm2wasm.h +++ b/src/asm2wasm.h @@ -34,7 +34,6 @@ #include "ast_utils.h" #include "wasm-builder.h" #include "wasm-emscripten.h" -#include "wasm-printing.h" #include "wasm-module-building.h" namespace wasm { @@ -788,7 +787,7 @@ private: } // Some conversions might trap, so emit them safely if necessary - Expression* makeTrappingFloatToInt(bool signed_, Expression* value) { + Expression* makeTrappingFloatToInt32(bool signed_, Expression* value) { if (trapMode == TrapMode::Allow) { auto ret = allocator.alloc<Unary>(); ret->value = value; @@ -879,6 +878,76 @@ private: return ret; } + Expression* makeTrappingFloatToInt64(bool signed_, Expression* value) { + if (trapMode == TrapMode::Allow) { + auto ret = allocator.alloc<Unary>(); + ret->value = value; + bool isF64 = ret->value->type == f64; + if (signed_) { + ret->op = isF64 ? TruncSFloat64ToInt64 : TruncSFloat32ToInt64; + } else { + ret->op = isF64 ? TruncUFloat64ToInt64 : TruncUFloat32ToInt64; + } + ret->type = WasmType::i64; + return ret; + } + // 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<Unary>(); + conv->op = PromoteFloat32; + conv->value = input; + conv->type = WasmType::f64; + input = conv; + } + // 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<Call>(); + ret->target = F64_TO_INT64; + ret->operands.push_back(input); + ret->type = i64; + static bool added = false; + if (!added) { + added = true; + auto func = new Function; + func->name = ret->target; + func->params.push_back(f64); + func->result = i64; + func->body = builder.makeUnary(TruncSFloat64ToInt64, + builder.makeGetLocal(0, f64) + ); + // too small + func->body = builder.makeIf( + builder.makeBinary(LeFloat64, + builder.makeGetLocal(0, f64), + builder.makeConst(Literal(double(std::numeric_limits<int64_t>::min()) - 1)) + ), + builder.makeConst(Literal(int64_t(std::numeric_limits<int64_t>::min()))), + func->body + ); + // too big + func->body = builder.makeIf( + builder.makeBinary(GeFloat64, + builder.makeGetLocal(0, f64), + builder.makeConst(Literal(double(std::numeric_limits<int64_t>::max()) + 1)) + ), + builder.makeConst(Literal(int64_t(std::numeric_limits<int64_t>::min()))), // NB: min here as well. anything out of range => to the min + func->body + ); + // nan + func->body = builder.makeIf( + builder.makeBinary(NeFloat64, + builder.makeGetLocal(0, f64), + builder.makeGetLocal(0, f64) + ), + builder.makeConst(Literal(int64_t(std::numeric_limits<int64_t>::min()))), // NB: min here as well. anything invalid => to the min + func->body + ); + wasm.addFunction(func); + } + return ret; + } + Expression* truncateToInt32(Expression* value) { if (value->type == i64) return builder.makeUnary(UnaryOp::WrapInt64, value); // either i32, or a call_import whose type we don't know yet (but would be legalized to i32 anyhow) @@ -1302,10 +1371,12 @@ void Asm2WasmBuilder::processAsm(Ref ast) { } auto importResult = getModule()->getFunctionType(getModule()->getImport(curr->target)->functionType)->result; if (curr->type != importResult) { + auto old = curr->type; + curr->type = importResult; if (importResult == f64) { // we use a JS f64 value which is the most general, and convert to it - switch (curr->type) { - case i32: replaceCurrent(parent->builder.makeUnary(TruncSFloat64ToInt32, curr)); break; + switch (old) { + case i32: replaceCurrent(parent->makeTrappingFloatToInt32(true /* signed, asm.js ffi */, curr)); break; case f32: replaceCurrent(parent->builder.makeUnary(DemoteFloat64, curr)); break; case none: { // this function returns a value, but we are not using it, so it must be dropped. @@ -1315,11 +1386,10 @@ void Asm2WasmBuilder::processAsm(Ref ast) { default: WASM_UNREACHABLE(); } } else { - assert(curr->type == none); + assert(old == none); // we don't want a return value here, but the import does provide one // autodrop will do that for us. } - curr->type = importResult; } } @@ -1836,7 +1906,7 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { // ~, might be ~~ as a coercion or just a not if (ast[2]->isArray(UNARY_PREFIX) && ast[2][1] == B_NOT) { // if we have an unsigned coercion on us, it is an unsigned op - return makeTrappingFloatToInt(!isParentUnsignedCoercion(astStackHelper.getParent()), process(ast[2][2])); + return makeTrappingFloatToInt32(!isParentUnsignedCoercion(astStackHelper.getParent()), process(ast[2][2])); } // no bitwise unary not, so do xor with -1 auto ret = allocator.alloc<Binary>(); @@ -2038,10 +2108,8 @@ Function* Asm2WasmBuilder::processFunction(Ref ast) { if (name == I64_S2D) return builder.makeUnary(UnaryOp::ConvertSInt64ToFloat64, value); if (name == I64_U2F) return builder.makeUnary(UnaryOp::ConvertUInt64ToFloat32, value); if (name == I64_U2D) return builder.makeUnary(UnaryOp::ConvertUInt64ToFloat64, value); - if (name == I64_F2S) return builder.makeUnary(UnaryOp::TruncSFloat32ToInt64, value); - if (name == I64_D2S) return builder.makeUnary(UnaryOp::TruncSFloat64ToInt64, value); - if (name == I64_F2U) return builder.makeUnary(UnaryOp::TruncUFloat32ToInt64, value); - if (name == I64_D2U) return builder.makeUnary(UnaryOp::TruncUFloat64ToInt64, value); + if (name == I64_F2S || name == I64_D2S) return makeTrappingFloatToInt64(true /* signed */, value); + if (name == I64_F2U || name == I64_D2U) return makeTrappingFloatToInt64(false /* unsigned */, value); if (name == I64_BC2D) return builder.makeUnary(UnaryOp::ReinterpretInt64, value); if (name == I64_BC2I) return builder.makeUnary(UnaryOp::ReinterpretFloat64, value); if (name == I64_CTTZ) return builder.makeUnary(UnaryOp::CtzInt64, value); diff --git a/src/asmjs/shared-constants.cpp b/src/asmjs/shared-constants.cpp index 02e80d36b..f1c5ac536 100644 --- a/src/asmjs/shared-constants.cpp +++ b/src/asmjs/shared-constants.cpp @@ -40,6 +40,7 @@ cashew::IString GLOBAL("global"), ASM2WASM("asm2wasm"), F64_REM("f64-rem"), F64_TO_INT("f64-to-int"), + F64_TO_INT64("f64-to-int64"), I32S_DIV("i32s-div"), I32U_DIV("i32u-div"), I32S_REM("i32s-rem"), diff --git a/src/asmjs/shared-constants.h b/src/asmjs/shared-constants.h index f13023778..e3108c81e 100644 --- a/src/asmjs/shared-constants.h +++ b/src/asmjs/shared-constants.h @@ -43,6 +43,7 @@ extern cashew::IString GLOBAL, ASM2WASM, F64_REM, F64_TO_INT, + F64_TO_INT64, I32S_DIV, I32U_DIV, I32S_REM, diff --git a/test/unit.fromasm b/test/unit.fromasm index e5ff23645..c869e2398 100644 --- a/test/unit.fromasm +++ b/test/unit.fromasm @@ -613,7 +613,7 @@ (drop (if (result i32) (call $return_int) - (i32.trunc_s/f64 + (call $f64-to-int (call $abort (f64.convert_s/i32 (i32.const 5) diff --git a/test/unit.fromasm.clamp b/test/unit.fromasm.clamp index e21d0f229..370e66c4d 100644 --- a/test/unit.fromasm.clamp +++ b/test/unit.fromasm.clamp @@ -637,7 +637,7 @@ (drop (if (result i32) (call $return_int) - (i32.trunc_s/f64 + (call $f64-to-int (call $abort (f64.convert_s/i32 (i32.const 5) diff --git a/test/unit.fromasm.clamp.no-opts b/test/unit.fromasm.clamp.no-opts index 18f16d316..8ff26568e 100644 --- a/test/unit.fromasm.clamp.no-opts +++ b/test/unit.fromasm.clamp.no-opts @@ -1097,7 +1097,7 @@ (set_local $x (if (result i32) (call $return_int) - (i32.trunc_s/f64 + (call $f64-to-int (call $abort (f64.convert_s/i32 (i32.const 5) diff --git a/test/unit.fromasm.no-opts b/test/unit.fromasm.no-opts index 841a4d38f..dba91cfcd 100644 --- a/test/unit.fromasm.no-opts +++ b/test/unit.fromasm.no-opts @@ -1073,7 +1073,7 @@ (set_local $x (if (result i32) (call $return_int) - (i32.trunc_s/f64 + (call $f64-to-int (call $abort (f64.convert_s/i32 (i32.const 5) diff --git a/test/wasm-only.fromasm b/test/wasm-only.fromasm index b8bda7fee..f12226b1d 100644 --- a/test/wasm-only.fromasm +++ b/test/wasm-only.fromasm @@ -191,10 +191,38 @@ ) ) ) + (func $f64-to-int64 (param $0 f64) (result i64) + (if (result i64) + (f64.ne + (get_local $0) + (get_local $0) + ) + (i64.const -9223372036854775808) + (if (result i64) + (f64.ge + (get_local $0) + (f64.const 9223372036854775808) + ) + (i64.const -9223372036854775808) + (if (result i64) + (f64.le + (get_local $0) + (f64.const -9223372036854775808) + ) + (i64.const -9223372036854775808) + (i64.trunc_s/f64 + (get_local $0) + ) + ) + ) + ) + ) (func $test64 (local $0 i64) (local $1 i64) (local $2 i32) + (local $3 f32) + (local $4 f64) (drop (call $i64s-rem (call $i64u-rem @@ -203,27 +231,27 @@ (i64.mul (i64.sub (i64.add - (tee_local $0 + (tee_local $1 (i64.const 128849018897) ) (i64.const 100) ) - (get_local $0) + (get_local $1) ) - (get_local $0) + (get_local $1) ) - (get_local $0) + (get_local $1) ) - (get_local $0) + (get_local $1) ) - (get_local $0) + (get_local $1) ) - (get_local $0) + (get_local $1) ) ) (i64.store (i32.const 120) - (tee_local $1 + (tee_local $0 (i64.load (i32.const 120) ) @@ -231,30 +259,62 @@ ) (i64.store (i32.const 120) - (get_local $1) + (get_local $0) ) (i64.store align=2 (i32.const 120) - (get_local $1) + (get_local $0) ) (i64.store align=4 (i32.const 120) - (get_local $1) + (get_local $0) ) (i64.store (i32.const 120) - (get_local $1) + (get_local $0) ) (set_local $2 (i32.wrap/i64 - (get_local $1) + (get_local $0) ) ) - (set_local $1 + (set_local $0 (i64.extend_u/i32 (get_local $2) ) ) + (drop + (call $f64-to-int64 + (f64.promote/f32 + (tee_local $3 + (f32.convert_u/i64 + (get_local $0) + ) + ) + ) + ) + ) + (drop + (call $f64-to-int64 + (tee_local $4 + (f64.convert_u/i64 + (get_local $0) + ) + ) + ) + ) + (drop + (call $f64-to-int64 + (f64.promote/f32 + (get_local $3) + ) + ) + ) + (drop + (call $f64-to-int64 + (get_local $4) + ) + ) ) (func $imports (result i64) (call $legalfunc$illegalImport diff --git a/test/wasm-only.fromasm.clamp b/test/wasm-only.fromasm.clamp index b8bda7fee..f12226b1d 100644 --- a/test/wasm-only.fromasm.clamp +++ b/test/wasm-only.fromasm.clamp @@ -191,10 +191,38 @@ ) ) ) + (func $f64-to-int64 (param $0 f64) (result i64) + (if (result i64) + (f64.ne + (get_local $0) + (get_local $0) + ) + (i64.const -9223372036854775808) + (if (result i64) + (f64.ge + (get_local $0) + (f64.const 9223372036854775808) + ) + (i64.const -9223372036854775808) + (if (result i64) + (f64.le + (get_local $0) + (f64.const -9223372036854775808) + ) + (i64.const -9223372036854775808) + (i64.trunc_s/f64 + (get_local $0) + ) + ) + ) + ) + ) (func $test64 (local $0 i64) (local $1 i64) (local $2 i32) + (local $3 f32) + (local $4 f64) (drop (call $i64s-rem (call $i64u-rem @@ -203,27 +231,27 @@ (i64.mul (i64.sub (i64.add - (tee_local $0 + (tee_local $1 (i64.const 128849018897) ) (i64.const 100) ) - (get_local $0) + (get_local $1) ) - (get_local $0) + (get_local $1) ) - (get_local $0) + (get_local $1) ) - (get_local $0) + (get_local $1) ) - (get_local $0) + (get_local $1) ) - (get_local $0) + (get_local $1) ) ) (i64.store (i32.const 120) - (tee_local $1 + (tee_local $0 (i64.load (i32.const 120) ) @@ -231,30 +259,62 @@ ) (i64.store (i32.const 120) - (get_local $1) + (get_local $0) ) (i64.store align=2 (i32.const 120) - (get_local $1) + (get_local $0) ) (i64.store align=4 (i32.const 120) - (get_local $1) + (get_local $0) ) (i64.store (i32.const 120) - (get_local $1) + (get_local $0) ) (set_local $2 (i32.wrap/i64 - (get_local $1) + (get_local $0) ) ) - (set_local $1 + (set_local $0 (i64.extend_u/i32 (get_local $2) ) ) + (drop + (call $f64-to-int64 + (f64.promote/f32 + (tee_local $3 + (f32.convert_u/i64 + (get_local $0) + ) + ) + ) + ) + ) + (drop + (call $f64-to-int64 + (tee_local $4 + (f64.convert_u/i64 + (get_local $0) + ) + ) + ) + ) + (drop + (call $f64-to-int64 + (f64.promote/f32 + (get_local $3) + ) + ) + ) + (drop + (call $f64-to-int64 + (get_local $4) + ) + ) ) (func $imports (result i64) (call $legalfunc$illegalImport diff --git a/test/wasm-only.fromasm.clamp.no-opts b/test/wasm-only.fromasm.clamp.no-opts index 97533d796..baac47fba 100644 --- a/test/wasm-only.fromasm.clamp.no-opts +++ b/test/wasm-only.fromasm.clamp.no-opts @@ -341,6 +341,32 @@ ) ) ) + (func $f64-to-int64 (param $0 f64) (result i64) + (if (result i64) + (f64.ne + (get_local $0) + (get_local $0) + ) + (i64.const -9223372036854775808) + (if (result i64) + (f64.ge + (get_local $0) + (f64.const 9223372036854775808) + ) + (i64.const -9223372036854775808) + (if (result i64) + (f64.le + (get_local $0) + (f64.const -9223372036854775808) + ) + (i64.const -9223372036854775808) + (i64.trunc_s/f64 + (get_local $0) + ) + ) + ) + ) + ) (func $test64 (local $x i64) (local $y i64) @@ -573,22 +599,26 @@ ) ) (set_local $x - (i64.trunc_s/f32 - (get_local $float32) + (call $f64-to-int64 + (f64.promote/f32 + (get_local $float32) + ) ) ) (set_local $x - (i64.trunc_s/f64 + (call $f64-to-int64 (get_local $float64) ) ) (set_local $x - (i64.trunc_u/f32 - (get_local $float32) + (call $f64-to-int64 + (f64.promote/f32 + (get_local $float32) + ) ) ) (set_local $x - (i64.trunc_u/f64 + (call $f64-to-int64 (get_local $float64) ) ) diff --git a/test/wasm-only.fromasm.no-opts b/test/wasm-only.fromasm.no-opts index 97533d796..baac47fba 100644 --- a/test/wasm-only.fromasm.no-opts +++ b/test/wasm-only.fromasm.no-opts @@ -341,6 +341,32 @@ ) ) ) + (func $f64-to-int64 (param $0 f64) (result i64) + (if (result i64) + (f64.ne + (get_local $0) + (get_local $0) + ) + (i64.const -9223372036854775808) + (if (result i64) + (f64.ge + (get_local $0) + (f64.const 9223372036854775808) + ) + (i64.const -9223372036854775808) + (if (result i64) + (f64.le + (get_local $0) + (f64.const -9223372036854775808) + ) + (i64.const -9223372036854775808) + (i64.trunc_s/f64 + (get_local $0) + ) + ) + ) + ) + ) (func $test64 (local $x i64) (local $y i64) @@ -573,22 +599,26 @@ ) ) (set_local $x - (i64.trunc_s/f32 - (get_local $float32) + (call $f64-to-int64 + (f64.promote/f32 + (get_local $float32) + ) ) ) (set_local $x - (i64.trunc_s/f64 + (call $f64-to-int64 (get_local $float64) ) ) (set_local $x - (i64.trunc_u/f32 - (get_local $float32) + (call $f64-to-int64 + (f64.promote/f32 + (get_local $float32) + ) ) ) (set_local $x - (i64.trunc_u/f64 + (call $f64-to-int64 (get_local $float64) ) ) |