Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Runtime: Add float16 support to bigarray #1803

Merged
merged 7 commits into from
Jan 23, 2025
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Runtime: add support for float16 bigarrays
hhugo committed Jan 21, 2025
commit f08f3942097501ca85cd608185e47b7c252e1a4a
48 changes: 14 additions & 34 deletions compiler/tests-ocaml/lib-bigarray/bigarrays.expected
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
------ Array1 --------

create/set/get
1... 2... 3... 4... 5... 6... 7... 8... 9... 10... 11... 12... 13... 14... 15... 16...
1... 2... 3... 4... 5... 6... 7... 8... 9... 10... 11... 12... 13... 14... 15... 16... 17...
set/get (specialized)
1... 2... 3... 4... 5... 6... 7... 8... 8... 9... 10... 11... 12... 13... 14... 15... 16... 17... 18... 19...
set/get (unsafe, specialized)
@@ -21,6 +21,8 @@ blit, fill
1... 2... 3... 4... 5... 6... 7... 8... 9... 10... 11... 12...
slice
1... 2... 3... 6... 7... 8...
init
1... 2... 3... 4...

------ Array2 --------

@@ -38,6 +40,8 @@ sub
1... 2...
slice
1... 2... 3... 4... 5... 6... 7... 8...
init
1... 2... 3... 4...

------ Array3 --------

@@ -53,12 +57,18 @@ size_in_bytes_three
1...
slice1
1... 2... 3... 4... 5... 6... 7...
init
1... 2... 3... 4...
size_in_bytes_general
1...
init
1... 2... 3... 4...
------ Array0 --------

create/set/get
1... 2... 3... 4... 5... 6... 7... 8... 9... 10... 11... 12...
init
1... 2... 3... 4...
kind_size_in_bytes
1... 2... 3... 4... 5... 6... 7... 8... 9... 10... 11... 12... 13...

