Skip to content

Commit 015bf73

Browse files
committed
Fix static evaluation of caml_int64_float_of_bits
Do not statically evaluate caml_int64_float_of_bits when it would result in a non-canonical NaN, since there is no JavaScript syntax for non-canonical NaNs.
1 parent 74d4b10 commit 015bf73

File tree

3 files changed

+40
-11
lines changed

3 files changed

+40
-11
lines changed

compiler/lib/eval.ml

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ let nativeint_shiftop (l : constant list) (f : int32 -> int -> int32) : constant
139139
| [ NativeInt i; Int j ] -> Some (NativeInt (f i (Targetint.to_int_exn j)))
140140
| _ -> None
141141

142-
let eval_prim x =
142+
let eval_prim ~target x =
143143
match x with
144144
| Not, [ Int i ] -> bool (Targetint.is_zero i)
145145
| Lt, [ Int i; Int j ] -> bool Targetint.(i < j)
@@ -231,7 +231,13 @@ let eval_prim x =
231231
(* int32 *)
232232
| "caml_int32_bits_of_float", [ Float f ] ->
233233
int32 (Int32.bits_of_float (Int64.float_of_bits f))
234-
| "caml_int32_float_of_bits", [ Int32 i ] -> Some (float (Int32.float_of_bits i))
234+
| "caml_int32_float_of_bits", [ Int32 i ]
235+
when match target with
236+
| `JavaScript ->
237+
let f = Int32.float_of_bits i in
238+
(not (Float.is_nan f))
239+
|| Int64.equal (Int64.bits_of_float f) (Int64.bits_of_float nan)
240+
| `Wasm -> true -> Some (float (Int32.float_of_bits i))
235241
| "caml_int32_of_float", [ Float f ] ->
236242
int32 (Int32.of_float (Int64.float_of_bits f))
237243
| "caml_int32_to_float", [ Int32 i ] -> Some (float (Int32.to_float i))
@@ -258,8 +264,13 @@ let eval_prim x =
258264
(* nativeint *)
259265
| "caml_nativeint_bits_of_float", [ Float f ] ->
260266
nativeint (Int32.bits_of_float (Int64.float_of_bits f))
261-
| "caml_nativeint_float_of_bits", [ NativeInt i ] ->
262-
Some (float (Int32.float_of_bits i))
267+
| "caml_nativeint_float_of_bits", [ NativeInt i ]
268+
when match target with
269+
| `JavaScript ->
270+
let f = Int32.float_of_bits i in
271+
(not (Float.is_nan f))
272+
|| Int64.equal (Int64.bits_of_float f) (Int64.bits_of_float nan)
273+
| `Wasm -> true -> Some (float (Int32.float_of_bits i))
263274
| "caml_nativeint_of_float", [ Float f ] ->
264275
nativeint (Int32.of_float (Int64.float_of_bits f))
265276
| "caml_nativeint_to_float", [ NativeInt i ] -> Some (float (Int32.to_float i))
@@ -284,7 +295,12 @@ let eval_prim x =
284295
| "caml_nativeint_of_int", [ Int i ] -> nativeint (Targetint.to_int32 i)
285296
(* int64 *)
286297
| "caml_int64_bits_of_float", [ Float f ] -> int64 f
287-
| "caml_int64_float_of_bits", [ Int64 i ] -> Some (Float i)
298+
| "caml_int64_float_of_bits", [ Int64 i ]
299+
when match target with
300+
| `JavaScript ->
301+
(not (Float.is_nan (Int64.float_of_bits i)))
302+
|| Int64.equal i (Int64.bits_of_float nan)
303+
| `Wasm -> true -> Some (Float i)
288304
| "caml_int64_of_float", [ Float f ] ->
289305
int64 (Int64.of_float (Int64.float_of_bits f))
290306
| "caml_int64_to_float", [ Int64 i ] -> Some (float (Int64.to_float i))
@@ -632,6 +648,7 @@ let eval_instr update_count inline_constant ~target info i =
632648
| _ -> false)
633649
then
634650
eval_prim
651+
~target
635652
( prim
636653
, List.map prim_args' ~f:(function
637654
| Some c -> c

compiler/tests-full/stdlib.cma.expected.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8028,6 +8028,7 @@
80288028
caml_floatarray_make = runtime.caml_floatarray_make,
80298029
caml_floatarray_sub = runtime.caml_floatarray_sub,
80308030
caml_hash = runtime.caml_hash,
8031+
caml_int64_create_lo_mi_hi = runtime.caml_int64_create_lo_mi_hi,
80318032
caml_maybe_attach_backtrace = runtime.caml_maybe_attach_backtrace,
80328033
caml_nextafter_float = runtime.caml_nextafter_float,
80338034
caml_signbit_float = runtime.caml_signbit_float,
@@ -8050,7 +8051,10 @@
80508051
Stdlib = global_data.Stdlib,
80518052
infinity = Stdlib[22],
80528053
neg_infinity = Stdlib[23],
8053-
nan = Stdlib[24];
8054+
nan = Stdlib[24],
8055+
signaling_nan =
8056+
/*<<float.ml:38:20>>*/ runtime.caml_int64_float_of_bits
8057+
(caml_int64_create_lo_mi_hi(1, 0, 32752));
80548058
function is_finite(x){
80558059
/*<<float.ml:39:33>>*/ return x - x === 0. ? 1 : 0;
80568060
/*<<float.ml:39:38>>*/ }
@@ -8983,7 +8987,7 @@
89838987
infinity,
89848988
neg_infinity,
89858989
nan,
8986-
NaN,
8990+
signaling_nan,
89878991
nan,
89888992
3.141592653589793,
89898993
max_float,

runtime/js/ieee_754.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,14 @@ function caml_int64_bits_of_float(x) {
2727
jsoo_dataview.setFloat64(0, x, true);
2828
var lo32 = jsoo_dataview.getUint32(0, true);
2929
var hi32 = jsoo_dataview.getUint32(4, true);
30-
var r1 = lo32 & 0xffffff;
31-
var r2 = (lo32 >>> 24) | ((hi32 << 8) & 0xffffff);
32-
var r3 = (hi32 >>> 16) & 0xffff;
33-
return caml_int64_create_lo_mi_hi(r1, r2, r3);
30+
var lo = lo32 & 0xffffff;
31+
var mi = (lo32 >>> 24) | ((hi32 << 8) & 0xffffff);
32+
var hi = (hi32 >>> 16) & 0xffff;
33+
// V8 uses signaling NaNs as sentinal. So, NaNs are made quiet when
34+
// they are stored in an array. Make them quiet here so that we get
35+
// consistent results.
36+
if ((hi & 0x7ff8) === 0x7ff0 && (mi | lo | (hi & 0xf)) !== 0) hi |= 8;
37+
return caml_int64_create_lo_mi_hi(lo, mi, hi);
3438
}
3539

3640
//Provides: caml_int32_bits_of_float const
@@ -108,6 +112,10 @@ function caml_int64_float_of_bits(x) {
108112
var lo = x.lo;
109113
var mi = x.mi;
110114
var hi = x.hi;
115+
// V8 uses signaling NaNs as sentinal. So, NaNs are made quiet when
116+
// they are stored in an array. Make them quiet here so that we get
117+
// consistent results.
118+
if ((hi & 0x7ff8) === 0x7ff0 && (mi | lo | (hi & 0xf)) !== 0) hi |= 8;
111119
jsoo_dataview.setUint32(0, lo | (mi << 24), true);
112120
jsoo_dataview.setUint32(4, (mi >>> 8) | (hi << 16), true);
113121
return jsoo_dataview.getFloat64(0, true);

0 commit comments

Comments
 (0)