summaryrefslogtreecommitdiff
path: root/src
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
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')
-rw-r--r--src/wasm-binary-writer-spec.c15
-rw-r--r--src/wasm-interpreter.c37
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) {