diff options
Diffstat (limited to 'src/wasm-interpreter.c')
-rw-r--r-- | src/wasm-interpreter.c | 26 |
1 files changed, 23 insertions, 3 deletions
diff --git a/src/wasm-interpreter.c b/src/wasm-interpreter.c index 29d7ea82..2279cebc 100644 --- a/src/wasm-interpreter.c +++ b/src/wasm-interpreter.c @@ -133,7 +133,9 @@ void wasm_destroy_interpreter_thread(WasmAllocator* allocator, * 1 11111111 111...11 => 0xffffffff => -nan(0x7fffff) */ +#define F32_MAX 0x7f7fffffU #define F32_INF 0x7f800000U +#define F32_NEG_MAX 0xff7fffffU #define F32_NEG_INF 0xff800000U #define F32_NEG_ONE 0xbf800000U #define F32_NEG_ZERO 0x80000000U @@ -242,6 +244,20 @@ static WASM_INLINE WasmBool is_in_range_f64_demote_f32(uint64_t f64_bits) { (f64_bits >= F64_NEG_ZERO && f64_bits <= 0xc7efffffe0000000ULL); } +/* The WebAssembly rounding mode means that these values (which are > F32_MAX) + * should be rounded to F32_MAX and not set to infinity. Unfortunately, UBSAN + * complains that the value is not representable as a float, so we'll special + * case them. */ +static WASM_INLINE WasmBool +is_in_range_f64_demote_f32_round_to_f32_max(uint64_t f64_bits) { + return f64_bits > 0x47efffffe0000000ULL && f64_bits < 0x47effffff0000000ULL; +} + +static WASM_INLINE WasmBool +is_in_range_f64_demote_f32_round_to_neg_f32_max(uint64_t f64_bits) { + return f64_bits > 0xc7efffffe0000000ULL && f64_bits < 0xc7effffff0000000ULL; +} + #define IS_NAN_F32 is_nan_f32 #define IS_NAN_F64 is_nan_f64 #define IS_ZERO_F32 is_zero_f32 @@ -1342,7 +1358,13 @@ WasmInterpreterResult wasm_run_interpreter(WasmInterpreterModule* module, case WASM_OPCODE_F32_DEMOTE_F64: { VALUE_TYPE_F64 value = POP_F64(); - if (WASM_UNLIKELY(!is_in_range_f64_demote_f32(value))) { + if (WASM_LIKELY(is_in_range_f64_demote_f32(value))) { + PUSH_F32(BITCAST_FROM_F32((float)BITCAST_TO_F64(value))); + } else if (is_in_range_f64_demote_f32_round_to_f32_max(value)) { + PUSH_F32(F32_MAX); + } else if (is_in_range_f64_demote_f32_round_to_neg_f32_max(value)) { + PUSH_F32(F32_NEG_MAX); + } else { uint32_t sign = (value >> 32) & F32_SIGN_MASK; uint32_t tag = 0; if (IS_NAN_F64(value)) { @@ -1350,8 +1372,6 @@ WasmInterpreterResult wasm_run_interpreter(WasmInterpreterModule* module, ((value >> (F64_SIG_BITS - F32_SIG_BITS)) & F32_SIG_MASK); } PUSH_F32(sign | F32_INF | tag); - } else { - PUSH_F32(BITCAST_FROM_F32((float)BITCAST_TO_F64(value))); } break; } |