Skip to content

Commit 5e9ba5b

Browse files
committed
Wasm: specialization of number comparisons
1 parent 5e04f91 commit 5e9ba5b

File tree

2 files changed

+144
-10
lines changed

2 files changed

+144
-10
lines changed

compiler/lib-wasm/generate.ml

Lines changed: 110 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,13 +110,6 @@ module Generate (Target : Target_sig.S) = struct
110110
; "caml_erf_float", (`Pure, [ Float ], Float)
111111
; "caml_erfc_float", (`Pure, [ Float ], Float)
112112
; "caml_float_compare", (`Pure, [ Float; Float ], Int)
113-
; "caml_greaterthan", (`Mutable, [ Value; Value ], Int)
114-
; "caml_greaterequal", (`Mutable, [ Value; Value ], Int)
115-
; "caml_lessthan", (`Mutable, [ Value; Value ], Int)
116-
; "caml_lessequal", (`Mutable, [ Value; Value ], Int)
117-
; "caml_equal", (`Mutable, [ Value; Value ], Int)
118-
; "caml_notequal", (`Mutable, [ Value; Value ], Int)
119-
; "caml_compare", (`Mutable, [ Value; Value ], Int)
120113
];
121114
h
122115

@@ -285,6 +278,39 @@ module Generate (Target : Target_sig.S) = struct
285278
(transl_prim_arg ctx ?typ:tz z)
286279
| _ -> invalid_arity name l ~expected:3)
287280

