From 3636592dbb7901cbf56455c55d72d16c0e41ec0d Mon Sep 17 00:00:00 2001 From: Hugo Heuzard Date: Fri, 25 Oct 2024 21:45:57 +0200 Subject: [PATCH 01/14] Compiler: consume hints for immutable blocks --- compiler/lib/ocaml_compiler.ml | 2 + compiler/lib/ocaml_compiler.mli | 2 + compiler/lib/parse_bytecode.ml | 133 ++++- compiler/tests-compiler/gh747.ml | 2 +- compiler/tests-full/stdlib.cma.expected.js | 651 ++++++++++----------- 5 files changed, 438 insertions(+), 352 deletions(-) diff --git a/compiler/lib/ocaml_compiler.ml b/compiler/lib/ocaml_compiler.ml index 0c4ed37a34..9b396c1e9d 100644 --- a/compiler/lib/ocaml_compiler.ml +++ b/compiler/lib/ocaml_compiler.ml @@ -283,4 +283,6 @@ module Cmo_format = struct let imports (t : t) = t.cu_imports let force_link (t : t) = t.cu_force_link + + let hints_pos (t : t) = t.cu_hint end diff --git a/compiler/lib/ocaml_compiler.mli b/compiler/lib/ocaml_compiler.mli index 0c4c31dd8a..4f69e6197e 100644 --- a/compiler/lib/ocaml_compiler.mli +++ b/compiler/lib/ocaml_compiler.mli @@ -73,4 +73,6 @@ module Cmo_format : sig val force_link : t -> bool val imports : t -> (string * string option) list + + val hints_pos : t -> int end diff --git a/compiler/lib/parse_bytecode.ml b/compiler/lib/parse_bytecode.ml index 4f089e7f61..3ab9042875 100644 --- a/compiler/lib/parse_bytecode.ml +++ b/compiler/lib/parse_bytecode.ml @@ -333,6 +333,63 @@ end = struct StringSet.of_list (List.concat paths) end +module Hints = struct + module Primitive = struct + type boxed_integer = + | Pnativeint + | Pint32 + | Pint64 + + type native_repr = + | Same_as_ocaml_repr + | Unboxed_float + | Unboxed_integer of boxed_integer + | Untagged_immediate + + type description = + { prim_name : string (* Name of primitive or C function *) + ; prim_arity : int (* Number of arguments *) + ; prim_alloc : bool (* Does it allocates or raise? *) + ; prim_native_name : string (* Name of C function for the nat. code gen. *) + ; prim_native_repr_args : native_repr list + ; prim_native_repr_res : native_repr + } + [@@ocaml.warning "-unused-field"] + end + + type optimization_hint = + | Hint_immutable + | Hint_unsafe + | Hint_int of Primitive.boxed_integer + | Hint_array of Lambda.array_kind + | Hint_bigarray of + { unsafe : bool + ; elt_kind : Lambda.bigarray_kind + ; layout : Lambda.bigarray_layout + } + | Hint_primitive of Primitive.description + + type t = { hints : optimization_hint Int.Hashtbl.t } + + let equal (a : optimization_hint) b = Poly.equal a b + + let create () = { hints = Int.Hashtbl.create 17 } + + let read t ~orig ic = + let l : (int * optimization_hint) list = input_value ic in + + List.iter l ~f:(fun (pos, hint) -> Int.Hashtbl.add t.hints ((pos + orig) / 4) hint) + + let read_section t ic = + let len = input_binary_int ic in + for _i = 0 to len - 1 do + let orig = input_binary_int ic in + read t ~orig ic + done + + let find t pc = Int.Hashtbl.find_all t.hints pc +end + (* Block analysis *) (* Detect each block *) module Blocks : sig @@ -864,6 +921,7 @@ type compile_info = ; code : string ; limit : int ; debug : Debug.t + ; hints : Hints.t } let string_of_addr debug_data addr = @@ -886,9 +944,11 @@ let string_of_addr debug_data addr = in Printf.sprintf "%s:%s-%s %s" file (pos loc.loc_start) (pos loc.loc_end) kind) -let is_immutable _instr _infos _pc = (* We don't know yet *) Maybe_mutable +let is_immutable _instr infos pc = + let hints = Hints.find infos.hints pc in + if List.mem ~eq:Hints.equal Hints.Hint_immutable hints then Immutable else Maybe_mutable -let rec compile_block blocks joins debug_data code pc state : unit = +let rec compile_block blocks joins hints debug_data code pc state : unit = match Addr.Map.find_opt pc !tagged_blocks with | Some old_state -> ( (* Check that the shape of the stack is compatible with the one used to compile the block *) @@ -920,7 +980,7 @@ let rec compile_block blocks joins debug_data code pc state : unit = let state = if Addr.Set.mem pc joins then State.start_block pc state else state in tagged_blocks := Addr.Map.add pc state !tagged_blocks; let instr, last, state' = - compile { blocks; joins; code; limit; debug = debug_data } pc state [] + compile { blocks; joins; code; limit; debug = debug_data; hints } pc state [] in assert (not (Addr.Map.mem pc !compiled_blocks)); (* When jumping to a block that was already visited and the @@ -959,10 +1019,10 @@ let rec compile_block blocks joins debug_data code pc state : unit = !compiled_blocks; match last with | Branch (pc', _) -> - compile_block blocks joins debug_data code pc' (adjust_state pc') + compile_block blocks joins hints debug_data code pc' (adjust_state pc') | Cond (_, (pc1, _), (pc2, _)) -> - compile_block blocks joins debug_data code pc1 (adjust_state pc1); - compile_block blocks joins debug_data code pc2 (adjust_state pc2) + compile_block blocks joins hints debug_data code pc1 (adjust_state pc1); + compile_block blocks joins hints debug_data code pc2 (adjust_state pc2) | Poptrap (_, _) -> () | Switch (_, _) -> () | Raise _ | Return _ | Stop -> () @@ -1289,7 +1349,7 @@ and compile infos pc state (instrs : instr list) = let params, state' = State.make_stack nparams state' in if debug_parser () then Format.printf ") {@."; let state' = State.clear_accu state' in - compile_block infos.blocks infos.joins infos.debug code addr state'; + compile_block infos.blocks infos.joins infos.hints infos.debug code addr state'; if debug_parser () then Format.printf "}@."; compile infos @@ -1347,7 +1407,14 @@ and compile infos pc state (instrs : instr list) = let params, state' = State.make_stack nparams state' in if debug_parser () then Format.printf ") {@."; let state' = State.clear_accu state' in - compile_block infos.blocks infos.joins infos.debug code addr state'; + compile_block + infos.blocks + infos.joins + infos.hints + infos.debug + code + addr + state'; if debug_parser () then Format.printf "}@."; Let ( x @@ -1759,9 +1826,9 @@ and compile infos pc state (instrs : instr list) = let it = Array.init isize ~f:(fun i -> base + gets code (base + i)) in let bt = Array.init bsize ~f:(fun i -> base + gets code (base + isize + i)) in Array.iter it ~f:(fun pc' -> - compile_block infos.blocks infos.joins infos.debug code pc' state); + compile_block infos.blocks infos.joins infos.hints infos.debug code pc' state); Array.iter bt ~f:(fun pc' -> - compile_block infos.blocks infos.joins infos.debug code pc' state); + compile_block infos.blocks infos.joins infos.hints infos.debug code pc' state); match isize, bsize with | _, 0 -> instrs, Switch (x, Array.map it ~f:(fun pc -> pc, [])), state | 0, _ -> @@ -1828,10 +1895,18 @@ and compile infos pc state (instrs : instr list) = interm_addr (Some handler_ctx_state, [], Pushtrap ((body_addr, []), x, (handler_addr, []))) !compiled_blocks; - compile_block infos.blocks infos.joins infos.debug code handler_addr handler_state; compile_block infos.blocks infos.joins + infos.hints + infos.debug + code + handler_addr + handler_state; + compile_block + infos.blocks + infos.joins + infos.hints infos.debug code body_addr @@ -1850,6 +1925,7 @@ and compile infos pc state (instrs : instr list) = compile_block infos.blocks infos.joins + infos.hints infos.debug code addr @@ -2539,7 +2615,7 @@ type one = ; debug : Debug.summary } -let parse_bytecode code globals debug_data = +let parse_bytecode code globals hints debug_data = let immutable = Code.Var.Hashtbl.create 0 in let state = State.initial globals immutable in Code.Var.reset (); @@ -2550,7 +2626,7 @@ let parse_bytecode code globals debug_data = then ( let start = 0 in - compile_block blocks' joins debug_data code start state; + compile_block blocks' joins hints debug_data code start state; let blocks = Addr.Map.mapi (fun _ (state, instr, last) -> @@ -2674,6 +2750,7 @@ let from_exe ?(debug = false) ic = let debug_data = Debug.create ~include_cmis debug in + let hints = Hints.create () in let toc = Toc.read ic in let primitives = read_primitives toc ic in let primitive_table = Array.of_list primitives in @@ -2720,6 +2797,11 @@ let from_exe available.@."); if times () then Format.eprintf " read debug events: %a@." Timer.print t; + (try + ignore (Toc.seek_section toc ic "HINT"); + Hints.read_section hints ic + with Not_found -> ()); + let globals = make_globals (Array.length init_data) init_data primitive_table in if linkall then @@ -2727,7 +2809,7 @@ let from_exe Ocaml_compiler.Symtable.GlobalMap.iter symbols ~f:(fun id n -> globals.named_value.(n) <- Some (Ocaml_compiler.Symtable.Global.name id); globals.is_exported.(n) <- true); - let p = parse_bytecode code globals debug_data in + let p = parse_bytecode code globals hints debug_data in (* register predefined exception *) let body = List.fold_left predefined_exceptions ~init:[] ~f:(fun body (i, name) -> @@ -2835,6 +2917,7 @@ let from_exe (* As input: list of primitives + size of global table *) let from_bytes ~prims ~debug (code : bytecode) = let debug_data = Debug.create ~include_cmis:false true in + let hints = Hints.create () in let t = Timer.make () in if Debug.names debug_data then @@ -2857,7 +2940,7 @@ let from_bytes ~prims ~debug (code : bytecode) = t in let globals = make_globals 0 [||] prims in - let p = parse_bytecode code globals debug_data in + let p = parse_bytecode code globals hints debug_data in let gdata = Var.fresh_n "global_data" in let need_gdata = ref false in let find_name i = @@ -2989,7 +3072,7 @@ module Reloc = struct globals end -let from_compilation_units ~includes:_ ~include_cmis ~debug_data l = +let from_compilation_units ~includes:_ ~include_cmis ~hints ~debug_data l = let reloc = Reloc.create () in List.iter l ~f:(fun (compunit, code) -> Reloc.step1 reloc compunit code); List.iter l ~f:(fun (compunit, code) -> Reloc.step2 reloc compunit code); @@ -2998,7 +3081,7 @@ let from_compilation_units ~includes:_ ~include_cmis ~debug_data l = let l = List.map l ~f:(fun (_, c) -> Bytes.to_string c) in String.concat ~sep:"" l in - let prog = parse_bytecode code globals debug_data in + let prog = parse_bytecode code globals hints debug_data in let gdata = Var.fresh_n "global_data" in let need_gdata = ref false in let body = @@ -3050,12 +3133,20 @@ let from_cmo ?(includes = []) ?(include_cmis = false) ?(debug = false) compunit seek_in ic compunit.Cmo_format.cu_debug; Debug.read_event_list debug_data ~crcs:[] ~includes ~orig:0 ic); if times () then Format.eprintf " read debug events: %a@." Timer.print t; - let p = from_compilation_units ~includes ~include_cmis ~debug_data [ compunit, code ] in + let hints = Hints.create () in + if Ocaml_compiler.Cmo_format.hints_pos compunit <> 0 + then ( + seek_in ic (Ocaml_compiler.Cmo_format.hints_pos compunit); + Hints.read hints ~orig:0 ic); + let p = + from_compilation_units ~includes ~include_cmis ~hints ~debug_data [ compunit, code ] + in Code.invariant p.code; p let from_cma ?(includes = []) ?(include_cmis = false) ?(debug = false) lib ic = let debug_data = Debug.create ~include_cmis debug in + let hints = Hints.create () in let orig = ref 0 in let t = ref 0. in let units = @@ -3068,12 +3159,16 @@ let from_cma ?(includes = []) ?(include_cmis = false) ?(debug = false) lib ic = then ( seek_in ic compunit.Cmo_format.cu_debug; Debug.read_event_list debug_data ~crcs:[] ~includes ~orig:!orig ic); + if Ocaml_compiler.Cmo_format.hints_pos compunit <> 0 + then ( + seek_in ic (Ocaml_compiler.Cmo_format.hints_pos compunit); + Hints.read hints ~orig:!orig ic); t := !t +. Timer.get t0; orig := !orig + compunit.Cmo_format.cu_codesize; compunit, code) in if times () then Format.eprintf " read debug events: %.2f@." !t; - let p = from_compilation_units ~includes ~include_cmis ~debug_data units in + let p = from_compilation_units ~includes ~include_cmis ~hints ~debug_data units in Code.invariant p.code; p diff --git a/compiler/tests-compiler/gh747.ml b/compiler/tests-compiler/gh747.ml index c94af5cb4e..c51b386885 100644 --- a/compiler/tests-compiler/gh747.ml +++ b/compiler/tests-compiler/gh747.ml @@ -222,7 +222,7 @@ end 1: 2: //# unitInfo: Provides: Test 3: //# unitInfo: Requires: Stdlib__Printf - 4: //# shape: Test:[N,N,[N],N,N,N,N,N,N,N,N,N,N,F(2),F(2),[F(4)]] + 4: //# shape: Test:[N,N,[N],N,N,N,N,N,N,N,N,N,[N,N],F(2),F(2),[F(4)]] 5: (function 6: (globalThis){ 7: "use strict"; diff --git a/compiler/tests-full/stdlib.cma.expected.js b/compiler/tests-full/stdlib.cma.expected.js index 43fbad854a..d591948c07 100644 --- a/compiler/tests-full/stdlib.cma.expected.js +++ b/compiler/tests-full/stdlib.cma.expected.js @@ -350,7 +350,7 @@ //# unitInfo: Provides: Stdlib //# unitInfo: Requires: CamlinternalFormatBasics -//# shape: Stdlib:[F(1),F(1),N,N,N,N,N,N,N,N,N,N,N,N,N,F(2),F(2),F(1)*,N,N,F(1)*,N,N,N,N,N,N,F(2)*,F(1),F(1)*,F(1)*,F(1),F(1)*,F(1),F(1),F(1),F(2),N,N,N,F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(3),F(1),F(1),F(2),F(2),F(2),F(4),F(4),F(2),F(2),F(2),F(2),F(1),F(1),F(1),F(1),F(2),F(1),F(1),F(3),F(1),F(1),F(4),F(4),F(2),F(1),F(1),F(1),F(2),F(1),F(1),F(1),F(1),F(2),N,F(1)*,F(2),F(1),F(1),F(1),F(4),F(1),N] +//# shape: Stdlib:[F(1),F(1),[N,N],N,N,N,N,N,N,N,N,N,N,N,N,F(2),F(2),F(1)*,N,N,F(1)*,N,N,N,N,N,N,F(2)*,F(1),F(1)*,F(1)*,F(1),F(1)*,F(1),F(1),F(1),F(2),N,N,N,F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(3),F(1),F(1),F(2),F(2),F(2),F(4),F(4),F(2),F(2),F(2),F(2),F(1),F(1),F(1),F(1),F(2),F(1),F(1),F(3),F(1),F(1),F(4),F(4),F(2),F(1),F(1),F(1),F(2),F(1),F(1),F(1),F(1),F(2),[F(2),F(1),F(1),F(2),F(1),F(1)],F(1)*,F(2)->[N,N],F(1),F(1),F(1),F(4),F(1),N] (function (globalThis){ "use strict"; @@ -977,7 +977,7 @@ (globalThis)); //# unitInfo: Provides: Stdlib__Either -//# shape: Stdlib__Either:[F(1)*,F(1)*,F(1)*,F(1)*,F(1)*,F(1)*,F(2),F(2),F(3),F(3),F(3),F(3),F(4),F(4)] +//# shape: Stdlib__Either:[F(1)*->[N],F(1)*->[N],F(1)*,F(1)*,F(1)*,F(1)*,F(2),F(2),F(3)->[N],F(3),F(3),F(3),F(4),F(4)] (function (globalThis){ "use strict"; @@ -1095,7 +1095,7 @@ //# unitInfo: Provides: Stdlib__Sys //# unitInfo: Requires: Stdlib -//# shape: Stdlib__Sys:[N,F(1),N,N,[N],N,N,N,N,N,N,N,N,N,F(2)*,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,F(1)*,N,N,N,F(1),F(1),[F(2)*]] +//# shape: Stdlib__Sys:[N,F(1),N,N,[N],N,N,N,N,N,N,N,N,N,F(2)*,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,[N,N],F(1)*,N,N,N,F(1),F(1),[F(2)*->[N]]] (function (globalThis){ "use strict"; @@ -1104,8 +1104,8 @@ caml_maybe_attach_backtrace = runtime.caml_maybe_attach_backtrace, caml_wrap_exception = runtime.caml_wrap_exception, global_data = runtime.caml_get_global_data(), - ocaml_version = "5.3.0", - ocaml_release = [0, 5, 3, 0, 0], + ocaml_version = "5.3.1+dev0-2025-01-06", + ocaml_release = [0, 5, 3, 1, [0, [0, 0, "dev0-2025-01-06"]]], Stdlib = global_data.Stdlib, executable_name = /*<>*/ runtime.caml_sys_executable_name(0), @@ -1191,7 +1191,7 @@ Break, catch_break, ocaml_version, - 0, + 1, ocaml_release, runtime.caml_ml_enable_runtime_warnings, runtime.caml_ml_runtime_warnings_enabled, @@ -1203,7 +1203,7 @@ //# unitInfo: Provides: Stdlib__Obj //# unitInfo: Requires: Stdlib, Stdlib__Sys -//# shape: Stdlib__Obj:[F(1)*,F(2),F(3),N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,[F(1),F(1)*,F(1)*],N] +//# shape: Stdlib__Obj:[F(1)*,F(2),F(3),N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,[F(1),F(1)*,F(1)*],[F(1),F(1)*,F(2),F(2),F(3),F(2),F(2),F(5),F(1),F(1),F(2),F(1),F(1),F(2),N]] (function (globalThis){ "use strict"; @@ -1376,7 +1376,7 @@ //# unitInfo: Provides: Stdlib__Type //# unitInfo: Requires: Stdlib__Obj -//# shape: Stdlib__Type:[[F(1)*,F(1),F(2)*]] +//# shape: Stdlib__Type:[[F(1)*->[[N,N]],F(1),F(2)*]] (function (globalThis){ "use strict"; @@ -1443,7 +1443,7 @@ //# unitInfo: Provides: CamlinternalLazy //# unitInfo: Requires: Stdlib, Stdlib__Obj -//# shape: CamlinternalLazy:[N,F(1),F(2)] +//# shape: CamlinternalLazy:[[N,N],F(1),F(2)] (function (globalThis){ "use strict"; @@ -1520,7 +1520,7 @@ //# unitInfo: Provides: Stdlib__Lazy //# unitInfo: Requires: CamlinternalLazy, Stdlib, Stdlib__Obj -//# shape: Stdlib__Lazy:[N,F(2)*,F(1),F(1),F(2),F(1),F(1)] +//# shape: Stdlib__Lazy:[[N,N],F(2)*,F(1),F(1),F(2),F(1),F(1)] (function (globalThis){ "use strict"; @@ -1611,7 +1611,7 @@ //# unitInfo: Provides: Stdlib__Seq //# unitInfo: Requires: CamlinternalLazy, Stdlib, Stdlib__Atomic, Stdlib__Lazy -//# shape: Stdlib__Seq:[F(1),F(1),F(1),F(2),F(3),F(2),F(3),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(4),F(3),F(3),F(3),F(3),F(1)*,F(2)*,F(3)*,F(2),F(3),F(2)*,F(2),F(2),F(2)*->F(1)*,F(3),F(2)*->F(1),F(3),F(3),F(3)*->F(1)*,F(2),F(2),F(3),F(3),F(3),F(1)->F(1),N,F(1)*->F(1),F(2),F(3),F(2),F(3),F(3),F(3),F(4),F(3),F(4),F(2)*,F(3)*->F(1),F(1)*,F(1)*,F(2)*,F(2)*,F(1)*->F(1),F(1)*->F(1),F(2)*] +//# shape: Stdlib__Seq:[F(1),F(1),F(1),F(2),F(3),F(2),F(3),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(4),F(3),F(3),F(3),F(3),F(1)*,F(2)*->[N,F(1)*],F(3)*->[N,N],F(2),F(3),F(2)*->[N,F(1)],F(2)->[N,F(1)],F(2),F(2)*->F(1)*->[N,F(1)],F(3),F(2)*->F(1),F(3),F(3),F(3)*->F(1)*->[N,F(1)],F(2),F(2),F(3),F(3),F(3),F(1)->F(1),[N,N],F(1)*->F(1),F(2),F(3),F(2),F(3),F(3),F(3),F(4),F(3),F(4),F(2)*,F(3)*->F(1),F(1)*->[F(1),F(1)],F(1)*->[F(1),F(1)],F(2)*->[F(1),F(1)],F(2)*->[F(1),F(1)],F(1)*->F(1),F(1)*->F(1),F(2)*->[N,F(1)]] (function (globalThis){ "use strict"; @@ -2532,7 +2532,7 @@ //# unitInfo: Provides: Stdlib__Option //# unitInfo: Requires: Stdlib, Stdlib__Seq -//# shape: Stdlib__Option:[N,F(1)*,F(2)*,F(1),F(2),F(1)*,F(2),F(3),F(2),F(1)*,F(1)*,F(3),F(3),F(2)*,F(1)*,F(1)*->F(1)*] +//# shape: Stdlib__Option:[N,F(1)*->[N],F(2)*,F(1),F(2),F(1)*,F(2),F(3),F(2),F(1)*,F(1)*,F(3),F(3),F(2)*->[N],F(1)*,F(1)*->F(1)*] (function (globalThis){ "use strict"; @@ -2661,7 +2661,7 @@ //# unitInfo: Provides: Stdlib__Result //# unitInfo: Requires: Stdlib, Stdlib__Seq -//# shape: Stdlib__Result:[F(1)*,F(1)*,F(2)*,F(1),F(1),F(2),F(1)*,F(2),F(2),F(3),F(2),F(2),F(1)*,F(1)*,F(4),F(4),F(1)*,F(1)*,F(1)*->F(1)*] +//# shape: Stdlib__Result:[F(1)*->[N],F(1)*->[N],F(2)*,F(1),F(1),F(2),F(1)*,F(2),F(2),F(3),F(2),F(2),F(1)*,F(1)*,F(4),F(4),F(1)*,F(1)*,F(1)*->F(1)*] (function (globalThis){ "use strict"; @@ -3123,7 +3123,7 @@ //# unitInfo: Provides: Stdlib__List //# unitInfo: Requires: Stdlib -//# shape: Stdlib__List:[F(1),F(2),F(2),F(1)*,F(2)*,F(1),F(1),F(2),F(2),F(1),F(2),F(2),F(2),F(1),F(1),F(3),F(3),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(3),F(3),F(3),F(3),F(3),F(4),F(4),F(2),F(2),F(3),F(3),F(2),F(2),F(2),F(2),F(1)*->F(1),F(2),F(1)*->F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(1),F(2),F(2),F(2),F(2),F(2),F(3),F(1)*->F(1)*,F(1)] +//# shape: Stdlib__List:[F(1),F(2),F(2),F(1)*,F(2)*->[N,N],F(1),F(1),F(2),F(2),F(1),F(2),F(2),F(2),F(1),F(1),F(3),F(3),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(3)->[N,N],F(3),F(3),F(3),F(3),F(3),F(4),F(4),F(2),F(2),F(3),F(3),F(2),F(2),F(2),F(2),F(1)*->F(1),F(2),F(1)*->F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2)->[N,N],F(2)->[N,N],F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(1),F(2),F(2),F(2),F(2),F(2),F(3),F(1)*->F(1)*,F(1)] (function (globalThis){ "use strict"; @@ -4805,7 +4805,7 @@ //# unitInfo: Provides: Stdlib__Bytes //# unitInfo: Requires: Stdlib, Stdlib__Char, Stdlib__Int, Stdlib__Seq, Stdlib__Sys, Stdlib__Uchar -//# shape: Stdlib__Bytes:[F(2),F(2),N,F(1),F(1),F(1),F(3),F(3),F(3),F(4),F(5),F(5),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(3),F(2),F(2),F(1),F(1),F(2),F(2),F(2),F(2),F(3),F(3),F(3),F(3),F(2),F(3),F(3),F(1),F(1),F(1),F(1),F(2)*,F(2)*,F(2),F(2),F(1),F(1)*,F(2),F(1)*->F(1),F(1)*->F(1),F(1),F(2),F(3),F(1),F(2),F(3),F(1),F(2),F(3),F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(1)] +//# shape: Stdlib__Bytes:[F(2),F(2),N,F(1),F(1),F(1),F(3),F(3),F(3),F(4),F(5),F(5),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(3),F(2),F(2),F(1),F(1),F(2),F(2),F(2),F(2),F(3),F(3),F(3),F(3),F(2),F(3),F(3),F(1),F(1),F(1),F(1),F(2)*,F(2)*,F(2),F(2),F(1),F(1)*,F(2)->[N,N],F(1)*->F(1),F(1)*->F(1),F(1),F(2),F(3),F(1),F(2),F(3),F(1),F(2),F(3),F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(1)] (function (globalThis){ "use strict"; @@ -6391,7 +6391,7 @@ //# unitInfo: Provides: Stdlib__String //# unitInfo: Requires: Stdlib, Stdlib__Bytes -//# shape: Stdlib__String:[F(2),F(2),N,F(1),F(1),F(5),F(2),F(2)*,F(2)*,F(2)*,F(2),F(2),F(3),F(3),F(2),F(3),F(2),F(2),F(2),F(3),F(3),F(2),F(2),F(1),F(1),F(1),F(1),F(1),F(1),F(2),F(2),F(3),F(3),F(3),F(3),F(2),F(2),F(2),F(2),F(1)*,F(1)*,F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(1),F(2),F(2),F(2),F(2),F(2),F(2)] +//# shape: Stdlib__String:[F(2),F(2),N,F(1),F(1),F(5),F(2),F(2)*,F(2)*,F(2)*,F(2),F(2),F(3),F(3),F(2),F(3),F(2)->[N,N],F(2),F(2),F(3),F(3),F(2),F(2),F(1),F(1),F(1),F(1),F(1),F(1),F(2),F(2),F(3),F(3),F(3),F(3),F(2),F(2),F(2),F(2),F(1)*,F(1)*,F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(1),F(2),F(2),F(2),F(2),F(2),F(2)] (function (globalThis){ "use strict"; @@ -7055,7 +7055,7 @@ //# unitInfo: Provides: Stdlib__Array //# unitInfo: Requires: Stdlib, Stdlib__Seq, Stdlib__String -//# shape: Stdlib__Array:[F(2),F(3),F(3),F(2)*,F(1)*,F(3),F(1)*,F(4),F(5),F(1),F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(3),F(3),F(3),F(3),F(2),F(2),F(3),F(3),F(2),F(2),F(2),F(2),F(2),F(2),F(1),F(2),F(2),F(2),F(2),F(2),F(1)*->F(1)*,F(1)*->F(1)*,F(1),[]] +//# shape: Stdlib__Array:[F(2),F(3),F(3),F(2)*,F(1)*,F(3),F(1)*,F(4),F(5),F(1),F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(3)->[N,N],F(3),F(3),F(3),F(2),F(2),F(3),F(3),F(2),F(2),F(2),F(2),F(2),F(2),F(1)->[N,N],F(2),F(2),F(2),F(2),F(2),F(1)*->F(1)*,F(1)*->F(1)*,F(1),[]] (function (globalThis){ "use strict"; @@ -8012,7 +8012,7 @@ //# unitInfo: Provides: Stdlib__Float //# unitInfo: Requires: Stdlib, Stdlib__Array, Stdlib__List, Stdlib__Seq -//# shape: Stdlib__Float:[N,N,N,F(1)*,F(1)*,N,N,N,N,N,N,N,N,N,F(1)*,F(1)*,F(1)*,F(1)*,F(1),F(1),F(2)*,F(2)*,F(2)*,F(2)*,F(2)*,F(2)*,F(2)*,F(2)*,F(2)*,F(1)*,N,N] +//# shape: Stdlib__Float:[N,N,N,F(1)*,F(1)*,N,N,N,N,N,N,N,N,N,F(1)*,F(1)*,F(1)*,F(1)*,F(1),F(1),F(2)*,F(2)*,F(2)*,F(2)*,F(2)*->[N,N],F(2)*,F(2)*,F(2)*->[N,N],F(2)*,F(1)*,[F(1)*,F(2),F(3),F(2)*,F(1)*,F(2),F(3),F(3),F(2)*,F(1),F(3),F(1)*,F(4),F(5),F(1),F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(3),F(3),F(3),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(1)*->F(1)*,F(1)*->F(1)*,F(1),F(2),F(2)],[F(1)*,F(2),F(3),F(2)*,F(1)*,F(2),F(3),F(3),F(2)*,F(1),F(3),F(1)*,F(4),F(5),F(1),F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(3),F(3),F(3),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(1)*->F(1)*,F(1)*->F(1)*,F(1),F(2),F(2)]] (function (globalThis){ "use strict"; @@ -9795,7 +9795,7 @@ //# unitInfo: Provides: Stdlib__Parsing //# unitInfo: Requires: Stdlib, Stdlib__Array, Stdlib__Lexing, Stdlib__Obj -//# shape: Stdlib__Parsing:[F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),N,F(1),N,F(4),F(2),F(1),F(1)*] +//# shape: Stdlib__Parsing:[F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),[N,N],F(1),[N,N],F(4),F(2),F(1),F(1)*] (function (globalThis){ "use strict"; @@ -10043,7 +10043,7 @@ //# unitInfo: Provides: Stdlib__Set //# unitInfo: Requires: Stdlib, Stdlib__List, Stdlib__Seq -//# shape: Stdlib__Set:[F(1)*] +//# shape: Stdlib__Set:[F(1)*->[N,F(2),F(1)*->[N,N,N,N],F(2),F(2),F(2),F(2),F(2),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(2),F(2),F(2),F(2),F(2),F(1)*,F(2),F(2),F(2),F(2),F(2),F(2),F(1),F(1),F(2)->F(1),F(1)->F(1),F(1)->F(1),F(2),F(1)]] (function (globalThis){ "use strict"; @@ -11095,7 +11095,7 @@ //# unitInfo: Provides: Stdlib__Map //# unitInfo: Requires: Stdlib, Stdlib__List, Stdlib__Seq -//# shape: Stdlib__Map:[F(1)*] +//# shape: Stdlib__Map:[F(1)*->[N,F(3),F(3),F(3),F(2)*->[N,N,N,N,N],F(2),F(3),F(3),F(1),F(1),F(1)->[N,N],F(1),F(1)->[N,N],F(1),F(1)->[N,N],F(1),F(2),F(2),F(2)->[N,N],F(2),F(2)->[N,N],F(2),F(2),F(3),F(2),F(2),F(2),F(2),F(2),F(2),F(1)*,F(2),F(3),F(3),F(2),F(2),F(1),F(1),F(1)->F(1),F(1)->F(1),F(2)->F(1),F(2),F(1)]] (function (globalThis){ "use strict"; @@ -12139,7 +12139,7 @@ //# unitInfo: Provides: Stdlib__Stack //# unitInfo: Requires: Stdlib__List, Stdlib__Seq -//# shape: Stdlib__Stack:[N,F(1)*,F(2),F(1),F(1),F(1),F(1),F(1)*,F(1),F(1)*,F(1)*,F(1)*,F(2),F(3),F(1)*,F(2),F(1)] +//# shape: Stdlib__Stack:[[N,N],F(1)*,F(2),F(1),F(1),F(1),F(1),F(1)*,F(1),F(1)*,F(1)*,F(1)*,F(2),F(3),F(1)*,F(2),F(1)] (function (globalThis){ "use strict"; @@ -12260,7 +12260,7 @@ //# unitInfo: Provides: Stdlib__Queue //# unitInfo: Requires: Stdlib__Seq -//# shape: Stdlib__Queue:[N,F(1)*,F(2),F(2),F(1),F(1),F(1),F(1),F(1)*,F(1),F(1),F(1),F(1),F(1)*,F(1)*,F(2),F(3),F(2),F(1)*->F(1)*,F(2),F(1)] +//# shape: Stdlib__Queue:[[N,N],F(1)*,F(2),F(2),F(1),F(1),F(1),F(1),F(1)*,F(1),F(1),F(1),F(1),F(1)*,F(1)*,F(2),F(3),F(2),F(1)*->F(1)*,F(2),F(1)] (function (globalThis){ "use strict"; @@ -13278,7 +13278,7 @@ //# unitInfo: Provides: Stdlib__Domain //# unitInfo: Requires: Stdlib, Stdlib__Array, Stdlib__Atomic, Stdlib__Condition, Stdlib__List, Stdlib__Mutex -//# shape: Stdlib__Domain:[F(1),F(1),F(1)*,F(1),F(1),F(1),F(1),F(1),F(1),F(1),N] +//# shape: Stdlib__Domain:[F(1)->[N,N],F(1),F(1)*,F(1),F(1),F(1),F(1),F(1),F(1),F(1),[F(2)->[N,N],F(1),F(2)]] (function (globalThis){ "use strict"; @@ -13543,7 +13543,7 @@ //# unitInfo: Provides: CamlinternalFormat //# unitInfo: Requires: CamlinternalFormatBasics, Stdlib, Stdlib__Buffer, Stdlib__Bytes, Stdlib__Char, Stdlib__Int, Stdlib__String, Stdlib__Sys -//# shape: CamlinternalFormat:[F(2),F(1),F(1),F(2),F(1),F(2)*,F(3),F(3),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(1)*,F(1),F(1),F(1),F(1),F(1),F(2),F(2)] +//# shape: CamlinternalFormat:[F(2),F(1),F(1),F(2),F(1),F(2)*->[N],F(3),F(3),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(1)*,F(1),F(1),F(1),F(1),F(1),F(2),F(2)] (function (globalThis){ "use strict"; @@ -20656,7 +20656,7 @@ //# unitInfo: Provides: Stdlib__Arg //# unitInfo: Requires: Stdlib, Stdlib__Array, Stdlib__Buffer, Stdlib__Int, Stdlib__List, Stdlib__Printf, Stdlib__String, Stdlib__Sys -//# shape: Stdlib__Arg:[F(3),F(3),F(5),F(5),F(5),F(3),N,N,F(2),F(2),F(2),N,F(1),F(1),F(2),F(2)] +//# shape: Stdlib__Arg:[F(3),F(3),F(5),F(5),F(5),F(3),[N,N],[N,N],F(2),F(2),F(2),N,F(1),F(1),F(2),F(2)] (function (globalThis){ "use strict"; @@ -21510,7 +21510,7 @@ //# unitInfo: Provides: Stdlib__Printexc //# unitInfo: Requires: Stdlib, Stdlib__Atomic, Stdlib__Buffer, Stdlib__Obj, Stdlib__Printf -//# shape: Stdlib__Printexc:[F(1),F(1),F(2),F(2),F(1),F(1),F(1),F(1),F(1),F(1),F(1)*,F(1)*,F(2),F(1),F(2),F(1),F(1),F(1),N,F(1)*,F(2),F(1),F(1),F(1),F(1),F(1)] +//# shape: Stdlib__Printexc:[F(1),F(1),F(2),F(2),F(1),F(1),F(1),F(1),F(1),F(1),F(1)*,F(1)*,F(2),F(1),F(2),F(1),F(1),F(1),[F(1)*,F(1)*,F(1)*,F(1)*,F(2)],F(1)*,F(2),F(1),F(1),F(1),F(1),F(1)] (function (globalThis){ "use strict"; @@ -22133,7 +22133,7 @@ //# unitInfo: Provides: Stdlib__Fun //# unitInfo: Requires: Stdlib, Stdlib__Printexc -//# shape: Stdlib__Fun:[F(2)*,F(3),F(3),F(2),F(2),N] +//# shape: Stdlib__Fun:[F(2)*,F(3),F(3),F(2),F(2),[N,N]] (function (globalThis){ "use strict"; @@ -22232,7 +22232,7 @@ //# unitInfo: Provides: Stdlib__Gc //# unitInfo: Requires: Stdlib, Stdlib__Atomic, Stdlib__Domain, Stdlib__Fun, Stdlib__Printf, Stdlib__Sys -//# shape: Stdlib__Gc:[F(1),F(1),F(2)*,F(2),F(1)*,F(1),F(1),F(1)*,F(1)*,N] +//# shape: Stdlib__Gc:[F(1),F(1),F(2)*,F(2),F(1)*,F(1),F(1),F(1)*,F(1)*,[[F(1)*,F(1)*,F(1)*,F(1)*,F(1)*],F(3),F(1),F(1)]] (function (globalThis){ "use strict"; @@ -22441,7 +22441,7 @@ //# unitInfo: Provides: Stdlib__In_channel //# unitInfo: Requires: Stdlib, Stdlib__Bytes, Stdlib__Fun, Stdlib__Sys -//# shape: Stdlib__In_channel:[N,F(1),F(1),F(3),F(2),F(2),F(4),F(1),F(1),F(1),F(1),F(1),F(2),F(1),F(1),F(4),F(4),F(4),F(4),F(3),N,N,N,F(2),F(1),F(1)] +//# shape: Stdlib__In_channel:[N,F(1),F(1),F(3),F(2),F(2),F(4),F(1),F(1),F(1),F(1),F(1),F(2),F(1),F(1),F(4),F(4),F(4),F(4),F(3),F(2),F(1),F(1),F(2),F(1),F(1)] (function (globalThis){ "use strict"; @@ -22786,7 +22786,7 @@ //# unitInfo: Provides: Stdlib__Out_channel //# unitInfo: Requires: Stdlib, Stdlib__Fun -//# shape: Stdlib__Out_channel:[N,N,F(1),F(1),F(3),F(2),F(2),F(4),F(1),F(1),F(2),F(2),F(2),F(2),F(4),F(4),F(4),F(1),F(1),N,N,N,F(2),F(1),F(2),F(1),F(1)] +//# shape: Stdlib__Out_channel:[N,N,F(1),F(1),F(3),F(2),F(2),F(4),F(1),F(1),F(2),F(2),F(2),F(2),F(4),F(4),F(4),F(1),F(1),F(2),F(1),F(1),F(2),F(1),F(2),F(1),F(1)] (function (globalThis){ "use strict"; @@ -22897,7 +22897,7 @@ //# unitInfo: Provides: Stdlib__Digest //# unitInfo: Requires: Stdlib, Stdlib__Bytes, Stdlib__Char, Stdlib__In_channel, Stdlib__Int, Stdlib__String -//# shape: Stdlib__Digest:[F(2)*,F(2)*,F(1),F(1),F(3),F(3),F(2),F(1),F(2),F(1),F(1),F(1),F(1),N,N,N,N] +//# shape: Stdlib__Digest:[F(2)*,F(2)*,F(1),F(1),F(3),F(3),F(2),F(1),F(2),F(1),F(1),F(1),F(1),N,N,N,[N,F(2)*,F(2)*,F(1),F(1),F(3),F(3),F(2),F(1),F(2),F(1),F(1),F(1)]] (function (globalThis){ "use strict"; @@ -23208,7 +23208,7 @@ //# unitInfo: Provides: Stdlib__Bigarray //# unitInfo: Requires: Stdlib, Stdlib__Array, Stdlib__Sys -//# shape: Stdlib__Bigarray:[N,N,N,N,N,N,N,N,N,N,N,N,N,N,F(1)*,N,N,N,N,N,N,N,F(1),F(1),F(1),F(1),F(2),F(1),F(2),F(3),F(4)] +//# shape: Stdlib__Bigarray:[N,N,N,N,N,N,N,N,N,N,N,N,N,N,F(1)*,N,N,[F(4),F(1),F(1)],[F(2),F(3),F(2),F(1),F(1),F(1)*->F(1),F(3)],[F(3),F(4),F(2),F(1),F(2),F(3)],[F(4),F(5),F(2),F(1),F(2),F(2),F(3)],[F(5),F(6),F(2),F(1),F(3),F(3),F(2),F(2),F(3)],F(1),F(1),F(1),F(1),F(2),F(1),F(2),F(3),F(4)] (function (globalThis){ "use strict"; @@ -23835,7 +23835,7 @@ //# unitInfo: Provides: Stdlib__Random //# unitInfo: Requires: Stdlib, Stdlib__Bigarray, Stdlib__Bytes, Stdlib__Digest, Stdlib__Domain, Stdlib__Int32, Stdlib__Int64, Stdlib__Nativeint, Stdlib__String, Stdlib__Sys -//# shape: Stdlib__Random:[F(1),F(1),F(1),F(1),F(1),F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(1),F(1),F(1),F(1),N,F(1),F(1),F(1)] +//# shape: Stdlib__Random:[F(1),F(1),F(1),F(1),F(1),F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(1),F(1),F(1),F(1),[F(1),F(1),F(1),F(1)*,F(2),F(2),F(3),F(2),F(3),F(2),F(3),F(2),F(3),F(2),F(1),F(1)*,F(1)*,F(1)*,F(1),F(1),F(1)],F(1),F(1),F(1)] (function (globalThis){ "use strict"; @@ -23857,23 +23857,7 @@ caml_lxm_next = runtime.caml_lxm_next, caml_mod = runtime.caml_mod, caml_notequal = runtime.caml_notequal, - caml_sys_random_seed = runtime.caml_sys_random_seed; - function caml_call1(f, a0){ - return (f.l >= 0 ? f.l : f.l = f.length) === 1 - ? f(a0) - : runtime.caml_call_gen(f, [a0]); - } - function caml_call2(f, a0, a1){ - return (f.l >= 0 ? f.l : f.l = f.length) === 2 - ? f(a0, a1) - : runtime.caml_call_gen(f, [a0, a1]); - } - function caml_call3(f, a0, a1, a2){ - return (f.l >= 0 ? f.l : f.l = f.length) === 3 - ? f(a0, a1, a2) - : runtime.caml_call_gen(f, [a0, a1, a2]); - } - var + caml_sys_random_seed = runtime.caml_sys_random_seed, global_data = runtime.caml_get_global_data(), serialization_prefix = "lxm1:", Stdlib_Domain = global_data.Stdlib__Domain, @@ -23892,7 +23876,7 @@ _d_ = caml_int64_create_lo_mi_hi(2, 0, 0), _e_ = caml_int64_create_lo_mi_hi(1, 0, 0); function create(param){ - /*<>*/ return caml_call3(Stdlib_Bigarray[20][1], 7, 0, 4) /*<>*/ ; + /*<>*/ return Stdlib_Bigarray[20][1].call(null, 7, 0, 4) /*<>*/ ; } function set(s, i1, i2, i3, i4){ /*<>*/ /*<>*/ caml_ba_set_1 @@ -24228,102 +24212,101 @@ } var random_key = - /*<>*/ caml_call2 - (Stdlib_Domain[11][1], [0, split], mk_default); + /*<>*/ Stdlib_Domain[11][1].call + (null, [0, split], mk_default); function bits$0(param){ /*<>*/ return /*<>*/ bits - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], random_key)) /*<>*/ ; + ( /*<>*/ Stdlib_Domain[11][2].call + (null, random_key)) /*<>*/ ; } function int$0(bound){ /*<>*/ return /*<>*/ int - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], random_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, random_key), bound) /*<>*/ ; } function full_int$0(bound){ /*<>*/ return /*<>*/ full_int - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], random_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, random_key), bound) /*<>*/ ; } function int_in_range$0(min, max){ /*<>*/ return /*<>*/ int_in_range - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], random_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, random_key), min, max) /*<>*/ ; } function int32$0(bound){ /*<>*/ return /*<>*/ int32 - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], random_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, random_key), bound) /*<>*/ ; } function int32_in_range$0(min, max){ /*<>*/ return /*<>*/ int32_in_range - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], random_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, random_key), min, max) /*<>*/ ; } function nativeint$0(bound){ /*<>*/ return /*<>*/ nativeint - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], random_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, random_key), bound) /*<>*/ ; } function nativeint_in_range$0(min, max){ /*<>*/ return /*<>*/ nativeint_in_range - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], random_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, random_key), min, max) /*<>*/ ; } function int64$0(bound){ /*<>*/ return /*<>*/ int64 - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], random_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, random_key), bound) /*<>*/ ; } function int64_in_range$0(min, max){ /*<>*/ return /*<>*/ int64_in_range - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], random_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, random_key), min, max) /*<>*/ ; } function float$0(scale){ /*<>*/ return /*<>*/ float - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], random_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, random_key), scale) /*<>*/ ; } function bool$0(param){ /*<>*/ return /*<>*/ bool - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], random_key)) /*<>*/ ; + ( /*<>*/ Stdlib_Domain[11][2].call + (null, random_key)) /*<>*/ ; } function bits32$0(param){ /*<>*/ return /*<>*/ bits32 - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], random_key)) /*<>*/ ; + ( /*<>*/ Stdlib_Domain[11][2].call + (null, random_key)) /*<>*/ ; } function bits64$0(param){ var - s = - /*<>*/ caml_call1(Stdlib_Domain[11][2], random_key); + s = /*<>*/ Stdlib_Domain[11][2].call(null, random_key); /*<>*/ return caml_lxm_next(s) /*<>*/ ; } function nativebits$0(param){ /*<>*/ return /*<>*/ nativebits - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], random_key)) /*<>*/ ; + ( /*<>*/ Stdlib_Domain[11][2].call + (null, random_key)) /*<>*/ ; } function full_init(seed){ /*<>*/ return /*<>*/ reinit - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], random_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, random_key), seed) /*<>*/ ; } function init(seed){ @@ -24335,18 +24318,18 @@ } function split$0(param){ /*<>*/ return /*<>*/ split - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], random_key)) /*<>*/ ; + ( /*<>*/ Stdlib_Domain[11][2].call + (null, random_key)) /*<>*/ ; } function get_state(param){ /*<>*/ return /*<>*/ copy - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], random_key)) /*<>*/ ; + ( /*<>*/ Stdlib_Domain[11][2].call + (null, random_key)) /*<>*/ ; } function set_state(src){ var dst = - /*<>*/ caml_call1(Stdlib_Domain[11][2], random_key); + /*<>*/ Stdlib_Domain[11][2].call(null, random_key); /*<>*/ return caml_ba_blit(src, dst) /*<>*/ ; } var @@ -24402,7 +24385,7 @@ //# unitInfo: Provides: Stdlib__Hashtbl //# unitInfo: Requires: Stdlib, Stdlib__Array, Stdlib__Atomic, Stdlib__Domain, Stdlib__Int, Stdlib__Random, Stdlib__Seq, Stdlib__String, Stdlib__Sys -//# shape: Stdlib__Hashtbl:[F(2),F(1),F(1),F(1),F(3),F(2),F(2),F(2),F(2),F(2),F(3),F(2),F(2),F(3),F(1)*,F(1),F(1),F(2),F(1),F(1)*->F(1),F(1)*->F(1),F(1)*->F(1),F(2),F(2),F(1),F(1)*,F(1)*,F(1)*,F(2)*,F(3)*,F(4)*] +//# shape: Stdlib__Hashtbl:[F(2),F(1),F(1),F(1),F(3),F(2),F(2),F(2),F(2),F(2),F(3),F(2),F(2),F(3),F(1)*,F(1),F(1),F(2),F(1)->[N,N,N,N],F(1)*->F(1),F(1)*->F(1),F(1)*->F(1),F(2),F(2),F(1),F(1)*->[F(1),N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,F(1)],F(1)*->[F(2),F(1),F(1),F(1),F(3),F(2),F(2),F(2),F(2),F(3),F(2),F(2),F(2),F(3),F(1)*,F(1)->[N,N,N,N],F(1)*->F(1),F(1)*->F(1),F(1)*->F(1),F(2),F(2),F(1)],F(1)*,F(2)*,F(3)*,F(4)*] (function (globalThis){ "use strict"; @@ -24491,8 +24474,8 @@ } var prng_key = - /*<>*/ caml_call2 - (Stdlib_Domain[11][1], 0, Stdlib_Random[19][2]); + /*<>*/ Stdlib_Domain[11][1].call + (null, 0, Stdlib_Random[19][2]); function power_2_above(x$1, n){ var x = /*<>*/ x$1; for(;;){ @@ -24513,10 +24496,11 @@ /*<>*/ if(random) var _J_ = - /*<>*/ caml_call1(Stdlib_Domain[11][2], prng_key), + /*<>*/ Stdlib_Domain[11][2].call(null, prng_key), seed = - /*<>*/ /*<>*/ caml_call1 - (Stdlib_Random[19][4], _J_); + /*<>*/ /*<>*/ Stdlib_Random[19] + [4].call + (null, _J_); else var seed = /*<>*/ 0; /*<>*/ return [0, 0, caml_array_make(s, 0), seed, s] /*<>*/ ; @@ -25178,11 +25162,11 @@ add_seq = include[20], replace_seq = include[21]; function create(sz){ - /*<>*/ return caml_call2(_g_, _a_, sz) /*<>*/ ; + /*<>*/ return _g_(_a_, sz) /*<>*/ ; } function of_seq(i){ - var tbl = /*<>*/ caml_call2(_g_, _a_, 16); - /*<>*/ caml_call2(replace_seq, tbl, i); + var tbl = /*<>*/ _g_(_a_, 16); + /*<>*/ replace_seq(tbl, i); /*<>*/ return tbl; /*<>*/ } /*<>*/ return [0, @@ -25472,10 +25456,12 @@ /*<>*/ if(random) var _c_ = - /*<>*/ caml_call1(Stdlib_Domain[11][2], prng_key), + /*<>*/ Stdlib_Domain[11][2].call(null, prng_key), seed = - /*<>*/ /*<>*/ caml_call1 - (Stdlib_Random[19][4], _c_); + /*<>*/ /*<>*/ Stdlib_Random + [19] + [4].call + (null, _c_); else var seed = /*<>*/ 4 <= h.length - 1 ? h[3] : 0; var @@ -25530,7 +25516,7 @@ //# unitInfo: Provides: Stdlib__Weak //# unitInfo: Requires: Stdlib, Stdlib__Array, Stdlib__Int, Stdlib__Obj, Stdlib__Sys -//# shape: Stdlib__Weak:[F(1),F(1)*,F(3),F(2),F(2),F(2),F(4),F(5),F(1)] +//# shape: Stdlib__Weak:[F(1),F(1)*,F(3),F(2),F(2),F(2),F(4),F(5),F(1)->[F(1)*,F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(1),F(1)->[N,N,N,N,N,N]]] (function (globalThis){ "use strict"; @@ -26090,7 +26076,7 @@ //# unitInfo: Provides: Stdlib__Format //# unitInfo: Requires: CamlinternalFormat, Stdlib, Stdlib__Array, Stdlib__Buffer, Stdlib__Bytes, Stdlib__Domain, Stdlib__Int, Stdlib__List, Stdlib__Queue, Stdlib__Seq, Stdlib__Stack, Stdlib__String -//# shape: Stdlib__Format:[F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(4),F(3),F(2),F(1),F(3),F(2),F(5),F(4),F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(2)*,F(2),F(1),F(2),F(1),F(3),F(2),F(3),F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(1),N,F(2),F(1),F(2)*,F(1),F(2),F(1),F(2)*,F(1),F(1)*,F(3),F(2),F(3),F(2),F(2),F(1),F(2)*,F(1),F(2),F(1),F(2)*,F(1),F(2)*,F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(3),F(2),F(2),F(1),F(2)*,F(1),N,F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(2)*,F(1),F(2)*,F(1),F(2),F(1),F(3),F(2),F(2)*,F(1),F(2),F(1),F(2)*,F(1),F(2),F(1),F(2)*,F(1),F(1),F(1),N,F(1),N,F(1),F(1),N,F(1),N,F(1),F(1),F(2),F(2),F(1),F(1)*,F(1),F(1),F(1),F(2),F(1),F(5),F(4),F(4),F(4),F(2),F(4),F(4),F(4),F(1)*->F(1),F(1),F(1),F(1),F(1),F(1),F(2),F(3),F(2),F(3),F(2),F(2)] +//# shape: Stdlib__Format:[F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(4),F(3),F(2),F(1),F(3),F(2),F(5),F(4),F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(2)*,F(2),F(1),F(2),F(1),F(3),F(2),F(3),F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(1),N,F(2),F(1),F(2)*,F(1),F(2),F(1),F(2)*,F(1),F(1)*,F(3),F(2),F(3),F(2),F(2),F(1),F(2)*->[N,N],F(1),F(2),F(1),F(2)*,F(1),F(2)*,F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(3),F(2),F(2),F(1),F(2)*,F(1),[N,N],F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(2)*,F(1),F(2)*,F(1),F(2),F(1),F(3),F(2),F(2)*->[N,N],F(1),F(2),F(1),F(2)*->[N,N,N,N,N],F(1),F(2),F(1),F(2)*->[N,N,N,N],F(1),F(1),F(1),N,F(1),N,F(1),F(1),N,F(1),N,F(1),F(1),F(2),F(2),F(1),F(1)*,F(1),F(1),F(1),F(2),F(1),F(5),F(4),F(4),F(4),F(2),F(4),F(4),F(4),F(1)*->F(1),F(1),F(1),F(1),F(1),F(1),F(2),F(3),F(2),F(3),F(2),F(2)] (function (globalThis){ "use strict"; @@ -27051,31 +27037,30 @@ /*<>*/ formatter_of_out_channel(Stdlib[40]), str_formatter = /*<>*/ formatter_of_buffer(stdbuf), stdbuf_key = - /*<>*/ caml_call2 - (Stdlib_Domain[11][1], 0, pp_make_buffer); - /*<>*/ caml_call2 - (Stdlib_Domain[11][3], stdbuf_key, stdbuf); + /*<>*/ Stdlib_Domain[11][1].call + (null, 0, pp_make_buffer); + /*<>*/ Stdlib_Domain[11][3].call + (null, stdbuf_key, stdbuf); var str_formatter_key = - /*<>*/ caml_call2 - (Stdlib_Domain[11][1], + /*<>*/ Stdlib_Domain[11][1].call + (null, 0, function(param){ /*<>*/ return /*<>*/ formatter_of_buffer - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], stdbuf_key)) /*<>*/ ; + ( /*<>*/ Stdlib_Domain[11][2].call + (null, stdbuf_key)) /*<>*/ ; }); - /*<>*/ caml_call2 - (Stdlib_Domain[11][3], str_formatter_key, str_formatter); + /*<>*/ Stdlib_Domain[11][3].call + (null, str_formatter_key, str_formatter); function buffered_out_string(key, str, ofs, len){ - var - _P_ = /*<>*/ caml_call1(Stdlib_Domain[11][2], key); + var _P_ = /*<>*/ Stdlib_Domain[11][2].call(null, key); /*<>*/ return Stdlib_Buffer[18].call (null, _P_, str, ofs, len) /*<>*/ ; } function buffered_out_flush(oc, key, param){ var - buf = /*<>*/ caml_call1(Stdlib_Domain[11][2], key), + buf = /*<>*/ Stdlib_Domain[11][2].call(null, key), len = /*<>*/ Stdlib_Buffer[7].call(null, buf), str = /*<>*/ Stdlib_Buffer[2].call(null, buf); /*<>*/ Stdlib[69].call(null, oc, str, 0, len); @@ -27084,24 +27069,24 @@ } var std_buf_key = - /*<>*/ caml_call2 - (Stdlib_Domain[11][1], + /*<>*/ Stdlib_Domain[11][1].call + (null, 0, function(param){ /*<>*/ return Stdlib_Buffer[1].call (null, pp_buffer_size) /*<>*/ ; }), err_buf_key = - /*<>*/ caml_call2 - (Stdlib_Domain[11][1], + /*<>*/ Stdlib_Domain[11][1].call + (null, 0, function(param){ /*<>*/ return Stdlib_Buffer[1].call (null, pp_buffer_size) /*<>*/ ; }), std_formatter_key = - /*<>*/ caml_call2 - (Stdlib_Domain[11][1], + /*<>*/ Stdlib_Domain[11][1].call + (null, 0, function(param){ var @@ -27138,12 +27123,12 @@ }); /*<>*/ return ppf; /*<>*/ }); - /*<>*/ caml_call2 - (Stdlib_Domain[11][3], std_formatter_key, std_formatter); + /*<>*/ Stdlib_Domain[11][3].call + (null, std_formatter_key, std_formatter); var err_formatter_key = - /*<>*/ caml_call2 - (Stdlib_Domain[11][1], + /*<>*/ Stdlib_Domain[11][1].call + (null, 0, function(param){ var @@ -27180,23 +27165,23 @@ }); /*<>*/ return ppf; /*<>*/ }); - /*<>*/ caml_call2 - (Stdlib_Domain[11][3], err_formatter_key, err_formatter); + /*<>*/ Stdlib_Domain[11][3].call + (null, err_formatter_key, err_formatter); function get_std_formatter(param){ - /*<>*/ return caml_call1 - (Stdlib_Domain[11][2], std_formatter_key) /*<>*/ ; + /*<>*/ return Stdlib_Domain[11][2].call + (null, std_formatter_key) /*<>*/ ; } function get_err_formatter(param){ - /*<>*/ return caml_call1 - (Stdlib_Domain[11][2], err_formatter_key) /*<>*/ ; + /*<>*/ return Stdlib_Domain[11][2].call + (null, err_formatter_key) /*<>*/ ; } function get_str_formatter(param){ - /*<>*/ return caml_call1 - (Stdlib_Domain[11][2], str_formatter_key) /*<>*/ ; + /*<>*/ return Stdlib_Domain[11][2].call + (null, str_formatter_key) /*<>*/ ; } function get_stdbuf(param){ - /*<>*/ return caml_call1 - (Stdlib_Domain[11][2], stdbuf_key) /*<>*/ ; + /*<>*/ return Stdlib_Domain[11][2].call + (null, stdbuf_key) /*<>*/ ; } function flush_buffer_formatter(buf, ppf){ /*<>*/ pp_flush_queue(ppf, 0); @@ -27207,16 +27192,16 @@ function flush_str_formatter(param){ var stdbuf = - /*<>*/ caml_call1(Stdlib_Domain[11][2], stdbuf_key), + /*<>*/ Stdlib_Domain[11][2].call(null, stdbuf_key), str_formatter = - /*<>*/ caml_call1 - (Stdlib_Domain[11][2], str_formatter_key); + /*<>*/ Stdlib_Domain[11][2].call + (null, str_formatter_key); /*<>*/ return flush_buffer_formatter (stdbuf, str_formatter) /*<>*/ ; } function make_synchronized_formatter(output, flush){ - /*<>*/ return caml_call2 - (Stdlib_Domain[11][1], + /*<>*/ return Stdlib_Domain[11][1].call + (null, 0, function(param){ var @@ -27295,70 +27280,70 @@ } function open_hbox(v){ /*<>*/ return /*<>*/ pp_open_hbox - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function open_vbox(v){ /*<>*/ return /*<>*/ pp_open_vbox - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function open_hvbox(v){ /*<>*/ return /*<>*/ pp_open_hvbox - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function open_hovbox(v){ /*<>*/ return /*<>*/ pp_open_hovbox - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function open_box(v){ /*<>*/ return /*<>*/ pp_open_box - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function close_box(v){ /*<>*/ return /*<>*/ pp_close_box - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function open_stag(v){ /*<>*/ return /*<>*/ pp_open_stag - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function close_stag(v){ /*<>*/ return /*<>*/ pp_close_stag - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function print_as(isize, w){ var state = - /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key); + /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key); /*<>*/ return pp_print_as_size(state, isize, w) /*<>*/ ; } function print_string(v){ /*<>*/ return /*<>*/ pp_print_string - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function print_substring(pos, len, v){ var state = - /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key); + /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key); /*<>*/ return pp_print_substring_as (pos, len, state, len, v) /*<>*/ ; } @@ -27366,272 +27351,272 @@ /*<>*/ return /*<>*/ pp_print_substring_as (pos, len, - /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), as_len, v) /*<>*/ ; } function print_bytes(v){ /*<>*/ return /*<>*/ pp_print_bytes - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function print_int(v){ /*<>*/ return /*<>*/ pp_print_int - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function print_float(v){ /*<>*/ return /*<>*/ pp_print_float - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function print_char(v){ /*<>*/ return /*<>*/ pp_print_char - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function print_bool(v){ /*<>*/ return /*<>*/ pp_print_bool - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function print_break(v, w){ /*<>*/ return /*<>*/ pp_print_break - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v, w) /*<>*/ ; } function print_cut(v){ /*<>*/ return /*<>*/ pp_print_cut - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function print_space(v){ /*<>*/ return /*<>*/ pp_print_space - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function force_newline(v){ /*<>*/ return /*<>*/ pp_force_newline - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function print_flush(v){ /*<>*/ return /*<>*/ pp_print_flush - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function print_newline(v){ /*<>*/ return /*<>*/ pp_print_newline - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function print_if_newline(v){ /*<>*/ return /*<>*/ pp_print_if_newline - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function open_tbox(v){ /*<>*/ return /*<>*/ pp_open_tbox - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function close_tbox(v){ /*<>*/ return /*<>*/ pp_close_tbox - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function print_tbreak(v, w){ /*<>*/ return /*<>*/ pp_print_tbreak - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v, w) /*<>*/ ; } function set_tab(v){ /*<>*/ return /*<>*/ pp_set_tab - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function print_tab(v){ /*<>*/ return /*<>*/ pp_print_tab - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function set_margin(v){ /*<>*/ return /*<>*/ pp_set_margin - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function get_margin(v){ var state = - /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key); + /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key); /*<>*/ return state[6]; /*<>*/ } function set_max_indent(v){ /*<>*/ return /*<>*/ pp_set_max_indent - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function get_max_indent(v){ var state = - /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key); + /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key); /*<>*/ return state[8]; /*<>*/ } function set_geometry(max_indent, margin){ /*<>*/ return /*<>*/ pp_set_geometry - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), max_indent, margin) /*<>*/ ; } function safe_set_geometry(max_indent, margin){ /*<>*/ return /*<>*/ pp_safe_set_geometry - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), max_indent, margin) /*<>*/ ; } function get_geometry(v){ /*<>*/ return /*<>*/ pp_get_geometry - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function update_geometry(v){ /*<>*/ return /*<>*/ pp_update_geometry - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function set_max_boxes(v){ /*<>*/ return /*<>*/ pp_set_max_boxes - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function get_max_boxes(v){ var state = - /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key); + /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key); /*<>*/ return state[15]; /*<>*/ } function over_max_boxes(v){ /*<>*/ return /*<>*/ pp_over_max_boxes - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function set_ellipsis_text(v){ /*<>*/ return /*<>*/ pp_set_ellipsis_text - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function get_ellipsis_text(v){ var state = - /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key); + /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key); /*<>*/ return state[16]; /*<>*/ } function set_formatter_out_channel(v){ /*<>*/ return /*<>*/ pp_set_formatter_out_channel - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function set_formatter_out_functions(v){ /*<>*/ return /*<>*/ pp_set_formatter_out_functions - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function get_formatter_out_functions(v){ /*<>*/ return /*<>*/ pp_get_formatter_out_functions - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function set_formatter_output_functions(v, w){ /*<>*/ return /*<>*/ pp_set_formatter_output_functi - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v, w) /*<>*/ ; } function get_formatter_output_functions(v){ /*<>*/ return /*<>*/ pp_get_formatter_output_functi - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function set_formatter_stag_functions(v){ /*<>*/ return /*<>*/ pp_set_formatter_stag_function - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function get_formatter_stag_functions(v){ /*<>*/ return /*<>*/ pp_get_formatter_stag_function - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function set_print_tags(v){ /*<>*/ return /*<>*/ pp_set_print_tags - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function get_print_tags(v){ var state = - /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key); + /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key); /*<>*/ return state[22]; /*<>*/ } function set_mark_tags(v){ /*<>*/ return /*<>*/ pp_set_mark_tags - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function get_mark_tags(v){ var state = - /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key); + /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key); /*<>*/ return state[23]; /*<>*/ } function set_tags(v){ /*<>*/ return /*<>*/ pp_set_tags - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), v) /*<>*/ ; } function pp_print_iter(opt, iter, pp_v, ppf, v){ @@ -28023,8 +28008,8 @@ (null, function(acc){ /*<>*/ return /*<>*/ output_acc - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), acc) /*<>*/ ; }, 0, @@ -28036,8 +28021,8 @@ (null, function(acc){ /*<>*/ return /*<>*/ output_acc - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], err_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, err_formatter_key), acc) /*<>*/ ; }, 0, @@ -28098,12 +28083,12 @@ } function flush_standard_formatters(param){ /*<>*/ /*<>*/ pp_print_flush - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], std_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, std_formatter_key), 0); /*<>*/ return /*<>*/ pp_print_flush - ( /*<>*/ caml_call1 - (Stdlib_Domain[11][2], err_formatter_key), + ( /*<>*/ Stdlib_Domain[11][2].call + (null, err_formatter_key), 0) /*<>*/ ; } /*<>*/ Stdlib[100].call(null, flush_standard_formatters); @@ -28314,7 +28299,7 @@ //# unitInfo: Provides: Stdlib__Scanf //# unitInfo: Requires: CamlinternalFormat, CamlinternalFormatBasics, Stdlib, Stdlib__Buffer, Stdlib__Bytes, Stdlib__Int, Stdlib__Printf, Stdlib__String -//# shape: Stdlib__Scanf:[N,N,F(2),F(2),F(2),F(2),F(1),F(1),F(3),F(3),F(3),F(3),F(2),F(1)] +//# shape: Stdlib__Scanf:[[N,F(1),F(1),F(1),F(1),F(1),F(1)*,F(1)*,F(1)*,F(1),F(1)*,F(1)*],[N,N],F(2),F(2),F(2),F(2),F(1),F(1),F(3),F(3),F(3),F(3),F(2),F(1)] (function (globalThis){ "use strict"; @@ -30505,7 +30490,7 @@ //# unitInfo: Provides: CamlinternalOO //# unitInfo: Requires: Stdlib, Stdlib__Array, Stdlib__List, Stdlib__Map, Stdlib__Obj, Stdlib__Sys -//# shape: CamlinternalOO:[F(1),F(1),F(2),F(3),F(2),F(2),F(2),F(2),F(2),F(3),F(2),F(4),F(1),F(2),N,F(1),F(1),F(6),F(2),F(3),F(1)*,F(1),F(1),F(2),F(2),F(3),F(2),F(2),N,F(1)*] +//# shape: CamlinternalOO:[F(1),F(1),F(2),F(3),F(2),F(2),F(2),F(2),F(2),F(3),F(2),F(4),F(1),F(2),N,F(1),F(1),F(6),F(2)->[N,N,N],F(3),F(1)*->[F(1),F(1),N],F(1),F(1),F(2),F(2),F(3),F(2),F(2),N,F(1)*->[N,N,N]] (function (globalThis){ "use strict"; @@ -30735,7 +30720,7 @@ } /*<>*/ } function to_list(arr){ - /*<>*/ return 0 === arr + /*<>*/ return arr === 0 ? 0 : /*<>*/ Stdlib_Array [10].call @@ -30967,7 +30952,7 @@ return 0; /*<>*/ } function create_table(public_methods){ - /*<>*/ if(0 === public_methods) + /*<>*/ if(public_methods === 0) /*<>*/ return new_table([0]) /*<>*/ ; var tags = @@ -32980,7 +32965,7 @@ //# unitInfo: Provides: Stdlib__Ephemeron //# unitInfo: Requires: CamlinternalLazy, Stdlib, Stdlib__Array, Stdlib__Hashtbl, Stdlib__Int, Stdlib__List, Stdlib__Obj, Stdlib__Random, Stdlib__Seq, Stdlib__Sys -//# shape: Stdlib__Ephemeron:[N,N,N] +//# shape: Stdlib__Ephemeron:[[F(2),F(2),F(1)*->[F(1),N,N,N,N,N,N,N,N,N,N,N,N,N,N,F(1),N,N],F(1)*,[F(1)*,F(3),F(2),F(2),F(1),F(1)]],[F(3),F(3),F(2)*->[F(1),N,N,N,N,N,N,N,N,N,N,N,N,N,N,F(1),N,N],F(2)*,[F(1)*,F(4),F(3),F(3),F(1),F(1)]],[F(2),F(2),F(1)*->[F(1),N,N,N,N,N,N,N,N,N,N,N,N,N,N,F(1),N,N],F(1)*,[F(1)*,F(3),F(2),F(2),F(1),F(1)]]] (function (globalThis){ "use strict"; @@ -33023,7 +33008,7 @@ Stdlib_Random = global_data.Stdlib__Random; function MakeSeeded(H){ var - prng = [246, function(_I_){return caml_call1(Stdlib_Random[19][2], 0);}]; + prng = [246, function(_I_){return Stdlib_Random[19][2].call(null, 0);}]; function create(opt, initial_size){ var random = @@ -33048,8 +33033,10 @@ } var seed = - /*<>*/ /*<>*/ caml_call1 - (Stdlib_Random[19][4], _I_); + /*<>*/ /*<>*/ Stdlib_Random + [19] + [4].call + (null, _I_); } else var seed = /*<>*/ 0; @@ -33521,24 +33508,24 @@ stats_alive]; } function create(param){ - /*<>*/ return caml_call1(Stdlib_Obj[23][1], 1) /*<>*/ ; + /*<>*/ return Stdlib_Obj[23][1].call(null, 1) /*<>*/ ; } function get_key(t){ - var x = /*<>*/ caml_call2(Stdlib_Obj[23][3], t, 0); + var x = /*<>*/ Stdlib_Obj[23][3].call(null, t, 0); /*<>*/ return x; /*<>*/ } function set_key(t, k){ - /*<>*/ return caml_call3(Stdlib_Obj[23][5], t, 0, k) /*<>*/ ; + /*<>*/ return Stdlib_Obj[23][5].call(null, t, 0, k) /*<>*/ ; } function check_key(t){ - /*<>*/ return caml_call2(Stdlib_Obj[23][7], t, 0) /*<>*/ ; + /*<>*/ return Stdlib_Obj[23][7].call(null, t, 0) /*<>*/ ; } function get_data(t){ - var x = /*<>*/ caml_call1(Stdlib_Obj[23][9], t); + var x = /*<>*/ Stdlib_Obj[23][9].call(null, t); /*<>*/ return x; /*<>*/ } function set_data(t, d){ - /*<>*/ return caml_call2(Stdlib_Obj[23][11], t, d) /*<>*/ ; + /*<>*/ return Stdlib_Obj[23][11].call(null, t, d) /*<>*/ ; } function make(key, data){ var eph = /*<>*/ create(0); @@ -33571,7 +33558,7 @@ /*<>*/ return caml_call2(H[1], k, k$0) ? 0 : 1 /*<>*/ ; } function set_key_data(c, k, d){ - /*<>*/ caml_call1(Stdlib_Obj[23][12], c); + /*<>*/ Stdlib_Obj[23][12].call(null, c); /*<>*/ set_key(c, k); /*<>*/ return set_data(c, d) /*<>*/ ; } @@ -33609,11 +33596,11 @@ clean = include[17], stats_alive = include[18]; function create(sz){ - /*<>*/ return caml_call2(_v_, _a_, sz) /*<>*/ ; + /*<>*/ return _v_(_a_, sz) /*<>*/ ; } function of_seq(i){ - var tbl = /*<>*/ caml_call2(_v_, _a_, 16); - /*<>*/ caml_call2(replace_seq, tbl, i); + var tbl = /*<>*/ _v_(_a_, 16); + /*<>*/ replace_seq(tbl, i); /*<>*/ return tbl; /*<>*/ } /*<>*/ return [0, @@ -33690,28 +33677,28 @@ return 0; /*<>*/ } function create$0(param){ - /*<>*/ return caml_call1(Stdlib_Obj[23][1], 2) /*<>*/ ; + /*<>*/ return Stdlib_Obj[23][1].call(null, 2) /*<>*/ ; } function get_key1(t){ - var x = /*<>*/ caml_call2(Stdlib_Obj[23][3], t, 0); + var x = /*<>*/ Stdlib_Obj[23][3].call(null, t, 0); /*<>*/ return x; /*<>*/ } function set_key1(t, k){ - /*<>*/ return caml_call3(Stdlib_Obj[23][5], t, 0, k) /*<>*/ ; + /*<>*/ return Stdlib_Obj[23][5].call(null, t, 0, k) /*<>*/ ; } function get_key2(t){ - var x = /*<>*/ caml_call2(Stdlib_Obj[23][3], t, 1); + var x = /*<>*/ Stdlib_Obj[23][3].call(null, t, 1); /*<>*/ return x; /*<>*/ } function set_key2(t, k){ - /*<>*/ return caml_call3(Stdlib_Obj[23][5], t, 1, k) /*<>*/ ; + /*<>*/ return Stdlib_Obj[23][5].call(null, t, 1, k) /*<>*/ ; } function get_data$0(t){ - var x = /*<>*/ caml_call1(Stdlib_Obj[23][9], t); + var x = /*<>*/ Stdlib_Obj[23][9].call(null, t); /*<>*/ return x; /*<>*/ } function set_data$0(t, d){ - /*<>*/ return caml_call2(Stdlib_Obj[23][11], t, d) /*<>*/ ; + /*<>*/ return Stdlib_Obj[23][11].call(null, t, d) /*<>*/ ; } function make$1(key1, key2, data){ var eph = /*<>*/ create$0(0); @@ -33772,17 +33759,16 @@ /*<>*/ } function set_key_data(c, param, d){ var k2 = /*<>*/ param[2], k1 = param[1]; - /*<>*/ caml_call1(Stdlib_Obj[23][12], c); + /*<>*/ Stdlib_Obj[23][12].call(null, c); /*<>*/ set_key1(c, k1); /*<>*/ set_key2(c, k2); /*<>*/ return set_data$0(c, d) /*<>*/ ; } function check_key(c){ var - _v_ = /*<>*/ caml_call2(Stdlib_Obj[23][7], c, 0); + _v_ = /*<>*/ Stdlib_Obj[23][7].call(null, c, 0); /*<>*/ return _v_ - ? /*<>*/ caml_call2 - (Stdlib_Obj[23][7], c, 1) + ? /*<>*/ Stdlib_Obj[23][7].call(null, c, 1) : _v_ /*<>*/ ; } /*<>*/ return MakeSeeded @@ -33825,11 +33811,11 @@ clean = include[17], stats_alive = include[18]; function create(sz){ - /*<>*/ return caml_call2(_v_, _b_, sz) /*<>*/ ; + /*<>*/ return _v_(_b_, sz) /*<>*/ ; } function of_seq(i){ - var tbl = /*<>*/ caml_call2(_v_, _b_, 16); - /*<>*/ caml_call2(replace_seq, tbl, i); + var tbl = /*<>*/ _v_(_b_, 16); + /*<>*/ replace_seq(tbl, i); /*<>*/ return tbl; /*<>*/ } /*<>*/ return [0, @@ -33910,24 +33896,24 @@ return 0; /*<>*/ } function create$1(n){ - /*<>*/ return caml_call1(Stdlib_Obj[23][1], n) /*<>*/ ; + /*<>*/ return Stdlib_Obj[23][1].call(null, n) /*<>*/ ; } function length$1(k){ - /*<>*/ return caml_call1(Stdlib_Obj[23][2], k) /*<>*/ ; + /*<>*/ return Stdlib_Obj[23][2].call(null, k) /*<>*/ ; } function get_key$0(t, n){ - var x = /*<>*/ caml_call2(Stdlib_Obj[23][3], t, n); + var x = /*<>*/ Stdlib_Obj[23][3].call(null, t, n); /*<>*/ return x; /*<>*/ } function set_key$0(t, n, k){ - /*<>*/ return caml_call3(Stdlib_Obj[23][5], t, n, k) /*<>*/ ; + /*<>*/ return Stdlib_Obj[23][5].call(null, t, n, k) /*<>*/ ; } function get_data$1(t){ - var x = /*<>*/ caml_call1(Stdlib_Obj[23][9], t); + var x = /*<>*/ Stdlib_Obj[23][9].call(null, t); /*<>*/ return x; /*<>*/ } function set_data$1(t, d){ - /*<>*/ return caml_call2(Stdlib_Obj[23][11], t, d) /*<>*/ ; + /*<>*/ return Stdlib_Obj[23][11].call(null, t, d) /*<>*/ ; } function make$3(keys, data){ var @@ -34044,7 +34030,7 @@ } /*<>*/ } function set_key_data(c, k, d){ - /*<>*/ caml_call1(Stdlib_Obj[23][12], c); + /*<>*/ Stdlib_Obj[23][12].call(null, c); var _h_ = /*<>*/ k.length - 2 | 0, _i_ = 0; if(_h_ >= 0){ var i = _i_; @@ -34068,7 +34054,7 @@ var _h_ = _g_; else{ var - _f_ = /*<>*/ caml_call2(Stdlib_Obj[23][7], c, i); + _f_ = /*<>*/ Stdlib_Obj[23][7].call(null, c, i); /*<>*/ if(_f_){ var i$0 = i - 1 | 0; i = i$0; @@ -34113,11 +34099,11 @@ clean = include[17], stats_alive = include[18]; function create(sz){ - /*<>*/ return caml_call2(_f_, _c_, sz) /*<>*/ ; + /*<>*/ return _f_(_c_, sz) /*<>*/ ; } function of_seq(i){ - var tbl = /*<>*/ caml_call2(_f_, _c_, 16); - /*<>*/ caml_call2(replace_seq, tbl, i); + var tbl = /*<>*/ _f_(_c_, 16); + /*<>*/ replace_seq(tbl, i); /*<>*/ return tbl; /*<>*/ } /*<>*/ return [0, @@ -34246,7 +34232,7 @@ //# unitInfo: Provides: Stdlib__Filename //# unitInfo: Requires: Stdlib, Stdlib__Buffer, Stdlib__Domain, Stdlib__List, Stdlib__Printf, Stdlib__Random, Stdlib__String, Stdlib__Sys -//# shape: Stdlib__Filename:[N,N,N,F(2),F(1),F(1),F(2),F(2),F(2),F(1),F(1),F(1),F(1),F(1),N,F(3),F(5),F(4),F(1),F(1),F(1),F(5)] +//# shape: Stdlib__Filename:[N,N,N,F(2),F(1),F(1),F(2),F(2),F(2),F(1),F(1),F(1),F(1),F(1),N,F(3),F(5)->[N,N],F(4),F(1),F(1),F(1),F(5)] (function (globalThis){ "use strict"; @@ -34273,11 +34259,6 @@ caml_trampoline = runtime.caml_trampoline, caml_trampoline_return = runtime.caml_trampoline_return, caml_wrap_exception = runtime.caml_wrap_exception; - function caml_call1(f, a0){ - return (f.l >= 0 ? f.l : f.l = f.length) === 1 - ? f(a0) - : runtime.caml_call_gen(f, [a0]); - } function caml_call2(f, a0, a1){ return (f.l >= 0 ? f.l : f.l = f.length) === 2 ? f(a0, a1) @@ -35097,15 +35078,15 @@ } var prng_key = - /*<>*/ caml_call2 - (Stdlib_Domain[11][1], 0, Stdlib_Random[19][2]); + /*<>*/ Stdlib_Domain[11][1].call + (null, 0, Stdlib_Random[19][2]); function temp_file_name(temp_dir, prefix, suffix){ var random_state = - /*<>*/ caml_call1(Stdlib_Domain[11][2], prng_key), + /*<>*/ Stdlib_Domain[11][2].call(null, prng_key), rnd = - /*<>*/ caml_call1 - (Stdlib_Random[19][4], random_state) + /*<>*/ Stdlib_Random[19][4].call + (null, random_state) & 16777215; /*<>*/ return /*<>*/ concat (temp_dir, @@ -35114,27 +35095,29 @@ } var current_temp_dir_name = - /*<>*/ caml_call2 - (Stdlib_Domain[11][1], + /*<>*/ Stdlib_Domain[11][1].call + (null, [0, function(_i_){ /*<>*/ return _i_;}], function(param){ /*<>*/ return temp_dir_name$1; /*<>*/ }); function set_temp_dir_name(s){ - /*<>*/ return caml_call2 - (Stdlib_Domain[11][3], current_temp_dir_name, s) /*<>*/ ; + /*<>*/ return Stdlib_Domain[11][3].call + (null, current_temp_dir_name, s) /*<>*/ ; } function get_temp_dir_name(param){ - /*<>*/ return caml_call1 - (Stdlib_Domain[11][2], current_temp_dir_name) /*<>*/ ; + /*<>*/ return Stdlib_Domain[11][2].call + (null, current_temp_dir_name) /*<>*/ ; } function temp_file(opt, prefix, suffix){ var temp_dir = /*<>*/ opt ? opt[1] - : /*<>*/ caml_call1 - (Stdlib_Domain[11][2], current_temp_dir_name), + : /*<>*/ Stdlib_Domain + [11] + [2].call + (null, current_temp_dir_name), counter = /*<>*/ 0; for(;;){ var @@ -35162,8 +35145,10 @@ temp_dir = opt ? opt[1] - : /*<>*/ caml_call1 - (Stdlib_Domain[11][2], current_temp_dir_name), + : /*<>*/ Stdlib_Domain + [11] + [2].call + (null, current_temp_dir_name), counter = /*<>*/ 0; for(;;){ var @@ -35192,8 +35177,10 @@ temp_dir = /*<>*/ _g_ ? _g_[1] - : /*<>*/ caml_call1 - (Stdlib_Domain[11][2], current_temp_dir_name), + : /*<>*/ Stdlib_Domain + [11] + [2].call + (null, current_temp_dir_name), perms = /*<>*/ opt ? opt[1] : 448, counter = /*<>*/ 0; for(;;){ @@ -35246,7 +35233,7 @@ //# unitInfo: Provides: Stdlib__Complex //# unitInfo: Requires: Stdlib, Stdlib__Float -//# shape: Stdlib__Complex:[N,N,N,F(1)*,F(1)*,F(2)*,F(2)*,F(2)*,F(1)*,F(2)*,F(1)*,F(1)*,F(1)*,F(1)*,F(2)*,F(1)*,F(1)*,F(2)*] +//# shape: Stdlib__Complex:[N,N,N,F(1)*->[N,N],F(1)*->[N,N],F(2)*->[N,N],F(2)*->[N,N],F(2)*->[N,N],F(1)*,F(2)*->[N,N],F(1)*,F(1)*,F(1)*,F(1)*,F(2)*->[N,N],F(1)*->[N,N],F(1)*->[N,N],F(2)*] (function (globalThis){ "use strict"; @@ -35385,7 +35372,7 @@ //# unitInfo: Provides: Stdlib__ArrayLabels //# unitInfo: Requires: Stdlib__Array -//# shape: Stdlib__ArrayLabels:[F(2),F(3),F(3),F(2)*,F(1)*,F(3),F(1)*,F(4),F(5),F(1),F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(3),F(3),F(3),F(3),F(2),F(2),F(3),F(3),F(2),F(2),F(2),F(2),F(2),F(2),F(1),F(2),F(2),F(2),F(2),F(2),F(1)*->F(1)*,F(1)*->F(1)*,F(1),[]] +//# shape: Stdlib__ArrayLabels:[F(2),F(3),F(3),F(2)*,F(1)*,F(3),F(1)*,F(4),F(5),F(1),F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(3)->[N,N],F(3),F(3),F(3),F(2),F(2),F(3),F(3),F(2),F(2),F(2),F(2),F(2),F(2),F(1)->[N,N],F(2),F(2),F(2),F(2),F(2),F(1)*->F(1)*,F(1)*->F(1)*,F(1),[]] (function (globalThis){ "use strict"; @@ -35486,7 +35473,7 @@ //# unitInfo: Provides: Stdlib__ListLabels //# unitInfo: Requires: Stdlib__List -//# shape: Stdlib__ListLabels:[F(1),F(2),F(2),F(1)*,F(2)*,F(1),F(1),F(2),F(2),F(1),F(2),F(2),F(2),F(1),F(1),F(3),F(3),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(3),F(3),F(3),F(3),F(3),F(4),F(4),F(2),F(2),F(3),F(3),F(2),F(2),F(2),F(2),F(1)*->F(1),F(2),F(1)*->F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(1),F(2),F(2),F(2),F(2),F(2),F(3),F(1)*->F(1)*,F(1)] +//# shape: Stdlib__ListLabels:[F(1),F(2),F(2),F(1)*,F(2)*->[N,N],F(1),F(1),F(2),F(2),F(1),F(2),F(2),F(2),F(1),F(1),F(3),F(3),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(3)->[N,N],F(3),F(3),F(3),F(3),F(3),F(4),F(4),F(2),F(2),F(3),F(3),F(2),F(2),F(2),F(2),F(1)*->F(1),F(2),F(1)*->F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2)->[N,N],F(2)->[N,N],F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(1),F(2),F(2),F(2),F(2),F(2),F(3),F(1)*->F(1)*,F(1)] (function (globalThis){ "use strict"; @@ -35641,7 +35628,7 @@ //# unitInfo: Provides: Stdlib__BytesLabels //# unitInfo: Requires: Stdlib__Bytes -//# shape: Stdlib__BytesLabels:[F(2),F(2),N,F(1),F(1),F(1),F(3),F(3),F(3),F(4),F(5),F(5),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(3),F(2),F(2),F(1),F(1),F(2),F(2),F(2),F(2),F(3),F(3),F(3),F(3),F(2),F(3),F(3),F(1),F(1),F(1),F(1),F(2)*,F(2)*,F(2),F(2),F(1),F(1)*,F(2),F(1)*->F(1),F(1)*->F(1),F(1),F(2),F(3),F(1),F(2),F(3),F(1),F(2),F(3),F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(1)] +//# shape: Stdlib__BytesLabels:[F(2),F(2),N,F(1),F(1),F(1),F(3),F(3),F(3),F(4),F(5),F(5),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(3),F(2),F(2),F(1),F(1),F(2),F(2),F(2),F(2),F(3),F(3),F(3),F(3),F(2),F(3),F(3),F(1),F(1),F(1),F(1),F(2)*,F(2)*,F(2),F(2),F(1),F(1)*,F(2)->[N,N],F(1)*->F(1),F(1)*->F(1),F(1),F(2),F(3),F(1),F(2),F(3),F(1),F(2),F(3),F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(3),F(1)] (function (globalThis){ "use strict"; @@ -35832,7 +35819,7 @@ //# unitInfo: Provides: Stdlib__StringLabels //# unitInfo: Requires: Stdlib__String -//# shape: Stdlib__StringLabels:[F(2),F(2),N,F(1),F(1),F(5),F(2),F(2)*,F(2)*,F(2)*,F(2),F(2),F(3),F(3),F(2),F(3),F(2),F(2),F(2),F(3),F(3),F(2),F(2),F(1),F(1),F(1),F(1),F(1),F(1),F(2),F(2),F(3),F(3),F(3),F(3),F(2),F(2),F(2),F(2),F(1)*,F(1)*,F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(1),F(2),F(2),F(2),F(2),F(2),F(2)] +//# shape: Stdlib__StringLabels:[F(2),F(2),N,F(1),F(1),F(5),F(2),F(2)*,F(2)*,F(2)*,F(2),F(2),F(3),F(3),F(2),F(3),F(2)->[N,N],F(2),F(2),F(3),F(3),F(2),F(2),F(1),F(1),F(1),F(1),F(1),F(1),F(2),F(2),F(3),F(3),F(3),F(3),F(2),F(2),F(2),F(2),F(1)*,F(1)*,F(1),F(2),F(1),F(2),F(1),F(2),F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(1),F(2),F(2),F(2),F(2),F(2),F(2)] (function (globalThis){ "use strict"; @@ -35978,7 +35965,7 @@ //# unitInfo: Provides: Stdlib__MoreLabels //# unitInfo: Requires: Stdlib__Hashtbl, Stdlib__Map, Stdlib__Set -//# shape: Stdlib__MoreLabels:[[F(2),F(1),F(1),F(1),F(3),F(2),F(2),F(2),F(2),F(2),F(3),F(2),F(2),F(3),F(1)*,F(1),F(1),F(2),F(1),F(1)*->F(1),F(1)*->F(1),F(1)*->F(1),F(2),F(2),F(1),F(1)*,F(1)*,F(1)*,F(2)*,F(3)*,F(4)*],[F(1)*],[F(1)*]] +//# shape: Stdlib__MoreLabels:[[F(2),F(1),F(1),F(1),F(3),F(2),F(2),F(2),F(2),F(2),F(3),F(2),F(2),F(3),F(1)*,F(1),F(1),F(2),F(1)->[N,N,N,N],F(1)*->F(1),F(1)*->F(1),F(1)*->F(1),F(2),F(2),F(1),F(1)*->[F(1),N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,F(1)],F(1)*->[F(2),F(1),F(1),F(1),F(3),F(2),F(2),F(2),F(2),F(3),F(2),F(2),F(2),F(3),F(1)*,F(1)->[N,N,N,N],F(1)*->F(1),F(1)*->F(1),F(1)*->F(1),F(2),F(2),F(1)],F(1)*,F(2)*,F(3)*,F(4)*],[F(1)*->[N,F(3),F(3),F(3),F(2)*->[N,N,N,N,N],F(2),F(3),F(3),F(1),F(1),F(1)->[N,N],F(1),F(1)->[N,N],F(1),F(1)->[N,N],F(1),F(2),F(2),F(2)->[N,N],F(2),F(2)->[N,N],F(2),F(2),F(3),F(2),F(2),F(2),F(2),F(2),F(2),F(1)*,F(2),F(3),F(3),F(2),F(2),F(1),F(1),F(1)->F(1),F(1)->F(1),F(2)->F(1),F(2),F(1)]],[F(1)*->[N,F(2),F(1)*->[N,N,N,N],F(2),F(2),F(2),F(2),F(2),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(1),F(2),F(2),F(2),F(2),F(2),F(2),F(2),F(3),F(2),F(2),F(2),F(2),F(2),F(1)*,F(2),F(2),F(2),F(2),F(2),F(2),F(1),F(1),F(2)->F(1),F(1)->F(1),F(1)->F(1),F(2),F(1)]]] (function (globalThis){ "use strict"; @@ -36008,7 +35995,7 @@ //# unitInfo: Provides: Stdlib__Effect //# unitInfo: Requires: Stdlib, Stdlib__Callback, Stdlib__Printexc, Stdlib__Printf //# unitInfo: Effects_without_cps: true -//# shape: Stdlib__Effect:[N,N,[F(2),F(2),F(3),F(3),F(3)],N] +//# shape: Stdlib__Effect:[[N,N],[N,N],[F(2),F(2),F(3),F(3),F(3)],[F(1),F(3),F(3),F(4)]] (function (globalThis){ "use strict"; From f890028f54f67c2bee68582269d8f0a510d869cb Mon Sep 17 00:00:00 2001 From: Hugo Heuzard Date: Mon, 16 Jun 2025 12:13:06 +0200 Subject: [PATCH 02/14] fix compat --- compiler/lib/ocaml_compiler.ml | 8 +++++++- compiler/lib/ocaml_compiler.mli | 2 ++ compiler/lib/parse_bytecode.ml | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/compiler/lib/ocaml_compiler.ml b/compiler/lib/ocaml_compiler.ml index 9b396c1e9d..53470ee395 100644 --- a/compiler/lib/ocaml_compiler.ml +++ b/compiler/lib/ocaml_compiler.ml @@ -284,5 +284,11 @@ module Cmo_format = struct let force_link (t : t) = t.cu_force_link - let hints_pos (t : t) = t.cu_hint + let hints_pos (t : t) = t.cu_hint [@@if ocaml_version >= (5, 3, 1)] + + let hints_size (t : t) = t.cu_hintsize [@@if ocaml_version >= (5, 3, 1)] + + let hints_size _ = 0 [@@if ocaml_version < (5, 3, 1)] + + let hints_pos _ = 0 [@@if ocaml_version < (5, 3, 1)] end diff --git a/compiler/lib/ocaml_compiler.mli b/compiler/lib/ocaml_compiler.mli index 4f69e6197e..d0883bbcb9 100644 --- a/compiler/lib/ocaml_compiler.mli +++ b/compiler/lib/ocaml_compiler.mli @@ -75,4 +75,6 @@ module Cmo_format : sig val imports : t -> (string * string option) list val hints_pos : t -> int + + val hints_size : t -> int end diff --git a/compiler/lib/parse_bytecode.ml b/compiler/lib/parse_bytecode.ml index 3ab9042875..5125daa2c9 100644 --- a/compiler/lib/parse_bytecode.ml +++ b/compiler/lib/parse_bytecode.ml @@ -3134,7 +3134,7 @@ let from_cmo ?(includes = []) ?(include_cmis = false) ?(debug = false) compunit Debug.read_event_list debug_data ~crcs:[] ~includes ~orig:0 ic); if times () then Format.eprintf " read debug events: %a@." Timer.print t; let hints = Hints.create () in - if Ocaml_compiler.Cmo_format.hints_pos compunit <> 0 + if Ocaml_compiler.Cmo_format.hints_size compunit > 0 then ( seek_in ic (Ocaml_compiler.Cmo_format.hints_pos compunit); Hints.read hints ~orig:0 ic); @@ -3159,7 +3159,7 @@ let from_cma ?(includes = []) ?(include_cmis = false) ?(debug = false) lib ic = then ( seek_in ic compunit.Cmo_format.cu_debug; Debug.read_event_list debug_data ~crcs:[] ~includes ~orig:!orig ic); - if Ocaml_compiler.Cmo_format.hints_pos compunit <> 0 + if Ocaml_compiler.Cmo_format.hints_size compunit > 0 then ( seek_in ic (Ocaml_compiler.Cmo_format.hints_pos compunit); Hints.read hints ~orig:!orig ic); From 1d9eedc5598e11f02f64f9095f83f5290af26fe4 Mon Sep 17 00:00:00 2001 From: Hugo Heuzard Date: Fri, 25 Oct 2024 22:59:18 +0200 Subject: [PATCH 03/14] Compiler: consume hints for unsafe string/bytes/ba get/set --- compiler/lib-wasm/generate.ml | 15 +++ compiler/lib/parse_bytecode.ml | 33 +++++- compiler/tests-full/stdlib.cma.expected.js | 33 +++--- runtime/js/bigarray.js | 59 ++++++++++ runtime/js/mlBytes.js | 87 ++++++++++++-- runtime/wasm/bigarray.wat | 60 ++++++++++ runtime/wasm/string.wat | 128 +++++++++++++++++++++ 7 files changed, 384 insertions(+), 31 deletions(-) diff --git a/compiler/lib-wasm/generate.ml b/compiler/lib-wasm/generate.ml index 5c51a05321..e9e11b7006 100644 --- a/compiler/lib-wasm/generate.ml +++ b/compiler/lib-wasm/generate.ml @@ -94,21 +94,36 @@ module Generate (Target : Target_sig.S) = struct ; "caml_nativeint_compare", (`Pure, [ Nativeint; Nativeint ], Int) ; "caml_int64_compare", (`Pure, [ Int64; Int64 ], Int) ; "caml_string_get16", (`Mutator, [ Value; Int ], Int) + ; "caml_string_get16u", (`Mutator, [ Value; Int ], Int) ; "caml_string_get32", (`Mutator, [ Value; Int ], Int32) + ; "caml_string_get32u", (`Mutator, [ Value; Int ], Int32) ; "caml_string_get64", (`Mutator, [ Value; Int ], Int64) + ; "caml_string_get64u", (`Mutator, [ Value; Int ], Int64) ; "caml_bytes_get16", (`Mutator, [ Value; Int ], Int) + ; "caml_bytes_get16u", (`Mutator, [ Value; Int ], Int) ; "caml_bytes_get32", (`Mutator, [ Value; Int ], Int32) + ; "caml_bytes_get32u", (`Mutator, [ Value; Int ], Int32) ; "caml_bytes_get64", (`Mutator, [ Value; Int ], Int64) + ; "caml_bytes_get64u", (`Mutator, [ Value; Int ], Int64) ; "caml_bytes_set16", (`Mutator, [ Value; Int; Int ], Value) + ; "caml_bytes_set16u", (`Mutator, [ Value; Int; Int ], Value) ; "caml_bytes_set32", (`Mutator, [ Value; Int; Int32 ], Value) + ; "caml_bytes_set32u", (`Mutator, [ Value; Int; Int32 ], Value) ; "caml_bytes_set64", (`Mutator, [ Value; Int; Int64 ], Value) + ; "caml_bytes_set64u", (`Mutator, [ Value; Int; Int64 ], Value) ; "caml_lxm_next", (`Mutable, [ Value ], Int64) ; "caml_ba_uint8_get16", (`Mutator, [ Value; Int ], Int) + ; "caml_ba_uint8_get16u", (`Mutator, [ Value; Int ], Int) ; "caml_ba_uint8_get32", (`Mutator, [ Value; Int ], Int32) + ; "caml_ba_uint8_get32u", (`Mutator, [ Value; Int ], Int32) ; "caml_ba_uint8_get64", (`Mutator, [ Value; Int ], Int64) + ; "caml_ba_uint8_get64u", (`Mutator, [ Value; Int ], Int64) ; "caml_ba_uint8_set16", (`Mutator, [ Value; Int; Int ], Value) + ; "caml_ba_uint8_set16u", (`Mutator, [ Value; Int; Int ], Value) ; "caml_ba_uint8_set32", (`Mutator, [ Value; Int; Int32 ], Value) + ; "caml_ba_uint8_set32u", (`Mutator, [ Value; Int; Int32 ], Value) ; "caml_ba_uint8_set64", (`Mutator, [ Value; Int; Int64 ], Value) + ; "caml_ba_uint8_set64u", (`Mutator, [ Value; Int; Int64 ], Value) ; "caml_nextafter_float", (`Pure, [ Float; Float ], Float) ; "caml_classify_float", (`Pure, [ Float ], Value) ; "caml_ldexp_float", (`Pure, [ Float; Int ], Float) diff --git a/compiler/lib/parse_bytecode.ml b/compiler/lib/parse_bytecode.ml index 5125daa2c9..75f53c8102 100644 --- a/compiler/lib/parse_bytecode.ml +++ b/compiler/lib/parse_bytecode.ml @@ -1971,7 +1971,23 @@ and compile infos pc state (instrs : instr list) = let y = State.accu state in let z = State.peek 0 state in let x, state = State.fresh_var state in - + let prim = + match prim with + | "caml_ba_uint8_get16" + | "caml_ba_uint8_get32" + | "caml_ba_uint8_get64" + | "caml_string_get16" + | "caml_string_get32" + | "caml_string_get64" + | "caml_bytes_get16" + | "caml_bytes_get32" + | "caml_bytes_get64" -> + let hints = Hints.find infos.hints pc in + if List.mem ~eq:Hints.equal Hints.Hint_unsafe hints + then prim ^ "u" + else prim + | _ -> prim + in if debug_parser () then Format.printf @@ -1994,7 +2010,20 @@ and compile infos pc state (instrs : instr list) = let z = State.peek 0 state in let t = State.peek 1 state in let x, state = State.fresh_var state in - + let prim = + match prim with + | "caml_ba_uint8_set16" + | "caml_ba_uint8_set32" + | "caml_ba_uint8_set64" + | "caml_bytes_set16" + | "caml_bytes_set32" + | "caml_bytes_set64" -> + let hints = Hints.find infos.hints pc in + if List.mem ~eq:Hints.equal Hints.Hint_unsafe hints + then prim ^ "u" + else prim + | _ -> prim + in if debug_parser () then Format.printf diff --git a/compiler/tests-full/stdlib.cma.expected.js b/compiler/tests-full/stdlib.cma.expected.js index d591948c07..6116504e03 100644 --- a/compiler/tests-full/stdlib.cma.expected.js +++ b/compiler/tests-full/stdlib.cma.expected.js @@ -4817,11 +4817,13 @@ caml_bswap16 = runtime.caml_bswap16, caml_bytes_get = runtime.caml_bytes_get, caml_bytes_get16 = runtime.caml_bytes_get16, + caml_bytes_get16u = runtime.caml_bytes_get16u, caml_bytes_get32 = runtime.caml_bytes_get32, caml_bytes_get64 = runtime.caml_bytes_get64, caml_bytes_of_string = runtime.caml_bytes_of_string, caml_bytes_set = runtime.caml_bytes_set, caml_bytes_set16 = runtime.caml_bytes_set16, + caml_bytes_set16u = runtime.caml_bytes_set16u, caml_bytes_set32 = runtime.caml_bytes_set32, caml_bytes_set64 = runtime.caml_bytes_set64, caml_bytes_unsafe_get = runtime.caml_bytes_unsafe_get, @@ -5633,14 +5635,14 @@ function unsafe_get_uint16_le(b, i){ /*<>*/ return Stdlib_Sys[11] ? /*<>*/ caml_bswap16 - ( /*<>*/ caml_bytes_get16(b, i)) - : /*<>*/ caml_bytes_get16(b, i) /*<>*/ ; + ( /*<>*/ caml_bytes_get16u(b, i)) + : /*<>*/ caml_bytes_get16u(b, i) /*<>*/ ; } function unsafe_get_uint16_be(b, i){ /*<>*/ return Stdlib_Sys[11] - ? /*<>*/ caml_bytes_get16(b, i) + ? /*<>*/ caml_bytes_get16u(b, i) : /*<>*/ caml_bswap16 - ( /*<>*/ caml_bytes_get16(b, i)) /*<>*/ ; + ( /*<>*/ caml_bytes_get16u(b, i)) /*<>*/ ; } function get_int8(b, i){ var @@ -5704,17 +5706,17 @@ } function unsafe_set_uint16_le(b, i, x){ /*<>*/ if(Stdlib_Sys[11]){ - /*<>*/ caml_bytes_set16(b, i, caml_bswap16(x)); + /*<>*/ caml_bytes_set16u(b, i, caml_bswap16(x)); /*<>*/ return; } - /*<>*/ caml_bytes_set16(b, i, x); + /*<>*/ caml_bytes_set16u(b, i, x); /*<>*/ } function unsafe_set_uint16_be(b, i, x){ /*<>*/ if(Stdlib_Sys[11]){ - /*<>*/ caml_bytes_set16(b, i, x); + /*<>*/ caml_bytes_set16u(b, i, x); /*<>*/ return; } - /*<>*/ caml_bytes_set16(b, i, caml_bswap16(x)); + /*<>*/ caml_bytes_set16u(b, i, caml_bswap16(x)); /*<>*/ } function set_int16_le(b, i, x){ /*<>*/ return Stdlib_Sys[11] @@ -12486,9 +12488,6 @@ caml_bswap16 = runtime.caml_bswap16, caml_bytes_get = runtime.caml_bytes_get, caml_bytes_set = runtime.caml_bytes_set, - caml_bytes_set16 = runtime.caml_bytes_set16, - caml_bytes_set32 = runtime.caml_bytes_set32, - caml_bytes_set64 = runtime.caml_bytes_set64, caml_bytes_unsafe_set = runtime.caml_bytes_unsafe_set, caml_create_bytes = runtime.caml_create_bytes, caml_int32_bswap = runtime.caml_int32_bswap, @@ -12982,10 +12981,10 @@ new_position = /*<>*/ position + 2 | 0; /*<>*/ if(length < new_position){ /*<>*/ resize(b, 2); - /*<>*/ caml_bytes_set16(b[1][1], b[2], x); + /*<>*/ runtime.caml_bytes_set16(b[1][1], b[2], x); } else - /*<>*/ caml_bytes_set16(buffer, position, x); + /*<>*/ runtime.caml_bytes_set16u(buffer, position, x); /*<>*/ b[2] = new_position; return 0; /*<>*/ } @@ -12998,10 +12997,10 @@ new_position = /*<>*/ position + 4 | 0; /*<>*/ if(length < new_position){ /*<>*/ resize(b, 4); - /*<>*/ caml_bytes_set32(b[1][1], b[2], x); + /*<>*/ runtime.caml_bytes_set32(b[1][1], b[2], x); } else - /*<>*/ caml_bytes_set32(buffer, position, x); + /*<>*/ runtime.caml_bytes_set32u(buffer, position, x); /*<>*/ b[2] = new_position; return 0; /*<>*/ } @@ -13014,10 +13013,10 @@ new_position = /*<>*/ position + 8 | 0; /*<>*/ if(length < new_position){ /*<>*/ resize(b, 8); - /*<>*/ caml_bytes_set64(b[1][1], b[2], x); + /*<>*/ runtime.caml_bytes_set64(b[1][1], b[2], x); } else - /*<>*/ caml_bytes_set64(buffer, position, x); + /*<>*/ runtime.caml_bytes_set64u(buffer, position, x); /*<>*/ b[2] = new_position; return 0; /*<>*/ } diff --git a/runtime/js/bigarray.js b/runtime/js/bigarray.js index 16a479a331..8846261e54 100644 --- a/runtime/js/bigarray.js +++ b/runtime/js/bigarray.js @@ -548,6 +548,14 @@ function caml_ba_get_generic(ba, i) { return ba.get(ofs); } + +//Provides: caml_ba_uint8_get16u +function caml_ba_uint8_get16u(ba, i0) { + var ofs = ba.offset(i0); + var b1 = ba.get(ofs); + var b2 = ba.get(ofs + 1); + return b1 | (b2 << 8); +} //Provides: caml_ba_uint8_get16 //Requires: caml_array_bound_error function caml_ba_uint8_get16(ba, i0) { @@ -558,6 +566,16 @@ function caml_ba_uint8_get16(ba, i0) { return b1 | (b2 << 8); } +//Provides: caml_ba_uint8_get32u +function caml_ba_uint8_get32u(ba, i0) { + var ofs = ba.offset(i0); + var b1 = ba.get(ofs + 0); + var b2 = ba.get(ofs + 1); + var b3 = ba.get(ofs + 2); + var b4 = ba.get(ofs + 3); + return (b1 << 0) | (b2 << 8) | (b3 << 16) | (b4 << 24); +} + //Provides: caml_ba_uint8_get32 //Requires: caml_array_bound_error function caml_ba_uint8_get32(ba, i0) { @@ -570,6 +588,21 @@ function caml_ba_uint8_get32(ba, i0) { return (b1 << 0) | (b2 << 8) | (b3 << 16) | (b4 << 24); } +//Provides: caml_ba_uint8_get64u +//Requires: caml_int64_of_bytes +function caml_ba_uint8_get64u(ba, i0) { + var ofs = ba.offset(i0); + var b1 = ba.get(ofs + 0); + var b2 = ba.get(ofs + 1); + var b3 = ba.get(ofs + 2); + var b4 = ba.get(ofs + 3); + var b5 = ba.get(ofs + 4); + var b6 = ba.get(ofs + 5); + var b7 = ba.get(ofs + 6); + var b8 = ba.get(ofs + 7); + return caml_int64_of_bytes([b8, b7, b6, b5, b4, b3, b2, b1]); +} + //Provides: caml_ba_uint8_get64 //Requires: caml_array_bound_error, caml_int64_of_bytes function caml_ba_uint8_get64(ba, i0) { @@ -608,6 +641,14 @@ function caml_ba_set_generic(ba, i, v) { return 0; } +//Provides: caml_ba_uint8_set16u +function caml_ba_uint8_set16u(ba, i0, v) { + var ofs = ba.offset(i0); + ba.set(ofs + 0, v & 0xff); + ba.set(ofs + 1, (v >>> 8) & 0xff); + return 0; +} + //Provides: caml_ba_uint8_set16 //Requires: caml_array_bound_error function caml_ba_uint8_set16(ba, i0, v) { @@ -618,6 +659,15 @@ function caml_ba_uint8_set16(ba, i0, v) { return 0; } +//Provides: caml_ba_uint8_set32u +function caml_ba_uint8_set32u(ba, i0, v) { + var ofs = ba.offset(i0); + ba.set(ofs + 0, v & 0xff); + ba.set(ofs + 1, (v >>> 8) & 0xff); + ba.set(ofs + 2, (v >>> 16) & 0xff); + ba.set(ofs + 3, (v >>> 24) & 0xff); + return 0; +} //Provides: caml_ba_uint8_set32 //Requires: caml_array_bound_error function caml_ba_uint8_set32(ba, i0, v) { @@ -630,6 +680,15 @@ function caml_ba_uint8_set32(ba, i0, v) { return 0; } +//Provides: caml_ba_uint8_set64u +//Requires: caml_int64_to_bytes +function caml_ba_uint8_set64u(ba, i0, v) { + var ofs = ba.offset(i0); + var v = caml_int64_to_bytes(v); + for (var i = 0; i < 8; i++) ba.set(ofs + i, v[7 - i]); + return 0; +} + //Provides: caml_ba_uint8_set64 //Requires: caml_array_bound_error, caml_int64_to_bytes function caml_ba_uint8_set64(ba, i0, v) { diff --git a/runtime/js/mlBytes.js b/runtime/js/mlBytes.js index 6e724f0ff9..4f12bb8b65 100644 --- a/runtime/js/mlBytes.js +++ b/runtime/js/mlBytes.js @@ -142,29 +142,50 @@ function caml_string_get(s, i) { } //Provides: caml_string_get16 -//Requires: caml_string_unsafe_get, caml_string_bound_error +//Requires: caml_string_bound_error //Requires: caml_ml_string_length +//Requires: caml_string_get16u function caml_string_get16(s, i) { if (i >>> 0 >= caml_ml_string_length(s) - 1) caml_string_bound_error(); + return caml_string_get16u(s,i); +} + +//Provides: caml_string_get16u +//Requires: caml_string_unsafe_get +function caml_string_get16u(s, i) { var b1 = caml_string_unsafe_get(s, i), b2 = caml_string_unsafe_get(s, i + 1); return (b2 << 8) | b1; } //Provides: caml_bytes_get16 -//Requires: caml_bytes_unsafe_get, caml_bytes_bound_error +//Requires: caml_bytes_bound_error +//Requires: caml_bytes_get16u function caml_bytes_get16(s, i) { if (i >>> 0 >= s.l - 1) caml_bytes_bound_error(); + return caml_bytes_get16u(s,i) +} + +//Provides: caml_bytes_get16u +//Requires: caml_bytes_unsafe_get +function caml_bytes_get16u(s, i) { var b1 = caml_bytes_unsafe_get(s, i), b2 = caml_bytes_unsafe_get(s, i + 1); return (b2 << 8) | b1; } //Provides: caml_string_get32 -//Requires: caml_string_unsafe_get, caml_string_bound_error +//Requires: caml_string_bound_error //Requires: caml_ml_string_length +//Requires: caml_string_get32u function caml_string_get32(s, i) { if (i >>> 0 >= caml_ml_string_length(s) - 3) caml_string_bound_error(); + return caml_string_get32u(s,i); +} + +//Provides: caml_string_get32u +//Requires: caml_string_unsafe_get +function caml_string_get32u(s, i) { var b1 = caml_string_unsafe_get(s, i), b2 = caml_string_unsafe_get(s, i + 1), b3 = caml_string_unsafe_get(s, i + 2), @@ -173,9 +194,16 @@ function caml_string_get32(s, i) { } //Provides: caml_bytes_get32 -//Requires: caml_bytes_unsafe_get, caml_bytes_bound_error +//Requires: caml_bytes_bound_error +//Requires: caml_bytes_get32u function caml_bytes_get32(s, i) { if (i >>> 0 >= s.l - 3) caml_bytes_bound_error(); + return caml_bytes_get32u(s,i) +} + +//Provides: caml_bytes_get32u +//Requires: caml_bytes_unsafe_get +function caml_bytes_get32u(s, i) { var b1 = caml_bytes_unsafe_get(s, i), b2 = caml_bytes_unsafe_get(s, i + 1), b3 = caml_bytes_unsafe_get(s, i + 2), @@ -184,11 +212,18 @@ function caml_bytes_get32(s, i) { } //Provides: caml_string_get64 -//Requires: caml_string_unsafe_get, caml_string_bound_error -//Requires: caml_int64_of_bytes +//Requires: caml_string_bound_error //Requires: caml_ml_string_length +//Requires: caml_string_get64u function caml_string_get64(s, i) { if (i >>> 0 >= caml_ml_string_length(s) - 7) caml_string_bound_error(); + return caml_string_get64u(s,i); +} + +//Provides: caml_string_get64u +//Requires: caml_string_unsafe_get +//Requires: caml_int64_of_bytes +function caml_string_get64u(s, i) { var a = new Array(8); for (var j = 0; j < 8; j++) { a[7 - j] = caml_string_unsafe_get(s, i + j); @@ -197,10 +232,17 @@ function caml_string_get64(s, i) { } //Provides: caml_bytes_get64 -//Requires: caml_bytes_unsafe_get, caml_bytes_bound_error -//Requires: caml_int64_of_bytes +//Requires: caml_bytes_bound_error +//Requires: caml_bytes_get64u function caml_bytes_get64(s, i) { if (i >>> 0 >= s.l - 7) caml_bytes_bound_error(); + return caml_bytes_get64u(s,i) +} + +//Provides: caml_bytes_get64u +//Requires: caml_bytes_unsafe_get +//Requires: caml_int64_of_bytes +function caml_bytes_get64u(s, i) { var a = new Array(8); for (var j = 0; j < 8; j++) { a[7 - j] = caml_bytes_unsafe_get(s, i + j); @@ -231,9 +273,16 @@ function caml_string_set(s, i, c) { } //Provides: caml_bytes_set16 -//Requires: caml_bytes_bound_error, caml_bytes_unsafe_set +//Requires: caml_bytes_bound_error +//Requires: caml_bytes_set16u function caml_bytes_set16(s, i, i16) { if (i >>> 0 >= s.l - 1) caml_bytes_bound_error(); + return caml_bytes_set16u(s,i,i16); +} + +//Provides: caml_bytes_set16u +//Requires: caml_bytes_unsafe_set +function caml_bytes_set16u(s, i, i16) { var b2 = 0xff & (i16 >> 8), b1 = 0xff & i16; caml_bytes_unsafe_set(s, i + 0, b1); @@ -242,9 +291,16 @@ function caml_bytes_set16(s, i, i16) { } //Provides: caml_bytes_set32 -//Requires: caml_bytes_bound_error, caml_bytes_unsafe_set +//Requires: caml_bytes_bound_error +//Requires: caml_bytes_set32u function caml_bytes_set32(s, i, i32) { if (i >>> 0 >= s.l - 3) caml_bytes_bound_error(); + return caml_bytes_set32u(s,i,i32); +} + +//Provides: caml_bytes_set32u +//Requires: caml_bytes_unsafe_set +function caml_bytes_set32u(s, i, i32) { var b4 = 0xff & (i32 >> 24), b3 = 0xff & (i32 >> 16), b2 = 0xff & (i32 >> 8), @@ -257,10 +313,17 @@ function caml_bytes_set32(s, i, i32) { } //Provides: caml_bytes_set64 -//Requires: caml_bytes_bound_error, caml_bytes_unsafe_set -//Requires: caml_int64_to_bytes +//Requires: caml_bytes_bound_error +//Requires: caml_bytes_set64u function caml_bytes_set64(s, i, i64) { if (i >>> 0 >= s.l - 7) caml_bytes_bound_error(); + return caml_bytes_set64u(s,i,i64); +} + +//Provides: caml_bytes_set64u +//Requires: caml_bytes_unsafe_set +//Requires: caml_int64_to_bytes +function caml_bytes_set64u(s, i, i64) { var a = caml_int64_to_bytes(i64); for (var j = 0; j < 8; j++) { caml_bytes_unsafe_set(s, i + 7 - j, a[j]); diff --git a/runtime/wasm/bigarray.wat b/runtime/wasm/bigarray.wat index 0fe421874e..5564646cf4 100644 --- a/runtime/wasm/bigarray.wat +++ b/runtime/wasm/bigarray.wat @@ -2032,6 +2032,15 @@ (call $dv_get_ui16_unaligned (local.get $view) (local.get $i) (i32.const 1))) + (func (export "caml_ba_uint8_get16u") + (param $vba (ref eq)) (param $i i32) (result i32) + (local $ba (ref $bigarray)) + (local $view (ref extern)) + (local.set $ba (ref.cast (ref $bigarray) (local.get $vba))) + (local.set $view (struct.get $bigarray $ba_view (local.get $ba))) + (return_call $dv_get_ui16_unaligned + (local.get $view) (local.get $i) (i32.const 1))) + (func (export "caml_ba_uint8_get32") (param $vba (ref eq)) (param $i i32) (result i32) (local $ba (ref $bigarray)) @@ -2048,6 +2057,15 @@ (return_call $dv_get_i32_unaligned (local.get $view) (local.get $i) (i32.const 1))) + (func (export "caml_ba_uint8_get32u") + (param $vba (ref eq)) (param $i i32) (result i32) + (local $ba (ref $bigarray)) + (local $view (ref extern)) + (local.set $ba (ref.cast (ref $bigarray) (local.get $vba))) + (local.set $view (struct.get $bigarray $ba_view (local.get $ba))) + (return_call $dv_get_i32_unaligned + (local.get $view) (local.get $i) (i32.const 1))) + (func (export "caml_ba_uint8_get64") (param $vba (ref eq)) (param $i i32) (result i64) (local $ba (ref $bigarray)) @@ -2064,6 +2082,15 @@ (call $dv_get_i64_unaligned (local.get $view) (local.get $i) (i32.const 1))) + (func (export "caml_ba_uint8_get64u") + (param $vba (ref eq)) (param $i i32) (result i64) + (local $ba (ref $bigarray)) + (local $view (ref extern)) + (local.set $ba (ref.cast (ref $bigarray) (local.get $vba))) + (local.set $view (struct.get $bigarray $ba_view (local.get $ba))) + (call $dv_get_i64_unaligned + (local.get $view) (local.get $i) (i32.const 1))) + (func (export "caml_ba_uint8_set16") (param $vba (ref eq)) (param $i i32) (param $d i32) (result (ref eq)) @@ -2082,6 +2109,17 @@ (local.get $view) (local.get $i) (local.get $d) (i32.const 1)) (ref.i31 (i32.const 0))) + (func (export "caml_ba_uint8_set16u") + (param $vba (ref eq)) (param $i i32) (param $d i32) + (result (ref eq)) + (local $ba (ref $bigarray)) + (local $view (ref extern)) + (local.set $ba (ref.cast (ref $bigarray) (local.get $vba))) + (local.set $view (struct.get $bigarray $ba_view (local.get $ba))) + (call $dv_set_i16_unaligned + (local.get $view) (local.get $i) (local.get $d) (i32.const 1)) + (ref.i31 (i32.const 0))) + (func (export "caml_ba_uint8_set32") (param $vba (ref eq)) (param $i i32) (param $d i32) (result (ref eq)) @@ -2100,6 +2138,17 @@ (local.get $view) (local.get $i) (local.get $d) (i32.const 1)) (ref.i31 (i32.const 0))) + (func (export "caml_ba_uint8_set32u") + (param $vba (ref eq)) (param $i i32) (param $d i32) + (result (ref eq)) + (local $ba (ref $bigarray)) + (local $view (ref extern)) + (local.set $ba (ref.cast (ref $bigarray) (local.get $vba))) + (local.set $view (struct.get $bigarray $ba_view (local.get $ba))) + (call $dv_set_i32_unaligned + (local.get $view) (local.get $i) (local.get $d) (i32.const 1)) + (ref.i31 (i32.const 0))) + (func (export "caml_ba_uint8_set64") (param $vba (ref eq)) (param $i i32) (param $d i64) (result (ref eq)) @@ -2118,6 +2167,17 @@ (local.get $view) (local.get $i) (local.get $d) (i32.const 1)) (ref.i31 (i32.const 0))) + (func (export "caml_ba_uint8_set64u") + (param $vba (ref eq)) (param $i i32) (param $d i64) + (result (ref eq)) + (local $ba (ref $bigarray)) + (local $view (ref extern)) + (local.set $ba (ref.cast (ref $bigarray) (local.get $vba))) + (local.set $view (struct.get $bigarray $ba_view (local.get $ba))) + (call $dv_set_i64_unaligned + (local.get $view) (local.get $i) (local.get $d) (i32.const 1)) + (ref.i31 (i32.const 0))) + (export "caml_bytes_of_uint8_array" (func $caml_string_of_uint8_array)) (func $caml_string_of_uint8_array (export "caml_string_of_uint8_array") (param (ref eq)) (result (ref eq)) diff --git a/runtime/wasm/string.wat b/runtime/wasm/string.wat index b594de1206..b7319758a1 100644 --- a/runtime/wasm/string.wat +++ b/runtime/wasm/string.wat @@ -168,6 +168,17 @@ (i32.add (local.get $p) (i32.const 1))) (i32.const 8)))) + (export "caml_string_get16u" (func $caml_bytes_get16u)) + (func $caml_bytes_get16u (export "caml_bytes_get16u") + (param $v (ref eq)) (param $p i32) (result i32) + (local $s (ref $bytes)) + (local.set $s (ref.cast (ref $bytes) (local.get $v))) + (i32.or + (array.get_u $bytes (local.get $s) (local.get $p)) + (i32.shl (array.get_u $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 1))) + (i32.const 8)))) + (export "caml_string_get32" (func $caml_bytes_get32)) (func $caml_bytes_get32 (export "caml_bytes_get32") (param $v (ref eq)) (param $p i32) (result i32) @@ -192,6 +203,25 @@ (i32.add (local.get $p) (i32.const 3))) (i32.const 24))))) + (export "caml_string_get32u" (func $caml_bytes_get32u)) + (func $caml_bytes_get32u (export "caml_bytes_get32u") + (param $v (ref eq)) (param $p i32) (result i32) + (local $s (ref $bytes)) + (local.set $s (ref.cast (ref $bytes) (local.get $v))) + (i32.or + (i32.or + (array.get_u $bytes (local.get $s) (local.get $p)) + (i32.shl (array.get_u $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 1))) + (i32.const 8))) + (i32.or + (i32.shl (array.get_u $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 2))) + (i32.const 16)) + (i32.shl (array.get_u $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 3))) + (i32.const 24))))) + (export "caml_string_get64" (func $caml_bytes_get64)) (func $caml_bytes_get64 (export "caml_bytes_get64") (param $v (ref eq)) (param $p i32) (result i64) @@ -240,6 +270,49 @@ (i32.add (local.get $p) (i32.const 7)))) (i64.const 56)))))) + (export "caml_string_get64u" (func $caml_bytes_get64u)) + (func $caml_bytes_get64u (export "caml_bytes_get64u") + (param $v (ref eq)) (param $p i32) (result i64) + (local $s (ref $bytes)) + (local.set $s (ref.cast (ref $bytes) (local.get $v))) + (i64.or + (i64.or + (i64.or + (i64.extend_i32_u + (array.get_u $bytes (local.get $s) (local.get $p))) + (i64.shl (i64.extend_i32_u + (array.get_u $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 1)))) + (i64.const 8))) + (i64.or + (i64.shl (i64.extend_i32_u + (array.get_u $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 2)))) + (i64.const 16)) + (i64.shl (i64.extend_i32_u + (array.get_u $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 3)))) + (i64.const 24)))) + (i64.or + (i64.or + (i64.shl (i64.extend_i32_u + (array.get_u $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 4)))) + (i64.const 32)) + (i64.shl (i64.extend_i32_u + (array.get_u $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 5)))) + (i64.const 40))) + (i64.or + (i64.shl (i64.extend_i32_u + (array.get_u $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 6)))) + (i64.const 48)) + (i64.shl (i64.extend_i32_u + (array.get_u $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 7)))) + (i64.const 56)))))) + (func (export "caml_bytes_set16") (param (ref eq)) (param $p i32) (param $v i32) (result (ref eq)) (local $s (ref $bytes)) @@ -255,6 +328,16 @@ (i32.shr_u (local.get $v) (i32.const 8))) (ref.i31 (i32.const 0))) + (func (export "caml_bytes_set16u") + (param (ref eq)) (param $p i32) (param $v i32) (result (ref eq)) + (local $s (ref $bytes)) + (local.set $s (ref.cast (ref $bytes) (local.get 0))) + (array.set $bytes (local.get $s) (local.get $p) (local.get $v)) + (array.set $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 1)) + (i32.shr_u (local.get $v) (i32.const 8))) + (ref.i31 (i32.const 0))) + (func (export "caml_bytes_set32") (param (ref eq)) (param $p i32) (param $v i32) (result (ref eq)) (local $s (ref $bytes)) @@ -276,6 +359,22 @@ (i32.shr_u (local.get $v) (i32.const 24))) (ref.i31 (i32.const 0))) + (func (export "caml_bytes_set32u") + (param (ref eq)) (param $p i32) (param $v i32) (result (ref eq)) + (local $s (ref $bytes)) + (local.set $s (ref.cast (ref $bytes) (local.get 0))) + (array.set $bytes (local.get $s) (local.get $p) (local.get $v)) + (array.set $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 1)) + (i32.shr_u (local.get $v) (i32.const 8))) + (array.set $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 2)) + (i32.shr_u (local.get $v) (i32.const 16))) + (array.set $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 3)) + (i32.shr_u (local.get $v) (i32.const 24))) + (ref.i31 (i32.const 0))) + (func (export "caml_bytes_set64") (param (ref eq)) (param $p i32) (param $v i64) (result (ref eq)) (local $s (ref $bytes)) @@ -310,6 +409,35 @@ (i32.wrap_i64 (i64.shr_u (local.get $v) (i64.const 56)))) (ref.i31 (i32.const 0))) + (func (export "caml_bytes_set64u") + (param (ref eq)) (param $p i32) (param $v i64) (result (ref eq)) + (local $s (ref $bytes)) + (local.set $s (ref.cast (ref $bytes) (local.get 0))) + (array.set $bytes (local.get $s) (local.get $p) + (i32.wrap_i64 (local.get $v))) + (array.set $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 1)) + (i32.wrap_i64 (i64.shr_u (local.get $v) (i64.const 8)))) + (array.set $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 2)) + (i32.wrap_i64 (i64.shr_u (local.get $v) (i64.const 16)))) + (array.set $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 3)) + (i32.wrap_i64 (i64.shr_u (local.get $v) (i64.const 24)))) + (array.set $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 4)) + (i32.wrap_i64 (i64.shr_u (local.get $v) (i64.const 32)))) + (array.set $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 5)) + (i32.wrap_i64 (i64.shr_u (local.get $v) (i64.const 40)))) + (array.set $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 6)) + (i32.wrap_i64 (i64.shr_u (local.get $v) (i64.const 48)))) + (array.set $bytes (local.get $s) + (i32.add (local.get $p) (i32.const 7)) + (i32.wrap_i64 (i64.shr_u (local.get $v) (i64.const 56)))) + (ref.i31 (i32.const 0))) + (func (export "caml_string_concat") (param $vs1 (ref eq)) (param $vs2 (ref eq)) (result (ref eq)) (local $s1 (ref $bytes)) (local $s2 (ref $bytes)) From b872c4494e920fe485c6cf719c78467dfd147e54 Mon Sep 17 00:00:00 2001 From: Hugo Heuzard Date: Fri, 25 Oct 2024 23:24:30 +0200 Subject: [PATCH 04/14] Compiler: comsume hints for boxed int comparison --- compiler/lib/parse_bytecode.ml | 31 +++++++++++- compiler/tests-full/stdlib.cma.expected.js | 58 +++++++++------------- 2 files changed, 54 insertions(+), 35 deletions(-) diff --git a/compiler/lib/parse_bytecode.ml b/compiler/lib/parse_bytecode.ml index 75f53c8102..b98691f3b5 100644 --- a/compiler/lib/parse_bytecode.ml +++ b/compiler/lib/parse_bytecode.ml @@ -1999,11 +1999,40 @@ and compile infos pc state (instrs : instr list) = y Var.print z; + let prim, y, z = + match Config.target () with + | `Wasm -> Extern prim, y, z + | `JavaScript -> ( + match prim with + | "caml_equal" + | "caml_notequal" + | "caml_lessthan" + | "caml_greaterthan" + | "caml_lessequal" + | "caml_greaterequal" -> ( + let prim_of_ext = function + | "caml_equal" -> Eq, y, z + | "caml_notequal" -> Neq, y, z + | "caml_lessthan" -> Lt, y, z + | "caml_lessequal" -> Le, y, z + | "caml_greaterequal" -> Le, z, y + | "caml_greaterthan" -> Lt, z, y + | _ -> assert false + in + match Hints.find infos.hints pc with + | [ Hints.Hint_int boxed ] -> ( + match boxed with + | Pnativeint -> prim_of_ext prim + | Pint32 -> prim_of_ext prim + | Pint64 -> Extern prim, y, z) + | _ -> Extern prim, y, z) + | _ -> Extern prim, y, z) + in compile infos (pc + 2) (State.pop 1 state) - (Let (x, Prim (Extern prim, [ Pv y; Pv z ])) :: instrs) + (Let (x, Prim (prim, [ Pv y; Pv z ])) :: instrs) | C_CALL3 -> let prim = primitive_name state (getu code (pc + 1)) in let y = State.accu state in diff --git a/compiler/tests-full/stdlib.cma.expected.js b/compiler/tests-full/stdlib.cma.expected.js index 6116504e03..ce7a726d19 100644 --- a/compiler/tests-full/stdlib.cma.expected.js +++ b/compiler/tests-full/stdlib.cma.expected.js @@ -9115,11 +9115,8 @@ "use strict"; var runtime = globalThis.jsoo_runtime, - caml_greaterequal = runtime.caml_greaterequal, caml_hash = runtime.caml_hash, caml_int_compare = runtime.caml_int_compare, - caml_lessequal = runtime.caml_lessequal, - caml_lessthan = runtime.caml_lessthan, caml_maybe_attach_backtrace = runtime.caml_maybe_attach_backtrace, caml_mul = runtime.caml_mul, caml_wrap_exception = runtime.caml_wrap_exception, @@ -9132,7 +9129,7 @@ function succ(n){ /*<>*/ return n + 1 | 0;} function pred(n){ /*<>*/ return n - 1 | 0;} function abs(n){ - /*<>*/ return caml_greaterequal(n, 0) ? n : - n | 0 /*<>*/ ; + /*<>*/ return 0 <= n ? n : - n | 0 /*<>*/ ; } function lognot(n){ /*<>*/ return n ^ -1;} var @@ -9146,9 +9143,7 @@ max_int$0 = /*<>*/ Stdlib[19], unsigned_to_int = /*<>*/ function(n){ - /*<>*/ if - (caml_greaterequal(n, 0) - && /*<>*/ caml_lessequal(n, max_int$0)) + /*<>*/ if(0 <= n && n <= max_int$0) /*<>*/ return [0, n]; /*<>*/ return 0; /*<>*/ }; @@ -9176,7 +9171,8 @@ /*<>*/ throw caml_maybe_attach_backtrace(exn, 0); } /*<>*/ } - var compare = /*<>*/ caml_int_compare, equal = runtime.caml_equal; + var compare = /*<>*/ caml_int_compare; + function equal(x, y){ /*<>*/ return x === y ? 1 : 0;} function unsigned_compare(n, m){ var y = /*<>*/ m + 2147483648 | 0, @@ -9184,17 +9180,18 @@ /*<>*/ return caml_int_compare(x, y) /*<>*/ ; } function unsigned_lt(n, m){ - /*<>*/ return caml_lessthan - (n + 2147483648 | 0, m + 2147483648 | 0) /*<>*/ ; + /*<>*/ return (n + 2147483648 | 0) < (m + 2147483648 | 0) + ? 1 + : 0; } function min(x, y){ - /*<>*/ return caml_lessequal(x, y) ? x : y /*<>*/ ; + /*<>*/ return x <= y ? x : y /*<>*/ ; } function max(x, y){ - /*<>*/ return caml_greaterequal(x, y) ? x : y /*<>*/ ; + /*<>*/ return y <= x ? x : y /*<>*/ ; } function unsigned_div(n, d){ - /*<>*/ if(caml_lessthan(d, 0)) + /*<>*/ if(d < 0) /*<>*/ return unsigned_lt(n, d) ? zero : one /*<>*/ ; var q = /*<>*/ runtime.caml_div(n >>> 1 | 0, d) << 1, @@ -9400,11 +9397,8 @@ "use strict"; var runtime = globalThis.jsoo_runtime, - caml_greaterequal = runtime.caml_greaterequal, caml_hash = runtime.caml_hash, caml_int_compare = runtime.caml_int_compare, - caml_lessequal = runtime.caml_lessequal, - caml_lessthan = runtime.caml_lessthan, caml_maybe_attach_backtrace = runtime.caml_maybe_attach_backtrace, caml_mul = runtime.caml_mul, caml_wrap_exception = runtime.caml_wrap_exception, @@ -9416,7 +9410,7 @@ function succ(n){ /*<>*/ return n + 1 | 0;} function pred(n){ /*<>*/ return n - 1 | 0;} function abs(n){ - /*<>*/ return caml_greaterequal(n, 0) ? n : - n | 0 /*<>*/ ; + /*<>*/ return 0 <= n ? n : - n | 0 /*<>*/ ; } var size = /*<>*/ Stdlib_Sys[9], @@ -9425,9 +9419,7 @@ function lognot(n){ /*<>*/ return n ^ -1;} var max_int$0 = /*<>*/ Stdlib[19]; function unsigned_to_int(n){ - /*<>*/ if - (caml_greaterequal(n, 0) - && /*<>*/ caml_lessequal(n, max_int$0)) + /*<>*/ if(0 <= n && n <= max_int$0) /*<>*/ return [0, n]; /*<>*/ return 0; /*<>*/ } @@ -9456,17 +9448,18 @@ /*<>*/ return caml_int_compare(x, y) /*<>*/ ; } function unsigned_lt(n, m){ - /*<>*/ return caml_lessthan - (n - min_int | 0, m - min_int | 0) /*<>*/ ; + /*<>*/ return (n - min_int | 0) < (m - min_int | 0) + ? 1 + : 0; } function min(x, y){ - /*<>*/ return caml_lessequal(x, y) ? x : y /*<>*/ ; + /*<>*/ return x <= y ? x : y /*<>*/ ; } function max(x, y){ - /*<>*/ return caml_greaterequal(x, y) ? x : y /*<>*/ ; + /*<>*/ return y <= x ? x : y /*<>*/ ; } function unsigned_div(n, d){ - /*<>*/ if(caml_lessthan(d, 0)) + /*<>*/ if(d < 0) /*<>*/ return unsigned_lt(n, d) ? zero : one /*<>*/ ; var q = /*<>*/ runtime.caml_div(n >>> 1 | 0, d) << 1, @@ -24062,34 +24055,31 @@ var r = /*<>*/ bits32(s) >>> 1 | 0, v = /*<>*/ caml_mod(r, n); - /*<>*/ if - (! caml_greaterthan(r - v | 0, (Stdlib_Int32[9] - n | 0) + 1 | 0)) + /*<>*/ if + (((Stdlib_Int32[9] - n | 0) + 1 | 0) >= (r - v | 0)) /*<>*/ return v; } /*<>*/ } function int32(s, bound){ - /*<>*/ return caml_lessequal(bound, 0) + /*<>*/ return bound <= 0 ? /*<>*/ Stdlib[1].call(null, cst_Random_int32) : /*<>*/ int32aux(s, bound) /*<>*/ ; } function int32_in_range(s, min, max){ - /*<>*/ if(caml_greaterthan(min, max)) + /*<>*/ if(max < min) /*<>*/ return Stdlib[1].call (null, cst_Random_int32_in_range) /*<>*/ ; var span = /*<>*/ Stdlib_Int32[6].call(null, max - min | 0); - /*<>*/ if(! caml_lessequal(span, Stdlib_Int32[1])) + /*<>*/ if(span > Stdlib_Int32[1]) /*<>*/ return min + int32aux(s, span) | 0 /*<>*/ ; /*<>*/ for(;;){ var r = /*<>*/ /*<>*/ caml_int64_to_int32 ( /*<>*/ caml_lxm_next(s)); - /*<>*/ if - (! - caml_lessthan(r, min) - && ! /*<>*/ caml_greaterthan(r, max)) + /*<>*/ if(r >= min && max >= r) /*<>*/ return r; } /*<>*/ } From 8132b83e31f9eec35ca8c0f87050672e41bdfc55 Mon Sep 17 00:00:00 2001 From: Hugo Heuzard Date: Mon, 16 Jun 2025 10:31:55 +0200 Subject: [PATCH 05/14] accept --- compiler/tests-compiler/loops.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/tests-compiler/loops.ml b/compiler/tests-compiler/loops.ml index 4385668fa4..e2b0b77df7 100644 --- a/compiler/tests-compiler/loops.ml +++ b/compiler/tests-compiler/loops.ml @@ -522,7 +522,7 @@ let add_substitute = previous = 32; i$4 = next_i; } - else if(92 === previous){ + else if(previous === 92){ caml_call2(add_char, b, 92); caml_call2(add_char, b, previous$0); var i$6 = i$4 + 1 | 0; From 1685621d7af336f9116f8f601cf24d5b5e9c734a Mon Sep 17 00:00:00 2001 From: Hugo Heuzard Date: Mon, 16 Jun 2025 12:01:40 +0200 Subject: [PATCH 06/14] pin ocaml --- .github/workflows/js_of_ocaml.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/js_of_ocaml.yml b/.github/workflows/js_of_ocaml.yml index 19c8c76af1..7513c173f3 100644 --- a/.github/workflows/js_of_ocaml.yml +++ b/.github/workflows/js_of_ocaml.yml @@ -59,7 +59,8 @@ jobs: skip-doc: true - os: ubuntu-latest os-name: Ubuntu - ocaml-compiler: "5.3" + ocaml-name: "5.3.1+pr" + ocaml-compiler: "ocaml-variants.5.3.1+trunk" skip-effects: false skip-test: false skip-doc: false @@ -141,6 +142,10 @@ jobs: with: ocaml-compiler: ${{ matrix.ocaml-compiler }} + - name: patch compiler + if: matrix.ocaml-compiler == 'ocaml-variants.5.3.1+trunk' + run: opam pin ocaml-variants https://github.com/hhugo/ocaml.git#optimization-hints + # Work-around a race between reinstalling mingw-w64-shims # (because of conf-pkg-config optional dep) and installing other # packages that implicitly depend on mingw-w64-shims. From ea0562df03eaca3985a0757a8d035a2622595351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Vouillon?= Date: Fri, 18 Jul 2025 14:26:27 +0200 Subject: [PATCH 07/14] Propagate hints in intermediate code --- compiler/bin-js_of_ocaml/compile.ml | 8 +- compiler/lib-wasm/generate.ml | 68 ++++---- compiler/lib-wasm/typing.ml | 36 ++-- compiler/lib/code.ml | 29 ++-- compiler/lib/code.mli | 4 +- compiler/lib/deadcode.ml | 5 +- compiler/lib/driver.ml | 5 +- compiler/lib/effects.ml | 69 ++++---- compiler/lib/eval.ml | 43 ++--- compiler/lib/flow.ml | 14 +- compiler/lib/generate.ml | 52 +++--- compiler/lib/generate_closure.ml | 12 +- compiler/lib/global_flow.ml | 28 ++-- compiler/lib/inline.ml | 13 +- compiler/lib/optimization_hint.ml | 143 ++++++++++++++++ compiler/lib/optimization_hint.mli | 79 +++++++++ compiler/lib/parse_bytecode.ml | 241 +++++++++++++++++++-------- compiler/lib/partial_cps_analysis.ml | 4 +- compiler/lib/pseudo_fs.ml | 4 +- compiler/lib/pure_fun.ml | 2 +- compiler/lib/ref_unboxing.ml | 2 +- compiler/lib/specialize.ml | 4 +- compiler/lib/specialize_js.ml | 139 +++++++-------- 23 files changed, 689 insertions(+), 315 deletions(-) create mode 100644 compiler/lib/optimization_hint.ml create mode 100644 compiler/lib/optimization_hint.mli diff --git a/compiler/bin-js_of_ocaml/compile.ml b/compiler/bin-js_of_ocaml/compile.ml index deb995b991..f5183ce252 100644 --- a/compiler/bin-js_of_ocaml/compile.ml +++ b/compiler/bin-js_of_ocaml/compile.ml @@ -245,9 +245,11 @@ let run let var_k = Code.Var.fresh () in let var_v = Code.Var.fresh () in Code. - [ Let (var_k, Prim (Extern "caml_jsstring_of_string", [ Pc (String k) ])) - ; Let (var_v, Prim (Extern "caml_jsstring_of_string", [ Pc (String v) ])) - ; Let (Var.fresh (), Prim (Extern "caml_set_static_env", [ Pv var_k; Pv var_v ])) + [ Let (var_k, Prim (Extern ("caml_jsstring_of_string", None), [ Pc (String k) ])) + ; Let (var_v, Prim (Extern ("caml_jsstring_of_string", None), [ Pc (String v) ])) + ; Let + ( Var.fresh () + , Prim (Extern ("caml_set_static_env", None), [ Pv var_k; Pv var_v ]) ) ]) in let output diff --git a/compiler/lib-wasm/generate.ml b/compiler/lib-wasm/generate.ml index e9e11b7006..7aa959fb97 100644 --- a/compiler/lib-wasm/generate.ml +++ b/compiler/lib-wasm/generate.ml @@ -1446,12 +1446,12 @@ module Generate (Target : Target_sig.S) = struct | _ -> false) c | Special (Alias_prim _) -> assert false - | Prim (Extern "caml_alloc_dummy_function", [ _; Pc (Int arity) ]) -> + | Prim (Extern ("caml_alloc_dummy_function", _), [ _; Pc (Int arity) ]) -> (* Removed in OCaml 5.2 *) Closure.dummy ~cps:(effects_cps ()) ~arity:(Targetint.to_int_exn arity) - | Prim (Extern "caml_alloc_dummy_infix", _) -> + | Prim (Extern ("caml_alloc_dummy_infix", _), _) -> Closure.dummy ~cps:(effects_cps ()) ~arity:1 - | Prim (Extern "caml_get_global", [ Pc (String name) ]) -> + | Prim (Extern ("caml_get_global", _), [ Pc (String name) ]) -> let* x = let* context = get_context in match @@ -1469,7 +1469,7 @@ module Generate (Target : Target_sig.S) = struct register_import ~import_module:"OCaml" ~name (Global { mut = true; typ }) in return (W.GlobalGet x) - | Prim (Extern "caml_set_global", [ Pc (String name); v ]) -> + | Prim (Extern ("caml_set_global", _), [ Pc (String name); v ]) -> let v = transl_prim_arg ctx v in let x = Var.fresh_n name in let* () = @@ -1491,16 +1491,16 @@ module Generate (Target : Target_sig.S) = struct Memory.array_get (transl_prim_arg ctx x) (transl_prim_arg ctx ~typ:(Int Normalized) y) - | Prim (Extern "caml_array_unsafe_get", [ x; y ]) -> + | Prim (Extern ("caml_array_unsafe_get", _), [ x; y ]) -> Memory.gen_array_get (transl_prim_arg ctx x) (transl_prim_arg ctx ~typ:(Int Normalized) y) | Prim (p, l) -> ( match p with - | Extern name when String.Hashtbl.mem internal_primitives name -> + | Extern (name, _) when String.Hashtbl.mem internal_primitives name -> snd (String.Hashtbl.find internal_primitives name) ctx context l |> box_number_if_needed ctx x - | Extern name when String.Hashtbl.mem specialized_primitives name -> + | Extern (name, _) when String.Hashtbl.mem specialized_primitives name -> let ((_, arg_typ, _) as typ) = String.Hashtbl.find specialized_primitives name in @@ -1529,7 +1529,7 @@ module Generate (Target : Target_sig.S) = struct | _ -> ( let l = List.map ~f:(fun x -> transl_prim_arg ctx x) l in match p, l with - | Extern name, l -> + | Extern (name, _), l -> let* f = register_import ~name (Fun (Type.primitive_type (List.length l))) in @@ -1542,8 +1542,8 @@ module Generate (Target : Target_sig.S) = struct in loop [] l | IsInt, [ x ] -> Value.is_int x - | Vectlength, [ x ] -> Memory.gen_array_length x - | (Not | Lt | Le | Eq | Neq | Ult | Array_get | IsInt | Vectlength), _ -> + | Vectlength _, [ x ] -> Memory.gen_array_length x + | (Not | Lt | Le | Eq | Neq | Ult | Array_get | IsInt | Vectlength _), _ -> assert false)) and translate_instr ctx context i = @@ -1658,34 +1658,36 @@ module Generate (Target : Target_sig.S) = struct ( _ , Prim ( Extern - ( "caml_string_get" - | "caml_bytes_get" - | "caml_string_set" - | "caml_bytes_set" - | "caml_check_bound" - | "caml_check_bound_gen" - | "caml_check_bound_float" - | "caml_ba_get_1" - | "caml_ba_get_2" - | "caml_ba_get_3" - | "caml_ba_get_generic" - | "caml_ba_set_1" - | "caml_ba_set_2" - | "caml_ba_set_3" - | "caml_ba_set_generic" ) + ( ( "caml_string_get" + | "caml_bytes_get" + | "caml_string_set" + | "caml_bytes_set" + | "caml_check_bound" + | "caml_check_bound_gen" + | "caml_check_bound_float" + | "caml_ba_get_1" + | "caml_ba_get_2" + | "caml_ba_get_3" + | "caml_ba_get_generic" + | "caml_ba_set_1" + | "caml_ba_set_2" + | "caml_ba_set_3" + | "caml_ba_set_generic" ) + , _ ) , _ ) ) -> fst n, true | Let ( _ , Prim ( Extern - ( "%int_div" - | "%int_mod" - | "caml_int32_div" - | "caml_int32_mod" - | "caml_int64_div" - | "caml_int64_mod" - | "caml_nativeint_div" - | "caml_nativeint_mod" ) + ( ( "%int_div" + | "%int_mod" + | "caml_int32_div" + | "caml_int32_mod" + | "caml_int64_div" + | "caml_int64_mod" + | "caml_nativeint_div" + | "caml_nativeint_mod" ) + , _ ) , _ ) ) -> true, snd n | _ -> n) ~init:n diff --git a/compiler/lib-wasm/typing.ml b/compiler/lib-wasm/typing.ml index 8785c88dfc..0fd29abffc 100644 --- a/compiler/lib-wasm/typing.ml +++ b/compiler/lib-wasm/typing.ml @@ -244,13 +244,14 @@ let update_deps st { blocks; _ } = ( x , Prim ( Extern - ( "%int_and" - | "%int_or" - | "%int_xor" - | "caml_ba_get_1" - | "caml_ba_get_2" - | "caml_ba_get_3" - | "caml_ba_get_generic" ) + ( ( "%int_and" + | "%int_or" + | "%int_xor" + | "caml_ba_get_1" + | "caml_ba_get_2" + | "caml_ba_get_3" + | "caml_ba_get_generic" ) + , _ ) , lst ) ) -> (* The return type of these primitives depend on the input type *) List.iter @@ -521,9 +522,10 @@ let propagate st approx x : Domain.t = | Top -> Top | _ -> Bot) | Prim - ( Extern ("caml_check_bound" | "caml_check_bound_float" | "caml_check_bound_gen") + ( Extern + (("caml_check_bound" | "caml_check_bound_float" | "caml_check_bound_gen"), _) , [ Pv y; _ ] ) -> Var.Tbl.get approx y - | Prim ((Array_get | Extern "caml_array_unsafe_get"), [ Pv y; _ ]) -> ( + | Prim ((Array_get | Extern ("caml_array_unsafe_get", _)), [ Pv y; _ ]) -> ( match Var.Tbl.get st.global_flow_info.info_approximation y with | Values { known; others } -> Domain.join_set @@ -549,8 +551,9 @@ let propagate st approx x : Domain.t = known | Top -> Top) | Prim (Array_get, _) -> Top - | Prim ((Vectlength | Not | IsInt | Eq | Neq | Lt | Le | Ult), _) -> Int Normalized - | Prim (Extern prim, args) -> prim_type ~st ~approx prim args + | Prim ((Vectlength _ | Not | IsInt | Eq | Neq | Lt | Le | Ult), _) -> + Int Normalized + | Prim (Extern (prim, _), args) -> prim_type ~st ~approx prim args | Special _ -> Top | Apply { f; args; _ } -> ( match Var.Tbl.get st.global_flow_info.info_approximation f with @@ -566,8 +569,9 @@ let propagate st approx x : Domain.t = (fun y -> match st.global_flow_state.defs.(Var.idx y) with | Expr - (Prim (Extern "caml_ba_create", [ Pv kind; Pv layout; _ ])) - -> ( + (Prim + ( Extern ("caml_ba_create", _) + , [ Pv kind; Pv layout; _ ] )) -> ( let m = List.fold_left2 ~f:(fun m p a -> Var.Map.add p a m) @@ -826,7 +830,7 @@ let box_numbers p st types = | Some (g, _) -> not (can_unbox_parameters st.fun_info g) then List.iter ~f:box args | Block (tag, lst, _, _) -> if tag <> 254 then Array.iter ~f:box lst - | Prim (Extern s, args) -> + | Prim (Extern (s, _), args) -> if not (String.Hashtbl.mem primitives_with_unboxed_parameters s @@ -846,7 +850,7 @@ let box_numbers p st types = | Pv y -> box y | Pc _ -> ()) args - | Prim ((Vectlength | Array_get | Not | IsInt | Lt | Le | Ult), _) + | Prim ((Vectlength _ | Array_get | Not | IsInt | Lt | Le | Ult), _) | Field _ | Closure _ | Constant _ | Special _ -> ()) | Set_field (_, _, Non_float, y) | Array_set (_, _, y) -> box y | Assign _ | Offset_ref _ | Set_field (_, _, Float, _) | Event _ -> ()) @@ -864,7 +868,7 @@ let box_numbers p st types = let print_opt types global_flow_state f e = match e with - | Prim (Extern name, args) + | Prim (Extern (name, _), args) when type_specialized_primitive types global_flow_state name args -> Format.fprintf f " OPT" | _ -> () diff --git a/compiler/lib/code.ml b/compiler/lib/code.ml index 4399705188..e659a73196 100644 --- a/compiler/lib/code.ml +++ b/compiler/lib/code.ml @@ -286,9 +286,9 @@ end type cont = Addr.t * Var.t list type prim = - | Vectlength + | Vectlength of Optimization_hint.array_kind | Array_get - | Extern of string + | Extern of string * Optimization_hint.t option | Not | IsInt | Eq @@ -547,17 +547,23 @@ module Print = struct | "%int_neg" -> "-" | _ -> raise Not_found + let hint f h = + match h with + | None -> () + | Some h -> Format.fprintf f " [hint:%a]" Optimization_hint.print h + let prim f p l = match p, l with - | Vectlength, [ x ] -> Format.fprintf f "%a.length" arg x + | Vectlength k, [ x ] -> + Format.fprintf f "%a.length%a" arg x hint (Some (Optimization_hint.Hint_array k)) | Array_get, [ x; y ] -> Format.fprintf f "%a[%a]" arg x arg y - | Extern s, [ x; y ] -> ( - try Format.fprintf f "%a %s %a" arg x (binop s) arg y - with Not_found -> Format.fprintf f "\"%s\"(%a)" s (list arg) l) - | Extern s, [ x ] -> ( - try Format.fprintf f "%s %a" (unop s) arg x - with Not_found -> Format.fprintf f "\"%s\"(%a)" s (list arg) l) - | Extern s, _ -> Format.fprintf f "\"%s\"(%a)" s (list arg) l + | Extern (s, h), [ x; y ] -> ( + try Format.fprintf f "%a %s %a%a" arg x (binop s) arg y hint h + with Not_found -> Format.fprintf f "\"%s\"(%a)%a" s (list arg) l hint h) + | Extern (s, h), [ x ] -> ( + try Format.fprintf f "%s %a%a" (unop s) arg x hint h + with Not_found -> Format.fprintf f "\"%s\"(%a) %a" s (list arg) l hint h) + | Extern (s, h), _ -> Format.fprintf f "\"%s\"(%a) %a" s (list arg) l hint h | Not, [ x ] -> Format.fprintf f "!%a" arg x | IsInt, [ x ] -> Format.fprintf f "is_int(%a)" arg x | Eq, [ x; y ] -> Format.fprintf f "%a === %a" arg x arg y @@ -689,7 +695,8 @@ let is_empty p = match v with | { body; branch = Stop; params = _ } -> ( match body with - | ([] | [ Let (_, Prim (Extern "caml_get_global_data", _)) ]) when true -> true + | ([] | [ Let (_, Prim (Extern ("caml_get_global_data", None), _)) ]) when true + -> true | _ -> false) | _ -> false) | _ -> false diff --git a/compiler/lib/code.mli b/compiler/lib/code.mli index bc9dcab0e8..464d10d167 100644 --- a/compiler/lib/code.mli +++ b/compiler/lib/code.mli @@ -112,9 +112,9 @@ end type cont = Addr.t * Var.t list type prim = - | Vectlength + | Vectlength of Optimization_hint.array_kind | Array_get - | Extern of string + | Extern of string * Optimization_hint.t option | Not | IsInt | Eq diff --git a/compiler/lib/deadcode.ml b/compiler/lib/deadcode.ml index fe6dec7bc6..84ef49c3b8 100644 --- a/compiler/lib/deadcode.ml +++ b/compiler/lib/deadcode.ml @@ -97,7 +97,7 @@ and mark_reachable st pc = let block = Addr.Map.find pc st.blocks in List.iter block.body ~f:(fun i -> match i with - | Let (_, Prim (Extern "caml_update_dummy", [ Pv x; Pv y ])) -> + | Let (_, Prim (Extern ("caml_update_dummy", _), [ Pv x; Pv y ])) -> if st.live.(Var.idx x) = 0 then (* We will keep this instruction only if x is live *) @@ -139,7 +139,8 @@ and mark_reachable st pc = let live_instr st i = match i with - | Let (_, Prim (Extern "caml_update_dummy", [ Pv x; Pv _ ])) -> st.live.(Var.idx x) > 0 + | Let (_, Prim (Extern ("caml_update_dummy", _), [ Pv x; Pv _ ])) -> + st.live.(Var.idx x) > 0 | Let (x, e) -> st.live.(Var.idx x) > 0 || not (pure_expr st.pure_funs e) | Assign (x, _) | Set_field (x, _, _, _) -> st.live.(Var.idx x) > 0 | Event _ | Offset_ref _ | Array_set _ -> true diff --git a/compiler/lib/driver.ml b/compiler/lib/driver.ml index 6dc828042b..56290fa146 100644 --- a/compiler/lib/driver.ml +++ b/compiler/lib/driver.ml @@ -112,7 +112,7 @@ let collects_shapes ~shapes (p : Code.program) = | Code.Let ( _ , Prim - ( Extern "caml_register_global" + ( Extern ("caml_register_global", _) , [ _code; Pv block; Pc (NativeString name) ] ) ) -> let name = match name with @@ -120,7 +120,8 @@ let collects_shapes ~shapes (p : Code.program) = | Utf (Utf8 s) -> s in shapes := StringMap.add name block !shapes - | Code.Let (_, Prim (Extern "caml_set_global", [ Pc (String name); Pv block ])) + | Code.Let + (_, Prim (Extern ("caml_set_global", _), [ Pc (String name); Pv block ])) -> shapes := StringMap.add name block !shapes | _ -> ())) p.blocks; diff --git a/compiler/lib/effects.ml b/compiler/lib/effects.ml index 449216f3b1..ed2bd30c31 100644 --- a/compiler/lib/effects.ml +++ b/compiler/lib/effects.ml @@ -157,7 +157,7 @@ let empty_body b = (****) let effect_primitive_or_application = function - | Prim (Extern ("%resume" | "%perform" | "%reperform"), _) | Apply _ -> true + | Prim (Extern (("%resume" | "%perform" | "%reperform"), _), _) | Apply _ -> true | Block (_, _, _, _) | Field (_, _, _) | Closure (_, _, _) @@ -453,7 +453,7 @@ let cps_last ~st ~alloc_jump_closures pc (last : last) ~k : instr list * last = [ Let ( x' , Prim - ( Extern "caml_maybe_attach_backtrace" + ( Extern ("caml_maybe_attach_backtrace", None) , [ Pv x ; Pc (Int (if force then Targetint.one else Targetint.zero)) ] ) ) @@ -463,7 +463,8 @@ let cps_last ~st ~alloc_jump_closures pc (last : last) ~k : instr list * last = in tail_call ~st - ~instrs:(Let (exn_handler, Prim (Extern "caml_pop_trap", [])) :: instrs) + ~instrs: + (Let (exn_handler, Prim (Extern ("caml_pop_trap", None), [])) :: instrs) ~exact:true ~in_cps:false ~check:false @@ -502,7 +503,7 @@ let cps_last ~st ~alloc_jump_closures pc (last : last) ~k : instr list * last = handler_cont in let push_trap = - Let (Var.fresh (), Prim (Extern "caml_push_trap", [ Pv exn_handler ])) + Let (Var.fresh (), Prim (Extern ("caml_push_trap", None), [ Pv exn_handler ])) in let body, branch = cps_branch ~st ~src:pc body_cont in constr_cont @ (push_trap :: body), branch) @@ -515,7 +516,7 @@ let cps_last ~st ~alloc_jump_closures pc (last : last) ~k : instr list * last = let exn_handler = Var.fresh () in let body, branch = cps_branch ~st ~src:pc cont in ( alloc_jump_closures - @ (Let (exn_handler, Prim (Extern "caml_pop_trap", [])) :: body) + @ (Let (exn_handler, Prim (Extern ("caml_pop_trap", None), [])) :: body) , branch )) let rewrite_instr ~st (instr : instr) : instr = @@ -529,15 +530,15 @@ let rewrite_instr ~st (instr : instr) : instr = let cps_params, cps_cont = Addr.Hashtbl.find st.closure_info pc in st.in_cps := Var.Set.add x !(st.in_cps); Let (x, Closure (cps_params, cps_cont, None)) - | Let (x, Prim (Extern "caml_alloc_dummy_function", [ size; arity ])) -> ( + | Let (x, Prim (Extern ("caml_alloc_dummy_function", _), [ size; arity ])) -> ( (* Removed in OCaml 5.2 *) match arity with | Pc (Int a) -> Let ( x , Prim - (Extern "caml_alloc_dummy_function", [ size; Pc (Int (Targetint.succ a)) ]) - ) + ( Extern ("caml_alloc_dummy_function", None) + , [ size; Pc (Int (Targetint.succ a)) ] ) ) | _ -> assert false) | Let (x, Apply { f; args; exact }) when not (Var.Set.mem x st.cps_needed) -> if double_translate () @@ -570,7 +571,8 @@ let call_exact flow_info (f : Var.t) nargs : bool = let cps_instr ~st (instr : instr) : instr list = match instr with - | Let (x, Prim (Extern "caml_assume_no_perform", [ Pv f ])) when double_translate () -> + | Let (x, Prim (Extern ("caml_assume_no_perform", _), [ Pv f ])) + when double_translate () -> (* When double translation is enabled, we just call [f] in direct style. Otherwise, the runtime primitive is used. *) let unit = Var.fresh_n "unit" in @@ -626,10 +628,10 @@ let cps_block ~st ~k ~orig_pc block = (fun ~k -> let e = match continuation_and_tail with - | None -> Prim (Extern "caml_perform_effect", [ Pv effect_; Pv k ]) + | None -> Prim (Extern ("caml_perform_effect", None), [ Pv effect_; Pv k ]) | Some (continuation, tail) -> Prim - ( Extern "caml_reperform_effect" + ( Extern ("caml_reperform_effect", None) , [ Pv effect_; continuation; tail; Pv k ] ) in let x = Var.fresh () in @@ -641,21 +643,25 @@ let cps_block ~st ~k ~orig_pc block = (fun ~k -> let exact = exact || call_exact st.flow_info f (List.length args) in tail_call ~st ~exact ~in_cps:true ~check:true ~f (args @ [ k ])) - | Prim (Extern "%resume", [ Pv stack; Pv f; Pv arg; tail ]) -> + | Prim (Extern ("%resume", _), [ Pv stack; Pv f; Pv arg; tail ]) -> Some (fun ~k -> let k' = Var.fresh_n "cont" in tail_call ~st ~instrs: - [ Let (k', Prim (Extern "caml_resume_stack", [ Pv stack; tail; Pv k ])) ] + [ Let + ( k' + , Prim (Extern ("caml_resume_stack", None), [ Pv stack; tail; Pv k ]) + ) + ] ~exact:(call_exact st.flow_info f 1) ~in_cps:true ~check:true ~f [ arg; k' ]) - | Prim (Extern "%perform", [ Pv effect_ ]) -> perform_effect ~effect_ None - | Prim (Extern "%reperform", [ Pv effect_; continuation; tail ]) -> + | Prim (Extern ("%perform", _), [ Pv effect_ ]) -> perform_effect ~effect_ None + | Prim (Extern ("%reperform", _), [ Pv effect_; continuation; tail ]) -> perform_effect ~effect_ (Some (continuation, tail)) | _ -> None in @@ -724,17 +730,17 @@ let rewrite_direct_block ~st ~cps_needed ~closure_info ~pc block = let cps_params, cps_cont = Addr.Hashtbl.find closure_info pc in [ Let (direct_c, Closure (params, cont, cloc)) ; Let (cps_c, Closure (cps_params, cps_cont, None)) - ; Let (x, Prim (Extern "caml_cps_closure", [ Pv direct_c; Pv cps_c ])) + ; Let (x, Prim (Extern ("caml_cps_closure", None), [ Pv direct_c; Pv cps_c ])) ] - | Let (x, Prim (Extern "%resume", [ stack; f; arg; tail ])) -> - [ Let (x, Prim (Extern "caml_resume", [ f; arg; stack; tail ])) ] - | Let (x, Prim (Extern "%perform", [ effect_ ])) -> + | Let (x, Prim (Extern ("%resume", _), [ stack; f; arg; tail ])) -> + [ Let (x, Prim (Extern ("caml_resume", None), [ f; arg; stack; tail ])) ] + | Let (x, Prim (Extern ("%perform", _), [ effect_ ])) -> (* In direct-style code, we just raise [Effect.Unhandled]. *) - [ Let (x, Prim (Extern "caml_raise_unhandled", [ effect_ ])) ] - | Let (x, Prim (Extern "%reperform", [ effect_; _continuation; _tail ])) -> + [ Let (x, Prim (Extern ("caml_raise_unhandled", None), [ effect_ ])) ] + | Let (x, Prim (Extern ("%reperform", _), [ effect_; _continuation; _tail ])) -> (* Similar to previous case *) - [ Let (x, Prim (Extern "caml_raise_unhandled", [ effect_ ])) ] - | Let (x, Prim (Extern "caml_assume_no_perform", [ Pv f ])) -> + [ Let (x, Prim (Extern ("caml_raise_unhandled", None), [ effect_ ])) ] + | Let (x, Prim (Extern ("caml_assume_no_perform", _), [ Pv f ])) -> (* We just need to call [f] in direct style. *) let unit = Var.fresh_n "unit" in let unit_val = Int Targetint.zero in @@ -980,8 +986,11 @@ let cps_transform ~live_vars ~flow_info ~cps_needed p = { params = [] ; body = [ Let (main, Closure (cps_params, cps_cont, None)) - ; Let (args, Prim (Extern "%js_array", [])) - ; Let (res, Prim (Extern "caml_cps_trampoline", [ Pv main; Pv args ])) + ; Let (args, Prim (Extern ("%js_array", None), [])) + ; Let + ( res + , Prim (Extern ("caml_cps_trampoline", None), [ Pv main; Pv args ]) + ) ] ; branch = Return res } @@ -1005,8 +1014,8 @@ let wrap_call ~cps_needed p x f args accu = let arg_array = Var.fresh () in ( p , Var.Set.remove x cps_needed - , [ Let (arg_array, Prim (Extern "%js_array", List.map ~f:(fun y -> Pv y) args)) - ; Let (x, Prim (Extern "caml_cps_trampoline", [ Pv f; Pv arg_array ])) + , [ Let (arg_array, Prim (Extern ("%js_array", None), List.map ~f:(fun y -> Pv y) args)) + ; Let (x, Prim (Extern ("caml_cps_trampoline", None), [ Pv f; Pv arg_array ])) ] :: accu ) @@ -1025,8 +1034,8 @@ let wrap_primitive ~cps_needed (p : program) x e accu = , Var.Set.remove x (Var.Set.add f cps_needed) , let args = Var.fresh () in [ Let (f, Closure ([], (closure_pc, []), None)) - ; Let (args, Prim (Extern "%js_array", [])) - ; Let (x, Prim (Extern "caml_cps_trampoline", [ Pv f; Pv args ])) + ; Let (args, Prim (Extern ("%js_array", None), [])) + ; Let (x, Prim (Extern ("caml_cps_trampoline", None), [ Pv f; Pv args ])) ] :: accu ) @@ -1034,7 +1043,7 @@ let rewrite_toplevel_instr (p, cps_needed, accu) instr = match instr with | Let (x, Apply { f; args; _ }) when Var.Set.mem x cps_needed -> wrap_call ~cps_needed p x f args accu - | Let (x, (Prim (Extern ("%resume" | "%perform" | "%reperform"), _) as e)) -> + | Let (x, (Prim (Extern (("%resume" | "%perform" | "%reperform"), _), _) as e)) -> wrap_primitive ~cps_needed p x e accu | _ -> p, cps_needed, [ instr ] :: accu diff --git a/compiler/lib/eval.ml b/compiler/lib/eval.ml index 27c78c6f35..e7abb8a928 100644 --- a/compiler/lib/eval.ml +++ b/compiler/lib/eval.ml @@ -147,7 +147,7 @@ let eval_prim x = | Eq, [ Int i; Int j ] -> bool Targetint.(i = j) | Neq, [ Int i; Int j ] -> bool Targetint.(i <> j) | Ult, [ Int i; Int j ] -> bool (Targetint.unsigned_lt i j) - | Extern name, l -> ( + | Extern (name, _), l -> ( match name, l with (* int *) | "%int_add", _ -> int_binop l Targetint.add @@ -338,8 +338,8 @@ let the_length_of info x = (fun x -> match Flow.Info.def info x with | Some (Constant (String s)) -> Some (Targetint.of_int_exn (String.length s)) - | Some (Prim (Extern "caml_create_string", [ arg ])) - | Some (Prim (Extern "caml_create_bytes", [ arg ])) -> the_int info arg + | Some (Prim (Extern ("caml_create_string", _), [ arg ])) + | Some (Prim (Extern ("caml_create_bytes", _), [ arg ])) -> the_int info arg | None | Some _ -> None) None (fun u v -> @@ -410,7 +410,8 @@ let the_cont_of info x (a : cont array) = info (fun x -> match Flow.Info.def info x with - | Some (Prim (Extern "%direct_obj_tag", [ b ])) -> the_tag_of info b get cont_equal + | Some (Prim (Extern ("%direct_obj_tag", _), [ b ])) -> + the_tag_of info b get cont_equal | Some (Constant (Int j)) -> get (Targetint.to_int_exn j) | None | Some _ -> None) None @@ -432,11 +433,11 @@ let rec int_predicate deep info pred x (i : Targetint.t) = info (fun x -> match Flow.Info.def info x with - | Some (Prim (Extern "%direct_obj_tag", [ b ])) -> + | Some (Prim (Extern ("%direct_obj_tag", _), [ b ])) -> the_tag_of info b (fun j -> Some (pred (Targetint.of_int_exn j) i)) Bool.equal - | Some (Prim (Extern "%int_sub", [ Pv a; Pc (Int b) ])) -> + | Some (Prim (Extern ("%int_sub", _), [ Pv a; Pc (Int b) ])) -> int_predicate (deep + 1) info (fun x y -> pred (Targetint.sub x b) y) a i - | Some (Prim (Extern "%int_add", [ Pv a; Pc (Int b) ])) -> + | Some (Prim (Extern ("%int_add", _), [ Pv a; Pc (Int b) ])) -> int_predicate (deep + 1) info (fun x y -> pred (Targetint.add x b) y) a i | Some (Constant (Int j)) -> Some (pred j i) | None | Some _ -> None) @@ -491,7 +492,7 @@ let constant_equal a b = let eval_instr update_count inline_constant ~target info i = match i with - | Let (x, Prim (Extern (("caml_equal" | "caml_notequal") as prim), [ y; z ])) -> ( + | Let (x, Prim (Extern ((("caml_equal" | "caml_notequal") as prim), _), [ y; z ])) -> ( let eq e1 e2 = match Code.Constant.ocaml_equal e1 e2 with | None -> false @@ -513,7 +514,8 @@ let eval_instr update_count inline_constant ~target info i = incr update_count; [ Let (x, c) ]) | _ -> [ i ]) - | Let (x, Prim (Extern ("caml_js_equals" | "caml_js_strict_equals"), [ y; z ])) -> ( + | Let (x, Prim (Extern (("caml_js_equals" | "caml_js_strict_equals"), _), [ y; z ])) + -> ( let eq e1 e2 = match constant_js_equal e1 e2 with | None -> false @@ -529,7 +531,7 @@ let eval_instr update_count inline_constant ~target info i = incr update_count; [ Let (x, c) ]) | _ -> [ i ]) - | Let (x, Prim (Extern "caml_ml_string_length", [ s ])) -> ( + | Let (x, Prim (Extern ("caml_ml_string_length", _), [ s ])) -> ( let c = match s with | Pc (String s) -> Some (Targetint.of_int_exn (String.length s)) @@ -547,18 +549,19 @@ let eval_instr update_count inline_constant ~target info i = ( _ , Prim ( ( Extern - ( "caml_array_unsafe_get" - | "caml_array_unsafe_set" - | "caml_floatarray_unsafe_get" - | "caml_floatarray_unsafe_set" - | "caml_array_unsafe_set_addr" ) + ( ( "caml_array_unsafe_get" + | "caml_array_unsafe_set" + | "caml_floatarray_unsafe_get" + | "caml_floatarray_unsafe_set" + | "caml_array_unsafe_set_addr" ) + , _ ) | Array_get ) , _ ) ) -> (* Fresh parameters can be introduced for these primitives in Specialize_js, which would make the call to [the_const_of] below fail. *) [ i ] - | Let (x, Prim (Extern "caml_atomic_load_field", [ Pv o; f ])) -> ( + | Let (x, Prim (Extern ("caml_atomic_load_field", _), [ Pv o; f ])) -> ( match the_int info f with | None -> [ i ] | Some i -> [ Let (x, Field (o, Targetint.to_int_exn i, Non_float)) ]) @@ -600,7 +603,7 @@ let eval_instr update_count inline_constant ~target info i = incr update_count; [ Let (x, c) ] | None -> [ i ]) - | Let (x, Prim (Extern "%direct_obj_tag", [ y ])) -> ( + | Let (x, Prim (Extern ("%direct_obj_tag", _), [ y ])) -> ( match the_tag_of info y (fun x -> Some x) ( = ) with | Some tag -> let c = Constant (Int (Targetint.of_int_exn tag)) in @@ -608,7 +611,7 @@ let eval_instr update_count inline_constant ~target info i = incr update_count; [ Let (x, c) ] | None -> [ i ]) - | Let (x, Prim (Extern "caml_sys_const_backend_type", [ _ ])) -> + | Let (x, Prim (Extern ("caml_sys_const_backend_type", _), [ _ ])) -> let jsoo = Code.Var.fresh () in let backend_name = match target with @@ -619,7 +622,7 @@ let eval_instr update_count inline_constant ~target info i = [ Let (jsoo, Constant (String backend_name)) ; Let (x, Block (0, [| jsoo |], NotArray, Immutable)) ] - | Let (_, Prim (Extern ("%resume" | "%perform" | "%reperform"), _)) -> + | Let (_, Prim (Extern (("%resume" | "%perform" | "%reperform"), _), _)) -> [ i ] (* We need that the arguments to this primitives remain variables *) | Let (x, Prim (prim, prim_args)) -> ( let prim_args' = @@ -749,7 +752,7 @@ let rec do_not_raise pc visited rewrite blocks = | Block (_, _, _, _) | Field (_, _, _) | Constant _ | Closure _ -> () | Apply _ -> raise May_raise | Special _ -> () - | Prim (Extern name, _) when Primitive.is_pure name -> () + | Prim (Extern (name, _), _) when Primitive.is_pure name -> () | Prim (Extern _, _) -> raise May_raise | Prim (_, _) -> ())); match b.branch with diff --git a/compiler/lib/flow.ml b/compiler/lib/flow.ml index 13de7ffb74..451d2fd281 100644 --- a/compiler/lib/flow.ml +++ b/compiler/lib/flow.ml @@ -209,7 +209,8 @@ let rec block_escape st x = | Maybe_mutable -> Code.Var.ISet.add st.possibly_mutable y); Array.iter l ~f:(fun z -> block_escape st z) | Expr - (Prim (Extern ("caml_make_array" | "caml_array_of_uniform_array"), [ Pv y ])) + (Prim + (Extern (("caml_make_array" | "caml_array_of_uniform_array"), _), [ Pv y ])) -> block_escape st y | _ -> Code.Var.ISet.add st.possibly_mutable y)) (Var.Tbl.get st.known_origins x) @@ -219,9 +220,9 @@ let expr_escape st _x e = | Special _ | Constant _ | Closure _ | Block _ | Field _ -> () | Apply { args; _ } -> List.iter args ~f:(fun x -> block_escape st x) | Prim (Array_get, [ Pv x; _ ]) -> block_escape st x - | Prim ((Vectlength | Array_get | Not | IsInt | Eq | Neq | Lt | Le | Ult), _) -> () - | Prim (Extern ("caml_make_array" | "caml_array_of_uniform_array"), [ Pv _ ]) -> () - | Prim (Extern name, l) -> + | Prim ((Vectlength _ | Array_get | Not | IsInt | Eq | Neq | Lt | Le | Ult), _) -> () + | Prim (Extern (("caml_make_array" | "caml_array_of_uniform_array"), _), [ Pv _ ]) -> () + | Prim (Extern (name, _), l) -> let ka = match Primitive.kind_args name with | Some l -> l @@ -247,7 +248,7 @@ let expr_escape st _x e = Array.iter a ~f:(fun x -> block_escape st x) | Expr (Prim - ( Extern ("caml_make_array" | "caml_array_of_uniform_array") + ( Extern (("caml_make_array" | "caml_array_of_uniform_array"), _) , [ Pv y ] )) -> ( match st.defs.(Var.idx y) with | Expr (Block (_, a, _, _)) -> @@ -435,7 +436,8 @@ let the_native_string_of info x = let the_block_contents_of info x = match the_def_of info x with | Some (Block (_, a, _, _)) -> Some a - | Some (Prim (Extern ("caml_make_array" | "caml_array_of_uniform_array"), [ x ])) -> ( + | Some (Prim (Extern (("caml_make_array" | "caml_array_of_uniform_array"), _), [ x ])) + -> ( match the_def_of info x with | Some (Block (_, a, _, _)) -> Some a | _ -> None) diff --git a/compiler/lib/generate.ml b/compiler/lib/generate.ml index bfbd93c5b9..07d3b352c1 100644 --- a/compiler/lib/generate.ml +++ b/compiler/lib/generate.ml @@ -182,7 +182,7 @@ module Share = struct if Primitive.exists name then add_prim name share else share in share - | Let (_, Prim (Extern name, args)) -> + | Let (_, Prim (Extern (name, _), args)) -> let name = Primitive.resolve name in let share = if Primitive.exists name then add_prim name share else share @@ -1499,7 +1499,7 @@ let rec translate_expr ctx loc x e level : (_ * J.statement_list) Expr_builder.t | Special (Alias_prim name) -> let prim = Share.get_prim (runtime_fun ctx) name ctx.Ctx.share in return (prim, []) - | Prim (Extern "debugger", _) -> + | Prim (Extern ("debugger", _), _) -> let ins = if Config.Flag.debugger () then J.Debugger_statement else J.Empty_statement in @@ -1507,7 +1507,7 @@ let rec translate_expr ctx loc x e level : (_ * J.statement_list) Expr_builder.t | Prim (p, l) -> let* res = match p, l with - | Vectlength, [ x ] -> + | Vectlength _, [ x ] -> let* cx = access' ~ctx x in return (Mlvalue.Array.length cx) | Array_get, [ x; y ] -> @@ -1515,8 +1515,8 @@ let rec translate_expr ctx loc x e level : (_ * J.statement_list) Expr_builder.t let* cy = access' ~ctx y in let* () = info mutable_p in return (Mlvalue.Array.field cx cy) - | Extern "caml_js_var", [ Pc (String nm) ] - | Extern ("caml_js_expr" | "caml_pure_js_expr"), [ Pc (String nm) ] -> ( + | Extern ("caml_js_var", _), [ Pc (String nm) ] + | Extern (("caml_js_expr" | "caml_pure_js_expr"), _), [ Pc (String nm) ] -> ( try let pos = match loc with @@ -1547,27 +1547,27 @@ let rec translate_expr ctx loc x e level : (_ * J.statement_list) Expr_builder.t | Some s -> Printf.sprintf ", file %S" s) pi.Parse_info.line pi.Parse_info.col)) - | Extern "%js_array", l -> + | Extern ("%js_array", _), l -> let* args = list_map (fun x -> access' ~ctx x) l in return (J.array args) - | Extern "%caml_js_opt_call", f :: o :: l -> + | Extern ("%caml_js_opt_call", _), f :: o :: l -> let* () = info ~need_loc:true mutator_p in let* cf = access' ~ctx f in let* co = access' ~ctx o in let* args = list_map (fun x -> access' ~ctx x) l in return (J.call (J.dot cf (Utf8_string.of_string_exn "call")) (co :: args) loc) - | Extern "%caml_js_opt_fun_call", f :: l -> + | Extern ("%caml_js_opt_fun_call", _), f :: l -> let* () = info ~need_loc:true mutator_p in let* cf = access' ~ctx f in let* args = list_map (fun x -> access' ~ctx x) l in return (J.call cf args loc) - | Extern "%caml_js_opt_meth_call", o :: Pc (NativeString (Utf m)) :: l -> + | Extern ("%caml_js_opt_meth_call", _), o :: Pc (NativeString (Utf m)) :: l -> let* () = info ~need_loc:true mutator_p in let* co = access' ~ctx o in let* args = list_map (fun x -> access' ~ctx x) l in return (J.call (J.dot co m) args loc) - | Extern "%caml_js_opt_meth_call", _ -> assert false - | Extern "%caml_js_opt_new", c :: l -> + | Extern ("%caml_js_opt_meth_call", _), _ -> assert false + | Extern ("%caml_js_opt_new", _), c :: l -> let* () = info ~need_loc:true mutator_p in let* cc = access' ~ctx c in let* args = @@ -1578,18 +1578,19 @@ let rec translate_expr ctx loc x e level : (_ * J.statement_list) Expr_builder.t l in return (J.ENew (cc, (if List.is_empty args then None else Some args), loc)) - | Extern "caml_js_get", [ Pv o; Pc (NativeString (Utf f)) ] when J.is_ident' f -> + | Extern ("caml_js_get", _), [ Pv o; Pc (NativeString (Utf f)) ] + when J.is_ident' f -> let* co = access ~ctx o in let* () = info mutable_p in return (J.dot co f) - | Extern "caml_js_set", [ Pv o; Pc (NativeString (Utf f)); v ] when J.is_ident' f - -> + | Extern ("caml_js_set", _), [ Pv o; Pc (NativeString (Utf f)); v ] + when J.is_ident' f -> let* co = access ~ctx o in let* cv = access' ~ctx v in let* () = info mutator_p in return (J.EBin (J.Eq, J.dot co f, cv)) - | Extern "caml_js_delete", [ Pv o; Pc (NativeString (Utf f)) ] when J.is_ident' f - -> + | Extern ("caml_js_delete", _), [ Pv o; Pc (NativeString (Utf f)) ] + when J.is_ident' f -> let* co = access ~ctx o in let* () = info mutator_p in return (J.EUn (J.Delete, J.dot co f)) @@ -1601,7 +1602,7 @@ let rec translate_expr ctx loc x e level : (_ * J.statement_list) Expr_builder.t | Extern "caml_js_delete", [ _; Pc (String _) ] -> assert false ]} *) - | Extern "%caml_js_opt_object", fields -> + | Extern ("%caml_js_opt_object", _), fields -> let rec build_fields l = match l with | [] -> return [] @@ -1614,7 +1615,7 @@ let rec translate_expr ctx loc x e level : (_ * J.statement_list) Expr_builder.t in let* fields = build_fields fields in return (J.EObj fields) - | Extern "caml_alloc_dummy_function", [ _; size ] -> + | Extern ("caml_alloc_dummy_function", _), [ _; size ] -> (* Removed in Ocaml 5.2 *) let* i = let* cx = access' ~ctx size in @@ -1635,8 +1636,8 @@ let rec translate_expr ctx loc x e level : (_ * J.statement_list) Expr_builder.t J.EFun (Some f, J.fun_ args [ J.Return_statement (Some call, J.N), J.N ] J.N) in return e - | Extern "caml_alloc_dummy_function", _ -> assert false - | Extern ("%resume" | "%perform" | "%reperform"), _ -> + | Extern ("caml_alloc_dummy_function", _), _ -> assert false + | Extern (("%resume" | "%perform" | "%reperform"), _), _ -> assert (not (cps_transform ())); if not !(ctx.effect_warning) then ( @@ -1649,15 +1650,16 @@ let rec translate_expr ctx loc x e level : (_ * J.statement_list) Expr_builder.t let prim = Share.get_prim (runtime_fun ctx) name ctx.Ctx.share in let* () = info ~need_loc:true (kind (Primitive.kind name)) in return (J.call prim [] loc) - | Extern "caml_string_notequal", [ a; b ] when Config.Flag.use_js_string () -> + | Extern ("caml_string_notequal", _), [ a; b ] when Config.Flag.use_js_string () + -> let* cx = access' ~ctx a in let* cy = access' ~ctx b in return (bool (J.EBin (J.NotEqEq, cx, cy))) - | Extern "caml_string_equal", [ a; b ] when Config.Flag.use_js_string () -> + | Extern ("caml_string_equal", _), [ a; b ] when Config.Flag.use_js_string () -> let* cx = access' ~ctx a in let* cy = access' ~ctx b in return (bool (J.EBin (J.EqEqEq, cx, cy))) - | Extern "caml_string_concat", [ a; b ] when Config.Flag.use_js_string () -> + | Extern ("caml_string_concat", _), [ a; b ] when Config.Flag.use_js_string () -> let* ca = access' ~ctx a in let* cb = access' ~ctx b in let rec add ca cb = @@ -1666,7 +1668,7 @@ let rec translate_expr ctx loc x e level : (_ * J.statement_list) Expr_builder.t | _ -> J.EBin (J.Plus, ca, cb) in return (add ca cb) - | Extern name_orig, l -> ( + | Extern (name_orig, _), l -> ( let name = Primitive.resolve name_orig in match internal_prim name with | Some f -> f name l ctx loc @@ -1703,7 +1705,7 @@ let rec translate_expr ctx loc x e level : (_ * J.statement_list) Expr_builder.t let* cx = access' ~ctx x in let* cy = access' ~ctx y in return (bool (J.EBin (J.LtInt, unsigned cx, unsigned cy))) - | (Vectlength | Array_get | Not | IsInt | Eq | Neq | Lt | Le | Ult), _ -> + | (Vectlength _ | Array_get | Not | IsInt | Eq | Neq | Lt | Le | Ult), _ -> assert false in return (res, []) diff --git a/compiler/lib/generate_closure.ml b/compiler/lib/generate_closure.ml index 6771a59473..293957b7d4 100644 --- a/compiler/lib/generate_closure.ml +++ b/compiler/lib/generate_closure.ml @@ -110,7 +110,8 @@ module Trampoline = struct ; body = [ Let ( counter_plus_1 - , Prim (Extern "%int_add", [ Pv counter; Pc (Int Targetint.one) ]) ) + , Prim (Extern ("%int_add", None), [ Pv counter; Pc (Int Targetint.one) ]) + ) ; Let (return, Apply { f; args = counter_plus_1 :: args; exact = true }) ] ; branch = Return return @@ -124,9 +125,10 @@ module Trampoline = struct [ Let ( new_args , Prim - ( Extern "%js_array" + ( Extern ("%js_array", None) , Pc (Int Targetint.zero) :: List.map args ~f:(fun x -> Pv x) ) ) - ; Let (return, Prim (Extern "caml_trampoline_return", [ Pv f; Pv new_args ])) + ; Let + (return, Prim (Extern ("caml_trampoline_return", None), [ Pv f; Pv new_args ])) ] ; branch = Return return } @@ -142,14 +144,14 @@ module Trampoline = struct [ Event loc ; Let (result1, Apply { f; args; exact = true }) ; Event Parse_info.zero - ; Let (result2, Prim (Extern "caml_trampoline", [ Pv result1 ])) + ; Let (result2, Prim (Extern ("caml_trampoline", None), [ Pv result1 ])) ] | Some counter -> [ Event loc ; Let (counter, Constant (Int Targetint.zero)) ; Let (result1, Apply { f; args = counter :: args; exact = true }) ; Event Parse_info.zero - ; Let (result2, Prim (Extern "caml_trampoline", [ Pv result1 ])) + ; Let (result2, Prim (Extern ("caml_trampoline", None), [ Pv result1 ])) ]) ; branch = Return result2 } diff --git a/compiler/lib/global_flow.ml b/compiler/lib/global_flow.ml index 6695dfb03b..29a7b145b6 100644 --- a/compiler/lib/global_flow.ml +++ b/compiler/lib/global_flow.ml @@ -162,16 +162,18 @@ let field_possibly_mutable st x n = let expr_deps blocks st x e = match e with - | Constant _ | Prim ((Vectlength | Not | IsInt | Eq | Neq | Lt | Le | Ult), _) | Block _ - -> () + | Constant _ + | Prim ((Vectlength _ | Not | IsInt | Eq | Neq | Lt | Le | Ult), _) + | Block _ -> () | Special _ -> () | Prim ( ( Extern - ( "caml_check_bound" - | "caml_check_bound_float" - | "caml_check_bound_gen" - | "caml_array_unsafe_get" - | "caml_floatarray_unsafe_get" ) + ( ( "caml_check_bound" + | "caml_check_bound_float" + | "caml_check_bound_gen" + | "caml_array_unsafe_get" + | "caml_floatarray_unsafe_get" ) + , _ ) | Array_get ) , l ) -> (* The analysis knowns about these primitives, and will compute @@ -189,7 +191,7 @@ let expr_deps blocks st x e = | Pc _ -> () | Pv y -> add_dep st x y) l - | Prim (Extern name, l) -> + | Prim (Extern (name, _), l) -> (* Set the escape status of the arguments *) let ka = match Primitive.kind_args name with @@ -286,7 +288,7 @@ let program_deps st { start; blocks; _ } = parse_bytecode.ml) and [Addr.Map.iter] iterate in increasing order *) match st.defs.(Code.Var.idx x) with - | Expr (Prim (Extern "%direct_obj_tag", [ Pv b ])) -> + | Expr (Prim (Extern ("%direct_obj_tag", _), [ Pv b ])) -> let h = Addr.Hashtbl.create 16 in Array.iteri a1 ~f:(fun i (pc, _) -> Addr.Hashtbl.replace @@ -478,10 +480,12 @@ let propagate st ~update approx x = known | Top -> Top) | Prim - ( Extern ("caml_check_bound" | "caml_check_bound_float" | "caml_check_bound_gen") + ( Extern + (("caml_check_bound" | "caml_check_bound_float" | "caml_check_bound_gen"), _) , [ Pv y; _ ] ) -> Var.Tbl.get approx y | Prim - ( (Array_get | Extern ("caml_array_unsafe_get" | "caml_floatarray_unsafe_get")) + ( ( Array_get + | Extern (("caml_array_unsafe_get" | "caml_floatarray_unsafe_get"), _) ) , [ Pv y; _ ] ) -> ( if st.fast then Domain.others @@ -516,7 +520,7 @@ let propagate st ~update approx x = known | Top -> Top) | Prim (Array_get, _) -> Domain.others - | Prim ((Vectlength | Not | IsInt | Eq | Neq | Lt | Le | Ult), _) -> + | Prim ((Vectlength _ | Not | IsInt | Eq | Neq | Lt | Le | Ult), _) -> (* The result of these primitive is neither a function nor a block *) Domain.bot diff --git a/compiler/lib/inline.ml b/compiler/lib/inline.ml index 0412d0d19c..09d083dd57 100644 --- a/compiler/lib/inline.ml +++ b/compiler/lib/inline.ml @@ -246,12 +246,13 @@ let rec block_size ~inline_comparisons ~recurse ~context { branch; body; _ } = ( _ , Prim ( Extern - ( "caml_lessthan" - | "caml_lessequal" - | "caml_greaterthan" - | "caml_greaterequal" - | "caml_equal" - | "caml_notequal" ) + ( ( "caml_lessthan" + | "caml_lessequal" + | "caml_greaterthan" + | "caml_greaterequal" + | "caml_equal" + | "caml_notequal" ) + , _ ) , _ ) ) when inline_comparisons -> (* Bias toward inlining functions containing polymorphic diff --git a/compiler/lib/optimization_hint.ml b/compiler/lib/optimization_hint.ml new file mode 100644 index 0000000000..77af56f8a2 --- /dev/null +++ b/compiler/lib/optimization_hint.ml @@ -0,0 +1,143 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2025 Jérôme Vouillon, Hugo Heuzard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, with linking exception; + * either version 2.1 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *) + +type boxed_integer = + | Int32 + | Int64 + | Nativeint + +type array_kind = + | Generic + | Value + | Float + +module Bigarray = struct + type kind = + | Float16 + | Float32 + | Float64 + | Int8_signed + | Int8_unsigned + | Int16_signed + | Int16_unsigned + | Int32 + | Int64 + | Int + | Nativeint + | Complex32 + | Complex64 + + type layout = + | C + | Fortran + + type t = + { unsafe : bool + ; kind : kind + ; layout : layout + } +end + +type repr = + | Value + | Float + | Int32 + | Nativeint + | Int64 + | Int + +type primitive = + { name : string + ; args : repr list + ; res : repr + } + +type t = + | Hint_immutable + | Hint_unsafe + | Hint_int of boxed_integer + | Hint_array of array_kind + | Hint_bigarray of Bigarray.t + | Hint_primitive of primitive + +let print f h = + match h with + | Hint_immutable -> Format.fprintf f "immutable" + | Hint_unsafe -> Format.fprintf f "unsafe" + | Hint_int kind -> + Format.fprintf + f + "%s" + (match kind with + | Nativeint -> "nativeint" + | Int32 -> "int32" + | Int64 -> "int64") + | Hint_array kind -> + Format.fprintf + f + "%s" + (match kind with + | Generic -> "generic" + | Value -> "value" + | Float -> "float") + | Hint_bigarray { unsafe; kind; layout } -> + Format.fprintf + f + "%s%s/%s" + (if unsafe then "unsafe/" else "") + (match kind with + | Float16 -> "float16" + | Float32 -> "float32" + | Float64 -> "float64" + | Int8_signed -> "sint8" + | Int8_unsigned -> "uint8" + | Int16_signed -> "sint16" + | Int16_unsigned -> "uint16" + | Int32 -> "int32" + | Int64 -> "int64" + | Int -> "int" + | Nativeint -> "nativeint" + | Complex32 -> "complex32" + | Complex64 -> "complex64") + (match layout with + | C -> "C" + | Fortran -> "Fortran") + | Hint_primitive { name; args; res } -> + let print_repr f r = + Format.fprintf + f + "%s" + (match r with + | Value -> "value" + | Float -> "float" + | Int32 -> "int32" + | Nativeint -> "nativeint" + | Int64 -> "int64" + | Int -> "int") + in + Format.fprintf + f + "%s:%a%a" + name + (Format.pp_print_list + ~pp_sep:(fun _ _ -> ()) + (fun f r -> Format.fprintf f "%a->" print_repr r)) + args + print_repr + res diff --git a/compiler/lib/optimization_hint.mli b/compiler/lib/optimization_hint.mli new file mode 100644 index 0000000000..b413c8943e --- /dev/null +++ b/compiler/lib/optimization_hint.mli @@ -0,0 +1,79 @@ +(* Js_of_ocaml compiler + * http://www.ocsigen.org/js_of_ocaml/ + * Copyright (C) 2025 Jérôme Vouillon, Hugo Heuzard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, with linking exception; + * either version 2.1 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + *) + +type boxed_integer = + | Int32 + | Int64 + | Nativeint + +type array_kind = + | Generic + | Value + | Float + +module Bigarray : sig + type kind = + | Float16 + | Float32 + | Float64 + | Int8_signed + | Int8_unsigned + | Int16_signed + | Int16_unsigned + | Int32 + | Int64 + | Int + | Nativeint + | Complex32 + | Complex64 + + type layout = + | C + | Fortran + + type t = + { unsafe : bool + ; kind : kind + ; layout : layout + } +end + +type repr = + | Value + | Float + | Int32 + | Nativeint + | Int64 + | Int + +type primitive = + { name : string + ; args : repr list + ; res : repr + } + +type t = + | Hint_immutable + | Hint_unsafe + | Hint_int of boxed_integer + | Hint_array of array_kind + | Hint_bigarray of Bigarray.t + | Hint_primitive of primitive + +val print : Format.formatter -> t -> unit diff --git a/compiler/lib/parse_bytecode.ml b/compiler/lib/parse_bytecode.ml index b98691f3b5..b08467381c 100644 --- a/compiler/lib/parse_bytecode.ml +++ b/compiler/lib/parse_bytecode.ml @@ -369,16 +369,80 @@ module Hints = struct } | Hint_primitive of Primitive.description - type t = { hints : optimization_hint Int.Hashtbl.t } - - let equal (a : optimization_hint) b = Poly.equal a b + type t = { hints : Optimization_hint.t Int.Hashtbl.t } let create () = { hints = Int.Hashtbl.create 17 } + let import h : Optimization_hint.t option = + match h with + | Hint_immutable -> Some Hint_immutable + | Hint_unsafe -> Some Hint_unsafe + | Hint_int kind -> + Some + (Hint_int + (match kind with + | Pnativeint -> Nativeint + | Pint32 -> Int32 + | Pint64 -> Int64)) + | Hint_array kind -> + Some + (Hint_array + (match kind with + | Pgenarray -> Generic + | Paddrarray | Pintarray -> Value + | Pfloatarray -> Float)) + | Hint_bigarray { elt_kind = Pbigarray_unknown; _ } + | Hint_bigarray { layout = Pbigarray_unknown_layout; _ } -> None + | Hint_bigarray { unsafe; elt_kind; layout } -> + let kind : Optimization_hint.Bigarray.kind = + match elt_kind with + | Pbigarray_unknown -> assert false + | (Pbigarray_float16 [@if ocaml_version >= (5, 2, 0)]) -> Float16 + | Pbigarray_float32 -> Float32 + | Pbigarray_float64 -> Float64 + | Pbigarray_sint8 -> Int8_signed + | Pbigarray_uint8 -> Int8_unsigned + | Pbigarray_sint16 -> Int16_signed + | Pbigarray_uint16 -> Int16_unsigned + | Pbigarray_int32 -> Int32 + | Pbigarray_int64 -> Int64 + | Pbigarray_caml_int -> Int + | Pbigarray_native_int -> Nativeint + | Pbigarray_complex32 -> Complex32 + | Pbigarray_complex64 -> Complex64 + in + let layout : Optimization_hint.Bigarray.layout = + match layout with + | Pbigarray_unknown_layout -> assert false + | Pbigarray_c_layout -> C + | Pbigarray_fortran_layout -> Fortran + in + Some (Hint_bigarray { unsafe; kind; layout }) + | Hint_primitive { prim_native_name; prim_native_repr_args; prim_native_repr_res; _ } + -> + let repr (r : Primitive.native_repr) : Optimization_hint.repr = + match r with + | Same_as_ocaml_repr -> Value + | Unboxed_float -> Float + | Unboxed_integer Pint32 -> Int32 + | Unboxed_integer Pnativeint -> Nativeint + | Unboxed_integer Pint64 -> Int64 + | Untagged_immediate -> Int + in + Some + (Hint_primitive + { name = prim_native_name + ; args = List.map ~f:repr prim_native_repr_args + ; res = repr prim_native_repr_res + }) + let read t ~orig ic = let l : (int * optimization_hint) list = input_value ic in - List.iter l ~f:(fun (pos, hint) -> Int.Hashtbl.add t.hints ((pos + orig) / 4) hint) + List.iter l ~f:(fun (pos, hint) -> + match import hint with + | Some hint -> Int.Hashtbl.add t.hints ((pos + orig) / 4) hint + | None -> ()) let read_section t ic = let len = input_binary_int ic in @@ -387,7 +451,7 @@ module Hints = struct read t ~orig ic done - let find t pc = Int.Hashtbl.find_all t.hints pc + let find_opt t pc = Int.Hashtbl.find_opt t.hints pc end (* Block analysis *) @@ -832,7 +896,9 @@ let register_global ?(force = false) g i rem = Var.set_name (access_global g i) name; Let ( Var.fresh () - , Prim (Extern "caml_set_global", [ Pc (String name); Pv (access_global g i) ]) ) + , Prim + ( Extern ("caml_set_global", None) + , [ Pc (String name); Pv (access_global g i) ] ) ) :: rem | true, _, (`JavaScript as target) | false, true, ((`Wasm | `JavaScript) as target) -> (* Register an exception (if force = true), or a compilation unit @@ -851,7 +917,7 @@ let register_global ?(force = false) g i rem = Let ( Var.fresh () , Prim - ( Extern "caml_register_global" + ( Extern ("caml_register_global", None) , Pc (Int (Targetint.of_int_exn i)) :: Pv (access_global g i) :: args ) ) :: rem | false, false, (`JavaScript | `Wasm) -> rem @@ -906,8 +972,8 @@ let get_global state instrs i = | Some shape -> Shape.State.assign x shape); ( x , state - , Let (x, Prim (Extern "caml_get_global", [ Pc (String name) ])) :: instrs - ))) + , Let (x, Prim (Extern ("caml_get_global", None), [ Pc (String name) ])) + :: instrs ))) let tagged_blocks = ref Addr.Map.empty @@ -945,8 +1011,9 @@ let string_of_addr debug_data addr = Printf.sprintf "%s:%s-%s %s" file (pos loc.loc_start) (pos loc.loc_end) kind) let is_immutable _instr infos pc = - let hints = Hints.find infos.hints pc in - if List.mem ~eq:Hints.equal Hints.Hint_immutable hints then Immutable else Maybe_mutable + match Hints.find_opt infos.hints pc with + | Some Optimization_hint.Hint_immutable -> Immutable + | _ -> Maybe_mutable let rec compile_block blocks joins hints debug_data code pc state : unit = match Addr.Map.find_opt pc !tagged_blocks with @@ -1729,7 +1796,12 @@ and compile infos pc state (instrs : instr list) = let x, state = State.fresh_var state in if debug_parser () then Format.printf "%a = %a.length@." Var.print x Var.print y; - compile infos (pc + 1) state (Let (x, Prim (Vectlength, [ Pv y ])) :: instrs) + let kind = + match Hints.find_opt infos.hints pc with + | Some (Hint_array kind) -> kind + | _ -> Generic + in + compile infos (pc + 1) state (Let (x, Prim (Vectlength kind, [ Pv y ])) :: instrs) | GETVECTITEM -> let y = State.accu state in let z = State.peek 0 state in @@ -1770,7 +1842,8 @@ and compile infos pc state (instrs : instr list) = infos (pc + 1) (State.pop 1 state) - (Let (x, Prim (Extern "caml_string_unsafe_get", [ Pv y; Pv z ])) :: instrs) + (Let (x, Prim (Extern ("caml_string_unsafe_get", None), [ Pv y; Pv z ])) + :: instrs) | GETBYTESCHAR -> let y = State.accu state in let z = State.peek 0 state in @@ -1782,7 +1855,8 @@ and compile infos pc state (instrs : instr list) = infos (pc + 1) (State.pop 1 state) - (Let (x, Prim (Extern "caml_bytes_unsafe_get", [ Pv y; Pv z ])) :: instrs) + (Let (x, Prim (Extern ("caml_bytes_unsafe_get", None), [ Pv y; Pv z ])) + :: instrs) | SETBYTESCHAR -> if debug_parser () then @@ -1799,7 +1873,8 @@ and compile infos pc state (instrs : instr list) = let z = State.peek 1 state in let t, state = State.fresh_var state in let instrs = - Let (t, Prim (Extern "caml_bytes_unsafe_set", [ Pv x; Pv y; Pv z ])) :: instrs + Let (t, Prim (Extern ("caml_bytes_unsafe_set", None), [ Pv x; Pv y; Pv z ])) + :: instrs in let x, state = State.fresh_var state in if debug_parser () then Format.printf "%a = 0@." Var.print x; @@ -1834,7 +1909,7 @@ and compile infos pc state (instrs : instr list) = | 0, _ -> let x_tag = Var.fresh () in let instrs = - Let (x_tag, Prim (Extern "%direct_obj_tag", [ Pv x ])) :: instrs + Let (x_tag, Prim (Extern ("%direct_obj_tag", None), [ Pv x ])) :: instrs in instrs, Switch (x_tag, Array.map bt ~f:(fun pc -> pc, [])), state | _, _ -> @@ -1858,7 +1933,9 @@ and compile infos pc state (instrs : instr list) = tagged_blocks := Addr.Map.add isblock_branch state !tagged_blocks; let x_tag = Var.fresh () in let b_args = State.stack_vars state in - let instrs = [ Let (x_tag, Prim (Extern "%direct_obj_tag", [ Pv x ])) ] in + let instrs = + [ Let (x_tag, Prim (Extern ("%direct_obj_tag", None), [ Pv x ])) ] + in compiled_blocks := Addr.Map.add isblock_branch @@ -1965,7 +2042,12 @@ and compile infos pc state (instrs : instr list) = let x, state = State.fresh_var state in if debug_parser () then Format.printf "%a = ccall \"%s\" (%a)@." Var.print x prim Var.print y; - compile infos (pc + 2) state (Let (x, Prim (Extern prim, [ Pv y ])) :: instrs) + compile + infos + (pc + 2) + state + (Let (x, Prim (Extern (prim, Hints.find_opt infos.hints pc), [ Pv y ])) + :: instrs) | C_CALL2 -> let prim = primitive_name state (getu code (pc + 1)) in let y = State.accu state in @@ -1981,11 +2063,10 @@ and compile infos pc state (instrs : instr list) = | "caml_string_get64" | "caml_bytes_get16" | "caml_bytes_get32" - | "caml_bytes_get64" -> - let hints = Hints.find infos.hints pc in - if List.mem ~eq:Hints.equal Hints.Hint_unsafe hints - then prim ^ "u" - else prim + | "caml_bytes_get64" -> ( + match Hints.find_opt infos.hints pc with + | Some Hint_unsafe -> prim ^ "u" + | _ -> prim) | _ -> prim in if debug_parser () @@ -2001,7 +2082,7 @@ and compile infos pc state (instrs : instr list) = z; let prim, y, z = match Config.target () with - | `Wasm -> Extern prim, y, z + | `Wasm -> Extern (prim, Hints.find_opt infos.hints pc), y, z | `JavaScript -> ( match prim with | "caml_equal" @@ -2019,14 +2100,14 @@ and compile infos pc state (instrs : instr list) = | "caml_greaterthan" -> Lt, z, y | _ -> assert false in - match Hints.find infos.hints pc with - | [ Hints.Hint_int boxed ] -> ( + match Hints.find_opt infos.hints pc with + | Some (Hint_int boxed) -> ( match boxed with - | Pnativeint -> prim_of_ext prim - | Pint32 -> prim_of_ext prim - | Pint64 -> Extern prim, y, z) - | _ -> Extern prim, y, z) - | _ -> Extern prim, y, z) + | Nativeint -> prim_of_ext prim + | Int32 -> prim_of_ext prim + | Int64 -> Extern (prim, None), y, z) + | _ -> Extern (prim, None), y, z) + | _ -> Extern (prim, Hints.find_opt infos.hints pc), y, z) in compile infos @@ -2046,11 +2127,10 @@ and compile infos pc state (instrs : instr list) = | "caml_ba_uint8_set64" | "caml_bytes_set16" | "caml_bytes_set32" - | "caml_bytes_set64" -> - let hints = Hints.find infos.hints pc in - if List.mem ~eq:Hints.equal Hints.Hint_unsafe hints - then prim ^ "u" - else prim + | "caml_bytes_set64" -> ( + match Hints.find_opt infos.hints pc with + | Some Hint_unsafe -> prim ^ "u" + | _ -> prim) | _ -> prim in if debug_parser () @@ -2070,7 +2150,9 @@ and compile infos pc state (instrs : instr list) = infos (pc + 2) (State.pop 2 state) - (Let (x, Prim (Extern prim, [ Pv y; Pv z; Pv t ])) :: instrs) + (Let + (x, Prim (Extern (prim, Hints.find_opt infos.hints pc), [ Pv y; Pv z; Pv t ])) + :: instrs) | C_CALL4 -> let nargs = 4 in let prim = primitive_name state (getu code (pc + 1)) in @@ -2090,7 +2172,12 @@ and compile infos pc state (instrs : instr list) = infos (pc + 2) state - (Let (x, Prim (Extern prim, List.map args ~f:(fun x -> Pv x))) :: instrs) + (Let + ( x + , Prim + ( Extern (prim, Hints.find_opt infos.hints pc) + , List.map args ~f:(fun x -> Pv x) ) ) + :: instrs) | C_CALL5 -> let nargs = 5 in let prim = primitive_name state (getu code (pc + 1)) in @@ -2110,7 +2197,12 @@ and compile infos pc state (instrs : instr list) = infos (pc + 2) state - (Let (x, Prim (Extern prim, List.map args ~f:(fun x -> Pv x))) :: instrs) + (Let + ( x + , Prim + ( Extern (prim, Hints.find_opt infos.hints pc) + , List.map args ~f:(fun x -> Pv x) ) ) + :: instrs) | C_CALLN -> let nargs = getu code (pc + 1) in let prim = primitive_name state (getu code (pc + 2)) in @@ -2130,7 +2222,12 @@ and compile infos pc state (instrs : instr list) = infos (pc + 3) state - (Let (x, Prim (Extern prim, List.map args ~f:(fun x -> Pv x))) :: instrs) + (Let + ( x + , Prim + ( Extern (prim, Hints.find_opt infos.hints pc) + , List.map args ~f:(fun x -> Pv x) ) ) + :: instrs) | (CONST0 | CONST1 | CONST2 | CONST3) as cc -> let x, state = State.fresh_var state in let n = @@ -2180,7 +2277,7 @@ and compile infos pc state (instrs : instr list) = infos (pc + 1) state - (Let (x, Prim (Extern "%int_neg", [ Pv y ])) :: instrs) + (Let (x, Prim (Extern ("%int_neg", None), [ Pv y ])) :: instrs) | ADDINT -> let y = State.accu state in let z = State.peek 0 state in @@ -2192,7 +2289,7 @@ and compile infos pc state (instrs : instr list) = infos (pc + 1) (State.pop 1 state) - (Let (x, Prim (Extern "%int_add", [ Pv y; Pv z ])) :: instrs) + (Let (x, Prim (Extern ("%int_add", None), [ Pv y; Pv z ])) :: instrs) | SUBINT -> let y = State.accu state in let z = State.peek 0 state in @@ -2204,7 +2301,7 @@ and compile infos pc state (instrs : instr list) = infos (pc + 1) (State.pop 1 state) - (Let (x, Prim (Extern "%int_sub", [ Pv y; Pv z ])) :: instrs) + (Let (x, Prim (Extern ("%int_sub", None), [ Pv y; Pv z ])) :: instrs) | MULINT -> let y = State.accu state in let z = State.peek 0 state in @@ -2216,7 +2313,7 @@ and compile infos pc state (instrs : instr list) = infos (pc + 1) (State.pop 1 state) - (Let (x, Prim (Extern "%int_mul", [ Pv y; Pv z ])) :: instrs) + (Let (x, Prim (Extern ("%int_mul", None), [ Pv y; Pv z ])) :: instrs) | DIVINT -> let y = State.accu state in let z = State.peek 0 state in @@ -2228,7 +2325,7 @@ and compile infos pc state (instrs : instr list) = infos (pc + 1) (State.pop 1 state) - (Let (x, Prim (Extern "%int_div", [ Pv y; Pv z ])) :: instrs) + (Let (x, Prim (Extern ("%int_div", None), [ Pv y; Pv z ])) :: instrs) | MODINT -> let y = State.accu state in let z = State.peek 0 state in @@ -2240,7 +2337,7 @@ and compile infos pc state (instrs : instr list) = infos (pc + 1) (State.pop 1 state) - (Let (x, Prim (Extern "%int_mod", [ Pv y; Pv z ])) :: instrs) + (Let (x, Prim (Extern ("%int_mod", None), [ Pv y; Pv z ])) :: instrs) | ANDINT -> let y = State.accu state in let z = State.peek 0 state in @@ -2252,7 +2349,7 @@ and compile infos pc state (instrs : instr list) = infos (pc + 1) (State.pop 1 state) - (Let (x, Prim (Extern "%int_and", [ Pv y; Pv z ])) :: instrs) + (Let (x, Prim (Extern ("%int_and", None), [ Pv y; Pv z ])) :: instrs) | ORINT -> let y = State.accu state in let z = State.peek 0 state in @@ -2264,7 +2361,7 @@ and compile infos pc state (instrs : instr list) = infos (pc + 1) (State.pop 1 state) - (Let (x, Prim (Extern "%int_or", [ Pv y; Pv z ])) :: instrs) + (Let (x, Prim (Extern ("%int_or", None), [ Pv y; Pv z ])) :: instrs) | XORINT -> let y = State.accu state in let z = State.peek 0 state in @@ -2276,7 +2373,7 @@ and compile infos pc state (instrs : instr list) = infos (pc + 1) (State.pop 1 state) - (Let (x, Prim (Extern "%int_xor", [ Pv y; Pv z ])) :: instrs) + (Let (x, Prim (Extern ("%int_xor", None), [ Pv y; Pv z ])) :: instrs) | LSLINT -> let y = State.accu state in let z = State.peek 0 state in @@ -2288,7 +2385,7 @@ and compile infos pc state (instrs : instr list) = infos (pc + 1) (State.pop 1 state) - (Let (x, Prim (Extern "%int_lsl", [ Pv y; Pv z ])) :: instrs) + (Let (x, Prim (Extern ("%int_lsl", None), [ Pv y; Pv z ])) :: instrs) | LSRINT -> let y = State.accu state in let z = State.peek 0 state in @@ -2300,7 +2397,7 @@ and compile infos pc state (instrs : instr list) = infos (pc + 1) (State.pop 1 state) - (Let (x, Prim (Extern "%int_lsr", [ Pv y; Pv z ])) :: instrs) + (Let (x, Prim (Extern ("%int_lsr", None), [ Pv y; Pv z ])) :: instrs) | ASRINT -> let y = State.accu state in let z = State.peek 0 state in @@ -2312,7 +2409,7 @@ and compile infos pc state (instrs : instr list) = infos (pc + 1) (State.pop 1 state) - (Let (x, Prim (Extern "%int_asr", [ Pv y; Pv z ])) :: instrs) + (Let (x, Prim (Extern ("%int_asr", None), [ Pv y; Pv z ])) :: instrs) | EQ -> let y = State.accu state in let z = State.peek 0 state in @@ -2403,7 +2500,7 @@ and compile infos pc state (instrs : instr list) = infos (pc + 2) state - (Let (x, Prim (Extern "%int_add", [ Pv y; Pv z ])) + (Let (x, Prim (Extern ("%int_add", None), [ Pv y; Pv z ])) :: Let (z, const32 n) :: instrs) | OFFSETREF -> @@ -2547,7 +2644,7 @@ and compile infos pc state (instrs : instr list) = (Let ( m , Prim - ( Extern "caml_get_cached_method" + ( Extern ("caml_get_cached_method", None) , [ Pv obj; Pc (Int (Targetint.of_int32_exn n)); Pv cache_id ] ) ) :: instrs) | GETDYNMET -> @@ -2569,7 +2666,8 @@ and compile infos pc state (instrs : instr list) = infos (pc + 1) state - (Let (m, Prim (Extern "caml_get_public_method", [ Pv obj; Pv tag ])) :: instrs) + (Let (m, Prim (Extern ("caml_get_public_method", None), [ Pv obj; Pv tag ])) + :: instrs) | GETMETHOD -> let lab = State.accu state in let obj = State.peek 0 state in @@ -2614,7 +2712,8 @@ and compile infos pc state (instrs : instr list) = infos (pc + 1) state - (Let (x, Prim (Extern "%resume", [ Pv stack; Pv func; Pv arg; tail ])) :: instrs) + (Let (x, Prim (Extern ("%resume", None), [ Pv stack; Pv func; Pv arg; tail ])) + :: instrs) | RESUMETERM -> let stack = State.accu state in let func = State.peek 0 state in @@ -2637,7 +2736,8 @@ and compile infos pc state (instrs : instr list) = func Var.print arg; - ( Let (x, Prim (Extern "%resume", [ Pv stack; Pv func; Pv arg; tail ])) :: instrs + ( Let (x, Prim (Extern ("%resume", None), [ Pv stack; Pv func; Pv arg; tail ])) + :: instrs , Return x , state ) | PERFORM -> @@ -2650,7 +2750,7 @@ and compile infos pc state (instrs : instr list) = infos (pc + 1) state - (Let (x, Prim (Extern "%perform", [ Pv eff ])) :: instrs) + (Let (x, Prim (Extern ("%perform", None), [ Pv eff ])) :: instrs) | REPERFORMTERM -> let eff = State.accu state in let stack = State.peek 0 state in @@ -2660,7 +2760,8 @@ and compile infos pc state (instrs : instr list) = if debug_parser () then Format.printf "return reperform(%a, %a)@." Var.print eff Var.print stack; - ( Let (x, Prim (Extern "%reperform", [ Pv eff; Pv stack; Pv tail ])) :: instrs + ( Let (x, Prim (Extern ("%reperform", None), [ Pv eff; Pv stack; Pv tail ])) + :: instrs , Return x , state ) | EVENT | BREAK | FIRST_UNIMPLEMENTED_OP -> assert false) @@ -2713,7 +2814,7 @@ let parse_bytecode code globals hints debug_data = let p = Code.compact p in let body = List.fold_left globals.cache_ids ~init:[] ~f:(fun body cache_id -> - Let (cache_id, Prim (Extern "caml_oo_cache_id", [])) :: body) + Let (cache_id, Prim (Extern ("caml_oo_cache_id", None), [])) :: body) in Code.prepend p body @@ -2915,7 +3016,7 @@ let from_exe :: Let ( Var.fresh () , Prim - ( Extern "caml_js_set" + ( Extern ("caml_js_set", None) , [ Pv gdata ; Pc (NativeString (Code.Native_string.of_string name)) ; Pv c @@ -2923,7 +3024,7 @@ let from_exe :: rem) in if !need_gdata - then Let (gdata, Prim (Extern "caml_get_global_data", [])) :: body + then Let (gdata, Prim (Extern ("caml_get_global_data", None), [])) :: body else body else body in @@ -3026,7 +3127,7 @@ let from_bytes ~prims ~debug (code : bytecode) = in let body = if !need_gdata - then Let (gdata, Prim (Extern "caml_get_global_data", [])) :: body + then Let (gdata, Prim (Extern ("caml_get_global_data", None), [])) :: body else body in prepend p body @@ -3160,7 +3261,7 @@ let from_compilation_units ~includes:_ ~include_cmis ~hints ~debug_data l = Let ( x , Prim - ( Extern "caml_js_get" + ( Extern ("caml_js_get", None) , [ Pv gdata; Pc (NativeString (Native_string.of_string name)) ] ) ) :: l) @@ -3168,7 +3269,7 @@ let from_compilation_units ~includes:_ ~include_cmis ~hints ~debug_data l = in let body = if !need_gdata - then Let (gdata, Prim (Extern "caml_get_global_data", [])) :: body + then Let (gdata, Prim (Extern ("caml_get_global_data", None), [])) :: body else body in let cmis = @@ -3302,19 +3403,19 @@ let predefined_exceptions () = ; Let ( Var.fresh () , Prim - ( Extern "caml_register_global" + ( Extern ("caml_register_global", None) , [ Pc (Int (Targetint.of_int_exn index)); Pv exn; Pv v_name_js ] ) ) ] | `Wasm -> [ Let ( Var.fresh () , Prim - ( Extern "caml_register_global" + ( Extern ("caml_register_global", None) , [ Pc (Int (Targetint.of_int_exn index)); Pv exn; Pv v_name ] ) ) (* Also make the exception available to the generated code *) ; Let ( Var.fresh () - , Prim (Extern "caml_set_global", [ Pc (String name); Pv exn ]) ) + , Prim (Extern ("caml_set_global", None), [ Pc (String name); Pv exn ]) ) ]) |> List.concat in @@ -3362,12 +3463,12 @@ let link_info ~symbols ~primitives ~crcs = :: Let ( Var.fresh () , Prim - ( Extern "caml_js_set" + ( Extern ("caml_js_set", None) , [ Pv gdata; Pc (NativeString (Native_string.of_string name)); Pv c ] ) ) :: rem) in - Let (gdata, Prim (Extern "caml_get_global_data", [])) :: body + Let (gdata, Prim (Extern ("caml_get_global_data", None), [])) :: body in let block = { params = []; body; branch = Stop } in { start = 0; blocks = Addr.Map.singleton 0 block; free_pc = 1 } diff --git a/compiler/lib/partial_cps_analysis.ml b/compiler/lib/partial_cps_analysis.ml index df7eeb8fcd..10f66d2535 100644 --- a/compiler/lib/partial_cps_analysis.ml +++ b/compiler/lib/partial_cps_analysis.ml @@ -93,7 +93,7 @@ let block_deps ~info ~vars ~tail_deps ~deps ~blocks ~fun_name pc = called functions must be in CPS *) if not (double_translate ()) then add_dep deps g x) known) - | Let (x, Prim (Extern ("%perform" | "%reperform" | "%resume"), _)) -> ( + | Let (x, Prim (Extern (("%perform" | "%reperform" | "%resume"), _), _)) -> ( add_var vars x; match fun_name with | None -> () @@ -155,7 +155,7 @@ let cps_needed ~info ~in_mutual_recursion ~rev_deps st x = && (* If a function escapes, it must be in CPS *) Var.ISet.mem info.Global_flow.info_may_escape x - | Expr (Prim (Extern ("%perform" | "%reperform" | "%resume"), _)) -> + | Expr (Prim (Extern (("%perform" | "%reperform" | "%resume"), _), _)) -> (* Effects primitives are in CPS *) true | Expr (Prim _ | Block _ | Constant _ | Field _ | Special _) | Phi _ -> false diff --git a/compiler/lib/pseudo_fs.ml b/compiler/lib/pseudo_fs.ml index b9f5ac442f..669a98e1f9 100644 --- a/compiler/lib/pseudo_fs.ml +++ b/compiler/lib/pseudo_fs.ml @@ -90,7 +90,7 @@ let instr_of_name_content prim ~name ~content = Let ( Var.fresh () , Prim - ( Extern prim + ( Extern (prim, None) , [ Pc (NativeString (Code.Native_string.of_string name)) ; Pc (NativeString (Code.Native_string.of_bytestring content)) ] ) ) @@ -98,7 +98,7 @@ let instr_of_name_content prim ~name ~content = let embed_file ~name ~filename = instr_of_name_content `create_file_extern ~name ~content:(Fs.read_file filename) -let init () = Code.(Let (Var.fresh (), Prim (Extern "caml_fs_init", []))) +let init () = Code.(Let (Var.fresh (), Prim (Extern ("caml_fs_init", None), []))) let f ~prim ~cmis ~files ~paths = let cmi_files, missing_cmis = diff --git a/compiler/lib/pure_fun.ml b/compiler/lib/pure_fun.ml index 153cfc157e..4ba4f9ada2 100644 --- a/compiler/lib/pure_fun.ml +++ b/compiler/lib/pure_fun.ml @@ -39,7 +39,7 @@ let pure_expr pure_funs e = exact && (Var.Set.mem f pure_funs || Shape.State.is_pure_fun f) | Prim (p, _l) -> ( match p with - | Extern f -> Primitive.is_pure f + | Extern (f, _) -> Primitive.is_pure f | _ -> true) let pure_instr pure_funs i = diff --git a/compiler/lib/ref_unboxing.ml b/compiler/lib/ref_unboxing.ml index 0569623d20..a86f2ec373 100644 --- a/compiler/lib/ref_unboxing.ml +++ b/compiler/lib/ref_unboxing.ml @@ -53,7 +53,7 @@ let rewrite_body unboxed_refs body ref_contents subst = , Let ( y , Prim - ( Extern "%int_add" + ( Extern ("%int_add", None) , [ Pv (Var.Map.find x ref_contents) ; Pc (Int (Targetint.of_int_exn n)) ] ) ) diff --git a/compiler/lib/specialize.ml b/compiler/lib/specialize.ml index c379847eb1..85366dc5b1 100644 --- a/compiler/lib/specialize.ml +++ b/compiler/lib/specialize.ml @@ -280,7 +280,9 @@ let optimize_switch_to_cond block x l (opt : switch_to_cond) = block.body @ [ Let ( shifted - , Prim (Extern "%int_sub", [ Pv x; Pc (Int (Targetint.of_int_exn i)) ]) ) + , Prim + ( Extern ("%int_sub", None) + , [ Pv x; Pc (Int (Targetint.of_int_exn i)) ] ) ) ; Let (c, Prim (Ult, [ Pv shifted; Pc (Int (Targetint.of_int_exn (j - i))) ])) ] ; branch = Cond (c, l.(i), l.(j)) diff --git a/compiler/lib/specialize_js.ml b/compiler/lib/specialize_js.ml index dda64b1063..eb38aad1f9 100644 --- a/compiler/lib/specialize_js.ml +++ b/compiler/lib/specialize_js.ml @@ -30,7 +30,7 @@ let debug_stats = Debug.find "stats-debug" let specialize_instr opt_count ~target info i = match i, target with - | Let (x, Prim (Extern "caml_format_int", [ y; z ])), `JavaScript -> ( + | Let (x, Prim (Extern ("caml_format_int", _), [ y; z ])), `JavaScript -> ( (* We can implement the special case where the format string is "%s" in JavaScript in a concise and efficient way with [""+x]. It does not make as much sense in Wasm to have a special case for this. *) @@ -39,9 +39,9 @@ let specialize_instr opt_count ~target info i = incr opt_count; match the_int info z with | Some i -> Let (x, Constant (String (Targetint.to_string i))) - | None -> Let (x, Prim (Extern "%caml_format_int_special", [ z ]))) + | None -> Let (x, Prim (Extern ("%caml_format_int_special", None), [ z ]))) | _ -> i) - | Let (x, Prim (Extern "%caml_format_int_special", [ z ])), `JavaScript -> ( + | Let (x, Prim (Extern ("%caml_format_int_special", _), [ z ])), `JavaScript -> ( match the_int info z with | Some i -> incr opt_count; @@ -51,39 +51,39 @@ let specialize_instr opt_count ~target info i = | ( Let ( x , Prim - ( Extern (("caml_js_var" | "caml_js_expr" | "caml_pure_js_expr") as prim) + ( Extern ((("caml_js_var" | "caml_js_expr" | "caml_pure_js_expr") as prim), _) , [ (Pv _ as y) ] ) ) , _ ) -> ( match the_string_of info y with | Some s -> incr opt_count; - Let (x, Prim (Extern prim, [ Pc (String s) ])) + Let (x, Prim (Extern (prim, None), [ Pc (String s) ])) | _ -> i) - | Let (x, Prim (Extern ("caml_register_named_value" as prim), [ (Pv _ as y); z ])), _ - -> ( + | ( Let (x, Prim (Extern (("caml_register_named_value" as prim), _), [ (Pv _ as y); z ])) + , _ ) -> ( match the_string_of info y with | Some s when Primitive.need_named_value s -> incr opt_count; - Let (x, Prim (Extern prim, [ Pc (String s); z ])) + Let (x, Prim (Extern (prim, None), [ Pc (String s); z ])) | Some _ -> incr opt_count; Let (x, Constant (Int Targetint.zero)) | None -> i) - | Let (x, Prim (Extern "caml_js_call", [ f; o; a ])), _ -> ( + | Let (x, Prim (Extern ("caml_js_call", _), [ f; o; a ])), _ -> ( match the_block_contents_of info a with | Some a -> incr opt_count; let a = Array.map a ~f:(fun x -> Pv x) in - Let (x, Prim (Extern "%caml_js_opt_call", f :: o :: Array.to_list a)) + Let (x, Prim (Extern ("%caml_js_opt_call", None), f :: o :: Array.to_list a)) | _ -> i) - | Let (x, Prim (Extern "caml_js_fun_call", [ f; a ])), _ -> ( + | Let (x, Prim (Extern ("caml_js_fun_call", _), [ f; a ])), _ -> ( match the_block_contents_of info a with | Some a -> incr opt_count; let a = Array.map a ~f:(fun x -> Pv x) in - Let (x, Prim (Extern "%caml_js_opt_fun_call", f :: Array.to_list a)) + Let (x, Prim (Extern ("%caml_js_opt_fun_call", None), f :: Array.to_list a)) | _ -> i) - | Let (x, Prim (Extern "caml_js_meth_call", [ o; m; a ])), _ -> ( + | Let (x, Prim (Extern ("caml_js_meth_call", _), [ o; m; a ])), _ -> ( match the_string_of info m with | Some m when Javascript.is_ident m -> ( match the_block_contents_of info a with @@ -93,20 +93,20 @@ let specialize_instr opt_count ~target info i = Let ( x , Prim - ( Extern "%caml_js_opt_meth_call" + ( Extern ("%caml_js_opt_meth_call", None) , o :: Pc (NativeString (Native_string.of_string m)) :: Array.to_list a ) ) | None -> i) | _ -> i) - | Let (x, Prim (Extern "caml_js_new", [ c; a ])), _ -> ( + | Let (x, Prim (Extern ("caml_js_new", _), [ c; a ])), _ -> ( match the_block_contents_of info a with | Some a -> incr opt_count; let a = Array.map a ~f:(fun x -> Pv x) in - Let (x, Prim (Extern "%caml_js_opt_new", c :: Array.to_list a)) + Let (x, Prim (Extern ("%caml_js_opt_new", None), c :: Array.to_list a)) | _ -> i) - | Let (x, Prim (Extern "caml_js_object", [ a ])), _ -> ( + | Let (x, Prim (Extern ("caml_js_object", _), [ a ])), _ -> ( try let a = match the_def_of info a with @@ -130,40 +130,42 @@ let specialize_instr opt_count ~target info i = | Some _ | None -> raise Exit) in incr opt_count; - Let (x, Prim (Extern "%caml_js_opt_object", List.flatten (Array.to_list a))) + Let + (x, Prim (Extern ("%caml_js_opt_object", None), List.flatten (Array.to_list a))) with Exit -> i) - | Let (x, Prim (Extern "caml_js_get", [ o; (Pv _ as f) ])), _ -> ( + | Let (x, Prim (Extern ("caml_js_get", _), [ o; (Pv _ as f) ])), _ -> ( match the_native_string_of info f with | Some s -> incr opt_count; - Let (x, Prim (Extern "caml_js_get", [ o; Pc (NativeString s) ])) + Let (x, Prim (Extern ("caml_js_get", None), [ o; Pc (NativeString s) ])) | _ -> i) - | Let (x, Prim (Extern "caml_js_set", [ o; (Pv _ as f); v ])), _ -> ( + | Let (x, Prim (Extern ("caml_js_set", _), [ o; (Pv _ as f); v ])), _ -> ( match the_native_string_of info f with | Some s -> incr opt_count; - Let (x, Prim (Extern "caml_js_set", [ o; Pc (NativeString s); v ])) + Let (x, Prim (Extern ("caml_js_set", None), [ o; Pc (NativeString s); v ])) | _ -> i) - | Let (x, Prim (Extern "caml_js_delete", [ o; (Pv _ as f) ])), _ -> ( + | Let (x, Prim (Extern ("caml_js_delete", _), [ o; (Pv _ as f) ])), _ -> ( match the_native_string_of info f with | Some s -> incr opt_count; - Let (x, Prim (Extern "caml_js_delete", [ o; Pc (NativeString s) ])) + Let (x, Prim (Extern ("caml_js_delete", None), [ o; Pc (NativeString s) ])) | _ -> i) - | Let (x, Prim (Extern ("caml_jsstring_of_string" | "caml_js_from_string"), [ y ])), _ - -> ( + | ( Let + (x, Prim (Extern (("caml_jsstring_of_string" | "caml_js_from_string"), _), [ y ])) + , _ ) -> ( match the_string_of info y with | Some s when String.is_valid_utf_8 s -> incr opt_count; Let (x, Constant (NativeString (Native_string.of_string s))) | Some _ | None -> i) - | Let (x, Prim (Extern "caml_jsbytes_of_string", [ y ])), _ -> ( + | Let (x, Prim (Extern ("caml_jsbytes_of_string", _), [ y ])), _ -> ( match the_string_of info y with | Some s -> incr opt_count; Let (x, Constant (NativeString (Native_string.of_bytestring s))) | None -> i) - | Let (x, Prim (Extern "%int_mul", [ y; z ])), `JavaScript -> ( + | Let (x, Prim (Extern ("%int_mul", _), [ y; z ])), `JavaScript -> ( let limit = Targetint.of_int_exn 0x200000 in (* Using * to multiply integers in JavaScript yields a float; and if the float is large enough, some bits can be lost. So, in the general case, @@ -171,22 +173,22 @@ let specialize_instr opt_count ~target info i = match the_int info y, the_int info z with | Some j, _ when Targetint.(abs j < limit) -> incr opt_count; - Let (x, Prim (Extern "%direct_int_mul", [ y; z ])) + Let (x, Prim (Extern ("%direct_int_mul", None), [ y; z ])) | _, Some j when Targetint.(abs j < limit) -> incr opt_count; - Let (x, Prim (Extern "%direct_int_mul", [ y; z ])) + Let (x, Prim (Extern ("%direct_int_mul", None), [ y; z ])) | _ -> i) - | Let (x, Prim (Extern "%int_div", [ y; z ])), _ -> ( + | Let (x, Prim (Extern ("%int_div", _), [ y; z ])), _ -> ( match the_int info z with | Some j when not (Targetint.is_zero j) -> incr opt_count; - Let (x, Prim (Extern "%direct_int_div", [ y; z ])) + Let (x, Prim (Extern ("%direct_int_div", None), [ y; z ])) | _ -> i) - | Let (x, Prim (Extern "%int_mod", [ y; z ])), _ -> ( + | Let (x, Prim (Extern ("%int_mod", _), [ y; z ])), _ -> ( match the_int info z with | Some j when not (Targetint.is_zero j) -> incr opt_count; - Let (x, Prim (Extern "%direct_int_mod", [ y; z ])) + Let (x, Prim (Extern ("%direct_int_mod", None), [ y; z ])) | _ -> i) | _, _ -> i @@ -196,7 +198,7 @@ let recognize_string_length cont = skip_event @@ fun l -> match l with - | (Let (len, Prim (Extern "caml_ml_string_length", [ Pv str ])) as i) :: l -> + | (Let (len, Prim (Extern ("caml_ml_string_length", _), [ Pv str ])) as i) :: l -> cont i ~len ~str l | _ -> None @@ -204,7 +206,7 @@ let recognize_int_add ~x ~y cont = skip_event @@ fun l -> match l with - | (Let (res, Prim (Extern "%int_add", [ Pv x'; Pv y' ])) as i) :: l + | (Let (res, Prim (Extern ("%int_add", _), [ Pv x'; Pv y' ])) as i) :: l when Code.Var.equal x x' && Code.Var.equal y y' -> cont i ~res l | _ -> None @@ -212,7 +214,7 @@ let recognize_create_bytes ~len cont = skip_event @@ fun l -> match l with - | Let (bytes, Prim (Extern "caml_create_bytes", [ Pv len' ])) :: l + | Let (bytes, Prim (Extern ("caml_create_bytes", _), [ Pv len' ])) :: l when Code.Var.equal len len' -> cont ~bytes l | _ -> None @@ -223,8 +225,8 @@ let recognize_blit_string ~str ~bytes ~ofs ~len cont = | Let ( _ , Prim - (Extern "caml_blit_string", [ Pv str'; Pc (Int zero); Pv bytes'; ofs'; Pv len' ]) - ) + ( Extern ("caml_blit_string", _) + , [ Pv str'; Pc (Int zero); Pv bytes'; ofs'; Pv len' ] ) ) :: l when Code.Var.equal str str' && Targetint.is_zero zero @@ -241,7 +243,7 @@ let recognize_string_of_bytes ~bytes cont = skip_event @@ fun l -> match l with - | Let (str, Prim (Extern "caml_string_of_bytes", [ Pv bytes' ])) :: l + | Let (str, Prim (Extern ("caml_string_of_bytes", _), [ Pv bytes' ])) :: l when Code.Var.equal bytes bytes' -> cont ~str l | _ -> None @@ -271,8 +273,8 @@ let specialize_string_concat opt_count l = [ len1 ; len2 ; len3 - ; Let (str, Prim (Extern "caml_string_concat", [ Pv a; Pv b ])) - ; Let (bytes, Prim (Extern "caml_bytes_of_string", [ Pv str ])) + ; Let (str, Prim (Extern ("caml_string_concat", None), [ Pv a; Pv b ])) + ; Let (bytes, Prim (Extern ("caml_bytes_of_string", None), [ Pv str ])) ]) let idx_equal (v1, c1) (v2, c2) = @@ -297,10 +299,11 @@ let specialize_instrs ~target opt_count info l = ( x , Prim ( Extern - (( "caml_array_get" - | "caml_array_get_float" - | "caml_floatarray_get" - | "caml_array_get_addr" ) as prim) + ( (( "caml_array_get" + | "caml_array_get_float" + | "caml_floatarray_get" + | "caml_array_get_addr" ) as prim) + , _ ) , [ Pv y; z ] ) ) -> let idx = match the_int info z with @@ -313,9 +316,9 @@ let specialize_instrs ~target opt_count info l = let instr y = let prim = match prim with - | "caml_array_get" -> Extern "caml_array_unsafe_get" + | "caml_array_get" -> Extern ("caml_array_unsafe_get", None) | "caml_array_get_float" | "caml_floatarray_get" -> - Extern "caml_floatarray_unsafe_get" + Extern ("caml_floatarray_unsafe_get", None) | "caml_array_get_addr" -> Array_get | _ -> assert false in @@ -337,16 +340,19 @@ let specialize_instrs ~target opt_count info l = in let y' = Code.Var.fresh () in incr opt_count; - let acc = instr y' :: Let (y', Prim (Extern check, [ Pv y; z ])) :: acc in + let acc = + instr y' :: Let (y', Prim (Extern (check, None), [ Pv y; z ])) :: acc + in aux info ((y, idx) :: checks) r acc | Let ( x , Prim ( Extern - (( "caml_array_set" - | "caml_array_set_float" - | "caml_floatarray_set" - | "caml_array_set_addr" ) as prim) + ( (( "caml_array_set" + | "caml_array_set_float" + | "caml_floatarray_set" + | "caml_array_set_addr" ) as prim) + , _ ) , [ Pv y; z; t ] ) ) -> let idx = match the_int info z with @@ -365,7 +371,7 @@ let specialize_instrs ~target opt_count info l = | "caml_array_set_addr" -> "caml_array_unsafe_set_addr" | _ -> assert false in - Let (x, Prim (Extern prim, [ Pv y; z; t ])) + Let (x, Prim (Extern (prim, None), [ Pv y; z; t ])) in if List.mem ~eq:idx_equal (y, idx) checks then ( @@ -382,7 +388,9 @@ let specialize_instrs ~target opt_count info l = | _ -> assert false in let y' = Code.Var.fresh () in - let acc = instr y' :: Let (y', Prim (Extern check, [ Pv y; z ])) :: acc in + let acc = + instr y' :: Let (y', Prim (Extern (check, None), [ Pv y; z ])) :: acc + in incr opt_count; aux info ((y, idx) :: checks) r acc | _ -> @@ -432,13 +440,14 @@ let f_once_before p = ( x , (Prim ( Extern - ( "caml_array_set" - | "caml_array_unsafe_set" - | "caml_array_set_float" - | "caml_floatarray_set" - | "caml_array_set_addr" - | "caml_array_unsafe_set_float" - | "caml_floatarray_unsafe_set" ) + ( ( "caml_array_set" + | "caml_array_unsafe_set" + | "caml_array_set_float" + | "caml_floatarray_set" + | "caml_array_set_addr" + | "caml_array_unsafe_set_float" + | "caml_floatarray_unsafe_set" ) + , _ ) , [ _; _; _ ] ) as p) ) -> let x' = Code.Var.fork x in let acc = Let (x', p) :: Let (x, Constant (Int Targetint.zero)) :: acc in @@ -470,9 +479,9 @@ let f_once_after p = let block = Addr.Map.find pc p.blocks in match block with | { body = - ( [ Let (y, Prim (Extern prim, args)) ] - | [ Event _; Let (y, Prim (Extern prim, args)) ] - | [ Event _; Let (y, Prim (Extern prim, args)); Event _ ] ) + ( [ Let (y, Prim (Extern (prim, _), args)) ] + | [ Event _; Let (y, Prim (Extern (prim, _), args)) ] + | [ Event _; Let (y, Prim (Extern (prim, _), args)); Event _ ] ) ; branch = Return y' ; params = [] } -> From 9a1a90b26810a8e717277bc7a12863f01c248d78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Vouillon?= Date: Fri, 18 Jul 2025 14:47:38 +0200 Subject: [PATCH 08/14] Optimize array length --- compiler/lib-wasm/generate.ml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/compiler/lib-wasm/generate.ml b/compiler/lib-wasm/generate.ml index 7aa959fb97..677c2b5a8c 100644 --- a/compiler/lib-wasm/generate.ml +++ b/compiler/lib-wasm/generate.ml @@ -1542,7 +1542,17 @@ module Generate (Target : Target_sig.S) = struct in loop [] l | IsInt, [ x ] -> Value.is_int x - | Vectlength _, [ x ] -> Memory.gen_array_length x + | Vectlength kind, [ x ] -> ( + match kind with + | Generic -> Memory.gen_array_length x + | Value -> Memory.array_length x + | Float -> + (* We use a generic array for empty float arrays. *) + let y = Var.fresh () in + let* cond = Memory.check_is_float_array (tee y x) in + let* ift = Memory.float_array_length (load y) in + let* iff = Arith.const 0l in + return (W.IfExpr (I32, cond, ift, iff))) | (Not | Lt | Le | Eq | Neq | Ult | Array_get | IsInt | Vectlength _), _ -> assert false)) From d3b4a585861a228d2e262e53769d91b92a1fe78f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Vouillon?= Date: Fri, 18 Jul 2025 19:06:20 +0200 Subject: [PATCH 09/14] Wasm: specialization of bigarray accesses --- compiler/lib-wasm/gc_target.ml | 26 +++++++---- compiler/lib-wasm/generate.ml | 77 +++++++++++++++++---------------- compiler/lib-wasm/target_sig.ml | 10 +++-- compiler/lib-wasm/typing.ml | 53 ++++++++--------------- compiler/lib-wasm/typing.mli | 30 +------------ 5 files changed, 82 insertions(+), 114 deletions(-) diff --git a/compiler/lib-wasm/gc_target.ml b/compiler/lib-wasm/gc_target.ml index df63676c68..2d133443d9 100644 --- a/compiler/lib-wasm/gc_target.ml +++ b/compiler/lib-wasm/gc_target.ml @@ -1413,7 +1413,7 @@ module Bigarray = struct (Memory.wasm_struct_get ty (Memory.wasm_cast ty a) 3) (Arith.const (Int32.of_int n)) - let get_at_offset ~(kind : Typing.Bigarray.kind) a i = + let get_at_offset ~(kind : Optimization_hint.Bigarray.kind) a i = let name, (typ : Wasm_ast.value_type), size, box = match kind with | Float32 -> @@ -1500,7 +1500,7 @@ module Bigarray = struct let set_at_offset ~kind a i v = let name, (typ : Wasm_ast.value_type), size, unbox = - match (kind : Typing.Bigarray.kind) with + match (kind : Optimization_hint.Bigarray.kind) with | Float32 -> ( "dv_set_f32" , F32 @@ -1585,7 +1585,12 @@ module Bigarray = struct let* y = unbox (Memory.wasm_array_get ~ty v (Arith.const 1l)) in instr (W.CallInstr (f, [ ta; ofs'; y; W.GlobalGet little_endian ])) - let offset ~bound_error_index ~(layout : Typing.Bigarray.layout) ta ~indices = + let offset + ~bound_error_index + ~unsafe + ~(layout : Optimization_hint.Bigarray.layout) + ta + ~indices = let l = List.mapi ~f:(fun pos i -> @@ -1598,8 +1603,11 @@ module Bigarray = struct let dim = Code.Var.fresh () in ( (let* () = store ~typ:I32 i' i in let* () = store ~typ:I32 dim (dimension pos ta) in - let* cond = Arith.uge (load i') (load dim) in - instr (W.Br_if (bound_error_index, cond))) + if unsafe + then return () + else + let* cond = Arith.uge (load i') (load dim) in + instr (W.Br_if (bound_error_index, cond))) , i' , dim )) indices @@ -1622,12 +1630,12 @@ module Bigarray = struct rem | [] -> return (), Arith.const 0l - let get ~bound_error_index ~kind ~layout ta ~indices = - let instrs, ofs = offset ~bound_error_index ~layout ta ~indices in + let get ~bound_error_index ~unsafe ~kind ~layout ta ~indices = + let instrs, ofs = offset ~bound_error_index ~unsafe ~layout ta ~indices in seq instrs (get_at_offset ~kind ta ofs) - let set ~bound_error_index ~kind ~layout ta ~indices v = - let instrs, ofs = offset ~bound_error_index ~layout ta ~indices in + let set ~bound_error_index ~unsafe ~kind ~layout ta ~indices v = + let instrs, ofs = offset ~bound_error_index ~unsafe ~layout ta ~indices in seq (let* () = instrs in set_at_offset ~kind ta ofs v) diff --git a/compiler/lib-wasm/generate.ml b/compiler/lib-wasm/generate.ml index 677c2b5a8c..ee76d2b203 100644 --- a/compiler/lib-wasm/generate.ml +++ b/compiler/lib-wasm/generate.ml @@ -245,7 +245,7 @@ module Generate (Target : Target_sig.S) = struct let h = String.Hashtbl.create 128 in List.iter ~f:(fun (nm, k, f) -> - String.Hashtbl.add h nm (k, fun ctx _ l -> f (fun x -> transl_prim_arg ctx x) l)) + String.Hashtbl.add h nm (k, fun ctx _ _ l -> f (fun x -> transl_prim_arg ctx x) l)) internal_primitives; h @@ -260,26 +260,26 @@ module Generate (Target : Target_sig.S) = struct (List.length l)) let register_un_prim name k ?typ f = - register_prim name k (fun ctx _ l -> + register_prim name k (fun ctx _ _ l -> match l with | [ x ] -> f (transl_prim_arg ctx ?typ x) | l -> invalid_arity name l ~expected:1) let register_bin_prim name k ?tx ?ty f = - register_prim name k (fun ctx _ l -> + register_prim name k (fun ctx _ _ l -> match l with | [ x; y ] -> f (transl_prim_arg ctx ?typ:tx x) (transl_prim_arg ctx ?typ:ty y) | _ -> invalid_arity name l ~expected:2) let register_bin_prim_ctx name ?tx ?ty f = - register_prim name `Mutator (fun ctx context l -> + register_prim name `Mutator (fun ctx context _ l -> match l with | [ x; y ] -> f context (transl_prim_arg ctx ?typ:tx x) (transl_prim_arg ctx ?typ:ty y) | _ -> invalid_arity name l ~expected:2) let register_tern_prim name ?ty ?tz f = - register_prim name `Mutator (fun ctx _ l -> + register_prim name `Mutator (fun ctx _ _ l -> match l with | [ x; y; z ] -> f @@ -289,7 +289,7 @@ module Generate (Target : Target_sig.S) = struct | _ -> invalid_arity name l ~expected:3) let register_tern_prim_ctx name ?ty ?tz f = - register_prim name `Mutator (fun ctx context l -> + register_prim name `Mutator (fun ctx context _ l -> match l with | [ x; y; z ] -> f @@ -300,7 +300,7 @@ module Generate (Target : Target_sig.S) = struct | _ -> invalid_arity name l ~expected:3) let register_comparison name cmp_int cmp_boxed_int cmp_float = - register_prim name `Mutator (fun ctx _ l -> + register_prim name `Mutator (fun ctx _ _ l -> match l with | [ x; y ] -> ( match get_type ctx x, get_type ctx y with @@ -1133,7 +1133,7 @@ module Generate (Target : Target_sig.S) = struct ~tx:(Int Normalized) ~ty:(Int Normalized) (fun i j -> Arith.((j < i) - (i < j))); - register_prim "%js_array" `Pure (fun ctx _ l -> + register_prim "%js_array" `Pure (fun ctx _ _ l -> Memory.allocate ~tag:0 (expression_list (fun x -> transl_prim_arg ctx x) l)); register_comparison "caml_greaterthan" @@ -1165,7 +1165,7 @@ module Generate (Target : Target_sig.S) = struct (fun ctx x y -> translate_int_equality ctx ~negate:true x y) Ne Ne; - register_prim "caml_compare" `Mutator (fun ctx _ l -> + register_prim "caml_compare" `Mutator (fun ctx _ _ l -> match l with | [ x; y ] -> ( match get_type ctx x, get_type ctx y with @@ -1218,7 +1218,7 @@ module Generate (Target : Target_sig.S) = struct | Pv indices -> Some (indices, ctx.global_flow_info.info_defs.(Var.idx indices)) | Pc _ -> None ) with - | Bigarray { kind; layout }, Some (indices, Expr (Block (_, l, _, _))) -> + | Bigarray { kind; layout; _ }, Some (indices, Expr (Block (_, l, _, _))) -> Some ( kind , layout @@ -1229,22 +1229,24 @@ module Generate (Target : Target_sig.S) = struct (Array.to_list l) ) | _, None | _, Some (_, (Expr _ | Phi _)) -> None in - let caml_ba_get ~ctx ~context ~kind ~layout ta indices = + let caml_ba_get ~ctx ~context ~unsafe ~kind ~layout ta indices = let ta' = transl_prim_arg ctx ta in Bigarray.get ~bound_error_index:(label_index context bound_error_pc) + ~unsafe ~kind ~layout ta' ~indices in - let caml_ba_get_n ~ctx ~context ta indices = - match get_type ctx ta with - | Bigarray { kind; layout } -> + let caml_ba_get_n ~ctx ~context ~hint ta indices = + match hint, get_type ctx ta with + | Some (Optimization_hint.Hint_bigarray { unsafe; kind; layout }), _ + | _, Bigarray { unsafe; kind; layout } -> let indices = List.map ~f:(fun i -> transl_prim_arg ctx ~typ:(Int Normalized) i) indices in - caml_ba_get ~ctx ~context ~kind ~layout ta indices + caml_ba_get ~ctx ~context ~unsafe ~kind ~layout ta indices | _ -> let n = List.length indices in let* f = @@ -1256,24 +1258,24 @@ module Generate (Target : Target_sig.S) = struct let* indices' = expression_list (transl_prim_arg ctx) indices in return (W.Call (f, ta' :: indices')) in - register_prim "caml_ba_get_1" `Mutator (fun ctx context l -> + register_prim "caml_ba_get_1" `Mutator (fun ctx context hint l -> match l with - | [ ta; i ] -> caml_ba_get_n ~ctx ~context ta [ i ] + | [ ta; i ] -> caml_ba_get_n ~ctx ~context ~hint ta [ i ] | _ -> invalid_arity "caml_ba_get_1" l ~expected:2); - register_prim "caml_ba_get_2" `Mutator (fun ctx context l -> + register_prim "caml_ba_get_2" `Mutator (fun ctx context hint l -> match l with - | [ ta; i; j ] -> caml_ba_get_n ~ctx ~context ta [ i; j ] + | [ ta; i; j ] -> caml_ba_get_n ~ctx ~context ~hint ta [ i; j ] | _ -> invalid_arity "caml_ba_get_2" l ~expected:3); - register_prim "caml_ba_get_3" `Mutator (fun ctx context l -> + register_prim "caml_ba_get_3" `Mutator (fun ctx context hint l -> match l with - | [ ta; i; j; k ] -> caml_ba_get_n ~ctx ~context ta [ i; j; k ] + | [ ta; i; j; k ] -> caml_ba_get_n ~ctx ~context ~hint ta [ i; j; k ] | _ -> invalid_arity "caml_ba_get_3" l ~expected:4); - register_prim "caml_ba_get_generic" `Mutator (fun ctx context l -> + register_prim "caml_ba_get_generic" `Mutator (fun ctx context _ l -> match l with | [ ta; indices ] -> ( match bigarray_generic_access ~ctx ta indices with | Some (kind, layout, indices) -> - caml_ba_get ~ctx ~context ~kind ~layout ta indices + caml_ba_get ~ctx ~context ~unsafe:false ~kind ~layout ta indices | _ -> let* f = register_import @@ -1295,13 +1297,14 @@ module Generate (Target : Target_sig.S) = struct ~indices v' in - let caml_ba_set_n ~ctx ~context ta indices v = - match get_type ctx ta with - | Bigarray { kind; layout } -> + let caml_ba_set_n ~ctx ~context ~hint ta indices v = + match hint, get_type ctx ta with + | Some (Optimization_hint.Hint_bigarray { unsafe; kind; layout }), _ + | _, Bigarray { unsafe; kind; layout } -> let indices = List.map ~f:(fun i -> transl_prim_arg ctx ~typ:(Int Normalized) i) indices in - caml_ba_set ~ctx ~context ~kind ~layout ta indices v + caml_ba_set ~ctx ~context ~unsafe ~kind ~layout ta indices v | _ -> let n = List.length indices in let* f = @@ -1314,24 +1317,24 @@ module Generate (Target : Target_sig.S) = struct let* v' = transl_prim_arg ctx v in return (W.Call (f, ta' :: (indices' @ [ v' ]))) in - register_prim "caml_ba_set_1" `Mutator (fun ctx context l -> + register_prim "caml_ba_set_1" `Mutator (fun ctx context hint l -> match l with - | [ ta; i; v ] -> caml_ba_set_n ~ctx ~context ta [ i ] v + | [ ta; i; v ] -> caml_ba_set_n ~ctx ~context ~hint ta [ i ] v | _ -> invalid_arity "caml_ba_set_1" l ~expected:3); - register_prim "caml_ba_set_2" `Mutator (fun ctx context l -> + register_prim "caml_ba_set_2" `Mutator (fun ctx context hint l -> match l with - | [ ta; i; j; v ] -> caml_ba_set_n ~ctx ~context ta [ i; j ] v + | [ ta; i; j; v ] -> caml_ba_set_n ~ctx ~context ~hint ta [ i; j ] v | _ -> invalid_arity "caml_ba_set_2" l ~expected:4); - register_prim "caml_ba_set_3" `Mutator (fun ctx context l -> + register_prim "caml_ba_set_3" `Mutator (fun ctx context hint l -> match l with - | [ ta; i; j; k; v ] -> caml_ba_set_n ~ctx ~context ta [ i; j; k ] v + | [ ta; i; j; k; v ] -> caml_ba_set_n ~ctx ~context ~hint ta [ i; j; k ] v | _ -> invalid_arity "caml_ba_set_3" l ~expected:5); - register_prim "caml_ba_set_generic" `Mutator (fun ctx context l -> + register_prim "caml_ba_set_generic" `Mutator (fun ctx context _ l -> match l with | [ ta; indices; v ] -> ( match bigarray_generic_access ~ctx ta indices with | Some (kind, layout, indices) -> - caml_ba_set ~ctx ~context ~kind ~layout ta indices v + caml_ba_set ~ctx ~context ~unsafe:false ~kind ~layout ta indices v | _ -> let* f = register_import @@ -1497,8 +1500,8 @@ module Generate (Target : Target_sig.S) = struct (transl_prim_arg ctx ~typ:(Int Normalized) y) | Prim (p, l) -> ( match p with - | Extern (name, _) when String.Hashtbl.mem internal_primitives name -> - snd (String.Hashtbl.find internal_primitives name) ctx context l + | Extern (name, hint) when String.Hashtbl.mem internal_primitives name -> + snd (String.Hashtbl.find internal_primitives name) ctx context hint l |> box_number_if_needed ctx x | Extern (name, _) when String.Hashtbl.mem specialized_primitives name -> let ((_, arg_typ, _) as typ) = diff --git a/compiler/lib-wasm/target_sig.ml b/compiler/lib-wasm/target_sig.ml index a0fc5e8ce9..8e194a4187 100644 --- a/compiler/lib-wasm/target_sig.ml +++ b/compiler/lib-wasm/target_sig.ml @@ -257,16 +257,18 @@ module type S = sig module Bigarray : sig val get : bound_error_index:int - -> kind:Typing.Bigarray.kind - -> layout:Typing.Bigarray.layout + -> unsafe:bool + -> kind:Optimization_hint.Bigarray.kind + -> layout:Optimization_hint.Bigarray.layout -> expression -> indices:expression list -> expression val set : bound_error_index:int - -> kind:Typing.Bigarray.kind - -> layout:Typing.Bigarray.layout + -> unsafe:bool + -> kind:Optimization_hint.Bigarray.kind + -> layout:Optimization_hint.Bigarray.layout -> expression -> indices:expression list -> expression diff --git a/compiler/lib-wasm/typing.ml b/compiler/lib-wasm/typing.ml index 0fd29abffc..bb4acf20bc 100644 --- a/compiler/lib-wasm/typing.ml +++ b/compiler/lib-wasm/typing.ml @@ -45,32 +45,9 @@ type boxed_status = | Unboxed module Bigarray = struct - type kind = - | Float16 - | Float32 - | Float64 - | Int8_signed - | Int8_unsigned - | Int16_signed - | Int16_unsigned - | Int32 - | Int64 - | Int - | Nativeint - | Complex32 - | Complex64 - - type layout = - | C - | Fortran - - type t = - { kind : kind - ; layout : layout - } - - let make ~kind ~layout = - { kind = + let make ~kind ~layout : Optimization_hint.Bigarray.t = + { unsafe = false + ; kind = (match kind with | 0 -> Float32 | 1 -> Float64 @@ -94,7 +71,7 @@ module Bigarray = struct | _ -> assert false) } - let print f { kind; layout } = + let print f { Optimization_hint.Bigarray.kind; layout; _ } = Format.fprintf f "bigarray{%s,%s}" @@ -116,8 +93,10 @@ module Bigarray = struct | C -> "C" | Fortran -> "Fortran") - let equal { kind; layout } { kind = kind'; layout = layout' } = - phys_equal kind kind' && phys_equal layout layout' + let equal + { Optimization_hint.Bigarray.unsafe; kind; layout } + { Optimization_hint.Bigarray.unsafe = unsafe'; kind = kind'; layout = layout' } = + Bool.equal unsafe unsafe' && phys_equal kind kind' && phys_equal layout layout' end type typ = @@ -128,7 +107,7 @@ type typ = (** This value is a block or an integer; if it's an integer, an overapproximation of the possible values of each of its fields is given by the array of types *) - | Bigarray of Bigarray.t + | Bigarray of Optimization_hint.Bigarray.t | Bot module Domain = struct @@ -298,7 +277,7 @@ let arg_type ~approx arg = | Pc c -> constant_type c | Pv x -> Var.Tbl.get approx x -let bigarray_element_type (kind : Bigarray.kind) = +let bigarray_element_type (kind : Optimization_hint.Bigarray.kind) = match kind with | Float16 | Float32 | Float64 -> Number (Float, Unboxed) | Int8_signed | Int8_unsigned | Int16_signed | Int16_unsigned -> Int Normalized @@ -314,7 +293,7 @@ let bigarray_type ~approx ba = | Bigarray { kind; _ } -> bigarray_element_type kind | _ -> Top -let prim_type ~st ~approx prim args = +let prim_type ~st ~approx prim hint args = match prim with | "%int_add" | "%int_sub" | "%int_mul" | "%direct_int_mul" | "%int_lsl" | "%int_neg" -> Int Unnormalized @@ -483,9 +462,11 @@ let prim_type ~st ~approx prim args = ~layout:(Targetint.to_int_exn layout)) | _ -> Top) | "caml_ba_get_1" | "caml_ba_get_2" | "caml_ba_get_3" -> ( - match args with - | ba :: _ -> bigarray_type ~approx ba - | [] -> Top) + match hint, args with + | Some (Optimization_hint.Hint_bigarray { kind; _ }), _ -> + bigarray_element_type kind + | _, ba :: _ -> bigarray_type ~approx ba + | _, [] -> Top) | "caml_ba_get_generic" -> ( match args with | ba :: Pv indices :: _ -> ( @@ -553,7 +534,7 @@ let propagate st approx x : Domain.t = | Prim (Array_get, _) -> Top | Prim ((Vectlength _ | Not | IsInt | Eq | Neq | Lt | Le | Ult), _) -> Int Normalized - | Prim (Extern (prim, _), args) -> prim_type ~st ~approx prim args + | Prim (Extern (prim, hint), args) -> prim_type ~st ~approx prim hint args | Special _ -> Top | Apply { f; args; _ } -> ( match Var.Tbl.get st.global_flow_info.info_approximation f with diff --git a/compiler/lib-wasm/typing.mli b/compiler/lib-wasm/typing.mli index 5ea4e7da51..174e70c131 100644 --- a/compiler/lib-wasm/typing.mli +++ b/compiler/lib-wasm/typing.mli @@ -15,45 +15,19 @@ type boxed_status = | Boxed | Unboxed -module Bigarray : sig - type kind = - | Float16 - | Float32 - | Float64 - | Int8_signed - | Int8_unsigned - | Int16_signed - | Int16_unsigned - | Int32 - | Int64 - | Int - | Nativeint - | Complex32 - | Complex64 - - type layout = - | C - | Fortran - - type t = - { kind : kind - ; layout : layout - } -end - type typ = | Top | Int of Integer.kind | Number of boxed_number * boxed_status | Tuple of typ array - | Bigarray of Bigarray.t + | Bigarray of Optimization_hint.Bigarray.t | Bot val constant_type : Code.constant -> typ val can_unbox_parameters : Call_graph_analysis.t -> Code.Var.t -> bool -val bigarray_element_type : Bigarray.kind -> typ +val bigarray_element_type : Optimization_hint.Bigarray.kind -> typ type t From 9db6879fb76deae5be3d9b513da74e29dd0123d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Vouillon?= Date: Wed, 23 Apr 2025 18:33:40 +0200 Subject: [PATCH 10/14] Wasm: specialization of number comparisons --- compiler/lib-wasm/generate.ml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/lib-wasm/generate.ml b/compiler/lib-wasm/generate.ml index ee76d2b203..403695e207 100644 --- a/compiler/lib-wasm/generate.ml +++ b/compiler/lib-wasm/generate.ml @@ -300,24 +300,25 @@ module Generate (Target : Target_sig.S) = struct | _ -> invalid_arity name l ~expected:3) let register_comparison name cmp_int cmp_boxed_int cmp_float = - register_prim name `Mutator (fun ctx _ _ l -> + register_prim name `Mutator (fun ctx _ (hint : Optimization_hint.t option) l -> match l with | [ x; y ] -> ( - match get_type ctx x, get_type ctx y with - | Int _, Int _ -> cmp_int ctx x y - | Number (Int32, _), Number (Int32, _) -> + match hint, get_type ctx x, get_type ctx y with + | _, Int _, Int _ -> cmp_int ctx x y + | Some (Hint_int Int32), _, _ | _, Number (Int32, _), Number (Int32, _) -> let x = transl_prim_arg ctx ~typ:(Number (Int32, Unboxed)) x in let y = transl_prim_arg ctx ~typ:(Number (Int32, Unboxed)) y in int32_bin_op cmp_boxed_int x y - | Number (Nativeint, _), Number (Nativeint, _) -> + | Some (Hint_int Nativeint), _, _ + | _, Number (Nativeint, _), Number (Nativeint, _) -> let x = transl_prim_arg ctx ~typ:(Number (Nativeint, Unboxed)) x in let y = transl_prim_arg ctx ~typ:(Number (Nativeint, Unboxed)) y in nativeint_bin_op cmp_boxed_int x y - | Number (Int64, _), Number (Int64, _) -> + | Some (Hint_int Int64), _, _ | _, Number (Int64, _), Number (Int64, _) -> let x = transl_prim_arg ctx ~typ:(Number (Int64, Unboxed)) x in let y = transl_prim_arg ctx ~typ:(Number (Int64, Unboxed)) y in int64_bin_op cmp_boxed_int x y - | Number (Float, _), Number (Float, _) -> + | _, Number (Float, _), Number (Float, _) -> let x = transl_prim_arg ctx ~typ:(Number (Float, Unboxed)) x in let y = transl_prim_arg ctx ~typ:(Number (Float, Unboxed)) y in float_bin_op cmp_float x y From c8126ca210363f0a6ccdc7825b78c4032e32a616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Vouillon?= Date: Fri, 18 Jul 2025 19:48:04 +0200 Subject: [PATCH 11/14] Benchmarks: use an OCaml compiler that produces hints --- bench.Dockerfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bench.Dockerfile b/bench.Dockerfile index e7712c34eb..824a6fe540 100644 --- a/bench.Dockerfile +++ b/bench.Dockerfile @@ -9,6 +9,10 @@ RUN sudo ln -sf /usr/bin/opam-2.3 /usr/bin/opam RUN opam remote add origin https://github.com/ocaml/opam-repository.git \ && opam update +# Switch to patched OCaml compiler +RUN opam switch create hints ocaml-variants.5.3.1+trunk \ + && opam pin ocaml-variants https://github.com/hhugo/ocaml.git#optimization-hints + # Install node ENV NODE_VERSION=v24.0.0-v8-canary2025030537242e55ac ENV NODE=node-$NODE_VERSION-linux-x64 From d3e9716e772b20438a19bd06f3893756a246e912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Vouillon?= Date: Wed, 20 Aug 2025 17:25:40 +0200 Subject: [PATCH 12/14] Update Wasm_of_ocaml CI --- .github/workflows/wasm_of_ocaml.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/wasm_of_ocaml.yml b/.github/workflows/wasm_of_ocaml.yml index c964c54c30..aacb34f536 100644 --- a/.github/workflows/wasm_of_ocaml.yml +++ b/.github/workflows/wasm_of_ocaml.yml @@ -46,6 +46,12 @@ jobs: # Jane Street tests disabled for now (basement only works on Linux) jane_street_tests: false all_jane_street_tests: false + - os: ubuntu-latest + os-name: Ubuntu + ocaml-compiler: "ocaml-variants.5.3.1+trunk" + separate_compilation: true + jane_street_tests: true + all_jane_street_tests: true - os: ubuntu-latest os-name: Ubuntu ocaml-compiler: "5.3" @@ -99,6 +105,10 @@ jobs: with: ocaml-compiler: ${{ matrix.ocaml-compiler }} + - name: patch compiler + if: matrix.ocaml-compiler == 'ocaml-variants.5.3.1+trunk' + run: opam pin ocaml-variants https://github.com/hhugo/ocaml.git#optimization-hints + - name: Set-up Binaryen uses: Aandreba/setup-binaryen@v1.0.0 with: From db559d8bfccd64be839226da63af9f812b4f4546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Vouillon?= Date: Tue, 16 Sep 2025 22:10:15 +0200 Subject: [PATCH 13/14] FIX --- compiler/lib-wasm/typing.ml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/lib-wasm/typing.ml b/compiler/lib-wasm/typing.ml index bb4acf20bc..6fb6dc227d 100644 --- a/compiler/lib-wasm/typing.ml +++ b/compiler/lib-wasm/typing.ml @@ -325,16 +325,16 @@ let prim_type ~st ~approx prim hint args = | "caml_int64_bswap" -> Number (Int64, Unboxed) | "caml_int32_compare" | "caml_nativeint_compare" | "caml_int64_compare" -> Int Normalized - | "caml_string_get16" -> Int Normalized - | "caml_string_get32" -> Number (Int32, Unboxed) - | "caml_string_get64" -> Number (Int64, Unboxed) - | "caml_bytes_get16" -> Int Normalized - | "caml_bytes_get32" -> Number (Int32, Unboxed) - | "caml_bytes_get64" -> Number (Int64, Unboxed) + | "caml_string_get16" | "caml_string_get16u" -> Int Normalized + | "caml_string_get32" | "caml_string_get32u" -> Number (Int32, Unboxed) + | "caml_string_get64" | "caml_string_get64u" -> Number (Int64, Unboxed) + | "caml_bytes_get16" | "caml_bytes_get16u" -> Int Normalized + | "caml_bytes_get32" | "caml_bytes_get32u" -> Number (Int32, Unboxed) + | "caml_bytes_get64" | "caml_bytes_get64u" -> Number (Int64, Unboxed) | "caml_lxm_next" -> Number (Int64, Unboxed) - | "caml_ba_uint8_get16" -> Int Normalized - | "caml_ba_uint8_get32" -> Number (Int32, Unboxed) - | "caml_ba_uint8_get64" -> Number (Int64, Unboxed) + | "caml_ba_uint8_get16" | "caml_ba_uint8_get16u" -> Int Normalized + | "caml_ba_uint8_get32" | "caml_ba_uint8_get32u" -> Number (Int32, Unboxed) + | "caml_ba_uint8_get64" | "caml_ba_uint8_get64u" -> Number (Int64, Unboxed) | "caml_nextafter_float" -> Number (Float, Unboxed) | "caml_classify_float" -> Int Ref | "caml_ldexp_float" | "caml_erf_float" | "caml_erfc_float" -> Number (Float, Unboxed) From e2ac1200b1c925d97c2e4c2e0cb9116b13efaf59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Vouillon?= Date: Tue, 16 Sep 2025 23:09:59 +0200 Subject: [PATCH 14/14] FIX --- benchmarks/benchmark-others/bigarrays/bench.ml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/benchmarks/benchmark-others/bigarrays/bench.ml b/benchmarks/benchmark-others/bigarrays/bench.ml index 6107c0661c..9d8550cdc0 100644 --- a/benchmarks/benchmark-others/bigarrays/bench.ml +++ b/benchmarks/benchmark-others/bigarrays/bench.ml @@ -4,7 +4,10 @@ let deltay = 40_000. /. 360. /. 3600. *. 1000. let deltax = deltay *. cos (44. *. pi /. 180.) -let precompute tile_height tile_width tile = +let precompute + tile_height + tile_width + (tile : (float, Bigarray.float32_elt, Bigarray.c_layout) Bigarray.Array2.t) = let normals = Bigarray.(Array3.create Int8_signed C_layout) (tile_height - 2) (tile_width - 2) 3 in