blob: bcc7ac94f638a60fed8f18fc45e3dbe8969440fd [file] [log] [blame] [edit]
(* 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