281+
let register_comparison name cmp_int cmp_boxed_int cmp_float =
282+
register_prim name `Mutable (fun ctx _ l ->
283+
match l with
284+
| [ x; y ] -> (
285+
match get_type ctx x, get_type ctx y with
286+
| Int _, Int _ -> cmp_int ctx x y
287+
| Number (Int32, _), Number (Int32, _) ->
288+
let x = transl_prim_arg ctx ~typ:(Number (Int32, Unboxed)) x in
289+
let y = transl_prim_arg ctx ~typ:(Number (Int32, Unboxed)) y in
290+
int32_bin_op cmp_boxed_int x y
291+
| Number (Nativeint, _), Number (Nativeint, _) ->
292+
let x = transl_prim_arg ctx ~typ:(Number (Nativeint, Unboxed)) x in
293+
let y = transl_prim_arg ctx ~typ:(Number (Nativeint, Unboxed)) y in
294+
nativeint_bin_op cmp_boxed_int x y
295+
| Number (Int64, _), Number (Int64, _) ->
296+
let x = transl_prim_arg ctx ~typ:(Number (Int64, Unboxed)) x in
297+
let y = transl_prim_arg ctx ~typ:(Number (Int64, Unboxed)) y in
298+
int64_bin_op cmp_boxed_int x y
299+
| Number (Float, _), Number (Float, _) ->
300+
let x = transl_prim_arg ctx ~typ:(Number (Float, Unboxed)) x in
301+
let y = transl_prim_arg ctx ~typ:(Number (Float, Unboxed)) y in
302+
float_bin_op cmp_float x y
303+
| _ ->
304+
let* f =
305+
register_import
306+
~name
307+
(Fun { W.params = [ Type.value; Type.value ]; result = [ I32 ] })
308+
in
309+
let* x = transl_prim_arg ctx x in
310+
let* y = transl_prim_arg ctx y in
311+
return (W.Call (f, [ x; y ])))
312+
| _ -> invalid_arity name l ~expected:2)
313+
288314
let () =
289315
register_bin_prim
290316
"caml_floatarray_unsafe_get"
@@ -1087,7 +1113,83 @@ module Generate (Target : Target_sig.S) = struct
10871113
~ty:(Int Normalized)
10881114
(fun i j -> Arith.((j < i) - (i < j)));
10891115
register_prim "%js_array" `Pure (fun ctx _ l ->
1090-
Memory.allocate ~tag:0 (expression_list (fun x -> transl_prim_arg ctx x) l))
1116+
Memory.allocate ~tag:0 (expression_list (fun x -> transl_prim_arg ctx x) l));
1117+
register_comparison
1118+
"caml_greaterthan"
1119+
(fun ctx x y -> translate_int_comparison ctx (fun y x -> Arith.(x < y)) x y)
1120+
(Gt S)
1121+
Gt;
1122+
register_comparison
1123+
"caml_greaterequal"
1124+
(fun ctx x y -> translate_int_comparison ctx (fun y x -> Arith.(x <= y)) x y)
1125+
(Ge S)
1126+
Ge;
1127+
register_comparison
1128+
"caml_lessthan"
1129+
(fun ctx x y -> translate_int_comparison ctx Arith.( < ) x y)
1130+
(Lt S)
1131+
Lt;
1132+
register_comparison
1133+
"caml_lessequal"
1134+
(fun ctx x y -> translate_int_comparison ctx Arith.( <= ) x y)
1135+
(Le S)
1136+
Le;
1137+
register_comparison
1138+
"caml_equal"
1139+
(fun ctx x y -> translate_int_equality ctx ~negate:false x y)
1140+
Eq
1141+
Eq;
1142+
register_comparison
1143+
"caml_notequal"
1144+
(fun ctx x y -> translate_int_equality ctx ~negate:true x y)
1145+
Ne
1146+
Ne;
1147+
register_prim "caml_compare" `Mutable (fun ctx _ l ->
1148+
match l with
1149+
| [ x; y ] -> (
1150+
match get_type ctx x, get_type ctx y with
1151+
| Int _, Int _ ->
1152+
let x' = transl_prim_arg ctx ~typ:(Int Normalized) x in
1153+
let y' = transl_prim_arg ctx ~typ:(Int Normalized) y in
1154+
Arith.((y' < x') - (x' < y'))
1155+
| Number (Int32, _), Number (Int32, _)
1156+
| Number (Nativeint, _), Number (Nativeint, _) ->
1157+
let* f =
1158+
register_import
1159+
~name:"caml_int32_compare"
1160+
(Fun { W.params = [ I32; I32 ]; result = [ I32 ] })
1161+
in
1162+
let* x' = transl_prim_arg ctx ~typ:(Number (Int32, Unboxed)) x in
1163+
let* y' = transl_prim_arg ctx ~typ:(Number (Int32, Unboxed)) y in
1164+
return (W.Call (f, [ x'; y' ]))
1165+
| Number (Int64, _), Number (Int64, _) ->
1166+
let* f =
1167+
register_import
1168+
~name:"caml_int64_compare"
1169+
(Fun { W.params = [ I64; I64 ]; result = [ I32 ] })
1170+
in
1171+
let* x' = transl_prim_arg ctx ~typ:(Number (Int64, Unboxed)) x in
1172+
let* y' = transl_prim_arg ctx ~typ:(Number (Int64, Unboxed)) y in
1173+
return (W.Call (f, [ x'; y' ]))
1174+
| Number (Float, _), Number (Float, _) ->
1175+
let* f =
1176+
register_import
1177+
~name:"caml_float_compare"
1178+
(Fun { W.params = [ F64; F64 ]; result = [ I32 ] })
1179+
in
1180+
let* x' = transl_prim_arg ctx ~typ:(Number (Float, Unboxed)) x in
1181+
let* y' = transl_prim_arg ctx ~typ:(Number (Float, Unboxed)) y in
1182+
return (W.Call (f, [ x'; y' ]))
1183+
| _ ->
1184+
let* f =
1185+
register_import
1186+
~name:"caml_compare"
1187+
(Fun { W.params = [ Type.value; Type.value ]; result = [ I32 ] })
1188+
in
1189+
let* x' = transl_prim_arg ctx x in
1190+
let* y' = transl_prim_arg ctx y in
1191+
return (W.Call (f, [ x'; y' ])))
1192+
| _ -> invalid_arity "caml_compare" l ~expected:2)
10911193

10921194
let unboxed_type ty : W.value_type option =
10931195
match ty with

compiler/lib-wasm/typing.ml

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,24 @@ let primitives_with_unboxed_parameters =
588588
];
589589
h
590590

591+
let type_specialized_primitive types name args =
592+
match name with
593+
| "caml_greaterthan"
594+
| "caml_greaterequal"
595+
| "caml_lessthan"
596+
| "caml_lessequal"
597+
| "caml_equal"
598+
| "caml_notequal"
599+
| "caml_compare" -> (
600+
match List.map ~f:(arg_type ~approx:types) args with
601+
| [ Int _; Int _ ]
602+
| [ Number (Int32, _); Number (Int32, _) ]
603+
| [ Number (Int64, _); Number (Int64, _) ]
604+
| [ Number (Nativeint, _); Number (Nativeint, _) ]
605+
| [ Number (Float, _); Number (Float, _) ] -> true
606+
| _ -> false)
607+
| _ -> false
608+
591609
let box_numbers p st types =
592610
(* We box numbers eagerly if the boxed value is ever used. *)
593611
let should_box = Var.ISet.empty () in
@@ -634,7 +652,9 @@ let box_numbers p st types =
634652
then List.iter ~f:box args
635653
| Block (tag, lst, _, _) -> if tag <> 254 then Array.iter ~f:box lst
636654
| Prim (Extern s, args) ->
637-
if not (String.Hashtbl.mem primitives_with_unboxed_parameters s)
655+
if
656+
(not (String.Hashtbl.mem primitives_with_unboxed_parameters s))
657+
|| type_specialized_primitive types s args
638658
then
639659
List.iter
640660
~f:(fun a ->
@@ -660,6 +680,12 @@ let box_numbers p st types =
660680
())
661681
()
662682

683+
let print_opt typ f e =
684+
match e with
685+
| Prim (Extern name, args) when type_specialized_primitive typ name args ->
686+
Format.fprintf f " OPT"
687+
| _ -> ()
688+
663689
type t =
664690
{ types : typ Var.Tbl.t
665691
; return_types : typ Var.Hashtbl.t
@@ -689,7 +715,13 @@ let f ~global_flow_state ~global_flow_info ~fun_info ~deadcode_sentinal p =
689715
Format.err_formatter
690716
(fun _ i ->
691717
match i with
692-
| Instr (Let (x, _)) -> Format.asprintf "{%a}" Domain.print (Var.Tbl.get types x)
718+
| Instr (Let (x, e)) ->
719+
Format.asprintf
720+
"{%a}%a"
721+
Domain.print
722+
(Var.Tbl.get types x)
723+
(print_opt types)
724+
e
693725
| _ -> "")
694726
p);
695727
let return_types = Var.Hashtbl.create 128 in

0 commit comments

Comments
 (0)