| (* WebAssembly-compatible type conversions to f32 implementation *) |
| |
| let demote_f64 x = |
| let xf = F64.to_float x in |
| if xf = xf then F32.of_float xf else |
| let nan64bits = F64.to_bits x in |
| let sign_field = Int64.(shift_left (shift_right_logical nan64bits 63) 31) in |
| let significand_field = Int64.(shift_right_logical (shift_left nan64bits 12) 41) in |
| let fields = Int64.logor sign_field significand_field in |
| let nan32bits = Int32.logor 0x7fc0_0000l (I32_convert.wrap_i64 fields) in |
| F32.of_bits nan32bits |
| |
| let convert_i32_s x = |
| F32.of_float (Int32.to_float x) |
| |
| (* |
| * Similar to convert_i64_u below, the high half of the i32 range are beyond |
| * the range where f32 can represent odd numbers, though we do need to adjust |
| * the least significant bit to round correctly. |
| *) |
| let convert_i32_u x = |
| F32.of_float Int32.( |
| if x >= zero then to_float x else |
| to_float (logor (shift_right_logical x 1) (logand x 1l)) *. 2.0 |
| ) |
| |
| (* |
| * Values that are too large would get rounded when represented in f64, |
| * but double rounding via i64->f64->f32 can produce inaccurate results. |
| * Hence, for large values we shift right but make sure to accumulate the lost |
| * bits in the least significant bit, such that rounding still is correct. |
| *) |
| let convert_i64_s x = |
| F32.of_float Int64.( |
| if abs x < 0x10_0000_0000_0000L then to_float x else |
| let r = if logand x 0xfffL = 0L then 0L else 1L in |
| to_float (logor (shift_right x 12) r) *. 0x1p12 |
| ) |
| |
| let convert_i64_u x = |
| F32.of_float Int64.( |
| if I64.lt_u x 0x10_0000_0000_0000L then to_float x else |
| let r = if logand x 0xfffL = 0L then 0L else 1L in |
| to_float (logor (shift_right_logical x 12) r) *. 0x1p12 |
| ) |
| |
| let reinterpret_i32 = F32.of_bits |