summaryrefslogtreecommitdiff
path: root/src/wasm-interpreter.c
diff options
context:
space:
mode:
authorBen Smith <binji@chromium.org>2016-07-29 15:32:18 -0700
committerBen Smith <binji@chromium.org>2016-07-29 15:32:18 -0700
commit2338246f9ea098d9581279ffcb20c0a980c3065a (patch)
tree0d2bf0529578c460d92395ad32bbfca2813fbbd2 /src/wasm-interpreter.c
parent1347a367c34876bfe92562f244a8c8b770372479 (diff)
downloadwabt-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.c37
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) {