@@ -319,37 +329,7 @@ Dump hexa: (full size is 96057)
00 c0 87 c8 00 00 00 00 00 40 8a e8 00 00 00 00 00 c0 8a e8 00 00 00 00 00 40 8e 08 00 00 00 00
00 c0 8e 08 00 00 00 00 00 40 90 94 00 00 00 00 00 c0 90 94 00 00 00 00 00 40 65 60 00 00 00 00
14...
Dump hexa: (full size is 16777265)
84 95 a6 be 01 00 00 1d 00 00 00 01 00 00 00 09 00 00 00 09 18 5f 62 69 67 61 72 72 30 32 00 00
00 00 1c 00 00 00 00 00 00 00 38 00 00 00 03 00 00 01 0b 00 01 00 01 ff ff 00 00 00 00 00 0f ff
ff 40 5b c0 00 00 00 00 00 c0 5b c0 00 00 00 00 00 40 5c 00 00 00 00 00 00 c0 5c 00 00 00 00 00
00 40 5c 40 00 00 00 00 00 c0 5c 40 00 00 00 00 00 40 5c 80 00 00 00 00 00 c0 5c 80 00 00 00 00
00 40 5c c0 00 00 00 00 00 c0 5c c0 00 00 00 00 00 40 5d 00 00 00 00 00 00 c0 5d 00 00 00 00 00
00 40 5d 40 00 00 00 00 00 c0 5d 40 00 00 00 00 00 40 5d 80 00 00 00 00 00 c0 5d 80 00 00 00 00
00 40 5d c0 00 00 00 00 00 c0 5d c0 00 00 00 00 00 40 5e 00 00 00 00 00 00 c0 5e 00 00 00 00 00
00 40 5e 40 00 00 00 00 00 c0 5e 40 00 00 00 00 00 40 5e 80 00 00 00 00 00 c0 5e 80 00 00 00 00
00 40 5e c0 00 00 00 00 00 c0 5e c0 00 00 00 00 00 40 5f 00 00 00 00 00 00 c0 5f 00 00 00 00 00
00 40 5f 40 00 00 00 00 00 c0 5f 40 00 00 00 00 00 40 5f 80 00 00 00 00 00 c0 5f 80 00 00 00 00
00 40 5f c0 00 00 00 00 00 c0 5f c0 00 00 00 00 00 40 60 00 00 00 00 00 00 c0 60 00 00 00 00 00
00 40 60 20 00 00 00 00 00 c0 60 20 00 00 00 00 00 40 60 40 00 00 00 00 00 c0 60 40 00 00 00 00
00 40 60 60 00 00 00 00 00 c0 60 60 00 00 00 00 00 40 60 80 00 00 00 00 00 c0 60 80 00 00 00 00
00 40 60 a0 00 00 00 00 00 c0 60 a0 00 00 00 00 00 40 60 c0 00 00 00 00 00 c0 60 c0 00 00 00 00
00 40 60 e0 00 00 00 00 00 c0 60 e0 00 00 00 00 00 40 61 00 00 00 00 00 00 c0 61 00 00 00 00 00
00 40 61 20 00 00 00 00 00 c0 61 20 00 00 00 00 00 40 61 40 00 00 00 00 00 c0 61 40 00 00 00 00
00 40 61 60 00 00 00 00 00 c0 61 60 00 00 00 00 00 40 61 80 00 00 00 00 00 c0 61 80 00 00 00 00
00 40 61 a0 00 00 00 00 00 c0 61 a0 00 00 00 00 00 40 61 c0 00 00 00 00 00 c0 61 c0 00 00 00 00
00 40 61 e0 00 00 00 00 00 c0 61 e0 00 00 00 00 00 40 62 00 00 00 00 00 00 c0 62 00 00 00 00 00
00 40 62 20 00 00 00 00 00 c0 62 20 00 00 00 00 00 40 62 40 00 00 00 00 00 c0 62 40 00 00 00 00
00 40 62 60 00 00 00 00 00 c0 62 60 00 00 00 00 00 40 62 80 00 00 00 00 00 c0 62 80 00 00 00 00
00 40 62 a0 00 00 00 00 00 c0 62 a0 00 00 00 00 00 40 62 c0 00 00 00 00 00 c0 62 c0 00 00 00 00
00 40 62 e0 00 00 00 00 00 c0 62 e0 00 00 00 00 00 40 63 00 00 00 00 00 00 c0 63 00 00 00 00 00
00 40 63 20 00 00 00 00 00 c0 63 20 00 00 00 00 00 40 63 40 00 00 00 00 00 c0 63 40 00 00 00 00
00 40 63 60 00 00 00 00 00 c0 63 60 00 00 00 00 00 40 63 80 00 00 00 00 00 c0 63 80 00 00 00 00
00 40 63 a0 00 00 00 00 00 c0 63 a0 00 00 00 00 00 40 63 c0 00 00 00 00 00 c0 63 c0 00 00 00 00
00 40 63 e0 00 00 00 00 00 c0 63 e0 00 00 00 00 00 40 64 00 00 00 00 00 00 c0 64 00 00 00 00 00
00 40 64 20 00 00 00 00 00 c0 64 20 00 00 00 00 00 40 64 40 00 00 00 00 00 c0 64 40 00 00 00 00
00 40 64 60 00 00 00 00 00 c0 64 60 00 00 00 00 00 40 64 80 00 00 00 00 00 c0 64 80 00 00 00 00
00 40 64 a0 00 00 00 00 00 c0 64 a0 00 00 00 00 00 40 64 c0 00 00 00 00 00 c0 64 c0 00 00 00 00
00 40 64 e0 00 00 00 00 00 c0 64 e0 00 00 00 00 00 40 65 00 00 00 00 00 00 c0 65 00 00 00 00 00
00 40 65 20 00 00 00 00 00 c0 65 20 00 00 00 00 00 40 65 40 00 00 00 00 00 c0 65 40 00 00 00 00
Dump hexa: (full size is 61)
84 95 a6 be 00 00 00 29 00 00 00 01 00 00 00 07 00 00 00 07 18 5f 62 69 67 61 72 72 30 32 00 00
00 00 14 00 00 00 00 00 00 00 28 00 00 00 01 00 00 00 0d 00 04 00 00 34 00 c4 00 42 48
15...
200 changes: 190 additions & 10 deletions compiler/tests-ocaml/lib-bigarray/bigarrays.ml
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
[@@@ocaml.warning "-27"]

(* TEST
*)
(* TEST *)

open Bigarray
open Printf
@@ -30,6 +27,12 @@ let test test_number answer correct_answer =
printf " %d..." test_number
end

let with_trace f =
let events = ref [] in
let trace e = events := e :: !events in
let v = f trace in
(v, List.rev !events)

(* One-dimensional arrays *)

