diff options
author | Ben Smith <binji@chromium.org> | 2016-07-29 15:32:18 -0700 |
---|---|---|
committer | Ben Smith <binji@chromium.org> | 2016-07-29 15:32:18 -0700 |
commit | 2338246f9ea098d9581279ffcb20c0a980c3065a (patch) | |
tree | 0d2bf0529578c460d92395ad32bbfca2813fbbd2 /src | |
parent | 1347a367c34876bfe92562f244a8c8b770372479 (diff) | |
download | wabt-2338246f9ea098d9581279ffcb20c0a980c3065a.tar.gz wabt-2338246f9ea098d9581279ffcb20c0a980c3065a.tar.bz2 wabt-2338246f9ea098d9581279ffcb20c0a980c3065a.zip |
fix bug with floating point min/max
f32.min(-0.0, 0.0) => -0.0, but the tests were using f32.eq inside
assert_return for this case. Since f32.eq(-0.0, 0.0) => 1, these tests
were passing.
This change fixes assert_return to always perform a bitwise comparison
when testing floating point values, and fixes the interpreter to
properly handle the f{32,64}.{min,max} operations for this case.
Diffstat (limited to 'src')
-rw-r--r-- | src/wasm-binary-writer-spec.c | 15 | ||||
-rw-r--r-- | src/wasm-interpreter.c | 37 |
2 files changed, 23 insertions, 29 deletions
diff --git a/src/wasm-binary-writer-spec.c b/src/wasm-binary-writer-spec.c index b5f749a3..b76529e6 100644 --- a/src/wasm-binary-writer-spec.c +++ b/src/wasm-binary-writer-spec.c @@ -48,15 +48,6 @@ typedef struct Context { WasmResult result; } Context; -static WasmBool is_nan_f32(uint32_t bits) { - return (bits & 0x7f800000) == 0x7f800000 && (bits & 0x007fffff) != 0; -} - -static WasmBool is_nan_f64(uint64_t bits) { - return (bits & 0x7ff0000000000000LL) == 0x7ff0000000000000LL && - (bits & 0x000fffffffffffffLL) != 0; -} - static WasmExpr* create_const_expr(WasmAllocator* allocator, WasmConst* const_) { WasmExpr* expr = wasm_new_const_expr(allocator); @@ -353,16 +344,14 @@ static void write_commands(Context* ctx, WasmScript* script) { WasmExpr* const_expr = create_const_expr(script->allocator, expected); - if (expected->type == WASM_TYPE_F32 && - is_nan_f32(expected->f32_bits)) { + if (expected->type == WASM_TYPE_F32) { caller->first_expr = create_eq_expr( script->allocator, WASM_TYPE_I32, create_reinterpret_expr(script->allocator, WASM_TYPE_F32, invoke_expr), create_reinterpret_expr(script->allocator, WASM_TYPE_F32, const_expr)); - } else if (expected->type == WASM_TYPE_F64 && - is_nan_f64(expected->f64_bits)) { + } else if (expected->type == WASM_TYPE_F64) { caller->first_expr = create_eq_expr( script->allocator, WASM_TYPE_I64, create_reinterpret_expr(script->allocator, WASM_TYPE_F64, diff --git a/src/wasm-interpreter.c b/src/wasm-interpreter.c index 9581417a..29d7ea82 100644 --- a/src/wasm-interpreter.c +++ b/src/wasm-interpreter.c @@ -523,22 +523,27 @@ DEFINE_BITCAST(bitcast_u64_to_f64, uint64_t, double) #define MIN_OP < #define MAX_OP > -#define MINMAX_FLOAT(type, op) \ - do { \ - VALUE_TYPE_##type rhs = POP_##type(); \ - VALUE_TYPE_##type lhs = POP_##type(); \ - VALUE_TYPE_##type result; \ - if (WASM_UNLIKELY(IS_NAN_##type(lhs))) { \ - result = lhs | type##_QUIET_NAN_BIT; \ - } else if (WASM_UNLIKELY(IS_NAN_##type(rhs))) { \ - result = rhs | type##_QUIET_NAN_BIT; \ - } else { \ - FLOAT_TYPE_##type float_rhs = BITCAST_TO_##type(rhs); \ - FLOAT_TYPE_##type float_lhs = BITCAST_TO_##type(lhs); \ - result = BITCAST_FROM_##type(float_lhs op##_OP float_rhs ? float_lhs \ - : float_rhs); \ - } \ - PUSH_##type(result); \ +#define MINMAX_FLOAT(type, op) \ + do { \ + VALUE_TYPE_##type rhs = POP_##type(); \ + VALUE_TYPE_##type lhs = POP_##type(); \ + VALUE_TYPE_##type result; \ + if (WASM_UNLIKELY(IS_NAN_##type(lhs))) { \ + result = lhs | type##_QUIET_NAN_BIT; \ + } else if (WASM_UNLIKELY(IS_NAN_##type(rhs))) { \ + result = rhs | type##_QUIET_NAN_BIT; \ + } else if ((lhs ^ rhs) & type##_SIGN_MASK) { \ + /* min(-0.0, 0.0) => -0.0; since we know the sign bits are different, we \ + * can just use the inverse integer comparison (because the sign bit is \ + * set when the value is negative) */ \ + result = !(lhs op##_OP rhs) ? lhs : rhs; \ + } else { \ + FLOAT_TYPE_##type float_rhs = BITCAST_TO_##type(rhs); \ + FLOAT_TYPE_##type float_lhs = BITCAST_TO_##type(lhs); \ + result = BITCAST_FROM_##type(float_lhs op##_OP float_rhs ? float_lhs \ + : float_rhs); \ + } \ + PUSH_##type(result); \ } while (0) static WASM_INLINE uint32_t read_u32_at(const uint8_t* pc) { |