blob: c7cdf09fc6bbe8020f0b421d520948aed80c8328 [file] [log] [blame] [edit]
exception InvalidConversion
module I8_ =
struct
let sat_s x = min (max x (-0x80)) 0x7f
let sat_u x = min (max x 0) 0xff
let wrap_i16 x = I8.of_int_s (I16.to_int_s x)
let wrap_i32 x = I8.of_int_s (I32.to_int_s x)
let narrow_sat_i16_s x = I8.of_int_s (sat_s (I16.to_int_s x))
let narrow_sat_i16_u x = I8.of_int_u (sat_u (I16.to_int_s x))
let narrow_sat_i32_s x = I8.of_int_s (sat_s (I32.to_int_s x))
let narrow_sat_i32_u x = I8.of_int_u (sat_u (I32.to_int_s x))
end
module I16_ =
struct
let sat_s x = min (max x (-0x8000)) 0x7fff
let sat_u x = min (max x 0) 0xffff
let extend_i8_s x = I16.of_int_s (I8.to_int_s x)
let extend_i8_u x = I16.of_int_u (I8.to_int_u x)
let wrap_i32 x = I16.of_int_s (I32.to_int_s x)
let narrow_sat_i32_s x = I16.of_int_s (sat_s (I32.to_int_s x))
let narrow_sat_i32_u x = I16.of_int_u (sat_u (I32.to_int_s x))
end
module I32_ =
struct
let sat_s x = Int64.min (Int64.max x (-0x8000_0000L)) 0x7fff_ffffL
let sat_u x = Int64.min (Int64.max x 0L) 0xffff_ffffL
let extend_i8_s x = I32.of_int_s (I8.to_int_s x)
let extend_i8_u x = I32.of_int_u (I8.to_int_u x)
let extend_i16_s x = I32.of_int_s (I16.to_int_s x)
let extend_i16_u x = I32.of_int_u (I16.to_int_u x)
let wrap_i64 x = Int64.to_int32 x
let narrow_sat_i64_s x = Int64.to_int32 (sat_s x)
let narrow_sat_i64_u x = Int64.to_int32 (sat_u x)
let trunc_f32_s x =
if F32.ne x x then
raise InvalidConversion
else
let xf = F32.to_float x in
if xf >= -.Int32.(to_float min_int) || xf < Int32.(to_float min_int) then
raise Ixx.Overflow
else
Int32.of_float xf
let trunc_f32_u x =
if F32.ne x x then
raise InvalidConversion
else
let xf = F32.to_float x in
if xf >= -.Int32.(to_float min_int) *. 2.0 || xf <= -1.0 then
raise Ixx.Overflow
else
Int64.(to_int32 (of_float xf))
let trunc_f64_s x =
if F64.ne x x then
raise InvalidConversion
else
let xf = F64.to_float x in
if xf >= -.Int32.(to_float min_int)
|| xf <= Int32.(to_float min_int) -. 1.0 then
raise Ixx.Overflow
else
Int32.of_float xf
let trunc_f64_u x =
if F64.ne x x then
raise InvalidConversion
else
let xf = F64.to_float x in
if xf >= -.Int32.(to_float min_int) *. 2.0 || xf <= -1.0 then
raise Ixx.Overflow
else
Int64.(to_int32 (of_float xf))
let trunc_sat_f32_s x =
if F32.ne x x then
0l
else
let xf = F32.to_float x in
if xf < Int32.(to_float min_int) then
Int32.min_int
else if xf >= -.Int32.(to_float min_int) then
Int32.max_int
else
Int32.of_float xf
let trunc_sat_f32_u x =
if F32.ne x x then
0l
else
let xf = F32.to_float x in
if xf <= -1.0 then
0l
else if xf >= -.Int32.(to_float min_int) *. 2.0 then
-1l
else
Int64.(to_int32 (of_float xf))
let trunc_sat_f64_s x =
if F64.ne x x then
0l
else
let xf = F64.to_float x in
if xf < Int32.(to_float min_int) then
Int32.min_int
else if xf >= -.Int32.(to_float min_int) then
Int32.max_int
else
Int32.of_float xf
let trunc_sat_f64_u x =
if F64.ne x x then
0l
else
let xf = F64.to_float x in
if xf <= -1.0 then
0l
else if xf >= -.Int32.(to_float min_int) *. 2.0 then
-1l
else
Int64.(to_int32 (of_float xf))
let reinterpret_f32 = F32.to_bits
end
module I64_ =
struct
let extend_i32_s x = Int64.of_int32 x
let extend_i32_u x = Int64.logand (Int64.of_int32 x) 0x0000_0000_ffff_ffffL
let trunc_f32_s x =
if F32.ne x x then
raise InvalidConversion
else
let xf = F32.to_float x in
if xf >= -.Int64.(to_float min_int) || xf < Int64.(to_float min_int) then
raise Ixx.Overflow
else
Int64.of_float xf
let trunc_f32_u x =
if F32.ne x x then
raise InvalidConversion
else
let xf = F32.to_float x in
if xf >= -.Int64.(to_float min_int) *. 2.0 || xf <= -1.0 then
raise Ixx.Overflow
else if xf >= -.Int64.(to_float min_int) then
Int64.(logxor (of_float (xf -. 0x1p63)) min_int)
else
Int64.of_float xf
let trunc_f64_s x =
if F64.ne x x then
raise InvalidConversion
else
let xf = F64.to_float x in
if xf >= -.Int64.(to_float min_int) || xf < Int64.(to_float min_int) then
raise Ixx.Overflow
else
Int64.of_float xf
let trunc_f64_u x =
if F64.ne x x then
raise InvalidConversion
else
let xf = F64.to_float x in
if xf >= -.Int64.(to_float min_int) *. 2.0 || xf <= -1.0 then
raise Ixx.Overflow
else if xf >= -.Int64.(to_float min_int) then
Int64.(logxor (of_float (xf -. 0x1p63)) min_int)
else
Int64.of_float xf
let trunc_sat_f32_s x =
if F32.ne x x then
0L
else
let xf = F32.to_float x in
if xf < Int64.(to_float min_int) then
Int64.min_int
else if xf >= -.Int64.(to_float min_int) then
Int64.max_int
else
Int64.of_float xf
let trunc_sat_f32_u x =
if F32.ne x x then
0L
else
let xf = F32.to_float x in
if xf <= -1.0 then
0L
else if xf >= -.Int64.(to_float min_int) *. 2.0 then
-1L
else if xf >= -.Int64.(to_float min_int) then
Int64.(logxor (of_float (xf -. 0x1p63)) min_int)
else
Int64.of_float xf
let trunc_sat_f64_s x =
if F64.ne x x then
0L
else
let xf = F64.to_float x in
if xf < Int64.(to_float min_int) then
Int64.min_int
else if xf >= -.Int64.(to_float min_int) then
Int64.max_int
else
Int64.of_float xf
let trunc_sat_f64_u x =
if F64.ne x x then
0L
else
let xf = F64.to_float x in
if xf <= -1.0 then
0L
else if xf >= -.Int64.(to_float min_int) *. 2.0 then
-1L
else if xf >= -.Int64.(to_float min_int) then
Int64.(logxor (of_float (xf -. 0x1p63)) min_int)
else
Int64.of_float xf
let reinterpret_f64 = F64.to_bits
end
module F32_ =
struct
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 = Int64.(shift_left (shift_right_logical nan64bits 63) 31) in
let significand = Int64.(shift_right_logical (shift_left nan64bits 12) 41) in
let fields = Int64.logor sign significand in
let nan32bits = Int32.logor 0x7fc0_0000l (I32_.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
end
module F64_ =
struct
let promote_f32 x =
let xf = F32.to_float x in
if xf = xf then F64.of_float xf else
let nan32bits = I64_.extend_i32_u (F32.to_bits x) in
let sign = Int64.(shift_left (shift_right_logical nan32bits 31) 63) in
let significand = Int64.(shift_right_logical (shift_left nan32bits 41) 12) in
let fields = Int64.logor sign significand in
let nan64bits = Int64.logor 0x7ff8_0000_0000_0000L fields in
F64.of_bits nan64bits
let convert_i32_s x =
F64.of_float (Int32.to_float x)
(*
* Unlike the other convert_u functions, the high half of the i32 range is
* within the range where f32 can represent odd numbers, so we can't do the
* shift. Instead, we can use int64 signed arithmetic.
*)
let convert_i32_u x =
F64.of_float Int64.(to_float (logand (of_int32 x) 0x0000_0000_ffff_ffffL))
let convert_i64_s x =
F64.of_float (Int64.to_float x)
(*
* Values in the low half of the int64 range can be converted with a signed
* conversion. The high half is beyond the range where f64 can represent odd
* numbers, so we can shift the value right, adjust the least significant
* bit to round correctly, do a conversion, and then scale it back up.
*)
let convert_i64_u x =
F64.of_float Int64.(
if x >= zero then to_float x else
to_float (logor (shift_right_logical x 1) (logand x 1L)) *. 2.0
)
let reinterpret_i64 = F64.of_bits
end