(* flambda can cause some of these values not to be reclaimed by the Gc, which
@@ -240,6 +243,21 @@ let tests () =
done;
test 16 true !return
end;
test 17 true
(test_setget float16
[0.0, 0.0;
-0.5, -0.5;
1.0, 1.0;
infinity, infinity;
neg_infinity, neg_infinity;
Float.min_float, 0.0;
Float.max_float, infinity;
65504.0, 65504.0;
-65504.0, -65504.0;
65519.0, 65504.0;
-65519.0, -65504.0;
65520.0, infinity;
-65520.0, neg_infinity]);

testing_function "set/get (specialized)";
let a = Array1.create int c_layout 3 in
@@ -491,6 +509,26 @@ let tests () =
test 7 (Array1.slice a 2) (Array0.of_value int fortran_layout 4);
test 8 (Array1.slice a 3) (Array0.of_value int fortran_layout 3);

testing_function "init";
let check1 arr graph = List.for_all (fun (i, fi) -> arr.{i} = fi) graph in

let ba, log = with_trace @@ fun trace ->
Array1.init int c_layout 5 (fun x -> trace (x,x); x) in
test 1 log [0,0;
1,1;
2,2;
3,3;
4,4];
test 2 true (check1 ba log);

let ba, log = with_trace @@ fun trace ->
Array1.init int fortran_layout 5 (fun x -> trace (x,x); x) in
test 3 log [1,1;
2,2;
3,3;
4,4;
5,5];
test 4 true (check1 ba log);

(* Bi-dimensional arrays *)

@@ -653,6 +691,25 @@ let tests () =
test 8 (Array2.slice_right a 3)
(from_list_fortran int [1003;2003;3003;4003;5003]);

testing_function "init";
let check2 arr graph = List.for_all (fun ((i,j), fij) -> arr.{i,j} = fij) graph in

let ba, log = with_trace @@ fun trace ->
Array2.init int c_layout 4 2
(fun x y -> let v = 10*x + y in trace ((x,y),v); v) in
test 1 log [(0,0), 00; (0,1), 01;
(1,0), 10; (1,1), 11;
(2,0), 20; (2,1), 21;
(3,0), 30; (3,1), 31];
test 2 true (check2 ba log);

let ba, log = with_trace @@ fun trace ->
Array2.init int fortran_layout 4 2
(fun x y -> let v = 10*x + y in trace ((x,y),v); v) in
test 3 log [(1,1), 11; (2,1), 21; (3,1), 31; (4,1), 41;
(1,2), 12; (2,2), 22; (3,2), 32; (4,2), 42];
test 4 true (check2 ba log);

(* Tri-dimensional arrays *)

print_newline();
@@ -780,10 +837,125 @@ let tests () =
test 6 (Array3.slice_right_1 a 1 2) (from_list_fortran int [112;212;312]);
test 7 (Array3.slice_right_1 a 3 1) (from_list_fortran int [131;231;331]);

testing_function "init";
let check3 arr graph =
List.for_all (fun ((i,j,k), fijk) -> arr.{i,j,k} = fijk) graph in

let ba, log = with_trace @@ fun trace ->
Array3.init int c_layout 4 2 3
(fun x y z -> let v = 100*x + 10*y + z in trace ((x,y,z),v); v) in
test 1 log [(0,0,0), 000; (0,0,1), 001; (0,0,2), 002;
(0,1,0), 010; (0,1,1), 011; (0,1,2), 012;

(1,0,0), 100; (1,0,1), 101; (1,0,2), 102;
(1,1,0), 110; (1,1,1), 111; (1,1,2), 112;

(2,0,0), 200; (2,0,1), 201; (2,0,2), 202;
(2,1,0), 210; (2,1,1), 211; (2,1,2), 212;

(3,0,0), 300; (3,0,1), 301; (3,0,2), 302;
(3,1,0), 310; (3,1,1), 311; (3,1,2), 312];
test 2 true (check3 ba log);

let ba, log = with_trace @@ fun trace ->
Array3.init int fortran_layout 4 2 3
(fun x y z -> let v = 100*x + 10*y + z in trace ((x,y,z), v); v) in
test 3 log [(1,1,1), 111; (2,1,1), 211; (3,1,1), 311; (4,1,1), 411;
(1,2,1), 121; (2,2,1), 221; (3,2,1), 321; (4,2,1), 421;

(1,1,2), 112; (2,1,2), 212; (3,1,2), 312; (4,1,2), 412;
(1,2,2), 122; (2,2,2), 222; (3,2,2), 322; (4,2,2), 422;

(1,1,3), 113; (2,1,3), 213; (3,1,3), 313; (4,1,3), 413;
(1,2,3), 123; (2,2,3), 223; (3,2,3), 323; (4,2,3), 423];
test 4 true (check3 ba log);

testing_function "size_in_bytes_general";
let a = Genarray.create int c_layout [|2;2;2;2;2|] in
test 1 (Genarray.size_in_bytes a) (32 * (kind_size_in_bytes int));

testing_function "init";
let checkgen arr graph =
List.for_all (fun (i, fi) -> Genarray.get arr i = fi) graph in

let ba, log = with_trace @@ fun trace ->
Genarray.init int c_layout [|4; 2; 3; 2|]
(fun i -> let v = 1000*i.(0) + 100*i.(1) + 10*i.(2) + i.(3) in
trace (Array.copy i, v); v) in
test 1 log [[|0;0;0;0|], 0000; [|0;0;0;1|], 0001;
[|0;0;1;0|], 0010; [|0;0;1;1|], 0011;
[|0;0;2;0|], 0020; [|0;0;2;1|], 0021;

[|0;1;0;0|], 0100; [|0;1;0;1|], 0101;
[|0;1;1;0|], 0110; [|0;1;1;1|], 0111;
[|0;1;2;0|], 0120; [|0;1;2;1|], 0121;

[|1;0;0;0|], 1000; [|1;0;0;1|], 1001;
[|1;0;1;0|], 1010; [|1;0;1;1|], 1011;
[|1;0;2;0|], 1020; [|1;0;2;1|], 1021;

[|1;1;0;0|], 1100; [|1;1;0;1|], 1101;
[|1;1;1;0|], 1110; [|1;1;1;1|], 1111;
[|1;1;2;0|], 1120; [|1;1;2;1|], 1121;

[|2;0;0;0|], 2000; [|2;0;0;1|], 2001;
[|2;0;1;0|], 2010; [|2;0;1;1|], 2011;
[|2;0;2;0|], 2020; [|2;0;2;1|], 2021;

[|2;1;0;0|], 2100; [|2;1;0;1|], 2101;
[|2;1;1;0|], 2110; [|2;1;1;1|], 2111;
[|2;1;2;0|], 2120; [|2;1;2;1|], 2121;

[|3;0;0;0|], 3000; [|3;0;0;1|], 3001;
[|3;0;1;0|], 3010; [|3;0;1;1|], 3011;
[|3;0;2;0|], 3020; [|3;0;2;1|], 3021;

[|3;1;0;0|], 3100; [|3;1;0;1|], 3101;
[|3;1;1;0|], 3110; [|3;1;1;1|], 3111;
[|3;1;2;0|], 3120; [|3;1;2;1|], 3121;];
test 2 true (checkgen ba log);

let ba, log = with_trace @@ fun trace ->
Genarray.init int fortran_layout [|4; 2; 3; 2|]
(fun i -> let v = 1000*i.(0) + 100*i.(1) + 10*i.(2) + i.(3) in
trace (Array.copy i, v); v) in
test 3 log [[|1;1;1;1|], 1111; [|2;1;1;1|], 2111;
[|3;1;1;1|], 3111; [|4;1;1;1|], 4111;

[|1;2;1;1|], 1211; [|2;2;1;1|], 2211;
[|3;2;1;1|], 3211; [|4;2;1;1|], 4211;

[|1;1;2;1|], 1121; [|2;1;2;1|], 2121;
[|3;1;2;1|], 3121; [|4;1;2;1|], 4121;

[|1;2;2;1|], 1221; [|2;2;2;1|], 2221;
[|3;2;2;1|], 3221; [|4;2;2;1|], 4221;

[|1;1;3;1|], 1131; [|2;1;3;1|], 2131;
[|3;1;3;1|], 3131; [|4;1;3;1|], 4131;

[|1;2;3;1|], 1231; [|2;2;3;1|], 2231;
[|3;2;3;1|], 3231; [|4;2;3;1|], 4231;

[|1;1;1;2|], 1112; [|2;1;1;2|], 2112;
[|3;1;1;2|], 3112; [|4;1;1;2|], 4112;

[|1;2;1;2|], 1212; [|2;2;1;2|], 2212;
[|3;2;1;2|], 3212; [|4;2;1;2|], 4212;

[|1;1;2;2|], 1122; [|2;1;2;2|], 2122;
[|3;1;2;2|], 3122; [|4;1;2;2|], 4122;

[|1;2;2;2|], 1222; [|2;2;2;2|], 2222;
[|3;2;2;2|], 3222; [|4;2;2;2|], 4222;

[|1;1;3;2|], 1132; [|2;1;3;2|], 2132;
[|3;1;3;2|], 3132; [|4;1;3;2|], 4132;

[|1;2;3;2|], 1232; [|2;2;3;2|], 2232;
[|3;2;3;2|], 3232; [|4;2;3;2|], 4232];
test 4 true (checkgen ba log);

(* Zero-dimensional arrays *)
testing_function "------ Array0 --------";
testing_function "create/set/get";
@@ -888,6 +1060,18 @@ let tests () =
{im=0.5;re= -2.0}, {im=0.5;re= -2.0};
{im=3.1415;re=1.2345678}, {im=3.1415;re=1.2345678}]);

