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/wasm-interpreter.c | |
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/wasm-interpreter.c')
-rw-r--r-- | src/wasm-interpreter.c | 37 |
1 files changed, 21 insertions, 16 deletions
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) { |