testing_function "init";
let ba = Array0.init int c_layout 10 in
test 1 ba (Array0.of_value int c_layout 10);

let ba = Array0.init int fortran_layout 10 in
test 2 ba (Array0.of_value int fortran_layout 10);

let ba = Bigarray.(Genarray.init float64 c_layout [||] (fun _ -> 5.)) in
test 3 5. (Bigarray.Genarray.get ba [||]);

let ba = Bigarray.(Genarray.init float64 fortran_layout [||] (fun _ -> 5.)) in
test 4 5. (Bigarray.Genarray.get ba [||]);

(* Kind size *)
testing_function "kind_size_in_bytes";
@@ -947,8 +1131,7 @@ let tests () =
test 9 (Genarray.get c [|0|]) 3;
test 10 (Genarray.get (Genarray.slice_left c [|0|]) [||]) 3;

(* I/O *)

(* I/O *)
let dump_content_hex file =
let ic = open_in_bin file in
let len = in_channel_length ic in
@@ -963,7 +1146,6 @@ let tests () =
close_in ic;
Printf.printf "\n"
in

print_newline();
testing_function "------ I/O --------";
testing_function "output_value/input_value";
@@ -996,9 +1178,7 @@ let tests () =
test_structured_io 13 (make_array2 complex32 c_layout 0 100 100 makecomplex);
test_structured_io 14 (make_array3 complex64 fortran_layout 1 10 20 30
makecomplex);
test_structured_io 15 (make_array3 complex64 fortran_layout 1 1 1 0xfffff
makecomplex);

test_structured_io 15 (from_list float16 [0.0; 0.25; -4.0; 3.141592654;]);
()
[@@inline never]

9 changes: 8 additions & 1 deletion compiler/tests-ocaml/lib-bigarray/dune
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
(tests
(names bigarrays change_layout fftba pr5115 weak_bigarray)
(names change_layout fftba pr5115 weak_bigarray)
(libraries)
(modes js wasm))

(tests
(names bigarrays specialized)
(build_if
(>= %{ocaml_version} 5.2))
(libraries)
(modes js wasm))
91 changes: 91 additions & 0 deletions compiler/tests-ocaml/lib-bigarray/specialized.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
(* TEST *)

open Bigarray

(* Check that type-specialized accesses produce the same results
as generic accesses *)

let generic (a: ('a, 'b, 'c) Array1.t) v0 v1 v2 =
a.{0} <- v0; a.{1} <- v1; a.{2} <- v2;
(a.{0}, a.{1}, a.{2})

let special_float16 (a: (float, float16_elt, c_layout) Array1.t) v0 v1 v2 =
a.{0} <- v0; a.{1} <- v1; a.{2} <- v2;
(a.{0}, a.{1}, a.{2})

let special_float32 (a: (float, float32_elt, c_layout) Array1.t) v0 v1 v2 =
a.{0} <- v0; a.{1} <- v1; a.{2} <- v2;
(a.{0}, a.{1}, a.{2})

let special_float64 (a: (float, float64_elt, c_layout) Array1.t) v0 v1 v2 =
a.{0} <- v0; a.{1} <- v1; a.{2} <- v2;
(a.{0}, a.{1}, a.{2})

let special_int8s (a: (int, int8_signed_elt, c_layout) Array1.t) v0 v1 v2 =
a.{0} <- v0; a.{1} <- v1; a.{2} <- v2;
(a.{0}, a.{1}, a.{2})

let special_int8u (a: (int, int8_unsigned_elt, c_layout) Array1.t) v0 v1 v2 =
a.{0} <- v0; a.{1} <- v1; a.{2} <- v2;
(a.{0}, a.{1}, a.{2})

let special_int16s (a: (int, int16_signed_elt, c_layout) Array1.t) v0 v1 v2 =
a.{0} <- v0; a.{1} <- v1; a.{2} <- v2;
(a.{0}, a.{1}, a.{2})

let special_int16u (a: (int, int16_unsigned_elt, c_layout) Array1.t) v0 v1 v2 =
a.{0} <- v0; a.{1} <- v1; a.{2} <- v2;
(a.{0}, a.{1}, a.{2})

let special_int32 (a: (int32, int32_elt, c_layout) Array1.t) v0 v1 v2 =
a.{0} <- v0; a.{1} <- v1; a.{2} <- v2;
(a.{0}, a.{1}, a.{2})

let special_int64 (a: (int64, int64_elt, c_layout) Array1.t) v0 v1 v2 =
a.{0} <- v0; a.{1} <- v1; a.{2} <- v2;
(a.{0}, a.{1}, a.{2})

let special_int (a: (int, int_elt, c_layout) Array1.t) v0 v1 v2 =
a.{0} <- v0; a.{1} <- v1; a.{2} <- v2;
(a.{0}, a.{1}, a.{2})

let special_nativeint (a: (nativeint, nativeint_elt, c_layout) Array1.t)
v0 v1 v2 =
a.{0} <- v0; a.{1} <- v1; a.{2} <- v2;
(a.{0}, a.{1}, a.{2})

let special_complex32 (a: (Complex.t, complex32_elt, c_layout) Array1.t)
v0 v1 v2 =
a.{0} <- v0; a.{1} <- v1; a.{2} <- v2;
(a.{0}, a.{1}, a.{2})

let special_complex64 (a: (Complex.t, complex64_elt, c_layout) Array1.t)
v0 v1 v2 =
a.{0} <- v0; a.{1} <- v1; a.{2} <- v2;
(a.{0}, a.{1}, a.{2})

let special_char (a: (char, int8_unsigned_elt, c_layout) Array1.t) v0 v1 v2 =
a.{0} <- v0; a.{1} <- v1; a.{2} <- v2;
(a.{0}, a.{1}, a.{2})

let test kind special v0 v1 v2 =
let a = Array1.create kind c_layout 3 in
let s = special a v0 v1 v2 in
let g = generic a v0 v1 v2 in
assert (s = g)

let _ =
test float16 special_float16 1.0 (-2.0) Float.pi;
test float32 special_float32 1.0 (-2.0) Float.pi;
test float64 special_float64 1.0 (-2.0) Float.pi;
test int8_signed special_int8s 123 (-456) 0xFF00FF;
test int8_unsigned special_int8u 123 (-456) 0xFF00FF;
test int16_signed special_int16s 123 (-456) 0xFF00FF;
test int16_unsigned special_int16u 123 (-456) 0xFF00FF;
test int32 special_int32 123l (-456l) (0x22334455l);
test int64 special_int64 123L (-456L) (0x2233445566778899L);
test int special_int 123 (-456) 0xFF00FF;
test nativeint special_nativeint 123n (-456n) (0x22334455n);
test complex32 special_complex32 Complex.zero Complex.one Complex.i;
test complex64 special_complex64 Complex.zero Complex.one Complex.i;
test char special_char 'A' '-' 'Z'
128 changes: 127 additions & 1 deletion runtime/js/bigarray.js
Original file line number Diff line number Diff line change
@@ -42,6 +42,79 @@ function caml_ba_get_size(dims) {
return size;
}

//Provides: caml_unpackFloat16
var caml_unpackFloat16 = (function () {
var pow = Math.pow;

var EXP_MASK16 = 31; // 2 ** 5 - 1
var SIGNIFICAND_MASK16 = 1023; // 2 ** 10 - 1
var MIN_SUBNORMAL16 = pow(2, -24); // 2 ** -10 * 2 ** -14
var SIGNIFICAND_DENOM16 = 0.0009765625; // 2 ** -10

return function (bytes) {
var sign = bytes >>> 15;
var exponent = (bytes >>> 10) & EXP_MASK16;
var significand = bytes & SIGNIFICAND_MASK16;
if (exponent === EXP_MASK16)
return significand === 0
? sign === 0
? Number.POSITIVE_INFINITY
: Number.NEGATIVE_INFINITY
: Number.NaN;
if (exponent === 0)
return significand * (sign === 0 ? MIN_SUBNORMAL16 : -MIN_SUBNORMAL16);
var r =
pow(2, exponent - 15) *
(sign === 0
? 1 + significand * SIGNIFICAND_DENOM16
: -1 - significand * SIGNIFICAND_DENOM16);
return r;
};
})();

//Provides: caml_packFloat16
var caml_packFloat16 = (function () {
var pow = Math.pow;
var MIN_INFINITY16 = 65520; // (2 - 2 ** -11) * 2 ** 15
var MIN_NORMAL16 = 0.000061005353927612305; // (1 - 2 ** -11) * 2 ** -14
var REC_MIN_SUBNORMAL16 = 16777216; // 2 ** 10 * 2 ** 14
var REC_SIGNIFICAND_DENOM16 = 1024; // 2 ** 10;

var EPSILON = 2.220446049250313e-16; // Number.EPSILON
var INVERSE_EPSILON = 1 / EPSILON;

function roundTiesToEven(n) {
return n + INVERSE_EPSILON - INVERSE_EPSILON;
}
return function (value) {
var orig = value;
if (Number.isNaN(value)) return 0x7e00; // NaN
if (value === 0) return (1 / value === Number.NEGATIVE_INFINITY) << 15; // +0 or -0

var neg = value < 0;
if (neg) value = -value;
if (value >= MIN_INFINITY16) return (neg << 15) | 0x7c00; // Infinity
if (value < MIN_NORMAL16)
return (neg << 15) | roundTiesToEven(value * REC_MIN_SUBNORMAL16); // subnormal

// normal
var exponent = Math.log2(value) | 0;
if (exponent === -15) {
// we round from a value between 2 ** -15 * (1 + 1022/1024) (the largest subnormal) and 2 ** -14 * (1 + 0/1024) (the smallest normal)
// to the latter (former impossible because of the subnormal check above)
return (neg << 15) | REC_SIGNIFICAND_DENOM16;
}
var significand = roundTiesToEven(
(value * pow(2, -exponent) - 1) * REC_SIGNIFICAND_DENOM16,
);
if (significand === REC_SIGNIFICAND_DENOM16) {
// we round from a value between 2 ** n * (1 + 1023/1024) and 2 ** (n + 1) * (1 + 0/1024) to the latter
return (neg << 15) | ((exponent + 16) << 10);
}
return (neg << 15) | ((exponent + 15) << 10) | significand;
};
})();

//Provides: caml_ba_get_size_per_element
function caml_ba_get_size_per_element(kind) {
switch (kind) {
@@ -99,6 +172,9 @@ function caml_ba_create_buffer(kind, size) {
case 12:
view = Uint8Array;
break;
case 13:
view = Uint16Array;
break;
}
if (!view) caml_invalid_argument("Bigarray.create: unsupported kind");
var data = new view(size * caml_ba_get_size_per_element(kind));
@@ -116,6 +192,7 @@ var caml_ba_custom_name = "_bigarr02";
//Provides: Ml_Bigarray
//Requires: caml_array_bound_error, caml_invalid_argument, caml_ba_custom_name
//Requires: caml_int64_create_lo_hi, caml_int64_hi32, caml_int64_lo32
//Requires: caml_packFloat16, caml_unpackFloat16
function Ml_Bigarray(kind, layout, dims, buffer) {
this.kind = kind;
this.layout = layout;
@@ -160,6 +237,8 @@ Ml_Bigarray.prototype.get = function (ofs) {
var r = this.data[ofs * 2 + 0];
var i = this.data[ofs * 2 + 1];
return [254, r, i];
case 13:
return caml_unpackFloat16(this.data[ofs]);
default:
return this.data[ofs];
}
@@ -178,6 +257,9 @@ Ml_Bigarray.prototype.set = function (ofs, v) {
this.data[ofs * 2 + 0] = v[1];
this.data[ofs * 2 + 1] = v[2];
break;
case 13:
this.data[ofs] = caml_packFloat16(v);
break;
default:
this.data[ofs] = v;
break;
@@ -212,6 +294,9 @@ Ml_Bigarray.prototype.fill = function (v) {
}
}
break;
case 13:
this.data.fill(caml_packFloat16(v));
break;
default:
this.data.fill(v);
break;
@@ -258,6 +343,14 @@ Ml_Bigarray.prototype.compare = function (b, total) {
if (this.data[i] >>> 0 > b.data[i] >>> 0) return 1;
}
break;
case 13:
for (var i = 0; i < this.data.length; i++) {
var aa = caml_unpackFloat16(this.data[i]);
var bb = caml_unpackFloat16(b.data[i]);
if (aa < bb) return -1;
if (aa > bb) return 1;
}
break;
case 2:
case 3:
case 4:
@@ -324,7 +417,8 @@ function caml_ba_create_unsafe(kind, layout, dims, data) {
if (
layout === 0 && // c_layout
dims.length === 1 && // Array1
size_per_element === 1
size_per_element === 1 &&
kind !== 13 // float16
)
// 1-to-1 mapping
return new Ml_Bigarray_c_1_1(kind, layout, dims, data);
@@ -613,6 +707,7 @@ function caml_ba_reshape(ba, vind) {
//Provides: caml_ba_serialize
//Requires: caml_int64_bits_of_float, caml_int64_to_bytes
//Requires: caml_int32_bits_of_float
//Requires: caml_packFloat16
function caml_ba_serialize(writer, ba, sz) {
writer.write(32, ba.dims.length);
writer.write(32, ba.kind | (ba.layout << 8));
@@ -664,6 +759,11 @@ function caml_ba_serialize(writer, ba, sz) {
for (var j = 0; j < 8; j++) writer.write(8, b[j]);
}
break;
case 13: // Float16Array
for (var i = 0; i < ba.data.length; i++) {
writer.write(16, ba.data[i]);
}
break;
case 0: // Float32Array
for (var i = 0; i < ba.data.length; i++) {
var b = caml_int32_bits_of_float(ba.get(i));
@@ -697,6 +797,7 @@ function caml_ba_serialize(writer, ba, sz) {
//Requires: caml_int64_of_bytes, caml_int64_float_of_bits
//Requires: caml_int32_float_of_bits
//Requires: caml_ba_create_buffer
//Requires: caml_unpackFloat16
function caml_ba_deserialize(reader, sz, name) {
var num_dims = reader.read32s();
if (num_dims < 0 || num_dims > 16)
@@ -775,6 +876,11 @@ function caml_ba_deserialize(reader, sz, name) {
ba.set(i, f);
}
break;
case 13: // Float16Array
for (var i = 0; i < size; i++) {
data[i] = reader.read16u();
}
break;
case 0: // Float32Array
for (var i = 0; i < size; i++) {
var f = caml_int32_float_of_bits(reader.read32s());
@@ -817,6 +923,7 @@ function caml_ba_create_from(data1, data2, jstyp, kind, layout, dims) {

//Provides: caml_ba_hash const
//Requires: caml_ba_get_size, caml_hash_mix_int, caml_hash_mix_float
//Requires: caml_unpackFloat16, caml_hash_mix_float16
function caml_ba_hash(ba) {
var num_elts = caml_ba_get_size(ba.dims);
var h = 0;
@@ -893,10 +1000,29 @@ function caml_ba_hash(ba) {
if (num_elts > 32) num_elts = 32;
for (var i = 0; i < num_elts; i++) h = caml_hash_mix_float(h, ba.data[i]);
break;
case 13:
if (num_elts > 128) num_elts = 128;
for (var i = 0; i < num_elts; i++) {
h = caml_hash_mix_float16(h, ba.data[i]);
}
break;
}
return h;
}

//Provides: caml_hash_mix_float16
//Requires: caml_hash_mix_int
function caml_hash_mix_float16(h, d) {
/* Normalize NaNs */
if ((d & 0x7c00) === 0x7c00 && (d & 0x03ff) !== 0) {
d = 0x7c01;
} else if (d === 0x8000) {
/* Normalize -0 into +0 */
d = 0;
}
return caml_hash_mix_int(hash, d);
}

//Provides: caml_ba_to_typed_array mutable
function caml_ba_to_typed_array(ba) {
return ba.data;