diff --git a/CHANGES.md b/CHANGES.md index 3490684715..5a7341fb72 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,10 @@ ## Features/Changes * Compiler: exit-loop-early in more cases (#2077) +* Compiler/wasm: omit code pointer from closures when not used (#2059) + +## Bug fixes +* Runtime/wasm: add back legacy function caml_string_of_array (#2081) # 6.1.1 (2025-07-07) - Lille diff --git a/compiler/lib-wasm/call_graph_analysis.ml b/compiler/lib-wasm/call_graph_analysis.ml new file mode 100644 index 0000000000..36666af462 --- /dev/null +++ b/compiler/lib-wasm/call_graph_analysis.ml @@ -0,0 +1,86 @@ +open! Stdlib +open Code + +let debug = Debug.find "call-graph" + +let times = Debug.find "times" + +let block_deps ~info ~non_escaping ~ambiguous ~blocks pc = + let block = Addr.Map.find pc blocks in + List.iter block.body ~f:(fun i -> + match i with + | Let (_, Apply { f; _ }) -> ( + try + match Var.Tbl.get info.Global_flow.info_approximation f with + | Top -> () + | Values { known; others } -> + if others || Var.Set.cardinal known > 1 + then Var.Set.iter (fun x -> Var.Hashtbl.replace ambiguous x ()) known; + if debug () + then + Format.eprintf + "CALL others:%b known:%d@." + others + (Var.Set.cardinal known) + with Invalid_argument _ -> ()) + | Let (x, Closure _) -> ( + match Var.Tbl.get info.Global_flow.info_approximation x with + | Top -> () + | Values { known; others } -> + if Var.Set.cardinal known = 1 && (not others) && Var.Set.mem x known + then ( + let may_escape = Var.ISet.mem info.Global_flow.info_may_escape x in + if debug () then Format.eprintf "CLOSURE may-escape:%b@." may_escape; + if not may_escape then Var.Hashtbl.replace non_escaping x ())) + | Let (_, (Prim _ | Block _ | Constant _ | Field _ | Special _)) + | Event _ | Assign _ | Set_field _ | Offset_ref _ | Array_set _ -> ()) + +type t = + { unambiguous_non_escaping : unit Var.Hashtbl.t + ; has_tail_calls : unit Var.Hashtbl.t + } + +let direct_calls_only info f = + Config.Flag.optcall () && Var.Hashtbl.mem info.unambiguous_non_escaping f + +let has_tail_calls info f = Var.Hashtbl.mem info.has_tail_calls f + +let f p info = + let t = Timer.make () in + let non_escaping = Var.Hashtbl.create 128 in + let ambiguous = Var.Hashtbl.create 128 in + let has_tail_calls = Var.Hashtbl.create 128 in + fold_closures + p + (fun name_opt _ (pc, _) _ () -> + traverse + { fold = Code.fold_children } + (fun pc () -> block_deps ~info ~non_escaping ~ambiguous ~blocks:p.blocks pc) + pc + p.blocks + (); + Option.iter + ~f:(fun f -> + traverse + { fold = Code.fold_children } + (fun pc () -> + let block = Addr.Map.find pc p.blocks in + match block.branch with + | Return x -> ( + match last_instr block.body with + | Some (Let (x', Apply _)) when Code.Var.equal x x' -> + Var.Hashtbl.replace has_tail_calls f () + | _ -> ()) + | _ -> ()) + pc + p.blocks + ()) + name_opt) + (); + if debug () + then Format.eprintf "SUMMARY non-escaping:%d" (Var.Hashtbl.length non_escaping); + Var.Hashtbl.iter (fun x () -> Var.Hashtbl.remove non_escaping x) ambiguous; + if debug () + then Format.eprintf " unambiguous-non-escaping:%d@." (Var.Hashtbl.length non_escaping); + if times () then Format.eprintf " call graph analysis: %a@." Timer.print t; + { unambiguous_non_escaping = non_escaping; has_tail_calls } diff --git a/compiler/lib-wasm/call_graph_analysis.mli b/compiler/lib-wasm/call_graph_analysis.mli new file mode 100644 index 0000000000..0d26a009dd --- /dev/null +++ b/compiler/lib-wasm/call_graph_analysis.mli @@ -0,0 +1,7 @@ +type t + +val direct_calls_only : t -> Code.Var.t -> bool + +val has_tail_calls : t -> Code.Var.t -> bool + +val f : Code.program -> Global_flow.info -> t diff --git a/compiler/lib-wasm/code_generation.ml b/compiler/lib-wasm/code_generation.ml index 4efeb11a1b..d9e3335d19 100644 --- a/compiler/lib-wasm/code_generation.ml +++ b/compiler/lib-wasm/code_generation.ml @@ -59,6 +59,7 @@ type context = ; mutable globalized_variables : Var.Set.t ; value_type : W.value_type ; mutable unit_name : string option + ; mutable no_tail_call : unit Var.Hashtbl.t } let make_context ~value_type = @@ -82,6 +83,7 @@ let make_context ~value_type = ; globalized_variables = Var.Set.empty ; value_type ; unit_name = None + ; no_tail_call = Var.Hashtbl.create 16 } type var = @@ -224,27 +226,30 @@ let get_global name = | Some { init; _ } -> init | _ -> None) -let register_import ?(import_module = "env") ~name typ st = - ( (try - let x, typ' = - StringMap.find name (StringMap.find import_module st.context.imports) - in - (*ZZZ error message*) - assert (Poly.equal typ typ'); - x - with Not_found -> - let x = Var.fresh_n name in - st.context.imports <- - StringMap.update - import_module - (fun m -> - Some - (match m with - | None -> StringMap.singleton name (x, typ) - | Some m -> StringMap.add name (x, typ) m)) - st.context.imports; - x) - , st ) +let register_import ?(allow_tail_call = true) ?(import_module = "env") ~name typ st = + let x = + try + let x, typ' = + StringMap.find name (StringMap.find import_module st.context.imports) + in + (*ZZZ error message*) + assert (Poly.equal typ typ'); + x + with Not_found -> + let x = Var.fresh_n name in + st.context.imports <- + StringMap.update + import_module + (fun m -> + Some + (match m with + | None -> StringMap.singleton name (x, typ) + | Some m -> StringMap.add name (x, typ) m)) + st.context.imports; + x + in + if not allow_tail_call then Var.Hashtbl.replace st.context.no_tail_call x (); + x, st let register_init_code code st = let st' = { var_count = 0; vars = Var.Map.empty; instrs = []; context = st.context } in @@ -368,6 +373,7 @@ module Arith = struct (match e, e' with | W.Const (I32 n), W.Const (I32 n') when Int32.(n' < 31l) -> W.Const (I32 (Int32.shift_left n (Int32.to_int n'))) + | _, W.Const (I32 0l) -> e | _ -> W.BinOp (I32 Shl, e, e')) let ( lsr ) = binary (Shr U) @@ -715,7 +721,7 @@ let function_body ~context ~param_names ~body = | Local (i, x, typ) -> local_types.(i) <- x, typ | Expr _ -> ()) st.vars; - let body = Tail_call.f body in + let body = Tail_call.f ~no_tail_call:context.no_tail_call body in let param_count = List.length param_names in let locals = local_types diff --git a/compiler/lib-wasm/code_generation.mli b/compiler/lib-wasm/code_generation.mli index 8655450dda..9bdc41e982 100644 --- a/compiler/lib-wasm/code_generation.mli +++ b/compiler/lib-wasm/code_generation.mli @@ -42,6 +42,7 @@ type context = ; mutable globalized_variables : Code.Var.Set.t ; value_type : Wasm_ast.value_type ; mutable unit_name : string option + ; mutable no_tail_call : unit Code.Var.Hashtbl.t } val make_context : value_type:Wasm_ast.value_type -> context @@ -156,7 +157,11 @@ val register_type : string -> (unit -> type_def t) -> Wasm_ast.var t val heap_type_sub : Wasm_ast.heap_type -> Wasm_ast.heap_type -> bool t val register_import : - ?import_module:string -> name:string -> Wasm_ast.import_desc -> Wasm_ast.var t + ?allow_tail_call:bool + -> ?import_module:string + -> name:string + -> Wasm_ast.import_desc + -> Wasm_ast.var t val register_global : Wasm_ast.var diff --git a/compiler/lib-wasm/curry.ml b/compiler/lib-wasm/curry.ml index b6d5ab0cab..32b339e5be 100644 --- a/compiler/lib-wasm/curry.ml +++ b/compiler/lib-wasm/curry.ml @@ -293,14 +293,7 @@ module Make (Target : Target_sig.S) = struct (fun ~typ closure -> let* l = expression_list load l in call ?typ ~cps:true ~arity closure l) - (let* args = - (* We don't need the deadcode sentinal when the tag is 0 *) - Memory.allocate - ~tag:0 - ~deadcode_sentinal:(Code.Var.fresh ()) - ~load - (List.map ~f:(fun x -> `Var x) (List.tl l)) - in + (let* args = Memory.allocate ~tag:0 (expression_list load (List.tl l)) in let* make_iterator = register_import ~name:"caml_apply_continuation" (Fun (Type.primitive_type 1)) in diff --git a/compiler/lib-wasm/gc_target.ml b/compiler/lib-wasm/gc_target.ml index 36ca054e4c..abc701f971 100644 --- a/compiler/lib-wasm/gc_target.ml +++ b/compiler/lib-wasm/gc_target.ml @@ -22,8 +22,6 @@ open Code_generation type expression = Wasm_ast.expression Code_generation.t -let include_closure_arity = false - module Type = struct let value = W.Ref { nullable = false; typ = Eq } @@ -215,13 +213,7 @@ module Type = struct let closure_common_fields ~cps = let* fun_ty = function_type ~cps 1 in return - (let function_pointer = - [ { W.mut = false; typ = W.Value (Ref { nullable = false; typ = Type fun_ty }) } - ] - in - if include_closure_arity - then { W.mut = false; typ = W.Value I32 } :: function_pointer - else function_pointer) + [ { W.mut = false; typ = W.Value (Ref { nullable = false; typ = Type fun_ty }) } ] let closure_type_1 ~cps = register_type @@ -289,36 +281,41 @@ module Type = struct }) env_type - let env_type ~cps ~arity ~env_type_id ~env_type = + let env_type ~cps ~arity ~no_code_pointer ~env_type_id ~env_type = register_type (if cps then Printf.sprintf "cps_env_%d_%d" arity env_type_id else Printf.sprintf "env_%d_%d" arity env_type_id) (fun () -> - let* cl_typ = closure_type ~usage:`Alloc ~cps arity in - let* common = closure_common_fields ~cps in - let* fun_ty' = function_type ~cps arity in - return - { supertype = Some cl_typ - ; final = true - ; typ = - W.Struct - ((if arity = 1 - then common - else if arity = 0 - then - [ { mut = false - ; typ = Value (Ref { nullable = false; typ = Type fun_ty' }) - } - ] - else - common - @ [ { mut = false + if no_code_pointer + then + return + { supertype = None; final = true; typ = W.Struct (make_env_type env_type) } + else + let* cl_typ = closure_type ~usage:`Alloc ~cps arity in + let* common = closure_common_fields ~cps in + let* fun_ty' = function_type ~cps arity in + return + { supertype = Some cl_typ + ; final = true + ; typ = + W.Struct + ((if arity = 1 + then common + else if arity = 0 + then + [ { mut = false ; typ = Value (Ref { nullable = false; typ = Type fun_ty' }) } - ]) - @ make_env_type env_type) - }) + ] + else + common + @ [ { mut = false + ; typ = Value (Ref { nullable = false; typ = Type fun_ty' }) + } + ]) + @ make_env_type env_type) + }) let rec_env_type ~function_count ~env_type_id ~env_type = register_type (Printf.sprintf "rec_env_%d_%d" function_count env_type_id) (fun () -> @@ -336,34 +333,48 @@ module Type = struct @ make_env_type env_type) }) - let rec_closure_type ~cps ~arity ~function_count ~env_type_id ~env_type = + let rec_closure_type ~cps ~arity ~no_code_pointer ~function_count ~env_type_id ~env_type + = register_type (if cps then Printf.sprintf "cps_closure_rec_%d_%d_%d" arity function_count env_type_id else Printf.sprintf "closure_rec_%d_%d_%d" arity function_count env_type_id) (fun () -> - let* cl_typ = closure_type ~usage:`Alloc ~cps arity in - let* common = closure_common_fields ~cps in - let* fun_ty' = function_type ~cps arity in let* env_ty = rec_env_type ~function_count ~env_type_id ~env_type in - return - { supertype = Some cl_typ - ; final = true - ; typ = - W.Struct - ((if arity = 1 - then common - else - common - @ [ { mut = false - ; typ = Value (Ref { nullable = false; typ = Type fun_ty' }) - } - ]) - @ [ { W.mut = false + if no_code_pointer + then + return + { supertype = None + ; final = true + ; typ = + W.Struct + [ { W.mut = false ; typ = W.Value (Ref { nullable = false; typ = Type env_ty }) } - ]) - }) + ] + } + else + let* cl_typ = closure_type ~usage:`Alloc ~cps arity in + let* common = closure_common_fields ~cps in + let* fun_ty' = function_type ~cps arity in + return + { supertype = Some cl_typ + ; final = true + ; typ = + W.Struct + ((if arity = 1 + then common + else + common + @ [ { mut = false + ; typ = Value (Ref { nullable = false; typ = Type fun_ty' }) + } + ]) + @ [ { W.mut = false + ; typ = W.Value (Ref { nullable = false; typ = Type env_ty }) + } + ]) + }) let rec curry_type ~cps arity m = register_type @@ -419,6 +430,38 @@ module Type = struct } ]) }) + + let int_array_type = + register_type "int_array" (fun () -> + return + { supertype = None + ; final = true + ; typ = W.Array { mut = true; typ = Value I32 } + }) + + let bigarray_type = + register_type "bigarray" (fun () -> + let* custom_operations = custom_operations_type in + let* int_array = int_array_type in + let* custom = custom_type in + return + { supertype = Some custom + ; final = true + ; typ = + W.Struct + [ { mut = false + ; typ = Value (Ref { nullable = false; typ = Type custom_operations }) + } + ; { mut = true; typ = Value (Ref { nullable = false; typ = Extern }) } + ; { mut = true; typ = Value (Ref { nullable = false; typ = Extern }) } + ; { mut = false + ; typ = Value (Ref { nullable = false; typ = Type int_array }) + } + ; { mut = false; typ = Packed I8 } + ; { mut = false; typ = Packed I8 } + ; { mut = false; typ = Packed I8 } + ] + }) end module Value = struct @@ -655,33 +698,16 @@ module Memory = struct let* ty = Type.float_type in wasm_struct_get ty (wasm_cast ty e) 0 - let allocate ~tag ~deadcode_sentinal ~load l = - if tag = 254 - then - let* l = - expression_list - (fun v -> - match v with - | `Var y -> - if Code.Var.equal y deadcode_sentinal - then return (W.Const (F64 0.)) - else unbox_float (load y) - | `Expr e -> unbox_float (return e)) - l - in - let* ty = Type.float_array_type in - return (W.ArrayNewFixed (ty, l)) - else - let* l = - expression_list - (fun v -> - match v with - | `Var y -> load y - | `Expr e -> return e) - l - in - let* ty = Type.block_type in - return (W.ArrayNewFixed (ty, RefI31 (Const (I32 (Int32.of_int tag))) :: l)) + let allocate ~tag l = + assert (tag <> 254); + let* l = l in + let* ty = Type.block_type in + return (W.ArrayNewFixed (ty, RefI31 (Const (I32 (Int32.of_int tag))) :: l)) + + let allocate_float_array l = + let* l = l in + let* ty = Type.float_array_type in + return (W.ArrayNewFixed (ty, l)) let tag e = wasm_array_get e (Arith.const 0l) @@ -730,10 +756,9 @@ module Memory = struct let array_set e e' e'' = wasm_array_set e Arith.(e' + const 1l) e'' - let float_array_get e e' = box_float (wasm_array_get ~ty:Type.float_array_type e e') + let float_array_get e e' = wasm_array_get ~ty:Type.float_array_type e e' - let float_array_set e e' e'' = - wasm_array_set ~ty:Type.float_array_type e e' (unbox_float e'') + let float_array_set e e' e'' = wasm_array_set ~ty:Type.float_array_type e e' e'' let gen_array_get e e' = let a = Code.Var.fresh_n "a" in @@ -806,17 +831,22 @@ module Memory = struct let set_field e idx e' = wasm_array_set e (Arith.const (Int32.of_int (idx + 1))) e' - let env_start arity = - if arity = 0 - then 1 - else (if include_closure_arity then 1 else 0) + if arity = 1 then 1 else 2 + let env_start ~no_code_pointer arity = + if no_code_pointer + then 0 + else + match arity with + | 0 | 1 -> 1 + | _ -> 2 let load_function_pointer ~cps ~arity ?(skip_cast = false) closure = let arity = if cps then arity - 1 else arity in let* ty = Type.closure_type ~usage:`Access ~cps arity in let* fun_ty = Type.function_type ~cps arity in let casted_closure = if skip_cast then closure else wasm_cast ty closure in - let* e = wasm_struct_get ty casted_closure (env_start arity - 1) in + let* e = + wasm_struct_get ty casted_closure (env_start ~no_code_pointer:false arity - 1) + in return (fun_ty, e) let load_real_closure ~cps ~arity closure = @@ -824,7 +854,12 @@ module Memory = struct let* ty = Type.dummy_closure_type ~cps ~arity in let* cl_typ = Type.closure_type ~usage:`Access ~cps arity in let* e = - wasm_cast cl_typ (wasm_struct_get ty (wasm_cast ty closure) (env_start arity)) + wasm_cast + cl_typ + (wasm_struct_get + ty + (wasm_cast ty closure) + (env_start ~no_code_pointer:false arity)) in return (cl_typ, e) @@ -1026,9 +1061,12 @@ module Constant = struct let* e = Memory.make_int32 ~kind:`Nativeint (return (W.Const (I32 i))) in return (Const, e) - let translate c = + let translate ~unboxed c = match c with | Code.Int i -> return (W.Const (I32 (Targetint.to_int32 i))) + | Float f when unboxed -> return (W.Const (F64 (Int64.float_of_bits f))) + | Int64 i when unboxed -> return (W.Const (I64 i)) + | (Int32 i | NativeInt i) when unboxed -> return (W.Const (I32 i)) | _ -> ( let* const, c = translate_rec c in match const with @@ -1061,7 +1099,7 @@ module Closure = struct | [ (g, _) ] -> Code.Var.equal f g | _ :: r -> is_last_fun r f - let translate ~context ~closures ~cps f = + let translate ~context ~closures ~cps ~no_code_pointer f = let info = Code.Var.Map.find f closures in let free_variables = get_free_variables ~context info in assert ( @@ -1070,29 +1108,29 @@ module Closure = struct ~f:(fun x -> Code.Var.Set.mem x context.globalized_variables) free_variables)); let _, arity = List.find ~f:(fun (f', _) -> Code.Var.equal f f') info.functions in - let arity = if cps then arity - 1 else arity in + let arity = if no_code_pointer then 0 else if cps then arity - 1 else arity in let* curry_fun = if arity > 1 then need_curry_fun ~cps ~arity else return f in if List.is_empty free_variables then - let* typ = Type.closure_type ~usage:`Alloc ~cps arity in - let name = Code.Var.fork f in - let* () = - register_global - name - { mut = false; typ = Type.value } - (W.StructNew - ( typ - , if arity = 0 - then [ W.RefFunc f ] - else - let code_pointers = - if arity = 1 then [ W.RefFunc f ] else [ RefFunc curry_fun; RefFunc f ] - in - if include_closure_arity - then Const (I32 (Int32.of_int arity)) :: code_pointers - else code_pointers )) - in - return (W.GlobalGet name) + if no_code_pointer + then Value.unit + else + let* typ = Type.closure_type ~usage:`Alloc ~cps arity in + let name = Code.Var.fork f in + let* () = + register_global + name + { mut = false; typ = Type.value } + (W.StructNew + ( typ + , if no_code_pointer + then [] + else + match arity with + | 0 | 1 -> [ W.RefFunc f ] + | _ -> [ RefFunc curry_fun; RefFunc f ] )) + in + return (W.GlobalGet name) else let* env_type = expression_list variable_type free_variables in let env_type_id = @@ -1106,22 +1144,17 @@ module Closure = struct match info.Closure_conversion.functions with | [] -> assert false | [ _ ] -> - let* typ = Type.env_type ~cps ~arity ~env_type_id ~env_type in + let* typ = Type.env_type ~cps ~arity ~no_code_pointer ~env_type_id ~env_type in let* l = expression_list load free_variables in return (W.StructNew ( typ - , (if arity = 0 - then [ W.RefFunc f ] + , (if no_code_pointer + then [] else - let code_pointers = - if arity = 1 - then [ W.RefFunc f ] - else [ RefFunc curry_fun; RefFunc f ] - in - if include_closure_arity - then W.Const (I32 (Int32.of_int arity)) :: code_pointers - else code_pointers) + match arity with + | 0 | 1 -> [ W.RefFunc f ] + | _ -> [ RefFunc curry_fun; RefFunc f ]) @ l )) | (g, _) :: _ as functions -> let function_count = List.length functions in @@ -1147,21 +1180,25 @@ module Closure = struct load env in let* typ = - Type.rec_closure_type ~cps ~arity ~function_count ~env_type_id ~env_type + Type.rec_closure_type + ~cps + ~arity + ~no_code_pointer + ~function_count + ~env_type_id + ~env_type in let res = let* env = env in return (W.StructNew ( typ - , (let code_pointers = - if arity = 1 - then [ W.RefFunc f ] - else [ RefFunc curry_fun; RefFunc f ] - in - if include_closure_arity - then W.Const (I32 (Int32.of_int arity)) :: code_pointers - else code_pointers) + , (if no_code_pointer + then [] + else + match arity with + | 0 | 1 -> [ W.RefFunc f ] + | _ -> [ RefFunc curry_fun; RefFunc f ]) @ [ env ] )) in if is_last_fun functions f @@ -1182,11 +1219,10 @@ module Closure = struct (load f) else res - let bind_environment ~context ~closures ~cps f = + let bind_environment ~context ~closures ~cps ~no_code_pointer f = let info = Code.Var.Map.find f closures in let free_variables = get_free_variables ~context info in - let free_variable_count = List.length free_variables in - if free_variable_count = 0 + if List.is_empty free_variables then (* The closures are all constants and the environment is empty. *) let* _ = add_var (Code.Var.fresh ()) in @@ -1194,11 +1230,13 @@ module Closure = struct else let env_type_id = Option.value ~default:(-1) info.id in let _, arity = List.find ~f:(fun (f', _) -> Code.Var.equal f f') info.functions in - let arity = if cps then arity - 1 else arity in - let offset = Memory.env_start arity in + let arity = if no_code_pointer then 0 else if cps then arity - 1 else arity in + let offset = Memory.env_start ~no_code_pointer arity in match info.Closure_conversion.functions with | [ _ ] -> - let* typ = Type.env_type ~cps ~arity ~env_type_id ~env_type:[] in + let* typ = + Type.env_type ~cps ~arity ~no_code_pointer ~env_type_id ~env_type:[] + in let* _ = add_var f in let env = Code.Var.fresh_n "env" in let* () = @@ -1218,7 +1256,13 @@ module Closure = struct | functions -> let function_count = List.length functions in let* typ = - Type.rec_closure_type ~cps ~arity ~function_count ~env_type_id ~env_type:[] + Type.rec_closure_type + ~cps + ~arity + ~no_code_pointer + ~function_count + ~env_type_id + ~env_type:[] in let* _ = add_var f in let env = Code.Var.fresh_n "env" in @@ -1247,13 +1291,7 @@ module Closure = struct in let* closure = Memory.wasm_cast cl_ty (load closure) in let* arg = load arg in - let closure_contents = [ W.RefFunc f; closure; arg ] in - return - (W.StructNew - ( ty - , if include_closure_arity - then Const (I32 1l) :: closure_contents - else closure_contents )) + return (W.StructNew (ty, [ W.RefFunc f; closure; arg ])) let curry_load ~cps ~arity m closure = let m = m + 1 in @@ -1264,7 +1302,7 @@ module Closure = struct else Type.curry_type ~cps arity (m + 1) in let cast e = if m = 2 then Memory.wasm_cast ty e else e in - let offset = Memory.env_start 1 in + let offset = Memory.env_start ~no_code_pointer:false 1 in return ( Memory.wasm_struct_get ty (cast (load closure)) (offset + 1) , Memory.wasm_struct_get ty (cast (load closure)) offset @@ -1283,12 +1321,7 @@ module Closure = struct then [ W.RefFunc dummy_fun; RefNull (Type cl_typ) ] else [ RefFunc curry_fun; RefFunc dummy_fun; RefNull (Type cl_typ) ] in - return - (W.StructNew - ( ty - , if include_closure_arity - then Const (I32 1l) :: closure_contents - else closure_contents )) + return (W.StructNew (ty, closure_contents)) end module Math = struct @@ -1296,7 +1329,13 @@ module Math = struct { W.params = List.init ~len:n ~f:(fun _ : W.value_type -> F64); result = [ F64 ] } let unary name x = - let* f = register_import ~import_module:"Math" ~name (Fun (float_func_type 1)) in + let* f = + register_import + ~allow_tail_call:false + ~import_module:"Math" + ~name + (Fun (float_func_type 1)) + in let* x = x in return (W.Call (f, [ x ])) @@ -1339,7 +1378,13 @@ module Math = struct let log10 f = unary "log10" f let binary name x y = - let* f = register_import ~import_module:"Math" ~name (Fun (float_func_type 2)) in + let* f = + register_import + ~allow_tail_call:false + ~import_module:"Math" + ~name + (Fun (float_func_type 2)) + in let* x = x in let* y = y in return (W.Call (f, [ x; y ])) @@ -1360,6 +1405,235 @@ module Math = struct let exp2 x = power (return (W.Const (F64 2.))) x end +module Bigarray = struct + let dimension n a = + let* ty = Type.bigarray_type in + Memory.wasm_array_get + ~ty:Type.int_array_type + (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 name, (typ : Wasm_ast.value_type), size, box = + match kind with + | Float32 -> + ( "dv_get_f32" + , F32 + , 2 + , fun x -> + let* x = x in + return (W.F64PromoteF32 x) ) + | Float64 -> "dv_get_f64", F64, 3, Fun.id + | Int8_signed -> "dv_get_i8", I32, 0, Fun.id + | Int8_unsigned -> "dv_get_ui8", I32, 0, Fun.id + | Int16_signed -> "dv_get_i16", I32, 1, Fun.id + | Int16_unsigned -> "dv_get_ui16", I32, 1, Fun.id + | Int32 -> "dv_get_i32", I32, 2, Fun.id + | Nativeint -> "dv_get_i32", I32, 2, Fun.id + | Int64 -> "dv_get_i64", I64, 3, Fun.id + | Int -> "dv_get_i32", I32, 2, Fun.id + | Float16 -> + ( "dv_get_i16" + , I32 + , 1 + , fun x -> + let* conv = + register_import + ~name:"caml_float16_to_double" + (Fun { W.params = [ I32 ]; result = [ F64 ] }) + in + let* x = x in + return (W.Call (conv, [ x ])) ) + | Complex32 -> + ( "dv_get_f32" + , F32 + , 3 + , fun x -> + let* x = x in + return (W.F64PromoteF32 x) ) + | Complex64 -> "dv_get_f64", F64, 4, Fun.id + in + let* little_endian = + register_import + ~import_module:"bindings" + ~name:"littleEndian" + (Global { mut = false; typ = I32 }) + in + let* f = + register_import + ~import_module:"bindings" + ~name + (Fun + { W.params = + Ref { nullable = true; typ = Extern } + :: I32 + :: (if size = 0 then [] else [ I32 ]) + ; result = [ typ ] + }) + in + let* ty = Type.bigarray_type in + let* ta = Memory.wasm_struct_get ty (Memory.wasm_cast ty a) 2 in + let* ofs = Arith.(i lsl const (Int32.of_int size)) in + match kind with + | Float32 + | Float64 + | Int8_signed + | Int8_unsigned + | Int16_signed + | Int16_unsigned + | Int32 + | Int64 + | Int + | Nativeint + | Float16 -> + box + (return + (W.Call + (f, ta :: ofs :: (if size = 0 then [] else [ W.GlobalGet little_endian ])))) + | Complex32 | Complex64 -> + let delta = Int32.shift_left 1l (size - 1) in + let* ofs' = Arith.(return ofs + const delta) in + let* x = box (return (W.Call (f, [ ta; ofs; W.GlobalGet little_endian ]))) in + let* y = box (return (W.Call (f, [ ta; ofs'; W.GlobalGet little_endian ]))) in + let* ty = Type.float_array_type in + return (W.ArrayNewFixed (ty, [ x; y ])) + + let set_at_offset ~kind a i v = + let name, (typ : Wasm_ast.value_type), size, unbox = + match (kind : Typing.Bigarray.kind) with + | Float32 -> + ( "dv_set_f32" + , F32 + , 2 + , fun x -> + let* x = x in + return (W.F32DemoteF64 x) ) + | Float64 -> "dv_set_f64", F64, 3, Fun.id + | Int8_signed | Int8_unsigned -> "dv_set_i8", I32, 0, Fun.id + | Int16_signed | Int16_unsigned -> "dv_set_i16", I32, 1, Fun.id + | Int32 -> "dv_set_i32", I32, 2, Fun.id + | Nativeint -> "dv_set_i32", I32, 2, Fun.id + | Int64 -> "dv_set_i64", I64, 3, Fun.id + | Int -> "dv_set_i32", I32, 2, Fun.id + | Float16 -> + ( "dv_set_i16" + , I32 + , 1 + , fun x -> + let* conv = + register_import + ~name:"caml_double_to_float16" + (Fun { W.params = [ F64 ]; result = [ I32 ] }) + in + let* x = Fun.id x in + return (W.Call (conv, [ x ])) ) + | Complex32 -> + ( "dv_set_f32" + , F32 + , 3 + , fun x -> + let* x = x in + return (W.F32DemoteF64 x) ) + | Complex64 -> "dv_set_f64", F64, 4, Fun.id + in + let* ty = Type.bigarray_type in + let* ta = Memory.wasm_struct_get ty (Memory.wasm_cast ty a) 2 in + let* ofs = Arith.(i lsl const (Int32.of_int size)) in + let* little_endian = + register_import + ~import_module:"bindings" + ~name:"littleEndian" + (Global { mut = false; typ = I32 }) + in + let* f = + register_import + ~import_module:"bindings" + ~name + (Fun + { W.params = + Ref { nullable = true; typ = Extern } + :: I32 + :: typ + :: (if size = 0 then [] else [ I32 ]) + ; result = [] + }) + in + match kind with + | Float32 + | Float64 + | Int8_signed + | Int8_unsigned + | Int16_signed + | Int16_unsigned + | Int32 + | Int64 + | Int + | Nativeint + | Float16 -> + let* v = unbox v in + instr + (W.CallInstr + ( f + , ta :: ofs :: v :: (if size = 0 then [] else [ W.GlobalGet little_endian ]) + )) + | Complex32 | Complex64 -> + let delta = Int32.shift_left 1l (size - 1) in + let* ofs' = Arith.(return ofs + const delta) in + let ty = Type.float_array_type in + let* x = unbox (Memory.wasm_array_get ~ty v (Arith.const 0l)) in + let* () = instr (W.CallInstr (f, [ ta; ofs; x; W.GlobalGet little_endian ])) in + 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 l = + List.mapi + ~f:(fun pos i -> + let i = + match layout with + | C -> i + | Fortran -> Arith.(i - const 1l) + in + let i' = Code.Var.fresh () in + 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))) + , i' + , dim )) + indices + in + let l = + match layout with + | C -> l + | Fortran -> List.rev l + in + match l with + | (instrs, i', _) :: rem -> + List.fold_left + ~f:(fun (instrs, ofs) (instrs', i', dim) -> + let ofs' = Code.Var.fresh () in + ( (let* () = instrs in + let* () = instrs' in + store ~typ:I32 ofs' Arith.((ofs * load dim) + load i')) + , load ofs' )) + ~init:(instrs, load i') + 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 + 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 + seq + (let* () = instrs in + set_at_offset ~kind ta ofs v) + Value.unit +end + module JavaScript = struct let anyref = W.Ref { nullable = true; typ = Any } diff --git a/compiler/lib-wasm/generate.ml b/compiler/lib-wasm/generate.ml index 6bbe9830c6..06e2869a73 100644 --- a/compiler/lib-wasm/generate.ml +++ b/compiler/lib-wasm/generate.ml @@ -35,9 +35,9 @@ module Generate (Target : Target_sig.S) = struct type ctx = { live : int array ; in_cps : Effects.in_cps - ; deadcode_sentinal : Var.t ; global_flow_info : Global_flow.info - ; types : Typing.typ Var.Tbl.t + ; fun_info : Call_graph_analysis.t + ; types : Typing.t ; blocks : block Addr.Map.t ; closures : Closure_conversion.closure Var.Map.t ; global_context : Code_generation.context @@ -68,6 +68,7 @@ module Generate (Target : Target_sig.S) = struct type repr = | Value | Float + | Int | Int32 | Nativeint | Int64 @@ -76,29 +77,12 @@ module Generate (Target : Target_sig.S) = struct match r with | Value -> Type.value | Float -> F64 - | Int32 -> I32 - | Nativeint -> I32 + | Int | Int32 | Nativeint -> I32 | Int64 -> I64 let specialized_primitive_type (_, params, result) = { W.params = List.map ~f:repr_type params; result = [ repr_type result ] } - let box_value r e = - match r with - | Value -> e - | Float -> Memory.box_float e - | Int32 -> Memory.box_int32 e - | Nativeint -> Memory.box_nativeint e - | Int64 -> Memory.box_int64 e - - let unbox_value r e = - match r with - | Value -> e - | Float -> Memory.unbox_float e - | Int32 -> Memory.unbox_int32 e - | Nativeint -> Memory.unbox_nativeint e - | Int64 -> Memory.unbox_int64 e - let specialized_primitives = let h = String.Hashtbl.create 18 in List.iter @@ -106,94 +90,93 @@ module Generate (Target : Target_sig.S) = struct [ "caml_int32_bswap", (`Pure, [ Int32 ], Int32) ; "caml_nativeint_bswap", (`Pure, [ Nativeint ], Nativeint) ; "caml_int64_bswap", (`Pure, [ Int64 ], Int64) - ; "caml_int32_compare", (`Pure, [ Int32; Int32 ], Value) - ; "caml_nativeint_compare", (`Pure, [ Nativeint; Nativeint ], Value) - ; "caml_int64_compare", (`Pure, [ Int64; Int64 ], Value) - ; "caml_string_get32", (`Mutator, [ Value; Value ], Int32) - ; "caml_string_get64", (`Mutator, [ Value; Value ], Int64) - ; "caml_bytes_get32", (`Mutator, [ Value; Value ], Int32) - ; "caml_bytes_get64", (`Mutator, [ Value; Value ], Int64) - ; "caml_bytes_set32", (`Mutator, [ Value; Value; Int32 ], Value) - ; "caml_bytes_set64", (`Mutator, [ Value; Value; Int64 ], Value) - ; "caml_lxm_next", (`Pure, [ Value ], Int64) - ; "caml_ba_uint8_get32", (`Mutator, [ Value; Value ], Int32) - ; "caml_ba_uint8_get64", (`Mutator, [ Value; Value ], Int64) - ; "caml_ba_uint8_set32", (`Mutator, [ Value; Value; Int32 ], Value) - ; "caml_ba_uint8_set64", (`Mutator, [ Value; Value; Int64 ], Value) + ; "caml_int32_compare", (`Pure, [ Int32; Int32 ], Int) + ; "caml_nativeint_compare", (`Pure, [ Nativeint; Nativeint ], Int) + ; "caml_int64_compare", (`Pure, [ Int64; Int64 ], Int) + ; "caml_string_get16", (`Mutator, [ Value; Int ], Int) + ; "caml_string_get32", (`Mutator, [ Value; Int ], Int32) + ; "caml_string_get64", (`Mutator, [ Value; Int ], Int64) + ; "caml_bytes_get16", (`Mutator, [ Value; Int ], Int) + ; "caml_bytes_get32", (`Mutator, [ Value; Int ], Int32) + ; "caml_bytes_get64", (`Mutator, [ Value; Int ], Int64) + ; "caml_bytes_set16", (`Mutator, [ Value; Int; Int ], Value) + ; "caml_bytes_set32", (`Mutator, [ Value; Int; Int32 ], Value) + ; "caml_bytes_set64", (`Mutator, [ Value; Int; Int64 ], Value) + ; "caml_lxm_next", (`Mutable, [ Value ], Int64) + ; "caml_ba_uint8_get16", (`Mutator, [ Value; Int ], Int) + ; "caml_ba_uint8_get32", (`Mutator, [ Value; Int ], Int32) + ; "caml_ba_uint8_get64", (`Mutator, [ Value; Int ], Int64) + ; "caml_ba_uint8_set16", (`Mutator, [ Value; Int; Int ], Value) + ; "caml_ba_uint8_set32", (`Mutator, [ Value; Int; Int32 ], Value) + ; "caml_ba_uint8_set64", (`Mutator, [ Value; Int; Int64 ], Value) ; "caml_nextafter_float", (`Pure, [ Float; Float ], Float) ; "caml_classify_float", (`Pure, [ Float ], Value) - ; "caml_ldexp_float", (`Pure, [ Float; Value ], Float) + ; "caml_ldexp_float", (`Pure, [ Float; Int ], Float) ; "caml_erf_float", (`Pure, [ Float ], Float) ; "caml_erfc_float", (`Pure, [ Float ], Float) - ; "caml_float_compare", (`Pure, [ Float; Float ], Value) + ; "caml_float_compare", (`Pure, [ Float; Float ], Int) ]; h - let float_bin_op' op f g = - Memory.box_float (op (Memory.unbox_float f) (Memory.unbox_float g)) - let float_bin_op op f g = - let* f = Memory.unbox_float f in - let* g = Memory.unbox_float g in - Memory.box_float (return (W.BinOp (F64 op, f, g))) - - let float_un_op' op f = Memory.box_float (op (Memory.unbox_float f)) + let* f = f in + let* g = g in + return (W.BinOp (F64 op, f, g)) let float_un_op op f = - let* f = Memory.unbox_float f in - Memory.box_float (return (W.UnOp (F64 op, f))) - - let float_comparison op f g = - let* f = Memory.unbox_float f in - let* g = Memory.unbox_float g in - return (W.BinOp (F64 op, f, g)) + let* f = f in + return (W.UnOp (F64 op, f)) let int32_bin_op op f g = - let* f = Memory.unbox_int32 f in - let* g = Memory.unbox_int32 g in - Memory.box_int32 (return (W.BinOp (I32 op, f, g))) - - let int32_shift_op op f g = - let* f = Memory.unbox_int32 f in + let* f = f in let* g = g in - Memory.box_int32 (return (W.BinOp (I32 op, f, g))) + return (W.BinOp (I32 op, f, g)) let int64_bin_op op f g = - let* f = Memory.unbox_int64 f in - let* g = Memory.unbox_int64 g in - Memory.box_int64 (return (W.BinOp (I64 op, f, g))) + let* f = f in + let* g = g in + return (W.BinOp (I64 op, f, g)) let int64_shift_op op f g = - let* f = Memory.unbox_int64 f in + let* f = f in let* g = g in - Memory.box_int64 (return (W.BinOp (I64 op, f, I64ExtendI32 (S, g)))) + return (W.BinOp (I64 op, f, I64ExtendI32 (S, g))) let nativeint_bin_op op f g = - let* f = Memory.unbox_nativeint f in - let* g = Memory.unbox_nativeint g in - Memory.box_nativeint (return (W.BinOp (I32 op, f, g))) - - let nativeint_shift_op op f g = - let* f = Memory.unbox_nativeint f in + let* f = f in let* g = g in - Memory.box_nativeint (return (W.BinOp (I32 op, f, g))) - - let get_var_type ctx x = Var.Tbl.get ctx.types x + return (W.BinOp (I32 op, f, g)) let get_type ctx p = match p with - | Pv x -> get_var_type ctx x + | Pv x -> Typing.var_type ctx.types x | Pc c -> Typing.constant_type c let convert ~(from : Typing.typ) ~(into : Typing.typ) e = match from, into with | Int Unnormalized, Int Normalized -> Arith.((e lsl const 1l) asr const 1l) | Int (Normalized | Unnormalized), Int (Normalized | Unnormalized) -> e + (* Dummy value *) + | Int (Unnormalized | Normalized), Number ((Int32 | Nativeint), Unboxed) -> + return (W.Const (I32 0l)) + | Int (Unnormalized | Normalized), Number (Int64, Unboxed) -> + return (W.Const (I64 0L)) + | Int (Unnormalized | Normalized), Number (Float, Unboxed) -> + return (W.Const (F64 0.)) | _, Int (Normalized | Unnormalized) -> Value.int_val e | Int (Unnormalized | Normalized), _ -> Value.val_int e + | Number (_, Unboxed), Number (_, Unboxed) -> e + | _, Number (Int32, Unboxed) -> Memory.unbox_int32 e + | _, Number (Int64, Unboxed) -> Memory.unbox_int64 e + | _, Number (Nativeint, Unboxed) -> Memory.unbox_nativeint e + | _, Number (Float, Unboxed) -> Memory.unbox_float e + | Number (Int32, Unboxed), _ -> Memory.box_int32 e + | Number (Int64, Unboxed), _ -> Memory.box_int64 e + | Number (Nativeint, Unboxed), _ -> Memory.box_nativeint e + | Number (Float, Unboxed), _ -> Memory.box_float e | _ -> e - let load_and_box ctx x = convert ~from:(get_var_type ctx x) ~into:Top (load x) + let load_and_box ctx x = convert ~from:(Typing.var_type ctx.types x) ~into:Top (load x) let transl_prim_arg ctx ?(typ = Typing.Top) x = convert @@ -201,7 +184,7 @@ module Generate (Target : Target_sig.S) = struct ~into:typ (match x with | Pv x -> load x - | Pc c -> Constant.translate c) + | Pc c -> Constant.translate ~unboxed:false c) let translate_int_comparison ctx op x y = match get_type ctx x, get_type ctx y with @@ -236,7 +219,8 @@ module Generate (Target : Target_sig.S) = struct (if negate then Value.phys_neq else Value.phys_eq) (transl_prim_arg ctx ~typ:Top x) (transl_prim_arg ctx ~typ:Top y) - | (Int _ | Number _ | Tuple _), _ | _, (Int _ | Number _ | Tuple _) -> + | (Int _ | Number _ | Tuple _ | Bigarray _), _ + | _, (Int _ | Number _ | Tuple _ | Bigarray _) -> (* Only Top may contain JavaScript values *) (if negate then Value.phys_neq else Value.phys_eq) (transl_prim_arg ctx ~typ:Top x) @@ -300,12 +284,40 @@ module Generate (Target : Target_sig.S) = struct (transl_prim_arg ctx ?typ:tz z) | _ -> invalid_arity name l ~expected:3) + let register_comparison name cmp_int cmp_boxed_int cmp_float = + register_prim name `Mutable (fun ctx _ 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, _) -> + 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, _) -> + 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, _) -> + 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, _) -> + 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 + | _ -> + let* f = + register_import + ~name + (Fun { W.params = [ Type.value; Type.value ]; result = [ I32 ] }) + in + let* x = transl_prim_arg ctx x in + let* y = transl_prim_arg ctx y in + return (W.Call (f, [ x; y ]))) + | _ -> invalid_arity name l ~expected:2) + let () = - register_bin_prim - "caml_array_unsafe_get" - `Mutable - ~ty:(Int Normalized) - Memory.gen_array_get; register_bin_prim "caml_floatarray_unsafe_get" `Mutable @@ -315,8 +327,11 @@ module Generate (Target : Target_sig.S) = struct seq (Memory.gen_array_set x y z) Value.unit); register_tern_prim "caml_array_unsafe_set_addr" ~ty:(Int Normalized) (fun x y z -> seq (Memory.array_set x y z) Value.unit); - register_tern_prim "caml_floatarray_unsafe_set" ~ty:(Int Normalized) (fun x y z -> - seq (Memory.float_array_set x y z) Value.unit); + register_tern_prim + "caml_floatarray_unsafe_set" + ~ty:(Int Normalized) + ~tz:(Number (Float, Unboxed)) + (fun x y z -> seq (Memory.float_array_set x y z) Value.unit); register_bin_prim "caml_string_unsafe_get" `Pure ~ty:(Int Normalized) Memory.bytes_get; register_bin_prim "caml_bytes_unsafe_get" @@ -477,91 +492,252 @@ module Generate (Target : Target_sig.S) = struct let* cond = Arith.uge y (Memory.float_array_length (load a)) in instr (W.Br_if (label, cond))) x); - register_bin_prim "caml_add_float" `Pure (fun f g -> float_bin_op Add f g); - register_bin_prim "caml_sub_float" `Pure (fun f g -> float_bin_op Sub f g); - register_bin_prim "caml_mul_float" `Pure (fun f g -> float_bin_op Mul f g); - register_bin_prim "caml_div_float" `Pure (fun f g -> float_bin_op Div f g); - register_bin_prim "caml_copysign_float" `Pure (fun f g -> float_bin_op CopySign f g); - register_un_prim "caml_signbit_float" `Pure (fun f -> - let* f = Memory.unbox_float f in + register_bin_prim + "caml_add_float" + `Pure + ~tx:(Number (Float, Unboxed)) + ~ty:(Number (Float, Unboxed)) + (fun f g -> float_bin_op Add f g); + register_bin_prim + "caml_sub_float" + ~tx:(Number (Float, Unboxed)) + ~ty:(Number (Float, Unboxed)) + `Pure + (fun f g -> float_bin_op Sub f g); + register_bin_prim + "caml_mul_float" + ~tx:(Number (Float, Unboxed)) + ~ty:(Number (Float, Unboxed)) + `Pure + (fun f g -> float_bin_op Mul f g); + register_bin_prim + "caml_div_float" + ~tx:(Number (Float, Unboxed)) + ~ty:(Number (Float, Unboxed)) + `Pure + (fun f g -> float_bin_op Div f g); + register_bin_prim + "caml_copysign_float" + `Pure + ~tx:(Number (Float, Unboxed)) + ~ty:(Number (Float, Unboxed)) + (fun f g -> float_bin_op CopySign f g); + register_un_prim + "caml_signbit_float" + `Pure + ~typ:(Number (Float, Unboxed)) + (fun f -> + let* f = f in let sign = W.BinOp (F64 CopySign, Const (F64 1.), f) in return (W.BinOp (F64 Lt, sign, Const (F64 0.)))); - register_un_prim "caml_neg_float" `Pure (fun f -> float_un_op Neg f); - register_un_prim "caml_abs_float" `Pure (fun f -> float_un_op Abs f); - register_un_prim "caml_ceil_float" `Pure (fun f -> float_un_op Ceil f); - register_un_prim "caml_floor_float" `Pure (fun f -> float_un_op Floor f); - register_un_prim "caml_trunc_float" `Pure (fun f -> float_un_op Trunc f); - register_un_prim "caml_round_float" `Pure (fun f -> float_un_op' Math.round f); - register_un_prim "caml_sqrt_float" `Pure (fun f -> float_un_op Sqrt f); - register_bin_prim "caml_eq_float" `Pure (fun f g -> float_comparison Eq f g); - register_bin_prim "caml_neq_float" `Pure (fun f g -> float_comparison Ne f g); - register_bin_prim "caml_ge_float" `Pure (fun f g -> float_comparison Ge f g); - register_bin_prim "caml_le_float" `Pure (fun f g -> float_comparison Le f g); - register_bin_prim "caml_gt_float" `Pure (fun f g -> float_comparison Gt f g); - register_bin_prim "caml_lt_float" `Pure (fun f g -> float_comparison Lt f g); - register_un_prim "caml_int_of_float" `Pure (fun f -> - let* f = Memory.unbox_float f in + register_un_prim + "caml_neg_float" + `Pure + ~typ:(Number (Float, Unboxed)) + (fun f -> float_un_op Neg f); + register_un_prim + "caml_abs_float" + `Pure + ~typ:(Number (Float, Unboxed)) + (fun f -> float_un_op Abs f); + register_un_prim + "caml_ceil_float" + `Pure + ~typ:(Number (Float, Unboxed)) + (fun f -> float_un_op Ceil f); + register_un_prim + "caml_floor_float" + `Pure + ~typ:(Number (Float, Unboxed)) + (fun f -> float_un_op Floor f); + register_un_prim + "caml_trunc_float" + `Pure + ~typ:(Number (Float, Unboxed)) + (fun f -> float_un_op Trunc f); + register_un_prim "caml_round_float" `Pure ~typ:(Number (Float, Unboxed)) Math.round; + register_un_prim + "caml_sqrt_float" + `Pure + ~typ:(Number (Float, Unboxed)) + (fun f -> float_un_op Sqrt f); + register_bin_prim + "caml_eq_float" + `Pure + ~tx:(Number (Float, Unboxed)) + ~ty:(Number (Float, Unboxed)) + (fun f g -> float_bin_op Eq f g); + register_bin_prim + "caml_neq_float" + `Pure + ~tx:(Number (Float, Unboxed)) + ~ty:(Number (Float, Unboxed)) + (fun f g -> float_bin_op Ne f g); + register_bin_prim + "caml_ge_float" + `Pure + ~tx:(Number (Float, Unboxed)) + ~ty:(Number (Float, Unboxed)) + (fun f g -> float_bin_op Ge f g); + register_bin_prim + "caml_le_float" + `Pure + ~tx:(Number (Float, Unboxed)) + ~ty:(Number (Float, Unboxed)) + (fun f g -> float_bin_op Le f g); + register_bin_prim + "caml_gt_float" + `Pure + ~tx:(Number (Float, Unboxed)) + ~ty:(Number (Float, Unboxed)) + (fun f g -> float_bin_op Gt f g); + register_bin_prim + "caml_lt_float" + ~tx:(Number (Float, Unboxed)) + ~ty:(Number (Float, Unboxed)) + `Pure + (fun f g -> float_bin_op Lt f g); + register_un_prim + "caml_int_of_float" + `Pure + ~typ:(Number (Float, Unboxed)) + (fun f -> + let* f = f in return (W.UnOp (I32 (TruncSatF64 S), f))); register_un_prim "caml_float_of_int" `Pure ~typ:(Int Normalized) (fun n -> let* n = n in - Memory.box_float (return (W.UnOp (F64 (Convert (`I32, S)), n)))); - register_un_prim "caml_cos_float" `Pure (fun f -> float_un_op' Math.cos f); - register_un_prim "caml_sin_float" `Pure (fun f -> float_un_op' Math.sin f); - register_un_prim "caml_tan_float" `Pure (fun f -> float_un_op' Math.tan f); - register_un_prim "caml_acos_float" `Pure (fun f -> float_un_op' Math.acos f); - register_un_prim "caml_asin_float" `Pure (fun f -> float_un_op' Math.asin f); - register_un_prim "caml_atan_float" `Pure (fun f -> float_un_op' Math.atan f); - register_bin_prim "caml_atan2_float" `Pure (fun f g -> float_bin_op' Math.atan2 f g); - register_un_prim "caml_cosh_float" `Pure (fun f -> float_un_op' Math.cosh f); - register_un_prim "caml_sinh_float" `Pure (fun f -> float_un_op' Math.sinh f); - register_un_prim "caml_tanh_float" `Pure (fun f -> float_un_op' Math.tanh f); - register_un_prim "caml_acosh_float" `Pure (fun f -> float_un_op' Math.acosh f); - register_un_prim "caml_asinh_float" `Pure (fun f -> float_un_op' Math.asinh f); - register_un_prim "caml_atanh_float" `Pure (fun f -> float_un_op' Math.atanh f); - register_un_prim "caml_cbrt_float" `Pure (fun f -> float_un_op' Math.cbrt f); - register_un_prim "caml_exp_float" `Pure (fun f -> float_un_op' Math.exp f); - register_un_prim "caml_exp2_float" `Pure (fun f -> float_un_op' Math.exp2 f); - register_un_prim "caml_log_float" `Pure (fun f -> float_un_op' Math.log f); - register_un_prim "caml_expm1_float" `Pure (fun f -> float_un_op' Math.expm1 f); - register_un_prim "caml_log1p_float" `Pure (fun f -> float_un_op' Math.log1p f); - register_un_prim "caml_log2_float" `Pure (fun f -> float_un_op' Math.log2 f); - register_un_prim "caml_log10_float" `Pure (fun f -> float_un_op' Math.log10 f); - register_bin_prim "caml_power_float" `Pure (fun f g -> float_bin_op' Math.power f g); - register_bin_prim "caml_hypot_float" `Pure (fun f g -> float_bin_op' Math.hypot f g); - register_bin_prim "caml_fmod_float" `Pure (fun f g -> float_bin_op' Math.fmod f g); - register_un_prim "caml_int32_bits_of_float" `Pure (fun f -> - let* f = Memory.unbox_float f in - Memory.box_int32 (return (W.UnOp (I32 ReinterpretF, F32DemoteF64 f)))); - register_un_prim "caml_int32_float_of_bits" `Pure (fun i -> - let* i = Memory.unbox_int32 i in - Memory.box_float (return (W.F64PromoteF32 (UnOp (F32 ReinterpretI, i))))); - register_un_prim "caml_int32_of_float" `Pure (fun f -> - let* f = Memory.unbox_float f in - Memory.box_int32 (return (W.UnOp (I32 (TruncSatF64 S), f)))); - register_un_prim "caml_int32_to_float" `Pure (fun n -> - let* n = Memory.unbox_int32 n in - Memory.box_float (return (W.UnOp (F64 (Convert (`I32, S)), n)))); - register_un_prim "caml_int32_neg" `Pure (fun i -> - let* i = Memory.unbox_int32 i in - Memory.box_int32 (return (W.BinOp (I32 Sub, Const (I32 0l), i)))); - register_bin_prim "caml_int32_add" `Pure (fun i j -> int32_bin_op Add i j); - register_bin_prim "caml_int32_sub" `Pure (fun i j -> int32_bin_op Sub i j); - register_bin_prim "caml_int32_mul" `Pure (fun i j -> int32_bin_op Mul i j); - register_bin_prim "caml_int32_and" `Pure (fun i j -> int32_bin_op And i j); - register_bin_prim "caml_int32_or" `Pure (fun i j -> int32_bin_op Or i j); - register_bin_prim "caml_int32_xor" `Pure (fun i j -> int32_bin_op Xor i j); - register_bin_prim_ctx "caml_int32_div" (fun context i j -> + return (W.UnOp (F64 (Convert (`I32, S)), n))); + register_un_prim "caml_cos_float" `Pure ~typ:(Number (Float, Unboxed)) Math.cos; + register_un_prim "caml_sin_float" `Pure ~typ:(Number (Float, Unboxed)) Math.sin; + register_un_prim "caml_tan_float" `Pure ~typ:(Number (Float, Unboxed)) Math.tan; + register_un_prim "caml_acos_float" `Pure ~typ:(Number (Float, Unboxed)) Math.acos; + register_un_prim "caml_asin_float" `Pure ~typ:(Number (Float, Unboxed)) Math.asin; + register_un_prim "caml_atan_float" `Pure ~typ:(Number (Float, Unboxed)) Math.atan; + register_bin_prim + "caml_atan2_float" + `Pure + ~tx:(Number (Float, Unboxed)) + ~ty:(Number (Float, Unboxed)) + Math.atan2; + register_un_prim "caml_cosh_float" `Pure ~typ:(Number (Float, Unboxed)) Math.cosh; + register_un_prim "caml_sinh_float" `Pure ~typ:(Number (Float, Unboxed)) Math.sinh; + register_un_prim "caml_tanh_float" `Pure ~typ:(Number (Float, Unboxed)) Math.tanh; + register_un_prim "caml_acosh_float" `Pure ~typ:(Number (Float, Unboxed)) Math.acosh; + register_un_prim "caml_asinh_float" `Pure ~typ:(Number (Float, Unboxed)) Math.asinh; + register_un_prim "caml_atanh_float" `Pure ~typ:(Number (Float, Unboxed)) Math.atanh; + register_un_prim "caml_cbrt_float" `Pure ~typ:(Number (Float, Unboxed)) Math.cbrt; + register_un_prim "caml_exp_float" `Pure ~typ:(Number (Float, Unboxed)) Math.exp; + register_un_prim "caml_exp2_float" `Pure ~typ:(Number (Float, Unboxed)) Math.exp2; + register_un_prim "caml_log_float" `Pure ~typ:(Number (Float, Unboxed)) Math.log; + register_un_prim "caml_expm1_float" `Pure ~typ:(Number (Float, Unboxed)) Math.expm1; + register_un_prim "caml_log1p_float" `Pure ~typ:(Number (Float, Unboxed)) Math.log1p; + register_un_prim "caml_log2_float" `Pure ~typ:(Number (Float, Unboxed)) Math.log2; + register_un_prim "caml_log10_float" `Pure ~typ:(Number (Float, Unboxed)) Math.log10; + register_bin_prim + "caml_power_float" + `Pure + ~tx:(Number (Float, Unboxed)) + ~ty:(Number (Float, Unboxed)) + Math.power; + register_bin_prim + "caml_hypot_float" + `Pure + ~tx:(Number (Float, Unboxed)) + ~ty:(Number (Float, Unboxed)) + Math.hypot; + register_bin_prim + "caml_fmod_float" + `Pure + ~tx:(Number (Float, Unboxed)) + ~ty:(Number (Float, Unboxed)) + Math.fmod; + register_un_prim + "caml_int32_bits_of_float" + `Pure + ~typ:(Number (Float, Unboxed)) + (fun f -> + let* f = f in + return (W.UnOp (I32 ReinterpretF, F32DemoteF64 f))); + register_un_prim + "caml_int32_float_of_bits" + `Pure + ~typ:(Number (Int32, Unboxed)) + (fun i -> + let* i = i in + return (W.F64PromoteF32 (UnOp (F32 ReinterpretI, i)))); + register_un_prim + "caml_int32_of_float" + `Pure + ~typ:(Number (Float, Unboxed)) + (fun f -> + let* f = f in + return (W.UnOp (I32 (TruncSatF64 S), f))); + register_un_prim + "caml_int32_to_float" + `Pure + ~typ:(Number (Int32, Unboxed)) + (fun n -> + let* n = n in + return (W.UnOp (F64 (Convert (`I32, S)), n))); + register_un_prim + "caml_int32_neg" + `Pure + ~typ:(Number (Int32, Unboxed)) + (fun i -> + let* i = i in + return (W.BinOp (I32 Sub, Const (I32 0l), i))); + register_bin_prim + "caml_int32_add" + `Pure + ~tx:(Number (Int32, Unboxed)) + ~ty:(Number (Int32, Unboxed)) + (fun i j -> int32_bin_op Add i j); + register_bin_prim + "caml_int32_sub" + `Pure + ~tx:(Number (Int32, Unboxed)) + ~ty:(Number (Int32, Unboxed)) + (fun i j -> int32_bin_op Sub i j); + register_bin_prim + "caml_int32_mul" + `Pure + ~tx:(Number (Int32, Unboxed)) + ~ty:(Number (Int32, Unboxed)) + (fun i j -> int32_bin_op Mul i j); + register_bin_prim + "caml_int32_and" + `Pure + ~tx:(Number (Int32, Unboxed)) + ~ty:(Number (Int32, Unboxed)) + (fun i j -> int32_bin_op And i j); + register_bin_prim + "caml_int32_or" + `Pure + ~tx:(Number (Int32, Unboxed)) + ~ty:(Number (Int32, Unboxed)) + (fun i j -> int32_bin_op Or i j); + register_bin_prim + "caml_int32_xor" + `Pure + ~tx:(Number (Int32, Unboxed)) + ~ty:(Number (Int32, Unboxed)) + (fun i j -> int32_bin_op Xor i j); + register_bin_prim_ctx + "caml_int32_div" + ~tx:(Number (Int32, Unboxed)) + ~ty:(Number (Int32, Unboxed)) + (fun context i j -> let res = Var.fresh () in (*ZZZ Can we do better?*) let i' = Var.fresh () in let j' = Var.fresh () in seq - (let* () = store ~typ:I32 j' (Memory.unbox_int32 j) in + (let* () = store ~typ:I32 j' j in let* () = let* j = load j' in instr (W.Br_if (label_index context zero_divide_pc, W.UnOp (I32 Eqz, j))) in - let* () = store ~typ:I32 i' (Memory.unbox_int32 i) in + let* () = store ~typ:I32 i' i in if_ { params = []; result = [] } Arith.( @@ -577,65 +753,137 @@ module Generate (Target : Target_sig.S) = struct (let* i = load i' in let* j = load j' in return (W.BinOp (I32 (Div S), i, j))))) - (Memory.box_int32 (load res))); - register_bin_prim_ctx "caml_int32_mod" (fun context i j -> + (load res)); + register_bin_prim_ctx + "caml_int32_mod" + ~tx:(Number (Int32, Unboxed)) + ~ty:(Number (Int32, Unboxed)) + (fun context i j -> let j' = Var.fresh () in seq - (let* () = store ~typ:I32 j' (Memory.unbox_int32 j) in + (let* () = store ~typ:I32 j' j in let* j = load j' in instr (W.Br_if (label_index context zero_divide_pc, W.UnOp (I32 Eqz, j)))) - (let* i = Memory.unbox_int32 i in + (let* i = i in let* j = load j' in - Memory.box_int32 (return (W.BinOp (I32 (Rem S), i, j))))); - register_bin_prim "caml_int32_shift_left" `Pure ~ty:(Int Unnormalized) (fun i j -> - int32_shift_op Shl i j); - register_bin_prim "caml_int32_shift_right" `Pure ~ty:(Int Unnormalized) (fun i j -> - int32_shift_op (Shr S) i j); + return (W.BinOp (I32 (Rem S), i, j)))); + register_bin_prim + "caml_int32_shift_left" + `Pure + ~tx:(Number (Int32, Unboxed)) + ~ty:(Int Unnormalized) + (fun i j -> int32_bin_op Shl i j); + register_bin_prim + "caml_int32_shift_right" + `Pure + ~tx:(Number (Int32, Unboxed)) + ~ty:(Int Unnormalized) + (fun i j -> int32_bin_op (Shr S) i j); register_bin_prim "caml_int32_shift_right_unsigned" `Pure + ~tx:(Number (Int32, Unboxed)) ~ty:(Int Unnormalized) - (fun i j -> int32_shift_op (Shr U) i j); - register_un_prim "caml_int32_to_int" `Pure (fun i -> Memory.unbox_int32 i); - register_un_prim "caml_int32_of_int" `Pure ~typ:(Int Normalized) (fun i -> - Memory.box_int32 i); - register_un_prim "caml_nativeint_of_int32" `Pure (fun i -> - Memory.box_nativeint (Memory.unbox_int32 i)); - register_un_prim "caml_nativeint_to_int32" `Pure (fun i -> - Memory.box_int32 (Memory.unbox_nativeint i)); - register_un_prim "caml_int64_bits_of_float" `Pure (fun f -> - let* f = Memory.unbox_float f in - Memory.box_int64 (return (W.UnOp (I64 ReinterpretF, f)))); - register_un_prim "caml_int64_float_of_bits" `Pure (fun i -> - let* i = Memory.unbox_int64 i in - Memory.box_float (return (W.UnOp (F64 ReinterpretI, i)))); - register_un_prim "caml_int64_of_float" `Pure (fun f -> - let* f = Memory.unbox_float f in - Memory.box_int64 (return (W.UnOp (I64 (TruncSatF64 S), f)))); - register_un_prim "caml_int64_to_float" `Pure (fun n -> - let* n = Memory.unbox_int64 n in - Memory.box_float (return (W.UnOp (F64 (Convert (`I64, S)), n)))); - register_un_prim "caml_int64_neg" `Pure (fun i -> - let* i = Memory.unbox_int64 i in - Memory.box_int64 (return (W.BinOp (I64 Sub, Const (I64 0L), i)))); - register_bin_prim "caml_int64_add" `Pure (fun i j -> int64_bin_op Add i j); - register_bin_prim "caml_int64_sub" `Pure (fun i j -> int64_bin_op Sub i j); - register_bin_prim "caml_int64_mul" `Pure (fun i j -> int64_bin_op Mul i j); - register_bin_prim "caml_int64_and" `Pure (fun i j -> int64_bin_op And i j); - register_bin_prim "caml_int64_or" `Pure (fun i j -> int64_bin_op Or i j); - register_bin_prim "caml_int64_xor" `Pure (fun i j -> int64_bin_op Xor i j); - register_bin_prim_ctx "caml_int64_div" (fun context i j -> + (fun i j -> int32_bin_op (Shr U) i j); + register_un_prim "caml_int32_to_int" `Pure ~typ:(Number (Int32, Unboxed)) (fun i -> i); + register_un_prim "caml_int32_of_int" `Pure ~typ:(Int Normalized) (fun i -> i); + register_un_prim + "caml_nativeint_of_int32" + `Pure + ~typ:(Number (Int32, Unboxed)) + (fun i -> i); + register_un_prim + "caml_nativeint_to_int32" + `Pure + ~typ:(Number (Nativeint, Unboxed)) + (fun i -> i); + register_un_prim + "caml_int64_bits_of_float" + `Pure + ~typ:(Number (Float, Unboxed)) + (fun f -> + let* f = f in + return (W.UnOp (I64 ReinterpretF, f))); + register_un_prim + "caml_int64_float_of_bits" + `Pure + ~typ:(Number (Int64, Unboxed)) + (fun i -> + let* i = i in + return (W.UnOp (F64 ReinterpretI, i))); + register_un_prim + "caml_int64_of_float" + `Pure + ~typ:(Number (Float, Unboxed)) + (fun f -> + let* f = f in + return (W.UnOp (I64 (TruncSatF64 S), f))); + register_un_prim + "caml_int64_to_float" + `Pure + ~typ:(Number (Int64, Unboxed)) + (fun n -> + let* n = n in + return (W.UnOp (F64 (Convert (`I64, S)), n))); + register_un_prim + "caml_int64_neg" + `Pure + ~typ:(Number (Int64, Unboxed)) + (fun i -> + let* i = i in + return (W.BinOp (I64 Sub, Const (I64 0L), i))); + register_bin_prim + "caml_int64_add" + `Pure + ~tx:(Number (Int64, Unboxed)) + ~ty:(Number (Int64, Unboxed)) + (fun i j -> int64_bin_op Add i j); + register_bin_prim + "caml_int64_sub" + `Pure + ~tx:(Number (Int64, Unboxed)) + ~ty:(Number (Int64, Unboxed)) + (fun i j -> int64_bin_op Sub i j); + register_bin_prim + "caml_int64_mul" + `Pure + ~tx:(Number (Int64, Unboxed)) + ~ty:(Number (Int64, Unboxed)) + (fun i j -> int64_bin_op Mul i j); + register_bin_prim + "caml_int64_and" + `Pure + ~tx:(Number (Int64, Unboxed)) + ~ty:(Number (Int64, Unboxed)) + (fun i j -> int64_bin_op And i j); + register_bin_prim + "caml_int64_or" + `Pure + ~tx:(Number (Int64, Unboxed)) + ~ty:(Number (Int64, Unboxed)) + (fun i j -> int64_bin_op Or i j); + register_bin_prim + "caml_int64_xor" + `Pure + ~tx:(Number (Int64, Unboxed)) + ~ty:(Number (Int64, Unboxed)) + (fun i j -> int64_bin_op Xor i j); + register_bin_prim_ctx + "caml_int64_div" + ~tx:(Number (Int64, Unboxed)) + ~ty:(Number (Int64, Unboxed)) + (fun context i j -> let res = Var.fresh () in (*ZZZ Can we do better?*) let i' = Var.fresh () in let j' = Var.fresh () in seq - (let* () = store ~typ:I64 j' (Memory.unbox_int64 j) in + (let* () = store ~typ:I64 j' j in let* () = let* j = load j' in instr (W.Br_if (label_index context zero_divide_pc, W.UnOp (I64 Eqz, j))) in - let* () = store ~typ:I64 i' (Memory.unbox_int64 i) in + let* () = store ~typ:I64 i' i in if_ { params = []; result = [] } Arith.( @@ -651,80 +899,166 @@ module Generate (Target : Target_sig.S) = struct (let* i = load i' in let* j = load j' in return (W.BinOp (I64 (Div S), i, j))))) - (Memory.box_int64 (load res))); - register_bin_prim_ctx "caml_int64_mod" (fun context i j -> + (load res)); + register_bin_prim_ctx + "caml_int64_mod" + ~tx:(Number (Int64, Unboxed)) + ~ty:(Number (Int64, Unboxed)) + (fun context i j -> let j' = Var.fresh () in seq - (let* () = store ~typ:I64 j' (Memory.unbox_int64 j) in + (let* () = store ~typ:I64 j' j in let* j = load j' in instr (W.Br_if (label_index context zero_divide_pc, W.UnOp (I64 Eqz, j)))) - (let* i = Memory.unbox_int64 i in + (let* i = i in let* j = load j' in - Memory.box_int64 (return (W.BinOp (I64 (Rem S), i, j))))); - register_bin_prim "caml_int64_shift_left" `Pure ~ty:(Int Unnormalized) (fun i j -> - int64_shift_op Shl i j); - register_bin_prim "caml_int64_shift_right" `Pure ~ty:(Int Unnormalized) (fun i j -> - int64_shift_op (Shr S) i j); + return (W.BinOp (I64 (Rem S), i, j)))); + register_bin_prim + "caml_int64_shift_left" + `Pure + ~tx:(Number (Int64, Unboxed)) + ~ty:(Int Unnormalized) + (fun i j -> int64_shift_op Shl i j); + register_bin_prim + "caml_int64_shift_right" + `Pure + ~tx:(Number (Int64, Unboxed)) + ~ty:(Int Unnormalized) + (fun i j -> int64_shift_op (Shr S) i j); register_bin_prim "caml_int64_shift_right_unsigned" + ~tx:(Number (Int64, Unboxed)) ~ty:(Int Unnormalized) `Pure (fun i j -> int64_shift_op (Shr U) i j); - register_un_prim "caml_int64_to_int" `Pure (fun i -> - let* i = Memory.unbox_int64 i in + register_un_prim + "caml_int64_to_int" + `Pure + ~typ:(Number (Int64, Unboxed)) + (fun i -> + let* i = i in return (W.I32WrapI64 i)); register_un_prim "caml_int64_of_int" `Pure ~typ:(Int Normalized) (fun i -> let* i = i in - Memory.box_int64 - (return - (match i with - | Const (I32 i) -> W.Const (I64 (Int64.of_int32 i)) - | _ -> W.I64ExtendI32 (S, i)))); - register_un_prim "caml_int64_to_int32" `Pure (fun i -> - let* i = Memory.unbox_int64 i in - Memory.box_int32 (return (W.I32WrapI64 i))); - register_un_prim "caml_int64_of_int32" `Pure (fun i -> - let* i = Memory.unbox_int32 i in - Memory.box_int64 (return (W.I64ExtendI32 (S, i)))); - register_un_prim "caml_int64_to_nativeint" `Pure (fun i -> - let* i = Memory.unbox_int64 i in - Memory.box_nativeint (return (W.I32WrapI64 i))); - register_un_prim "caml_int64_of_nativeint" `Pure (fun i -> - let* i = Memory.unbox_nativeint i in - Memory.box_int64 (return (W.I64ExtendI32 (S, i)))); - register_un_prim "caml_nativeint_bits_of_float" `Pure (fun f -> - let* f = Memory.unbox_float f in - Memory.box_nativeint (return (W.UnOp (I32 ReinterpretF, F32DemoteF64 f)))); - register_un_prim "caml_nativeint_float_of_bits" `Pure (fun i -> - let* i = Memory.unbox_int64 i in - Memory.box_float (return (W.F64PromoteF32 (UnOp (I32 ReinterpretF, i))))); - register_un_prim "caml_nativeint_of_float" `Pure (fun f -> - let* f = Memory.unbox_float f in - Memory.box_nativeint (return (W.UnOp (I32 (TruncSatF64 S), f)))); - register_un_prim "caml_nativeint_to_float" `Pure (fun n -> - let* n = Memory.unbox_nativeint n in - Memory.box_float (return (W.UnOp (F64 (Convert (`I32, S)), n)))); - register_un_prim "caml_nativeint_neg" `Pure (fun i -> - let* i = Memory.unbox_nativeint i in - Memory.box_nativeint (return (W.BinOp (I32 Sub, Const (I32 0l), i)))); - register_bin_prim "caml_nativeint_add" `Pure (fun i j -> nativeint_bin_op Add i j); - register_bin_prim "caml_nativeint_sub" `Pure (fun i j -> nativeint_bin_op Sub i j); - register_bin_prim "caml_nativeint_mul" `Pure (fun i j -> nativeint_bin_op Mul i j); - register_bin_prim "caml_nativeint_and" `Pure (fun i j -> nativeint_bin_op And i j); - register_bin_prim "caml_nativeint_or" `Pure (fun i j -> nativeint_bin_op Or i j); - register_bin_prim "caml_nativeint_xor" `Pure (fun i j -> nativeint_bin_op Xor i j); - register_bin_prim_ctx "caml_nativeint_div" (fun context i j -> + return + (match i with + | Const (I32 i) -> W.Const (I64 (Int64.of_int32 i)) + | _ -> W.I64ExtendI32 (S, i))); + register_un_prim + "caml_int64_to_int32" + `Pure + ~typ:(Number (Int64, Unboxed)) + (fun i -> + let* i = i in + return (W.I32WrapI64 i)); + register_un_prim + "caml_int64_of_int32" + `Pure + ~typ:(Number (Int32, Unboxed)) + (fun i -> + let* i = i in + return (W.I64ExtendI32 (S, i))); + register_un_prim + "caml_int64_to_nativeint" + `Pure + ~typ:(Number (Int64, Unboxed)) + (fun i -> + let* i = i in + return (W.I32WrapI64 i)); + register_un_prim + "caml_int64_of_nativeint" + `Pure + ~typ:(Number (Nativeint, Unboxed)) + (fun i -> + let* i = i in + return (W.I64ExtendI32 (S, i))); + register_un_prim + "caml_nativeint_bits_of_float" + `Pure + ~typ:(Number (Float, Unboxed)) + (fun f -> + let* f = f in + return (W.UnOp (I32 ReinterpretF, F32DemoteF64 f))); + register_un_prim + "caml_nativeint_float_of_bits" + `Pure + ~typ:(Number (Nativeint, Unboxed)) + (fun i -> + let* i = i in + return (W.F64PromoteF32 (UnOp (I32 ReinterpretF, i)))); + register_un_prim + "caml_nativeint_of_float" + `Pure + ~typ:(Number (Float, Unboxed)) + (fun f -> + let* f = f in + return (W.UnOp (I32 (TruncSatF64 S), f))); + register_un_prim + "caml_nativeint_to_float" + `Pure + ~typ:(Number (Nativeint, Unboxed)) + (fun n -> + let* n = n in + return (W.UnOp (F64 (Convert (`I32, S)), n))); + register_un_prim + "caml_nativeint_neg" + `Pure + ~typ:(Number (Nativeint, Unboxed)) + (fun i -> + let* i = i in + return (W.BinOp (I32 Sub, Const (I32 0l), i))); + register_bin_prim + "caml_nativeint_add" + `Pure + ~tx:(Number (Nativeint, Unboxed)) + ~ty:(Number (Nativeint, Unboxed)) + (fun i j -> nativeint_bin_op Add i j); + register_bin_prim + "caml_nativeint_sub" + `Pure + ~tx:(Number (Nativeint, Unboxed)) + ~ty:(Number (Nativeint, Unboxed)) + (fun i j -> nativeint_bin_op Sub i j); + register_bin_prim + "caml_nativeint_mul" + `Pure + ~tx:(Number (Nativeint, Unboxed)) + ~ty:(Number (Nativeint, Unboxed)) + (fun i j -> nativeint_bin_op Mul i j); + register_bin_prim + "caml_nativeint_and" + `Pure + ~tx:(Number (Nativeint, Unboxed)) + ~ty:(Number (Nativeint, Unboxed)) + (fun i j -> nativeint_bin_op And i j); + register_bin_prim + "caml_nativeint_or" + `Pure + ~tx:(Number (Nativeint, Unboxed)) + ~ty:(Number (Nativeint, Unboxed)) + (fun i j -> nativeint_bin_op Or i j); + register_bin_prim + "caml_nativeint_xor" + `Pure + ~tx:(Number (Nativeint, Unboxed)) + ~ty:(Number (Nativeint, Unboxed)) + (fun i j -> nativeint_bin_op Xor i j); + register_bin_prim_ctx + "caml_nativeint_div" + ~tx:(Number (Nativeint, Unboxed)) + ~ty:(Number (Nativeint, Unboxed)) + (fun context i j -> let res = Var.fresh () in (*ZZZ Can we do better?*) let i' = Var.fresh () in let j' = Var.fresh () in seq - (let* () = store ~typ:I32 j' (Memory.unbox_nativeint j) in + (let* () = store ~typ:I32 j' j in let* () = let* j = load j' in instr (W.Br_if (label_index context zero_divide_pc, W.UnOp (I32 Eqz, j))) in - let* () = store ~typ:I32 i' (Memory.unbox_nativeint i) in + let* () = store ~typ:I32 i' i in if_ { params = []; result = [] } Arith.( @@ -740,31 +1074,44 @@ module Generate (Target : Target_sig.S) = struct (let* i = load i' in let* j = load j' in return (W.BinOp (I32 (Div S), i, j))))) - (Memory.box_nativeint (load res))); - register_bin_prim_ctx "caml_nativeint_mod" (fun context i j -> + (load res)); + register_bin_prim_ctx + "caml_nativeint_mod" + ~tx:(Number (Nativeint, Unboxed)) + ~ty:(Number (Nativeint, Unboxed)) + (fun context i j -> let j' = Var.fresh () in seq - (let* () = store ~typ:I32 j' (Memory.unbox_nativeint j) in + (let* () = store ~typ:I32 j' j in let* j = load j' in instr (W.Br_if (label_index context zero_divide_pc, W.UnOp (I32 Eqz, j)))) - (let* i = Memory.unbox_nativeint i in + (let* i = i in let* j = load j' in - Memory.box_nativeint (return (W.BinOp (I32 (Rem S), i, j))))); - register_bin_prim "caml_nativeint_shift_left" `Pure ~ty:(Int Unnormalized) (fun i j -> - nativeint_shift_op Shl i j); + return (W.BinOp (I32 (Rem S), i, j)))); + register_bin_prim + "caml_nativeint_shift_left" + `Pure + ~tx:(Number (Nativeint, Unboxed)) + ~ty:(Int Unnormalized) + (fun i j -> nativeint_bin_op Shl i j); register_bin_prim "caml_nativeint_shift_right" `Pure + ~tx:(Number (Nativeint, Unboxed)) ~ty:(Int Unnormalized) - (fun i j -> nativeint_shift_op (Shr S) i j); + (fun i j -> nativeint_bin_op (Shr S) i j); register_bin_prim "caml_nativeint_shift_right_unsigned" `Pure + ~tx:(Number (Nativeint, Unboxed)) ~ty:(Int Unnormalized) - (fun i j -> nativeint_shift_op (Shr U) i j); - register_un_prim "caml_nativeint_to_int" `Pure (fun i -> Memory.unbox_nativeint i); - register_un_prim "caml_nativeint_of_int" `Pure ~typ:(Int Normalized) (fun i -> - Memory.box_nativeint i); + (fun i j -> nativeint_bin_op (Shr U) i j); + register_un_prim + "caml_nativeint_to_int" + `Pure + ~typ:(Number (Nativeint, Unboxed)) + (fun i -> i); + register_un_prim "caml_nativeint_of_int" `Pure ~typ:(Int Normalized) (fun i -> i); register_bin_prim "caml_int_compare" `Pure @@ -772,84 +1119,317 @@ module Generate (Target : Target_sig.S) = struct ~ty:(Int Normalized) (fun i j -> Arith.((j < i) - (i < j))); register_prim "%js_array" `Pure (fun ctx _ l -> - let* l = - List.fold_right - ~f:(fun x acc -> - let* x = transl_prim_arg ctx x in - let* acc = acc in - return (`Expr x :: acc)) - l - ~init:(return []) - in - Memory.allocate ~tag:0 ~deadcode_sentinal:ctx.deadcode_sentinal ~load l) + Memory.allocate ~tag:0 (expression_list (fun x -> transl_prim_arg ctx x) l)); + register_comparison + "caml_greaterthan" + (fun ctx x y -> translate_int_comparison ctx (fun y x -> Arith.(x < y)) x y) + (Gt S) + Gt; + register_comparison + "caml_greaterequal" + (fun ctx x y -> translate_int_comparison ctx (fun y x -> Arith.(x <= y)) x y) + (Ge S) + Ge; + register_comparison + "caml_lessthan" + (fun ctx x y -> translate_int_comparison ctx Arith.( < ) x y) + (Lt S) + Lt; + register_comparison + "caml_lessequal" + (fun ctx x y -> translate_int_comparison ctx Arith.( <= ) x y) + (Le S) + Le; + register_comparison + "caml_equal" + (fun ctx x y -> translate_int_equality ctx ~negate:false x y) + Eq + Eq; + register_comparison + "caml_notequal" + (fun ctx x y -> translate_int_equality ctx ~negate:true x y) + Ne + Ne; + register_prim "caml_compare" `Mutable (fun ctx _ l -> + match l with + | [ x; y ] -> ( + match get_type ctx x, get_type ctx y with + | Int _, Int _ -> + let x' = transl_prim_arg ctx ~typ:(Int Normalized) x in + let y' = transl_prim_arg ctx ~typ:(Int Normalized) y in + Arith.((y' < x') - (x' < y')) + | Number (Int32, _), Number (Int32, _) + | Number (Nativeint, _), Number (Nativeint, _) -> + let* f = + register_import + ~name:"caml_int32_compare" + (Fun { W.params = [ I32; I32 ]; result = [ I32 ] }) + in + let* x' = transl_prim_arg ctx ~typ:(Number (Int32, Unboxed)) x in + let* y' = transl_prim_arg ctx ~typ:(Number (Int32, Unboxed)) y in + return (W.Call (f, [ x'; y' ])) + | Number (Int64, _), Number (Int64, _) -> + let* f = + register_import + ~name:"caml_int64_compare" + (Fun { W.params = [ I64; I64 ]; result = [ I32 ] }) + in + let* x' = transl_prim_arg ctx ~typ:(Number (Int64, Unboxed)) x in + let* y' = transl_prim_arg ctx ~typ:(Number (Int64, Unboxed)) y in + return (W.Call (f, [ x'; y' ])) + | Number (Float, _), Number (Float, _) -> + let* f = + register_import + ~name:"caml_float_compare" + (Fun { W.params = [ F64; F64 ]; result = [ I32 ] }) + in + let* x' = transl_prim_arg ctx ~typ:(Number (Float, Unboxed)) x in + let* y' = transl_prim_arg ctx ~typ:(Number (Float, Unboxed)) y in + return (W.Call (f, [ x'; y' ])) + | _ -> + let* f = + register_import + ~name:"caml_compare" + (Fun { W.params = [ Type.value; Type.value ]; result = [ I32 ] }) + in + let* x' = transl_prim_arg ctx x in + let* y' = transl_prim_arg ctx y in + return (W.Call (f, [ x'; y' ]))) + | _ -> invalid_arity "caml_compare" l ~expected:2); + let bigarray_generic_access ~ctx ta indices = + match + ( get_type ctx ta + , match indices with + | Pv indices -> Some (indices, ctx.global_flow_info.info_defs.(Var.idx indices)) + | Pc _ -> None ) + with + | Bigarray { kind; layout }, Some (indices, Expr (Block (_, l, _, _))) -> + Some + ( kind + , layout + , List.mapi + ~f:(fun i _ -> + Value.int_val + (Memory.array_get (load indices) (Arith.const (Int32.of_int (i + 1))))) + (Array.to_list l) ) + | _, None | _, Some (_, (Expr _ | Phi _)) -> None + in + let caml_ba_get ~ctx ~context ~kind ~layout ta indices = + let ta' = transl_prim_arg ctx ta in + Bigarray.get + ~bound_error_index:(label_index context bound_error_pc) + ~kind + ~layout + ta' + ~indices + in + let caml_ba_get_n ~ctx ~context ta indices = + match get_type ctx ta with + | Bigarray { 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 + | _ -> + let n = List.length indices in + let* f = + register_import + ~name:(Printf.sprintf "caml_ba_get_%d" n) + (Fun (Type.primitive_type (n + 1))) + in + let* ta' = transl_prim_arg ctx ta in + 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 -> + match l with + | [ ta; i ] -> caml_ba_get_n ~ctx ~context ta [ i ] + | _ -> invalid_arity "caml_ba_get_1" l ~expected:2); + register_prim "caml_ba_get_2" `Mutator (fun ctx context l -> + match l with + | [ ta; i; j ] -> caml_ba_get_n ~ctx ~context ta [ i; j ] + | _ -> invalid_arity "caml_ba_get_2" l ~expected:3); + register_prim "caml_ba_get_3" `Mutator (fun ctx context l -> + match l with + | [ ta; i; j; k ] -> caml_ba_get_n ~ctx ~context ta [ i; j; k ] + | _ -> invalid_arity "caml_ba_get_3" l ~expected:4); + 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 + | _ -> + let* f = + register_import + ~name:"caml_ba_get_generic" + (Fun (Type.primitive_type 2)) + in + let* ta' = transl_prim_arg ctx ta in + let* indices' = transl_prim_arg ctx indices in + return (W.Call (f, [ ta'; indices' ]))) + | _ -> invalid_arity "caml_ba_get_generic" l ~expected:2); + let caml_ba_set ~ctx ~context ~kind ~layout ta indices v = + let ta' = transl_prim_arg ctx ta in + let v' = transl_prim_arg ctx ~typ:(Typing.bigarray_element_type kind) v in + Bigarray.set + ~bound_error_index:(label_index context bound_error_pc) + ~kind + ~layout + ta' + ~indices + v' + in + let caml_ba_set_n ~ctx ~context ta indices v = + match get_type ctx ta with + | Bigarray { 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 + | _ -> + let n = List.length indices in + let* f = + register_import + ~name:(Printf.sprintf "caml_ba_set_%d" n) + (Fun (Type.primitive_type (n + 2))) + in + let* ta' = transl_prim_arg ctx ta in + let* indices' = expression_list (transl_prim_arg ctx) indices in + 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 -> + match l with + | [ ta; i; v ] -> caml_ba_set_n ~ctx ~context ta [ i ] v + | _ -> invalid_arity "caml_ba_set_1" l ~expected:3); + register_prim "caml_ba_set_2" `Mutator (fun ctx context l -> + match l with + | [ ta; i; j; v ] -> caml_ba_set_n ~ctx ~context ta [ i; j ] v + | _ -> invalid_arity "caml_ba_set_2" l ~expected:4); + register_prim "caml_ba_set_3" `Mutator (fun ctx context l -> + match l with + | [ ta; i; j; k; v ] -> caml_ba_set_n ~ctx ~context 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 -> + 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 + | _ -> + let* f = + register_import + ~name:"caml_ba_set_generic" + (Fun (Type.primitive_type 3)) + in + let* ta' = transl_prim_arg ctx ta in + let* indices' = transl_prim_arg ctx indices in + let* v' = transl_prim_arg ctx v in + return (W.Call (f, [ ta'; indices'; v' ]))) + | _ -> invalid_arity "caml_ba_set_generic" l ~expected:3) + + let unboxed_type ty : W.value_type option = + match ty with + | Typing.Int (Normalized | Unnormalized) | Number ((Int32 | Nativeint), Unboxed) -> + Some I32 + | Number (Int64, Unboxed) -> Some I64 + | Number (Float, Unboxed) -> Some F64 + | _ -> None + + let box_number_if_needed ctx x e = + match Typing.var_type ctx.types x with + | Number (n, Boxed) as into -> convert ~from:(Number (n, Unboxed)) ~into e + | _ -> e let rec translate_expr ctx context x e = match e with | Apply { f; args; exact; _ } -> + let* closure = load f in if exact || List.length args = if Var.Set.mem x ctx.in_cps then 2 else 1 then - let rec loop acc l = - match l with - | [] -> ( - let arity = List.length args in - let funct = Var.fresh () in - let* closure = tee funct (load f) in - let* ty, funct = - Memory.load_function_pointer - ~cps:(Var.Set.mem x ctx.in_cps) - ~arity - (load funct) - in - let* b = is_closure f in - if b - then return (W.Call (f, List.rev (closure :: acc))) - else - match funct with - | W.RefFunc g -> - (* Functions with constant closures ignore their - environment. In case of partial application, we - still need the closure. *) - let* cl = if exact then Value.unit else return closure in - return (W.Call (g, List.rev (cl :: acc))) - | _ -> ( - match - if exact - then Global_flow.get_unique_closure ctx.global_flow_info f - else None - with - | Some g -> return (W.Call (g, List.rev (closure :: acc))) - | None -> return (W.Call_ref (ty, funct, List.rev (closure :: acc))) - )) - | x :: r -> - let* x = load_and_box ctx x in - loop (x :: acc) r - in - loop [] args + match + if exact then Global_flow.get_unique_closure ctx.global_flow_info f else None + with + | Some (g, params) -> + let* cl = + (* Functions with constant closures ignore their environment. *) + match closure with + | GlobalGet global -> + let* init = get_global global in + if Option.is_some init then Value.unit else return closure + | _ -> return closure + in + let* args = + expression_list + Fun.id + (List.map2 + ~f:(fun a p -> + convert + ~from:(Typing.var_type ctx.types a) + ~into:(Typing.var_type ctx.types p) + (load a)) + args + params) + in + convert + ~from:(Typing.return_type ctx.types g) + ~into:(Typing.var_type ctx.types x) + (return (W.Call (g, args @ [ cl ]))) + | None -> ( + let funct = Var.fresh () in + let* closure = tee funct (return closure) in + let* ty, funct = + Memory.load_function_pointer + ~cps:(Var.Set.mem x ctx.in_cps) + ~arity:(List.length args) + (load funct) + in + let* args = expression_list (fun x -> load_and_box ctx x) args in + match funct with + | W.RefFunc g -> return (W.Call (g, args @ [ closure ])) + | _ -> return (W.Call_ref (ty, funct, args @ [ closure ]))) else let* apply = need_apply_fun ~cps:(Var.Set.mem x ctx.in_cps) ~arity:(List.length args) in let* args = expression_list (fun x -> load_and_box ctx x) args in - let* closure = load f in return (W.Call (apply, args @ [ closure ])) | Block (tag, a, _, _) -> - Memory.allocate - ~deadcode_sentinal:ctx.deadcode_sentinal - ~tag - ~load:(fun x -> load_and_box ctx x) - (List.map ~f:(fun x -> `Var x) (Array.to_list a)) - | Field (x, n, Non_float) -> Memory.field (load_and_box ctx x) n - | Field (x, n, Float) -> + if tag = 254 + then + Memory.allocate_float_array + (expression_list + (fun x -> + convert + ~from:(Typing.var_type ctx.types x) + ~into:(Number (Float, Unboxed)) + (load x)) + (Array.to_list a)) + else + Memory.allocate + ~tag + (expression_list (fun x -> load_and_box ctx x) (Array.to_list a)) + | Field (y, n, Non_float) -> Memory.field (load_and_box ctx y) n + | Field (y, n, Float) -> Memory.float_array_get - (load_and_box ctx x) - (Constant.translate (Int (Targetint.of_int_warning_on_overflow n))) + (load_and_box ctx y) + (return (W.Const (I32 (Int32.of_int n)))) + |> box_number_if_needed ctx x | Closure _ -> Closure.translate ~context:ctx.global_context ~closures:ctx.closures ~cps:(Var.Set.mem x ctx.in_cps) + ~no_code_pointer:(Call_graph_analysis.direct_calls_only ctx.fun_info x) x - | Constant c -> Constant.translate c + | Constant c -> + Constant.translate + ~unboxed: + (match Typing.var_type ctx.types x with + | Number (_, Unboxed) -> true + | _ -> false) + c | Special (Alias_prim _) -> assert false | Prim (Extern "caml_alloc_dummy_function", [ _; Pc (Int arity) ]) -> (* Removed in OCaml 5.2 *) @@ -896,40 +1476,56 @@ 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 ]) -> + 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 -> 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 -> + let ((_, arg_typ, _) as typ) = + String.Hashtbl.find specialized_primitives name + in + let* f = register_import ~name (Fun (specialized_primitive_type typ)) in + let rec loop acc arg_typ l = + match arg_typ, l with + | [], [] -> return (W.Call (f, List.rev acc)) + | repr :: rem, x :: r -> + let* x = + transl_prim_arg + ctx + ?typ: + (match repr with + | Value -> None + | Float -> Some (Number (Float, Unboxed)) + | Int -> Some (Int Normalized) + | Int32 -> Some (Number (Int32, Unboxed)) + | Nativeint -> Some (Number (Nativeint, Unboxed)) + | Int64 -> Some (Number (Int64, Unboxed))) + x + in + loop (x :: acc) rem r + | [], _ :: _ | _ :: _, [] -> assert false + in + loop [] arg_typ l |> box_number_if_needed ctx x | _ -> ( let l = List.map ~f:(fun x -> transl_prim_arg ctx x) l in match p, l with - | Extern name, l -> ( - try - let ((_, arg_typ, res_typ) as typ) = - String.Hashtbl.find specialized_primitives name - in - let* f = register_import ~name (Fun (specialized_primitive_type typ)) in - let rec loop acc arg_typ l = - match arg_typ, l with - | [], [] -> box_value res_typ (return (W.Call (f, List.rev acc))) - | repr :: rem, x :: r -> - let* x = unbox_value repr x in - loop (x :: acc) rem r - | [], _ :: _ | _ :: _, [] -> assert false - in - loop [] arg_typ l - with Not_found -> - let* f = - register_import ~name (Fun (Type.primitive_type (List.length l))) - in - let rec loop acc l = - match l with - | [] -> return (W.Call (f, List.rev acc)) - | x :: r -> - let* x = x in - loop (x :: acc) r - in - loop [] l) + | Extern name, l -> + let* f = + register_import ~name (Fun (Type.primitive_type (List.length l))) + in + let rec loop acc l = + match l with + | [] -> return (W.Call (f, List.rev acc)) + | x :: r -> + let* x = x in + loop (x :: acc) r + 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), _ -> @@ -938,16 +1534,18 @@ module Generate (Target : Target_sig.S) = struct and translate_instr ctx context i = match i with | Assign (x, y) -> - assign x (convert ~from:(get_var_type ctx y) ~into:(get_var_type ctx x) (load y)) + assign + x + (convert + ~from:(Typing.var_type ctx.types y) + ~into:(Typing.var_type ctx.types x) + (load y)) | Let (x, e) -> if ctx.live.(Var.idx x) = 0 then drop (translate_expr ctx context x e) else store - ?typ: - (match get_var_type ctx x with - | Int (Normalized | Unnormalized) -> Some I32 - | _ -> None) + ?typ:(unboxed_type (Typing.var_type ctx.types x)) x (translate_expr ctx context x e) | Set_field (x, n, Non_float, y) -> @@ -955,8 +1553,11 @@ module Generate (Target : Target_sig.S) = struct | Set_field (x, n, Float, y) -> Memory.float_array_set (load_and_box ctx x) - (Constant.translate (Int (Targetint.of_int_warning_on_overflow n))) - (load y) + (return (W.Const (I32 (Int32.of_int n)))) + (convert + ~from:(Typing.var_type ctx.types y) + ~into:(Number (Float, Unboxed)) + (load y)) | Offset_ref (x, n) -> Memory.set_field (load x) @@ -966,7 +1567,7 @@ module Generate (Target : Target_sig.S) = struct | Array_set (x, y, z) -> Memory.array_set (load x) - (convert ~from:(get_var_type ctx y) ~into:(Int Normalized) (load y)) + (convert ~from:(Typing.var_type ctx.types y) ~into:(Int Normalized) (load y)) (load_and_box ctx z) | Event loc -> event loc @@ -986,8 +1587,8 @@ module Generate (Target : Target_sig.S) = struct if Code.Var.compare x y = 0 then visited, None, l else - let tx = get_var_type ctx x in - let ty = get_var_type ctx y in + let tx = Typing.var_type ctx.types x in + let ty = Typing.var_type ctx.types y in if Var.Set.mem y prev then let t = Code.Var.fresh () in @@ -1020,14 +1621,7 @@ module Generate (Target : Target_sig.S) = struct l ~f:(fun continuation (y, ty, x, tx) -> let* () = continuation in - store - ~always:true - ?typ: - (match ty with - | Typing.Int (Normalized | Unnormalized) -> Some I32 - | _ -> None) - y - (convert ~from:tx ~into:ty (load x))) + store ~always:true ?typ:(unboxed_type ty) y (convert ~from:tx ~into:ty (load x))) ~init:(return ()) let exception_name = "ocaml_exception" @@ -1055,7 +1649,15 @@ module Generate (Target : Target_sig.S) = struct | "caml_bytes_set" | "caml_check_bound" | "caml_check_bound_gen" - | "caml_check_bound_float" ) + | "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 ( _ @@ -1089,7 +1691,7 @@ module Generate (Target : Target_sig.S) = struct then handler else let* () = handler in - instr (W.Return (Some (RefI31 (Const (I32 0l))))) + instr W.Unreachable else body ~result_typ ~fall_through ~context let wrap_with_handlers p pc ~result_typ ~fall_through ~context body = @@ -1125,6 +1727,11 @@ module Generate (Target : Target_sig.S) = struct ((pc, _) as cont) cloc acc = + let return_type = + match name_opt with + | Some f -> Typing.return_type ctx.types f + | _ -> Typing.Top + in let g = Structure.build_graph ctx.blocks pc in let dom = Structure.dominator_tree g in let rec translate_tree result_typ fall_through pc context = @@ -1186,7 +1793,9 @@ module Generate (Target : Target_sig.S) = struct match branch with | Branch cont -> translate_branch result_typ fall_through pc cont context | Return x -> ( - let* e = load_and_box ctx x in + let* e = + convert ~from:(Typing.var_type ctx.types x) ~into:return_type (load x) + in match fall_through with | `Return -> instr (Push e) | `Block _ | `Catch | `Skip -> instr (Return (Some e))) @@ -1194,7 +1803,7 @@ module Generate (Target : Target_sig.S) = struct let context' = extend_context fall_through context in if_ { params = []; result = result_typ } - (match get_var_type ctx x with + (match Typing.var_type ctx.types x with | Int Normalized -> load x | Int Unnormalized -> Arith.(load x lsl const 1l) | _ -> Value.check_is_not_zero (load x)) @@ -1213,7 +1822,10 @@ module Generate (Target : Target_sig.S) = struct label_index context pc in let* e = - convert ~from:(get_var_type ctx x) ~into:(Int Normalized) (load x) + convert + ~from:(Typing.var_type ctx.types x) + ~into:(Int Normalized) + (load x) in instr (Br_table (e, List.map ~f:dest l, dest a.(len - 1))) | Raise (x, _) -> ( @@ -1259,7 +1871,17 @@ module Generate (Target : Target_sig.S) = struct List.fold_left ~f:(fun l x -> let* _ = l in - let* _ = add_var x in + let* _ = + add_var + ?typ: + (match Typing.var_type ctx.types x with + | Typing.Int (Normalized | Unnormalized) -> Some I32 + | Number ((Int32 | Nativeint), Unboxed) -> Some I32 + | Number (Int64, Unboxed) -> Some I64 + | Number (Float, Unboxed) -> Some F64 + | _ -> None) + x + in return ()) ~init:(return ()) params @@ -1272,6 +1894,7 @@ module Generate (Target : Target_sig.S) = struct ~context:ctx.global_context ~closures:ctx.closures ~cps:(Var.Set.mem f ctx.in_cps) + ~no_code_pointer:(Call_graph_analysis.direct_calls_only ctx.fun_info f) f | None -> return () in @@ -1303,7 +1926,7 @@ module Generate (Target : Target_sig.S) = struct wrap_with_handlers p pc - ~result_typ:[ Type.value ] + ~result_typ:[ Option.value ~default:Type.value (unboxed_type return_type) ] ~fall_through:`Return ~context:[] (fun ~result_typ ~fall_through ~context -> @@ -1327,7 +1950,20 @@ module Generate (Target : Target_sig.S) = struct ; signature = (match name_opt with | None -> Type.primitive_type param_count - | Some _ -> Type.func_type (param_count - 1)) + | Some f -> + if Typing.can_unbox_parameters ctx.fun_info f + then + { W.params = + List.map + ~f:(fun x : W.value_type -> + Option.value + ~default:Type.value + (unboxed_type (Typing.var_type ctx.types x))) + params + @ [ Type.value ] + ; result = [ Option.value ~default:Type.value (unboxed_type return_type) ] + } + else Type.func_type (param_count - 1)) ; param_names ; locals ; body @@ -1398,8 +2034,8 @@ module Generate (Target : Target_sig.S) = struct ~in_cps (* ~should_export *) - ~deadcode_sentinal ~global_flow_info + ~fun_info ~types = global_context.unit_name <- unit_name; let p, closures = Closure_conversion.f p in @@ -1409,8 +2045,8 @@ module Generate (Target : Target_sig.S) = struct let ctx = { live = live_vars ; in_cps - ; deadcode_sentinal ; global_flow_info + ; fun_info ; types ; blocks = p.blocks ; closures @@ -1519,21 +2155,16 @@ let init = G.init let start () = make_context ~value_type:Gc_target.Type.value let f ~context ~unit_name p ~live_vars ~in_cps ~deadcode_sentinal ~global_flow_data = - let state, info = global_flow_data in - let p = Structure.norm p in - let types = Typing.f ~state ~info ~deadcode_sentinal p in + let global_flow_state, global_flow_info = global_flow_data in + let fun_info = Call_graph_analysis.f p global_flow_info in + let types = + Typing.f ~global_flow_state ~global_flow_info ~fun_info ~deadcode_sentinal p + in let t = Timer.make () in + let p = Structure.norm p in let p = fix_switch_branches p in let res = - G.f - ~context - ~unit_name - ~live_vars - ~in_cps - ~deadcode_sentinal - ~global_flow_info:info - ~types - p + G.f ~context ~unit_name ~live_vars ~in_cps ~global_flow_info ~fun_info ~types p in if times () then Format.eprintf " code gen.: %a@." Timer.print t; res diff --git a/compiler/lib-wasm/tail_call.ml b/compiler/lib-wasm/tail_call.ml index b52142d72d..ab2cf29a85 100644 --- a/compiler/lib-wasm/tail_call.ml +++ b/compiler/lib-wasm/tail_call.ml @@ -24,25 +24,30 @@ let get_return ~tail i = | Push (LocalGet y) when tail -> Some y | _ -> None -let rewrite_tail_call ~y i = +let rewrite_tail_call ~no_tail_call ~y i = match i with - | Wasm_ast.LocalSet (x, Call (symb, l)) when Code.Var.equal x y -> + | Wasm_ast.LocalSet (x, Call (symb, l)) + when Code.Var.equal x y && not (Code.Var.Hashtbl.mem no_tail_call symb) -> Some (Wasm_ast.Return_call (symb, l)) | LocalSet (x, Call_ref (ty, e, l)) when Code.Var.equal x y -> Some (Return_call_ref (ty, e, l)) | _ -> None -let rec instruction ~tail i = +let rec instruction ~no_tail_call ~tail i = match i with - | Wasm_ast.Loop (ty, l) -> Wasm_ast.Loop (ty, instructions ~tail l) - | Block (ty, l) -> Block (ty, instructions ~tail l) - | If (ty, e, l1, l2) -> If (ty, e, instructions ~tail l1, instructions ~tail l2) - | Return (Some (Call (symb, l))) -> Return_call (symb, l) + | Wasm_ast.Loop (ty, l) -> Wasm_ast.Loop (ty, instructions ~no_tail_call ~tail l) + | Block (ty, l) -> Block (ty, instructions ~no_tail_call ~tail l) + | If (ty, e, l1, l2) -> + If (ty, e, instructions ~no_tail_call ~tail l1, instructions ~no_tail_call ~tail l2) + | Return (Some (Call (symb, l))) when not (Code.Var.Hashtbl.mem no_tail_call symb) -> + Return_call (symb, l) | Return (Some (Call_ref (ty, e, l))) -> Return_call_ref (ty, e, l) - | Push (Call (symb, l)) when tail -> Return_call (symb, l) + | Push (Call (symb, l)) when tail && not (Code.Var.Hashtbl.mem no_tail_call symb) -> + Return_call (symb, l) | Push (Call_ref (ty, e, l)) when tail -> Return_call_ref (ty, e, l) | Push (Call_ref _) -> i - | Drop (BlockExpr (typ, l)) -> Drop (BlockExpr (typ, instructions ~tail:false l)) + | Drop (BlockExpr (typ, l)) -> + Drop (BlockExpr (typ, instructions ~no_tail_call ~tail:false l)) | Drop _ | LocalSet _ | GlobalSet _ @@ -62,21 +67,28 @@ let rec instruction ~tail i = | Unreachable | Event _ -> i -and instructions ~tail l = +and instructions ~no_tail_call ~tail l = match l with | [] -> [] - | [ i ] -> [ instruction ~tail i ] - | i :: Nop :: rem -> instructions ~tail (i :: rem) - | i :: i' :: Nop :: rem -> instructions ~tail (i :: i' :: rem) + | [ i ] -> [ instruction ~no_tail_call ~tail i ] + | i :: Nop :: rem -> instructions ~no_tail_call ~tail (i :: rem) + | i :: i' :: Nop :: rem -> instructions ~no_tail_call ~tail (i :: i' :: rem) | i :: i' :: (([] | [ Event _ ]) as event_opt) -> ( (* There can be an event at the end of the function, which we should keep. *) match get_return ~tail i' with - | None -> instruction ~tail:false i :: instruction ~tail i' :: event_opt + | None -> + instruction ~no_tail_call ~tail:false i + :: instruction ~no_tail_call ~tail i' + :: event_opt | Some y -> ( - match rewrite_tail_call ~y i with - | None -> instruction ~tail:false i :: instruction ~tail i' :: event_opt + match rewrite_tail_call ~no_tail_call ~y i with + | None -> + instruction ~no_tail_call ~tail:false i + :: instruction ~no_tail_call ~tail i' + :: event_opt | Some i'' -> i'' :: event_opt)) - | i :: rem -> instruction ~tail:false i :: instructions ~tail rem + | i :: rem -> + instruction ~no_tail_call ~tail:false i :: instructions ~no_tail_call ~tail rem -let f l = instructions ~tail:true l +let f ~no_tail_call l = instructions ~no_tail_call ~tail:true l diff --git a/compiler/lib-wasm/tail_call.mli b/compiler/lib-wasm/tail_call.mli index 2bcf526ae2..ecd717f1c2 100644 --- a/compiler/lib-wasm/tail_call.mli +++ b/compiler/lib-wasm/tail_call.mli @@ -16,4 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *) -val f : Wasm_ast.instruction list -> Wasm_ast.instruction list +val f : + no_tail_call:unit Code.Var.Hashtbl.t + -> Wasm_ast.instruction list + -> Wasm_ast.instruction list diff --git a/compiler/lib-wasm/target_sig.ml b/compiler/lib-wasm/target_sig.ml index 053e3be066..a0fc5e8ce9 100644 --- a/compiler/lib-wasm/target_sig.ml +++ b/compiler/lib-wasm/target_sig.ml @@ -20,12 +20,9 @@ module type S = sig type expression = Code_generation.expression module Memory : sig - val allocate : - tag:int - -> deadcode_sentinal:Code.Var.t - -> load:(Code.Var.t -> expression) - -> [ `Expr of Wasm_ast.expression | `Var of Wasm_ast.var ] list - -> expression + val allocate : tag:int -> Wasm_ast.expression list Code_generation.t -> expression + + val allocate_float_array : Wasm_ast.expression list Code_generation.t -> expression val load_function_pointer : cps:bool @@ -166,7 +163,7 @@ module type S = sig end module Constant : sig - val translate : Code.constant -> expression + val translate : unboxed:bool -> Code.constant -> expression end module Closure : sig @@ -174,6 +171,7 @@ module type S = sig context:Code_generation.context -> closures:Closure_conversion.closure Code.Var.Map.t -> cps:bool + -> no_code_pointer:bool -> Code.Var.t -> expression @@ -181,6 +179,7 @@ module type S = sig context:Code_generation.context -> closures:Closure_conversion.closure Code.Var.Map.t -> cps:bool + -> no_code_pointer:bool -> Code.Var.t -> unit Code_generation.t @@ -255,6 +254,25 @@ module type S = sig val round : expression -> expression end + module Bigarray : sig + val get : + bound_error_index:int + -> kind:Typing.Bigarray.kind + -> layout:Typing.Bigarray.layout + -> expression + -> indices:expression list + -> expression + + val set : + bound_error_index:int + -> kind:Typing.Bigarray.kind + -> layout:Typing.Bigarray.layout + -> expression + -> indices:expression list + -> expression + -> expression + end + val internal_primitives : (string * Primitive.kind diff --git a/compiler/lib-wasm/typing.ml b/compiler/lib-wasm/typing.ml index 3e4781fcc9..0eeef3b0a0 100644 --- a/compiler/lib-wasm/typing.ml +++ b/compiler/lib-wasm/typing.ml @@ -4,6 +4,24 @@ open Global_flow let debug = Debug.find "typing" +let times = Debug.find "times" + +let can_unbox_parameters fun_info f = + (* We can unbox the parameters of a function when all its call sites + are known, and only this function is called there. It would be + more robust to deal with more cases by using an intermediate + function that unbox the parameters. When several functions can be + call from the same call site, one could enforce somehow that they + have the same signature. *) + Call_graph_analysis.direct_calls_only fun_info f + +let can_unbox_return_value fun_info f = + (* Unboxing return values can break tail-recursion. A simple way to + avoid this issue it to only perform it for functions with no tail + calls. We could eventually perform a more precise analysis. *) + Call_graph_analysis.direct_calls_only fun_info f + && not (Call_graph_analysis.has_tail_calls fun_info f) + module Integer = struct type kind = | Ref @@ -23,14 +41,95 @@ type boxed_number = | Nativeint | Float +type boxed_status = + | Boxed + | 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 = + (match kind with + | 0 -> Float32 + | 1 -> Float64 + | 2 -> Int8_signed + | 3 -> Int8_unsigned + | 4 -> Int16_signed + | 5 -> Int16_unsigned + | 6 -> Int32 + | 7 -> Int64 + | 8 -> Int + | 9 -> Nativeint + | 10 -> Complex32 + | 11 -> Complex64 + | 12 -> Int8_unsigned + | 13 -> Float16 + | _ -> assert false) + ; layout = + (match layout with + | 0 -> C + | 1 -> Fortran + | _ -> assert false) + } + + let print f { kind; layout } = + Format.fprintf + f + "bigarray{%s,%s}" + (match kind with + | 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" + | Float16 -> "float16") + (match layout with + | C -> "C" + | Fortran -> "Fortran") + + let equal { kind; layout } { kind = kind'; layout = layout' } = + phys_equal kind kind' && phys_equal layout layout' +end + type typ = | Top | Int of Integer.kind - | Number of boxed_number + | Number of boxed_number * boxed_status | Tuple of typ array (** 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 | Bot module Domain = struct @@ -40,7 +139,15 @@ module Domain = struct match t, t' with | Bot, t | t, Bot -> t | Int r, Int r' -> Int (Integer.join r r') - | Number n, Number n' -> if Poly.equal n n' then t else Top + | Number (n, b), Number (n', b') -> + if Poly.equal n n' + then + Number + ( n + , match b, b' with + | Unboxed, _ | _, Unboxed -> Unboxed + | Boxed, Boxed -> Boxed ) + else Top | Tuple t, Tuple t' -> let l = Array.length t in let l' = Array.length t' in @@ -52,8 +159,9 @@ module Domain = struct if i < l then if i < l' then join t.(i) t'.(i) else t.(i) else t'.(i))) | Int _, Tuple _ -> t' | Tuple _, Int _ -> t + | Bigarray b, Bigarray b' when Bigarray.equal b b' -> t | Top, _ | _, Top -> Top - | (Int _ | Number _ | Tuple _), _ -> Top + | (Int _ | Number _ | Tuple _ | Bigarray _), _ -> Top let join_set ?(others = false) f s = if others then Top else Var.Set.fold (fun x a -> join (f x) a) s Bot @@ -62,10 +170,11 @@ module Domain = struct match t, t' with | Top, Top | Bot, Bot -> true | Int t, Int t' -> Poly.equal t t' - | Number t, Number t' -> Poly.equal t t' + | Number (t, b), Number (t', b') -> Poly.equal t t' && Poly.equal b b' | Tuple t, Tuple t' -> Array.length t = Array.length t' && Array.for_all2 ~f:equal t t' - | (Top | Tuple _ | Int _ | Number _ | Bot), _ -> false + | Bigarray b, Bigarray b' -> Bigarray.equal b b' + | (Top | Tuple _ | Int _ | Number _ | Bigarray _ | Bot), _ -> false let bot = Bot @@ -73,12 +182,12 @@ module Domain = struct let rec depth t = match t with - | Top | Bot | Number _ | Int _ -> 0 + | Top | Bot | Number _ | Int _ | Bigarray _ -> 0 | Tuple l -> 1 + Array.fold_left ~f:(fun acc t' -> max (depth t') acc) l ~init:0 let rec truncate depth t = match t with - | Top | Bot | Number _ | Int _ -> t + | Top | Bot | Number _ | Int _ | Bigarray _ -> t | Tuple l -> if depth = 0 then Top @@ -89,6 +198,7 @@ module Domain = struct let box t = match t with | Int _ -> Int Ref + | Number (n, _) -> Number (n, Boxed) | _ -> t let rec print f t = @@ -103,10 +213,19 @@ module Domain = struct | Ref -> "ref" | Normalized -> "normalized" | Unnormalized -> "unnormalized") - | Number Int32 -> Format.fprintf f "int32" - | Number Int64 -> Format.fprintf f "int64" - | Number Nativeint -> Format.fprintf f "nativeint" - | Number Float -> Format.fprintf f "float" + | Number (n, b) -> + Format.fprintf + f + "%s{%s}" + (match n with + | Int32 -> "int32" + | Int64 -> "int64" + | Nativeint -> "nativeint" + | Float -> "float") + (match b with + | Boxed -> "boxed" + | Unboxed -> "unboxed") + | Bigarray b -> Bigarray.print f b | Tuple t -> Format.fprintf f @@ -122,7 +241,18 @@ let update_deps st { blocks; _ } = List.iter block.body ~f:(fun i -> match i with | Let (x, Block (_, lst, _, _)) -> Array.iter ~f:(fun y -> add_dep st x y) lst - | Let (x, Prim (Extern ("%int_and" | "%int_or" | "%int_xor"), lst)) -> + | Let + ( 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" ) + , lst ) ) -> (* The return type of these primitives depend on the input type *) List.iter ~f:(fun p -> @@ -133,31 +263,33 @@ let update_deps st { blocks; _ } = | _ -> ())) blocks -let mark_function_parameters { blocks; _ } = - let function_parameters = Var.ISet.empty () in - let set x = Var.ISet.add function_parameters x in +let mark_function_parameters ~fun_info { blocks; _ } = + let boxed_function_parameters = Var.ISet.empty () in + let set x = Var.ISet.add boxed_function_parameters x in Addr.Map.iter (fun _ block -> List.iter block.body ~f:(fun i -> match i with - | Let (_, Closure (params, _, _)) -> List.iter ~f:set params + | Let (x, Closure (params, _, _)) when not (can_unbox_parameters fun_info x) -> + List.iter ~f:set params | _ -> ())) blocks; - function_parameters + boxed_function_parameters type st = - { state : state - ; info : info - ; function_parameters : Var.ISet.t + { global_flow_state : state + ; global_flow_info : info + ; boxed_function_parameters : Var.ISet.t + ; fun_info : Call_graph_analysis.t } let rec constant_type (c : constant) = match c with | Int _ -> Int Normalized - | Int32 _ -> Number Int32 - | Int64 _ -> Number Int64 - | NativeInt _ -> Number Nativeint - | Float _ -> Number Float + | Int32 _ -> Number (Int32, Unboxed) + | Int64 _ -> Number (Int64, Unboxed) + | NativeInt _ -> Number (Nativeint, Unboxed) + | Float _ -> Number (Float, Unboxed) | Tuple (_, a, _) -> Tuple (Array.map ~f:(fun c' -> Domain.box (constant_type c')) a) | _ -> Top @@ -166,7 +298,23 @@ let arg_type ~approx arg = | Pc c -> constant_type c | Pv x -> Var.Tbl.get approx x -let prim_type ~approx prim args = +let bigarray_element_type (kind : Bigarray.kind) = + match kind with + | Float16 | Float32 | Float64 -> Number (Float, Unboxed) + | Int8_signed | Int8_unsigned | Int16_signed | Int16_unsigned -> Int Normalized + | Int -> Int Unnormalized + | Int32 -> Number (Int32, Unboxed) + | Int64 -> Number (Int64, Unboxed) + | Nativeint -> Number (Nativeint, Unboxed) + | Complex32 | Complex64 -> Tuple [| Number (Float, Boxed); Number (Float, Boxed) |] + +let bigarray_type ~approx ba = + match arg_type ~approx ba with + | Bot -> Bot + | Bigarray { kind; _ } -> bigarray_element_type kind + | _ -> Top + +let prim_type ~st ~approx prim args = match prim with | "%int_add" | "%int_sub" | "%int_mul" | "%direct_int_mul" | "%int_lsl" | "%int_neg" -> Int Unnormalized @@ -191,23 +339,28 @@ let prim_type ~approx prim args = | "caml_lessthan" | "caml_lessequal" | "caml_equal" - | "caml_compare" -> Int Ref - | "caml_int32_bswap" -> Number Int32 - | "caml_nativeint_bswap" -> Number Nativeint - | "caml_int64_bswap" -> Number Int64 - | "caml_int32_compare" | "caml_nativeint_compare" | "caml_int64_compare" -> Int Ref - | "caml_string_get32" -> Number Int32 - | "caml_string_get64" -> Number Int64 - | "caml_bytes_get32" -> Number Int32 - | "caml_bytes_get64" -> Number Int64 - | "caml_lxm_next" -> Number Int64 - | "caml_ba_uint8_get32" -> Number Int32 - | "caml_ba_uint8_get64" -> Number Int64 - | "caml_nextafter_float" -> Number Float + | "caml_notequal" + | "caml_compare" -> Int Normalized + | "caml_int32_bswap" -> Number (Int32, Unboxed) + | "caml_nativeint_bswap" -> Number (Nativeint, Unboxed) + | "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_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_nextafter_float" -> Number (Float, Unboxed) | "caml_classify_float" -> Int Ref - | "caml_ldexp_float" | "caml_erf_float" | "caml_erfc_float" -> Number Float - | "caml_float_compare" -> Int Ref - | "caml_floatarray_unsafe_get" -> Number Float + | "caml_ldexp_float" | "caml_erf_float" | "caml_erfc_float" -> Number (Float, Unboxed) + | "caml_float_compare" -> Int Normalized + | "caml_floatarray_unsafe_get" -> Number (Float, Unboxed) | "caml_bytes_unsafe_get" | "caml_string_unsafe_get" | "caml_bytes_get" @@ -219,7 +372,7 @@ let prim_type ~approx prim args = | "caml_sub_float" | "caml_mul_float" | "caml_div_float" - | "caml_copysign_float" -> Number Float + | "caml_copysign_float" -> Number (Float, Unboxed) | "caml_signbit_float" -> Int Normalized | "caml_neg_float" | "caml_abs_float" @@ -227,7 +380,7 @@ let prim_type ~approx prim args = | "caml_floor_float" | "caml_trunc_float" | "caml_round_float" - | "caml_sqrt_float" -> Number Float + | "caml_sqrt_float" -> Number (Float, Unboxed) | "caml_eq_float" | "caml_neq_float" | "caml_ge_float" @@ -259,11 +412,11 @@ let prim_type ~approx prim args = | "caml_log10_float" | "caml_power_float" | "caml_hypot_float" - | "caml_fmod_float" -> Number Float - | "caml_int32_bits_of_float" -> Number Int32 - | "caml_int32_float_of_bits" -> Number Float - | "caml_int32_of_float" -> Number Int32 - | "caml_int32_to_float" -> Number Float + | "caml_fmod_float" -> Number (Float, Unboxed) + | "caml_int32_bits_of_float" -> Number (Int32, Unboxed) + | "caml_int32_float_of_bits" -> Number (Float, Unboxed) + | "caml_int32_of_float" -> Number (Int32, Unboxed) + | "caml_int32_to_float" -> Number (Float, Unboxed) | "caml_int32_neg" | "caml_int32_add" | "caml_int32_sub" @@ -275,15 +428,15 @@ let prim_type ~approx prim args = | "caml_int32_mod" | "caml_int32_shift_left" | "caml_int32_shift_right" - | "caml_int32_shift_right_unsigned" -> Number Int32 + | "caml_int32_shift_right_unsigned" -> Number (Int32, Unboxed) | "caml_int32_to_int" -> Int Unnormalized - | "caml_int32_of_int" -> Number Int32 - | "caml_nativeint_of_int32" -> Number Nativeint - | "caml_nativeint_to_int32" -> Number Int32 - | "caml_int64_bits_of_float" -> Number Int64 - | "caml_int64_float_of_bits" -> Number Float - | "caml_int64_of_float" -> Number Int64 - | "caml_int64_to_float" -> Number Float + | "caml_int32_of_int" -> Number (Int32, Unboxed) + | "caml_nativeint_of_int32" -> Number (Nativeint, Unboxed) + | "caml_nativeint_to_int32" -> Number (Int32, Unboxed) + | "caml_int64_bits_of_float" -> Number (Int64, Unboxed) + | "caml_int64_float_of_bits" -> Number (Float, Unboxed) + | "caml_int64_of_float" -> Number (Int64, Unboxed) + | "caml_int64_to_float" -> Number (Float, Unboxed) | "caml_int64_neg" | "caml_int64_add" | "caml_int64_sub" @@ -295,17 +448,17 @@ let prim_type ~approx prim args = | "caml_int64_mod" | "caml_int64_shift_left" | "caml_int64_shift_right" - | "caml_int64_shift_right_unsigned" -> Number Int64 + | "caml_int64_shift_right_unsigned" -> Number (Int64, Unboxed) | "caml_int64_to_int" -> Int Unnormalized - | "caml_int64_of_int" -> Number Int64 - | "caml_int64_to_int32" -> Number Int32 - | "caml_int64_of_int32" -> Number Int64 - | "caml_int64_to_nativeint" -> Number Nativeint - | "caml_int64_of_nativeint" -> Number Int64 - | "caml_nativeint_bits_of_float" -> Number Nativeint - | "caml_nativeint_float_of_bits" -> Number Float - | "caml_nativeint_of_float" -> Number Nativeint - | "caml_nativeint_to_float" -> Number Float + | "caml_int64_of_int" -> Number (Int64, Unboxed) + | "caml_int64_to_int32" -> Number (Int32, Unboxed) + | "caml_int64_of_int32" -> Number (Int64, Unboxed) + | "caml_int64_to_nativeint" -> Number (Nativeint, Unboxed) + | "caml_int64_of_nativeint" -> Number (Int64, Unboxed) + | "caml_nativeint_bits_of_float" -> Number (Nativeint, Unboxed) + | "caml_nativeint_float_of_bits" -> Number (Float, Unboxed) + | "caml_nativeint_of_float" -> Number (Nativeint, Unboxed) + | "caml_nativeint_to_float" -> Number (Float, Unboxed) | "caml_nativeint_neg" | "caml_nativeint_add" | "caml_nativeint_sub" @@ -317,18 +470,37 @@ let prim_type ~approx prim args = | "caml_nativeint_mod" | "caml_nativeint_shift_left" | "caml_nativeint_shift_right" - | "caml_nativeint_shift_right_unsigned" -> Number Nativeint + | "caml_nativeint_shift_right_unsigned" -> Number (Nativeint, Unboxed) | "caml_nativeint_to_int" -> Int Unnormalized - | "caml_nativeint_of_int" -> Number Nativeint + | "caml_nativeint_of_int" -> Number (Nativeint, Unboxed) | "caml_int_compare" -> Int Normalized + | "caml_ba_create" -> ( + match args with + | [ Pc (Int kind); Pc (Int layout); _ ] -> + Bigarray + (Bigarray.make + ~kind:(Targetint.to_int_exn kind) + ~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) + | "caml_ba_get_generic" -> ( + match args with + | ba :: Pv indices :: _ -> ( + match st.global_flow_state.defs.(Var.idx indices) with + | Expr (Block _) -> bigarray_type ~approx ba + | _ -> Top) + | [] | [ _ ] | _ :: Pc _ :: _ -> Top) | _ -> Top let propagate st approx x : Domain.t = - match st.state.defs.(Var.idx x) with + match st.global_flow_state.defs.(Var.idx x) with | Phi { known; others; unit } -> let res = Domain.join_set ~others (fun y -> Var.Tbl.get approx y) known in let res = if unit then Domain.join (Int Unnormalized) res else res in - if Var.ISet.mem st.function_parameters x then Domain.box res else res + if Var.ISet.mem st.boxed_function_parameters x then Domain.box res else res | Expr e -> ( match e with | Constant c -> constant_type c @@ -337,13 +509,13 @@ let propagate st approx x : Domain.t = Tuple (Array.mapi ~f:(fun i y -> - match st.state.mutable_fields.(Var.idx x) with + match st.global_flow_state.mutable_fields.(Var.idx x) with | All_fields -> Top | Some_fields s when IntSet.mem i s -> Top | Some_fields _ | No_field -> Domain.limit (Domain.box (Var.Tbl.get approx y))) lst) - | Field (_, _, Float) -> Number Float + | Field (_, _, Float) -> Number (Float, Unboxed) | Field (y, n, Non_float) -> ( match Var.Tbl.get approx y with | Tuple t -> if n < Array.length t then t.(n) else Bot @@ -353,15 +525,15 @@ let propagate st approx x : Domain.t = ( 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; _ ]) -> ( - match Var.Tbl.get st.info.info_approximation y with + match Var.Tbl.get st.global_flow_info.info_approximation y with | Values { known; others } -> Domain.join_set ~others (fun z -> - match st.state.defs.(Var.idx z) with + match st.global_flow_state.defs.(Var.idx z) with | Expr (Block (_, lst, _, _)) -> let m = - match st.state.mutable_fields.(Var.idx z) with + match st.global_flow_state.mutable_fields.(Var.idx z) with | No_field -> false | Some_fields _ | All_fields -> true in @@ -379,21 +551,51 @@ let propagate st approx x : Domain.t = | Top -> Top) | Prim (Array_get, _) -> Top | Prim ((Vectlength | Not | IsInt | Eq | Neq | Lt | Le | Ult), _) -> Int Normalized - | Prim (Extern prim, args) -> prim_type ~approx prim args + | Prim (Extern prim, args) -> prim_type ~st ~approx prim args | Special _ -> Top | Apply { f; args; _ } -> ( - match Var.Tbl.get st.info.info_approximation f with + match Var.Tbl.get st.global_flow_info.info_approximation f with | Values { known; others } -> Domain.join_set ~others (fun g -> - match st.state.defs.(Var.idx g) with + match st.global_flow_state.defs.(Var.idx g) with | Expr (Closure (params, _, _)) when List.length args = List.length params -> - Domain.box - (Domain.join_set - (fun y -> Var.Tbl.get approx y) - (Var.Map.find g st.state.return_values)) + let res = + Domain.join_set + (fun y -> + match st.global_flow_state.defs.(Var.idx y) with + | Expr + (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) + ~init:Var.Map.empty + params + args + in + try + match + ( st.global_flow_state.defs.(Var.idx + (Var.Map.find kind m)) + , st.global_flow_state.defs.(Var.idx + (Var.Map.find layout m)) + ) + with + | ( Expr (Constant (Int kind)) + , Expr (Constant (Int layout)) ) -> + Bigarray + (Bigarray.make + ~kind:(Targetint.to_int_exn kind) + ~layout:(Targetint.to_int_exn layout)) + | _ -> raise Not_found + with Not_found -> Var.Tbl.get approx y) + | _ -> Var.Tbl.get approx y) + (Var.Map.find g st.global_flow_state.return_values) + in + if can_unbox_return_value st.fun_info g then res else Domain.box res | Expr (Closure (_, _, _)) -> (* The function is partially applied or over applied *) Top @@ -408,38 +610,319 @@ module Solver = G.Solver (Domain) let solver st = let associated_list h x = try Var.Hashtbl.find h x with Not_found -> [] in let g = - { G.domain = st.state.vars + { G.domain = st.global_flow_state.vars ; G.iter_children = (fun f x -> - List.iter ~f (Var.Tbl.get st.state.deps x); + List.iter ~f (Var.Tbl.get st.global_flow_state.deps x); List.iter - ~f:(fun g -> List.iter ~f (associated_list st.state.function_call_sites g)) - (associated_list st.state.functions_from_returned_value x)) + ~f:(fun g -> + List.iter ~f (associated_list st.global_flow_state.function_call_sites g)) + (associated_list st.global_flow_state.functions_from_returned_value x)) } in Solver.f () g (propagate st) -let f ~state ~info ~deadcode_sentinal p = - update_deps state p; - let function_parameters = mark_function_parameters p in - let typ = solver { state; info; function_parameters } in - Var.Tbl.set typ deadcode_sentinal (Int Normalized); +(* These are primitives which are handled internally by the compiler, + plus the specialized primitives listed in Generate. *) +let primitives_with_unboxed_parameters = + let h = String.Hashtbl.create 256 in + List.iter + ~f:(fun s -> String.Hashtbl.add h s ()) + [ "caml_int32_bswap" + ; "caml_nativeint_bswap" + ; "caml_int64_bswap" + ; "caml_int32_compare" + ; "caml_nativeint_compare" + ; "caml_int64_compare" + ; "caml_nextafter_float" + ; "caml_classify_float" + ; "caml_ldexp_float" + ; "caml_erf_float" + ; "caml_erfc_float" + ; "caml_float_compare" + ; "caml_add_float" + ; "caml_sub_float" + ; "caml_mul_float" + ; "caml_div_float" + ; "caml_copysign_float" + ; "caml_signbit_float" + ; "caml_neg_float" + ; "caml_abs_float" + ; "caml_ceil_float" + ; "caml_floor_float" + ; "caml_trunc_float" + ; "caml_round_float" + ; "caml_sqrt_float" + ; "caml_eq_float" + ; "caml_neq_float" + ; "caml_ge_float" + ; "caml_le_float" + ; "caml_gt_float" + ; "caml_lt_float" + ; "caml_int_of_float" + ; "caml_cos_float" + ; "caml_sin_float" + ; "caml_tan_float" + ; "caml_acos_float" + ; "caml_asin_float" + ; "caml_atan_float" + ; "caml_atan2_float" + ; "caml_cosh_float" + ; "caml_sinh_float" + ; "caml_tanh_float" + ; "caml_acosh_float" + ; "caml_asinh_float" + ; "caml_atanh_float" + ; "caml_cbrt_float" + ; "caml_exp_float" + ; "caml_exp2_float" + ; "caml_log_float" + ; "caml_expm1_float" + ; "caml_log1p_float" + ; "caml_log2_float" + ; "caml_log10_float" + ; "caml_power_float" + ; "caml_hypot_float" + ; "caml_fmod_float" + ; "caml_int32_bits_of_float" + ; "caml_int32_float_of_bits" + ; "caml_int32_of_float" + ; "caml_int32_to_float" + ; "caml_int32_neg" + ; "caml_int32_add" + ; "caml_int32_sub" + ; "caml_int32_mul" + ; "caml_int32_and" + ; "caml_int32_or" + ; "caml_int32_xor" + ; "caml_int32_div" + ; "caml_int32_mod" + ; "caml_int32_shift_left" + ; "caml_int32_shift_right" + ; "caml_int32_shift_right_unsigned" + ; "caml_int32_to_int" + ; "caml_nativeint_of_int32" + ; "caml_nativeint_to_int32" + ; "caml_int64_bits_of_float" + ; "caml_int64_float_of_bits" + ; "caml_int64_of_float" + ; "caml_int64_to_float" + ; "caml_int64_neg" + ; "caml_int64_add" + ; "caml_int64_sub" + ; "caml_int64_mul" + ; "caml_int64_and" + ; "caml_int64_or" + ; "caml_int64_xor" + ; "caml_int64_div" + ; "caml_int64_mod" + ; "caml_int64_shift_left" + ; "caml_int64_shift_right" + ; "caml_int64_shift_right_unsigned" + ; "caml_int64_to_int" + ; "caml_int64_to_int32" + ; "caml_int64_of_int32" + ; "caml_int64_to_nativeint" + ; "caml_int64_of_nativeint" + ; "caml_nativeint_bits_of_float" + ; "caml_nativeint_float_of_bits" + ; "caml_nativeint_of_float" + ; "caml_nativeint_to_float" + ; "caml_nativeint_neg" + ; "caml_nativeint_add" + ; "caml_nativeint_sub" + ; "caml_nativeint_mul" + ; "caml_nativeint_and" + ; "caml_nativeint_or" + ; "caml_nativeint_xor" + ; "caml_nativeint_div" + ; "caml_nativeint_mod" + ; "caml_nativeint_shift_left" + ; "caml_nativeint_shift_right" + ; "caml_nativeint_shift_right_unsigned" + ; "caml_nativeint_to_int" + ; "caml_floatarray_unsafe_set" + ]; + h + +let type_specialized_primitive types global_flow_state name args = + match name with + | "caml_greaterthan" + | "caml_greaterequal" + | "caml_lessthan" + | "caml_lessequal" + | "caml_equal" + | "caml_notequal" + | "caml_compare" -> ( + match List.map ~f:(arg_type ~approx:types) args with + | [ Int _; Int _ ] + | [ Number (Int32, _); Number (Int32, _) ] + | [ Number (Int64, _); Number (Int64, _) ] + | [ Number (Nativeint, _); Number (Nativeint, _) ] + | [ Number (Float, _); Number (Float, _) ] -> true + | _ -> false) + | "caml_ba_get_1" + | "caml_ba_get_2" + | "caml_ba_get_3" + | "caml_ba_set_1" + | "caml_ba_set_2" + | "caml_ba_set_3" -> ( + match args with + | Pv x :: _ -> ( + match Var.Tbl.get types x with + | Bigarray _ -> true + | _ -> false) + | _ -> false) + | "caml_ba_get_generic" | "caml_ba_set_generic" -> ( + match args with + | Pv x :: Pv indices :: _ -> ( + match Var.Tbl.get types x, global_flow_state.defs.(Var.idx indices) with + | Bigarray _, Expr (Block _) -> true + | _ -> false) + | _ -> false) + | _ -> false + +let box_numbers p st types = + (* We box numbers eagerly if the boxed value is ever used. *) + let should_box = Var.ISet.empty () in + let rec box y = + if not (Var.ISet.mem should_box y) + then ( + Var.ISet.add should_box y; + let typ = Var.Tbl.get types y in + (match typ with + | Number (n, Unboxed) -> Var.Tbl.set types y (Number (n, Boxed)) + | _ -> ()); + match typ with + | Number (_, Unboxed) | Top -> ( + match st.global_flow_state.defs.(Var.idx y) with + | Expr (Apply { f; _ }) -> ( + match Global_flow.get_unique_closure st.global_flow_info f with + | None -> () + | Some (g, _) -> + if can_unbox_return_value st.fun_info g + then + let s = Var.Map.find g st.global_flow_info.info_return_vals in + Var.Set.iter box s) + | Expr _ -> () + | Phi { known; _ } -> Var.Set.iter box known) + | Number (_, Boxed) | Int _ | Tuple _ | Bigarray _ | Bot -> ()) + in + Code.fold_closures + p + (fun name_opt _ (pc, _) _ () -> + traverse + { fold = Code.fold_children } + (fun pc () -> + let b = Addr.Map.find pc p.blocks in + List.iter + ~f:(fun i -> + match i with + | Let (_, e) -> ( + match e with + | Apply { f; args; _ } -> + if + match Global_flow.get_unique_closure st.global_flow_info f with + | None -> true + | 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) -> + if + (not (String.Hashtbl.mem primitives_with_unboxed_parameters s)) + || type_specialized_primitive types st.global_flow_state s args + then + List.iter + ~f:(fun a -> + match a with + | Pv y -> box y + | Pc _ -> ()) + args + | Prim ((Eq | Neq), args) -> + List.iter + ~f:(fun a -> + match a with + | Pv y -> box y + | Pc _ -> ()) + args + | 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 _ -> ()) + b.body; + match b.branch with + | Return y -> + Option.iter + ~f:(fun g -> if not (can_unbox_return_value st.fun_info g) then box y) + name_opt + | Raise _ | Stop | Branch _ | Cond _ | Switch _ | Pushtrap _ | Poptrap _ -> ()) + pc + p.blocks + ()) + () + +let print_opt types global_flow_state f e = + match e with + | Prim (Extern name, args) + when type_specialized_primitive types global_flow_state name args -> + Format.fprintf f " OPT" + | _ -> () + +type t = + { types : typ Var.Tbl.t + ; return_types : typ Var.Hashtbl.t + } + +let f ~global_flow_state ~global_flow_info ~fun_info ~deadcode_sentinal p = + let t = Timer.make () in + update_deps global_flow_state p; + let boxed_function_parameters = mark_function_parameters ~fun_info p in + let st = { global_flow_state; global_flow_info; boxed_function_parameters; fun_info } in + let types = solver st in + Var.Tbl.set types deadcode_sentinal (Int Normalized); + box_numbers p st types; + if times () then Format.eprintf " type analysis: %a@." Timer.print t; if debug () then ( Var.ISet.iter (fun x -> - match state.defs.(Var.idx x) with + match global_flow_state.defs.(Var.idx x) with | Expr _ -> () | Phi _ -> - let t = Var.Tbl.get typ x in + let t = Var.Tbl.get types x in if not (Domain.equal t Top) then Format.eprintf "%a: %a@." Var.print x Domain.print t) - state.vars; + global_flow_state.vars; Print.program Format.err_formatter (fun _ i -> match i with - | Instr (Let (x, _)) -> Format.asprintf "{%a}" Domain.print (Var.Tbl.get typ x) + | Instr (Let (x, e)) -> + Format.asprintf + "{%a}%a" + Domain.print + (Var.Tbl.get types x) + (print_opt types global_flow_state) + e | _ -> "") p); - typ + let return_types = Var.Hashtbl.create 128 in + Code.fold_closures + p + (fun name_opt _ _ _ () -> + Option.iter + ~f:(fun f -> + if can_unbox_return_value fun_info f + then + let s = Var.Map.find f global_flow_info.info_return_vals in + Var.Hashtbl.replace + return_types + f + (Var.Set.fold (fun x t -> Domain.join (Var.Tbl.get types x) t) s Bot)) + name_opt) + (); + { types; return_types } + +let var_type info x = Var.Tbl.get info.types x + +let return_type info f = try Var.Hashtbl.find info.return_types f with Not_found -> Top diff --git a/compiler/lib-wasm/typing.mli b/compiler/lib-wasm/typing.mli index 1860b4ac7c..5ea4e7da51 100644 --- a/compiler/lib-wasm/typing.mli +++ b/compiler/lib-wasm/typing.mli @@ -11,18 +11,60 @@ type boxed_number = | Nativeint | Float +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 + | Number of boxed_number * boxed_status | Tuple of typ array + | Bigarray of 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 + +type t + +val var_type : t -> Code.Var.t -> typ + +val return_type : t -> Code.Var.t -> typ + val f : - state:Global_flow.state - -> info:Global_flow.info + global_flow_state:Global_flow.state + -> global_flow_info:Global_flow.info + -> fun_info:Call_graph_analysis.t -> deadcode_sentinal:Code.Var.t -> Code.program - -> typ Code.Var.Tbl.t + -> t diff --git a/compiler/lib-wasm/wasm_output.ml b/compiler/lib-wasm/wasm_output.ml index 0617b0878c..88595ca03a 100644 --- a/compiler/lib-wasm/wasm_output.ml +++ b/compiler/lib-wasm/wasm_output.ml @@ -550,7 +550,9 @@ end = struct List.iter ~f:(fun e' -> output_expression st ch e') l; output_byte ch 0x10; output_uint ch (Code.Var.Hashtbl.find st.func_names f) - | Seq _ -> assert false + | Seq (l, e') -> + List.iter ~f:(fun i' -> output_instruction st ch i') l; + output_expression st ch e' | Pop _ -> () | RefFunc f -> Feature.require reference_types; @@ -939,7 +941,9 @@ end = struct List.fold_left ~f:(fun set i -> instr_function_references i set) ~init:set l | Call (_, l) | ArrayNewFixed (_, l) | StructNew (_, l) -> List.fold_left ~f:(fun set i -> expr_function_references i set) ~init:set l - | Seq _ -> assert false + | Seq (l, e) -> + List.fold_left ~f:(fun set i -> instr_function_references i set) ~init:set l + |> expr_function_references e | RefFunc f -> Code.Var.Set.add f set | Call_ref (_, e', l) -> List.fold_left diff --git a/compiler/lib/driver.ml b/compiler/lib/driver.ml index b5cd1aa938..cf65e4f3a1 100644 --- a/compiler/lib/driver.ml +++ b/compiler/lib/driver.ml @@ -217,6 +217,7 @@ let round profile : 'a -> 'a = print +> tailcall +> (flow +> specialize +> eval +> fst) + +> Ref_unboxing.f +> inline profile +> phi +> deadcode diff --git a/compiler/lib/global_flow.ml b/compiler/lib/global_flow.ml index b4dcdbc98f..6695dfb03b 100644 --- a/compiler/lib/global_flow.ml +++ b/compiler/lib/global_flow.ml @@ -791,9 +791,9 @@ let get_unique_closure info f = Var.Set.fold (fun g acc -> match info.info_defs.(Var.idx g) with - | Expr (Closure _) -> ( + | Expr (Closure (params, _, _)) -> ( match acc with - | None -> Some (Some g) + | None -> Some (Some (g, params)) | Some (Some _) -> Some None | Some None -> acc) | Expr (Block _) -> acc diff --git a/compiler/lib/global_flow.mli b/compiler/lib/global_flow.mli index 1eca38e567..07010ec5c9 100644 --- a/compiler/lib/global_flow.mli +++ b/compiler/lib/global_flow.mli @@ -84,6 +84,6 @@ val update_def : info -> Code.Var.t -> Code.expr -> unit val exact_call : info -> Var.t -> int -> bool -val get_unique_closure : info -> Var.t -> Var.t option +val get_unique_closure : info -> Var.t -> (Var.t * Var.t list) option val function_arity : info -> Var.t -> int option diff --git a/compiler/lib/inline.ml b/compiler/lib/inline.ml index cb9ac9de2e..6f030ca8d3 100644 --- a/compiler/lib/inline.ml +++ b/compiler/lib/inline.ml @@ -237,17 +237,39 @@ let sum ~context f pc = blocks 0 -let rec block_size ~recurse ~context { branch; body; _ } = +let rec block_size ~inline_comparisons ~recurse ~context { branch; body; _ } = List.fold_left ~f:(fun n i -> match i with | Event _ -> n + | Let + ( _ + , Prim + ( Extern + ( "caml_lessthan" + | "caml_lessequal" + | "caml_greaterthan" + | "caml_greaterequal" + | "caml_equal" + | "caml_notequal" ) + , _ ) ) + when inline_comparisons -> + (* Bias toward inlining functions containing polymorphic + comparisons, such as min and max, in the hope that + polymorphic comparisons can be specialized. *) + n - 1 | Let (f, Closure (_, (pc, _), _)) -> if recurse then match Var.Map.find f context.env with - | exception Not_found -> size ~recurse ~context pc + n + 1 - | info -> cache ~info info.full_size (size ~recurse:true ~context) + n + 1 + | exception Not_found -> size ~inline_comparisons ~recurse ~context pc + n + 1 + | info -> + cache + ~info + info.full_size + (size ~inline_comparisons ~recurse:true ~context) + + n + + 1 else n + 1 | _ -> n + 1) ~init: @@ -257,13 +279,21 @@ let rec block_size ~recurse ~context { branch; body; _ } = | _ -> 0) body -and size ~recurse ~context = sum ~context (block_size ~recurse ~context) +and size ~inline_comparisons ~recurse ~context = + sum ~context (block_size ~inline_comparisons ~recurse ~context) (** Size of the function body *) -let body_size ~context info = cache ~info info.body_size (size ~recurse:false ~context) +let body_size ~context info = + let inline_comparisons = + match Config.target () with + | `JavaScript -> false + | `Wasm -> true + in + cache ~info info.body_size (size ~inline_comparisons ~recurse:false ~context) (** Size of the function, including the size of the closures it contains *) -let full_size ~context info = cache ~info info.full_size (size ~recurse:true ~context) +let full_size ~context info = + cache ~info info.full_size (size ~inline_comparisons:false ~recurse:true ~context) let closure_count_uncached ~context = sum ~context (fun { body; _ } -> diff --git a/compiler/lib/phisimpl.ml b/compiler/lib/phisimpl.ml index 5f633db638..70229181ee 100644 --- a/compiler/lib/phisimpl.ml +++ b/compiler/lib/phisimpl.ml @@ -69,6 +69,10 @@ let program_deps { blocks; _ } = (fun _pc block -> List.iter block.body ~f:(fun i -> match i with + | Let (x, Prim (Extern "%identity", [ Pv y ])) -> + add_var vars x; + add_dep deps x y; + add_def vars defs x y | Let (x, e) -> add_var vars x; expr_deps blocks vars deps defs x e diff --git a/compiler/lib/ref_unboxing.ml b/compiler/lib/ref_unboxing.ml new file mode 100644 index 0000000000..de9fe92fd7 --- /dev/null +++ b/compiler/lib/ref_unboxing.ml @@ -0,0 +1,176 @@ +open! Stdlib +open Code + +(* +ocamlc does not perform reference unboxing when emitting debugging +information. Inlining can also enable additional reference unboxing. + +TODO: +- appropriate order +- handle assignment in handler + If a ref is used in an exception handler: + - add block that binds the contents of the reference right before pushtrap + - insert assignements for each update +*) + +let debug = Debug.find "unbox-refs" + +let times = Debug.find "times" + +let stats = Debug.find "stats" + +let rewrite refs block m = + let m, l = + List.fold_left + ~f:(fun (m, rem) i -> + match i with + | Let (x, Block (0, [| y |], (NotArray | Unknown), Maybe_mutable)) + when Var.Set.mem x refs -> Var.Map.add x y m, rem + | Let (y, Field (x, 0, Non_float)) when Var.Map.mem x m -> + (* Optimized away by Phisimpl *) + m, Let (y, Prim (Extern "%identity", [ Pv (Var.Map.find x m) ])) :: rem + | Offset_ref (x, n) when Var.Map.mem x m -> + let y = Var.fresh () in + ( Var.Map.add x y m + , Let + ( y + , Prim + ( Extern "%int_add" + , [ Pv (Var.Map.find x m); Pc (Int (Targetint.of_int_exn n)) ] ) ) + :: rem ) + | Set_field (x, _, Non_float, y) when Var.Map.mem x m -> Var.Map.add x y m, rem + | Event _ + when match rem with + | Event _ :: _ -> true + | _ -> false -> m, rem + | _ -> m, i :: rem) + block.body + ~init:(m, []) + in + m, List.rev l + +let rewrite_cont relevant_vars vars (pc', args) = + let refs, _ = Int.Hashtbl.find relevant_vars pc' in + let vars = Var.Map.filter (fun x _ -> Var.Set.mem x refs) vars in + pc', List.map ~f:snd (Var.Map.bindings vars) @ args + +let rewrite_function p variables pc = + let relevant_vars = Int.Hashtbl.create 16 in + let g = Structure.(dominator_tree (build_graph p.blocks pc)) in + let rec traverse_tree g pc vars = + let block = Addr.Map.find pc p.blocks in + let vars' = + List.fold_left + ~f:(fun s i -> + match i with + | Let (x, Block (0, [| _ |], (NotArray | Unknown), Maybe_mutable)) + when Var.Hashtbl.mem variables x -> Var.Set.add x s + | _ -> s) + ~init:vars + block.body + in + Int.Hashtbl.add relevant_vars pc (vars, vars'); + Addr.Set.iter (fun pc' -> traverse_tree g pc' vars') (Structure.get_edges g pc) + in + traverse_tree g pc Var.Set.empty; + let rec traverse_tree' g pc blocks = + let block = Addr.Map.find pc p.blocks in + let vars, refs = Int.Hashtbl.find relevant_vars pc in + let vars = + Var.Set.fold (fun x m -> Var.Map.add x (Var.fork x) m) vars Var.Map.empty + in + let params = List.map ~f:snd (Var.Map.bindings vars) @ block.params in + let vars, body = rewrite refs block vars in + let branch = + match block.branch with + | Return _ | Raise _ | Stop -> block.branch + | Branch cont -> Branch (rewrite_cont relevant_vars vars cont) + | Cond (x, cont, cont') -> + Cond + ( x + , rewrite_cont relevant_vars vars cont + , rewrite_cont relevant_vars vars cont' ) + | Switch (x, a) -> + Switch (x, Array.map ~f:(fun cont -> rewrite_cont relevant_vars vars cont) a) + | Pushtrap (cont, x, cont') -> + Pushtrap + ( rewrite_cont relevant_vars vars cont + , x + , rewrite_cont relevant_vars vars cont' ) + | Poptrap cont -> Poptrap (rewrite_cont relevant_vars vars cont) + in + let blocks = Addr.Map.add pc { params; body; branch } blocks in + Addr.Set.fold + (fun pc' blocks -> traverse_tree' g pc' blocks) + (Structure.get_edges g pc) + blocks + in + let blocks = traverse_tree' g pc p.blocks in + { p with blocks } + +let f p = + let t = Timer.make () in + let candidates = Var.Hashtbl.create 128 in + let updated = Var.Hashtbl.create 128 in + let visited = BitSet.create' p.free_pc in + let discard x = Var.Hashtbl.remove candidates x in + let check_field_access depth x = + match Var.Hashtbl.find candidates x with + | exception Not_found -> false + | depth' -> + if depth' = depth + then true + else ( + Var.Hashtbl.remove candidates x; + false) + in + let rec traverse depth start_pc pc = + if not (BitSet.mem visited pc) + then ( + BitSet.set visited pc; + let block = Addr.Map.find pc p.blocks in + List.iter + ~f:(fun i -> + match i with + | Let (x, Block (0, [| _ |], (NotArray | Unknown), Maybe_mutable)) -> + Freevars.iter_instr_free_vars discard i; + Var.Hashtbl.replace candidates x depth + | Let (_, Closure (_, (pc', _), _)) -> traverse (depth + 1) pc' pc' + | Let (_, Field (x, 0, Non_float)) -> ignore (check_field_access depth x) + | Offset_ref (x, _) -> + if check_field_access depth x then Var.Hashtbl.replace updated x start_pc + | Set_field (x, _, Non_float, y) -> + discard y; + if check_field_access depth x then Var.Hashtbl.replace updated x start_pc + | _ -> Freevars.iter_instr_free_vars discard i) + block.body; + Freevars.iter_last_free_var discard block.branch; + match block.branch with + | Pushtrap ((pc', _), _, (pc'', _)) -> + traverse (depth + 1) start_pc pc'; + traverse depth start_pc pc'' + | Poptrap (pc', _) -> traverse (depth - 1) start_pc pc' + | _ -> Code.fold_children p.blocks pc (fun pc' () -> traverse depth start_pc pc') ()) + in + traverse 0 p.start p.start; + if debug () + then + Print.program + Format.err_formatter + (fun _ i -> + match i with + | Instr (Let (x, _)) + when Var.Hashtbl.mem candidates x && Var.Hashtbl.mem updated x -> "REF" + | _ -> "") + p; + Var.Hashtbl.filter_map_inplace + (fun x _depth -> try Some (Var.Hashtbl.find updated x) with Not_found -> None) + candidates; + let functions = + Var.Hashtbl.fold (fun _ pc s -> Addr.Set.add pc s) candidates Addr.Set.empty + in + let p = Addr.Set.fold (fun pc p -> rewrite_function p candidates pc) functions p in + if times () then Format.eprintf " reference unboxing: %a@." Timer.print t; + if stats () + then Format.eprintf "Stats - reference unboxing: %d@." (Var.Hashtbl.length candidates); + p diff --git a/compiler/tests-compiler/double-translation/effects_continuations.ml b/compiler/tests-compiler/double-translation/effects_continuations.ml index 4659311a96..609abc8928 100644 --- a/compiler/tests-compiler/double-translation/effects_continuations.ml +++ b/compiler/tests-compiler/double-translation/effects_continuations.ml @@ -101,7 +101,7 @@ let%expect_test "test-compiler/lib-effects/test1.ml" = [%expect {| function exceptions$0(s){ - try{var _k_ = caml_int_of_string(s), n = _k_;} + try{var _l_ = caml_int_of_string(s), n = _l_;} catch(exn$0){ var exn = caml_wrap_exception(exn$0), tag = exn[1]; if(tag !== Stdlib[7]) throw caml_maybe_attach_backtrace(exn, 0); @@ -110,7 +110,7 @@ let%expect_test "test-compiler/lib-effects/test1.ml" = try{ if(caml_string_equal(s, cst$0)) throw caml_maybe_attach_backtrace(Stdlib[8], 1); - var _j_ = 7, m = _j_; + var _k_ = 7, m = _k_; } catch(exn){ var exn$0 = caml_wrap_exception(exn); @@ -120,8 +120,8 @@ let%expect_test "test-compiler/lib-effects/test1.ml" = try{ if(caml_string_equal(s, cst)) throw caml_maybe_attach_backtrace(Stdlib[8], 1); - var _i_ = [0, [0, caml_call1(Stdlib[79], cst_toto), n, m]]; - return _i_; + var _j_ = [0, [0, caml_call1(Stdlib[79], cst_toto), n, m]]; + return _j_; } catch(exn){ var exn$1 = caml_wrap_exception(exn); @@ -131,7 +131,7 @@ let%expect_test "test-compiler/lib-effects/test1.ml" = } //end function exceptions$1(s, cont){ - try{var _i_ = caml_int_of_string(s), n = _i_;} + try{var _j_ = caml_int_of_string(s), n = _j_;} catch(exn){ var exn$2 = caml_wrap_exception(exn), tag = exn$2[1]; if(tag !== Stdlib[7]){ @@ -145,7 +145,7 @@ let%expect_test "test-compiler/lib-effects/test1.ml" = try{ if(caml_string_equal(s, cst$0)) throw caml_maybe_attach_backtrace(Stdlib[8], 1); - var _h_ = 7, m = _h_; + var _i_ = 7, m = _i_; } catch(exn$0){ var exn$1 = caml_wrap_exception(exn$0); @@ -165,9 +165,9 @@ let%expect_test "test-compiler/lib-effects/test1.ml" = return caml_trampoline_cps_call2 (Stdlib[79], cst_toto, - function(_i_){caml_pop_trap(); return cont([0, [0, _i_, n, m]]);}); - var _g_ = Stdlib[8], raise = caml_pop_trap(); - return raise(caml_maybe_attach_backtrace(_g_, 1)); + function(_j_){caml_pop_trap(); return cont([0, [0, _j_, n, m]]);}); + var _h_ = Stdlib[8], raise = caml_pop_trap(); + return raise(caml_maybe_attach_backtrace(_h_, 1)); } //end var exceptions = caml_cps_closure(exceptions$0, exceptions$1); @@ -180,10 +180,10 @@ let%expect_test "test-compiler/lib-effects/test1.ml" = } //end function cond1$1(b, cont){ - function _g_(ic){return cont([0, ic, 7]);} + function _h_(ic){return cont([0, ic, 7]);} return b - ? caml_trampoline_cps_call2(Stdlib[79], cst_toto$0, _g_) - : caml_trampoline_cps_call2(Stdlib[79], cst_titi, _g_); + ? caml_trampoline_cps_call2(Stdlib[79], cst_toto$0, _h_) + : caml_trampoline_cps_call2(Stdlib[79], cst_titi, _h_); } //end var cond1 = caml_cps_closure(cond1$0, cond1$1); @@ -197,26 +197,26 @@ let%expect_test "test-compiler/lib-effects/test1.ml" = } //end function cond2$1(b, cont){ - function _g_(_g_){return cont(7);} + function _h_(_h_){return cont(7);} return b - ? caml_trampoline_cps_call2(Stdlib_Printf[3], _a_, _g_) - : caml_trampoline_cps_call2(Stdlib_Printf[3], _b_, _g_); + ? caml_trampoline_cps_call2(Stdlib_Printf[3], _a_, _h_) + : caml_trampoline_cps_call2(Stdlib_Printf[3], _b_, _h_); } //end var cond2 = caml_cps_closure(cond2$0, cond2$1); //end function cond3$0(b){ - var x = [0, 0]; - if(b) x[1] = 1; else caml_call1(Stdlib_Printf[3], _c_); - return x[1]; + var x = 0, x$0 = b ? 1 : (caml_call1(Stdlib_Printf[3], _c_), x); + return x$0; } //end function cond3$1(b, cont){ - var x = [0, 0]; - function _g_(_g_){return cont(x[1]);} + function _g_(x){return cont(x);} + var x = 0; return b - ? (x[1] = 1, _g_(0)) - : caml_trampoline_cps_call2(Stdlib_Printf[3], _c_, _g_); + ? _g_(1) + : caml_trampoline_cps_call2 + (Stdlib_Printf[3], _c_, function(_h_){return _g_(x);}); } //end var cond3 = caml_cps_closure(cond3$0, cond3$1); diff --git a/compiler/tests-compiler/effects_continuations.ml b/compiler/tests-compiler/effects_continuations.ml index adff198c65..ac55b7774a 100644 --- a/compiler/tests-compiler/effects_continuations.ml +++ b/compiler/tests-compiler/effects_continuations.ml @@ -102,7 +102,7 @@ let%expect_test "test-compiler/lib-effects/test1.ml" = [%expect {| function exceptions(s, cont){ - try{var _i_ = runtime.caml_int_of_string(s), n = _i_;} + try{var _j_ = runtime.caml_int_of_string(s), n = _j_;} catch(exn$0){ var exn = caml_wrap_exception(exn$0), tag = exn[1]; if(tag !== Stdlib[7]){ @@ -114,7 +114,7 @@ let%expect_test "test-compiler/lib-effects/test1.ml" = try{ if(caml_string_equal(s, cst$0)) throw caml_maybe_attach_backtrace(Stdlib[8], 1); - var _h_ = 7, m = _h_; + var _i_ = 7, m = _i_; } catch(exn){ var exn$0 = caml_wrap_exception(exn); @@ -136,31 +136,32 @@ let%expect_test "test-compiler/lib-effects/test1.ml" = return caml_trampoline_cps_call2 (Stdlib[79], cst_toto, - function(_i_){caml_pop_trap(); return cont([0, [0, _i_, n, m]]);}); - var _g_ = Stdlib[8], raise = caml_pop_trap(); - return raise(caml_maybe_attach_backtrace(_g_, 1)); + function(_j_){caml_pop_trap(); return cont([0, [0, _j_, n, m]]);}); + var _h_ = Stdlib[8], raise = caml_pop_trap(); + return raise(caml_maybe_attach_backtrace(_h_, 1)); } //end function cond1(b, cont){ - function _g_(ic){return cont([0, ic, 7]);} + function _h_(ic){return cont([0, ic, 7]);} return b - ? caml_trampoline_cps_call2(Stdlib[79], cst_toto$0, _g_) - : caml_trampoline_cps_call2(Stdlib[79], cst_titi, _g_); + ? caml_trampoline_cps_call2(Stdlib[79], cst_toto$0, _h_) + : caml_trampoline_cps_call2(Stdlib[79], cst_titi, _h_); } //end function cond2(b, cont){ - function _g_(_g_){return cont(7);} + function _h_(_h_){return cont(7);} return b - ? caml_trampoline_cps_call2(Stdlib_Printf[3], _a_, _g_) - : caml_trampoline_cps_call2(Stdlib_Printf[3], _b_, _g_); + ? caml_trampoline_cps_call2(Stdlib_Printf[3], _a_, _h_) + : caml_trampoline_cps_call2(Stdlib_Printf[3], _b_, _h_); } //end function cond3(b, cont){ - var x = [0, 0]; - function _g_(_g_){return cont(x[1]);} + function _g_(x){return cont(x);} + var x = 0; return b - ? (x[1] = 1, _g_(0)) - : caml_trampoline_cps_call2(Stdlib_Printf[3], _c_, _g_); + ? _g_(1) + : caml_trampoline_cps_call2 + (Stdlib_Printf[3], _c_, function(_h_){return _g_(x);}); } //end function loop1(b, cont){ diff --git a/compiler/tests-compiler/loops.ml b/compiler/tests-compiler/loops.ml index 605276270c..1a15b1b890 100644 --- a/compiler/tests-compiler/loops.ml +++ b/compiler/tests-compiler/loops.ml @@ -86,19 +86,19 @@ let rec fun_with_loop acc = function (list_rev, caml_call1(list_rev, caml_call1(list_rev, acc))); var x = param[1]; if(1 === x && ! param[2]) break; - var xs = param[2], a = [0, acc], i = 0; + var xs = param[2], a$2 = acc, i = 0; for(;;){ - a[1] = [0, 1, a[1]]; - var _a_ = i + 1 | 0; - if(10 === i){var acc$0 = [0, x, a[1]]; acc = acc$0; param = xs; break;} + var a = [0, 1, a$2], _a_ = i + 1 | 0; + if(10 === i){var acc$0 = [0, x, a]; acc = acc$0; param = xs; break;} + a$2 = a; i = _a_; } } - var a$0 = [0, acc], i$0 = 0; + var a$1 = acc, i$0 = 0; for(;;){ - a$0[1] = [0, 1, a$0[1]]; - var _b_ = i$0 + 1 | 0; - if(10 === i$0) return a$0[1]; + var a$0 = [0, 1, a$1], _b_ = i$0 + 1 | 0; + if(10 === i$0) return a$0; + a$1 = a$0; i$0 = _b_; } } @@ -582,34 +582,32 @@ let () = print_endline (trim " ") var s$0 = copy(caml_bytes_of_string(x)), len = caml_ml_bytes_length(s$0), - i = [0, 0]; + ofs = 0; for(;;){ - if(i[1] >= len) break; - if(! is_space(caml_bytes_unsafe_get(s$0, i[1]))) break; - i[1]++; + if(ofs >= len) break; + if(! is_space(caml_bytes_unsafe_get(s$0, ofs))) break; + ofs = ofs + 1 | 0; } - var j = [0, len - 1 | 0]; + var j = len - 1 | 0; for(;;){ - if(i[1] > j[1]) break; - if(! is_space(caml_bytes_unsafe_get(s$0, j[1]))) break; - j[1]--; - } - a: - { - if(i[1] <= j[1]){ - var len$0 = (j[1] - i[1] | 0) + 1 | 0, ofs = i[1]; - if - (0 <= ofs && 0 <= len$0 && (caml_ml_bytes_length(s$0) - len$0 | 0) >= ofs){ - var r = caml_create_bytes(len$0); - caml_blit_bytes(s$0, ofs, r, 0, len$0); - var b = r; - break a; + if(ofs <= j && is_space(caml_bytes_unsafe_get(s$0, j))){j = j - 1 | 0; continue;} + a: + { + if(ofs <= j){ + var len$0 = (j - ofs | 0) + 1 | 0; + if + (0 <= ofs && 0 <= len$0 && (caml_ml_bytes_length(s$0) - len$0 | 0) >= ofs){ + var r = caml_create_bytes(len$0); + caml_blit_bytes(s$0, ofs, r, 0, len$0); + var b = r; + break a; + } + throw caml_maybe_attach_backtrace([0, Invalid_argument, s], 1); } - throw caml_maybe_attach_backtrace([0, Invalid_argument, s], 1); + var b = empty; } - var b = empty; + return caml_string_of_bytes(copy(b)); } - return caml_string_of_bytes(copy(b)); } //end |}] diff --git a/compiler/tests-full/stdlib.cma.expected.js b/compiler/tests-full/stdlib.cma.expected.js index 6fd214a2e7..debcb52430 100644 --- a/compiler/tests-full/stdlib.cma.expected.js +++ b/compiler/tests-full/stdlib.cma.expected.js @@ -4862,16 +4862,16 @@ function init(n, f){ var s = /*<>*/ caml_create_bytes(n), - _L_ = /*<>*/ n - 1 | 0, - _M_ = 0; - if(_L_ >= 0){ - var i = _M_; + _Z_ = /*<>*/ n - 1 | 0, + ___ = 0; + if(_Z_ >= 0){ + var i = ___; for(;;){ /*<>*/ /*<>*/ caml_bytes_unsafe_set (s, i, /*<>*/ caml_call1(f, i)); - var _N_ = /*<>*/ i + 1 | 0; - if(_L_ === i) break; - i = _N_; + var _$_ = /*<>*/ i + 1 | 0; + if(_Z_ === i) break; + i = _$_; } } /*<>*/ return s; @@ -4926,11 +4926,11 @@ function symbol(a, b){ var c = /*<>*/ a + b | 0, - _L_ = /*<>*/ b < 0 ? 1 : 0, + _Z_ = /*<>*/ b < 0 ? 1 : 0, match = c < 0 ? 1 : 0; a: { - if(a < 0){if(! _L_ || match) break a;} else if(_L_ || ! match) break a; + if(a < 0){if(! _Z_ || match) break a;} else if(_Z_ || ! match) break a; /*<>*/ return Stdlib[1].call(null, cst_Bytes_extend) /*<>*/ ; } /*<>*/ return c; @@ -4988,30 +4988,30 @@ } function iter(f, a){ var - _J_ = /*<>*/ caml_ml_bytes_length(a) - 1 | 0, - _K_ = 0; - if(_J_ >= 0){ - var i = _K_; + _X_ = /*<>*/ caml_ml_bytes_length(a) - 1 | 0, + _Y_ = 0; + if(_X_ >= 0){ + var i = _Y_; for(;;){ /*<>*/ caml_call1(f, caml_bytes_unsafe_get(a, i)); - var _L_ = /*<>*/ i + 1 | 0; - if(_J_ === i) break; - i = _L_; + var _Z_ = /*<>*/ i + 1 | 0; + if(_X_ === i) break; + i = _Z_; } } /*<>*/ return 0; /*<>*/ } function iteri(f, a){ var - _H_ = /*<>*/ caml_ml_bytes_length(a) - 1 | 0, - _I_ = 0; - if(_H_ >= 0){ - var i = _I_; + _V_ = /*<>*/ caml_ml_bytes_length(a) - 1 | 0, + _W_ = 0; + if(_V_ >= 0){ + var i = _W_; for(;;){ /*<>*/ caml_call2(f, i, caml_bytes_unsafe_get(a, i)); - var _J_ = /*<>*/ i + 1 | 0; - if(_H_ === i) break; - i = _J_; + var _X_ = /*<>*/ i + 1 | 0; + if(_V_ === i) break; + i = _X_; } } /*<>*/ return 0; @@ -5023,7 +5023,7 @@ { var acc = /*<>*/ 0, param = l, pos$1 = 0; for(;;){ - /*<>*/ if(! param){var _H_ = acc; break a;} + /*<>*/ if(! param){var _V_ = acc; break a;} var hd = param[1]; if(! param[2]) break; var @@ -5041,10 +5041,10 @@ param = tl; } } - var _H_ = /*<>*/ caml_ml_bytes_length(hd) + acc | 0; + var _V_ = /*<>*/ caml_ml_bytes_length(hd) + acc | 0; } var - dst = /*<>*/ caml_create_bytes(_H_), + dst = /*<>*/ caml_create_bytes(_V_), pos = /*<>*/ pos$1, param$0 = l; for(;;){ @@ -5084,10 +5084,10 @@ /*<>*/ return r; /*<>*/ } function is_space(param){ - var _H_ = /*<>*/ param - 9 | 0; + var _V_ = /*<>*/ param - 9 | 0; a: { - if(4 < _H_ >>> 0){if(23 !== _H_) break a;} else if(2 === _H_) break a; + if(4 < _V_ >>> 0){if(23 !== _V_) break a;} else if(2 === _V_) break a; /*<>*/ return 1; } /*<>*/ return 0; @@ -5095,35 +5095,37 @@ function trim(s){ var len = /*<>*/ caml_ml_bytes_length(s), - i = /*<>*/ [0, 0]; - /*<>*/ for(;;){ - if(i[1] >= len) break; + i = /*<>*/ 0; + for(;;){ + if(i >= len) break; if (! /*<>*/ is_space - ( /*<>*/ caml_bytes_unsafe_get(s, i[1]))) + ( /*<>*/ caml_bytes_unsafe_get(s, i))) break; - /*<>*/ i[1]++; + /*<>*/ i = i + 1 | 0; } - var j = /*<>*/ [0, len - 1 | 0]; - /*<>*/ for(;;){ + var j = /*<>*/ len - 1 | 0; + for(;;){ if - (i[1] <= j[1] + (i <= j && /*<>*/ is_space - ( /*<>*/ caml_bytes_unsafe_get(s, j[1]))){ /*<>*/ j[1]--; continue;} - /*<>*/ return i[1] <= j[1] - ? /*<>*/ sub(s, i[1], (j[1] - i[1] | 0) + 1 | 0) + ( /*<>*/ caml_bytes_unsafe_get(s, j))){ /*<>*/ j = j - 1 | 0; continue;} + /*<>*/ return i <= j + ? /*<>*/ sub(s, i, (j - i | 0) + 1 | 0) : empty /*<>*/ ; } } function unsafe_escape(s){ var - n = /*<>*/ [0, 0], - _C_ = /*<>*/ caml_ml_bytes_length(s) - 1 | 0, - _E_ = 0; - if(_C_ >= 0){ - var i$0 = _E_; + _E_ = /*<>*/ 0, + _F_ = /*<>*/ caml_ml_bytes_length(s) - 1 | 0, + _Q_ = 0; + if(_F_ < 0) + var n$0 = _E_; + else{ + var n = _E_, i$0 = _Q_; for(;;){ var match = /*<>*/ caml_bytes_unsafe_get(s, i$0); a: @@ -5133,12 +5135,12 @@ c: { if(32 <= match){ - var _A_ = match - 34 | 0; - if(58 < _A_ >>> 0){ - if(93 <= _A_) break c; + var _C_ = match - 34 | 0; + if(58 < _C_ >>> 0){ + if(93 <= _C_) break c; } - else if(56 < _A_ - 1 >>> 0) break b; - var _B_ = /*<>*/ 1; + else if(56 < _C_ - 1 >>> 0) break b; + var _D_ = /*<>*/ 1; break a; } /*<>*/ if(11 <= match){ @@ -5146,26 +5148,26 @@ } else if(8 <= match) break b; } - var _B_ = /*<>*/ 4; + var _D_ = /*<>*/ 4; break a; } - var _B_ = /*<>*/ 2; + var _D_ = /*<>*/ 2; } - /*<>*/ n[1] = n[1] + _B_ | 0; - var _H_ = i$0 + 1 | 0; - if(_C_ === i$0) break; - i$0 = _H_; + var _H_ = /*<>*/ n + _D_ | 0, _U_ = i$0 + 1 | 0; + if(_F_ === i$0){var n$0 = _H_; break;} + n = _H_; + i$0 = _U_; } } - /*<>*/ if(n[1] === caml_ml_bytes_length(s)) + /*<>*/ if(n$0 === caml_ml_bytes_length(s)) /*<>*/ return s; - var s$0 = /*<>*/ caml_create_bytes(n[1]); - /*<>*/ n[1] = 0; var - _D_ = /*<>*/ caml_ml_bytes_length(s) - 1 | 0, - _F_ = 0; - if(_D_ >= 0){ - var i = _F_; + s$0 = /*<>*/ caml_create_bytes(n$0), + _G_ = /*<>*/ caml_ml_bytes_length(s) - 1 | 0, + _R_ = 0, + _S_ = 0; + if(_G_ >= 0){ + var n$1 = _R_, i = _S_; for(;;){ var c = /*<>*/ caml_bytes_unsafe_get(s, i); a: @@ -5182,53 +5184,60 @@ if(14 <= c) break b; switch(c){ case 8: - /*<>*/ caml_bytes_unsafe_set(s$0, n[1], 92); - /*<>*/ n[1]++; - /*<>*/ caml_bytes_unsafe_set(s$0, n[1], 98); + /*<>*/ caml_bytes_unsafe_set(s$0, n$1, 92); + var _I_ = /*<>*/ n$1 + 1 | 0; + /*<>*/ caml_bytes_unsafe_set(s$0, _I_, 98); + var n$2 = _I_; break a; case 9: - /*<>*/ caml_bytes_unsafe_set(s$0, n[1], 92); - /*<>*/ n[1]++; - /*<>*/ caml_bytes_unsafe_set(s$0, n[1], 116); + /*<>*/ caml_bytes_unsafe_set(s$0, n$1, 92); + var _J_ = /*<>*/ n$1 + 1 | 0; + /*<>*/ caml_bytes_unsafe_set(s$0, _J_, 116); + var n$2 = _J_; break a; case 10: - /*<>*/ caml_bytes_unsafe_set(s$0, n[1], 92); - /*<>*/ n[1]++; - /*<>*/ caml_bytes_unsafe_set(s$0, n[1], 110); + /*<>*/ caml_bytes_unsafe_set(s$0, n$1, 92); + var _K_ = /*<>*/ n$1 + 1 | 0; + /*<>*/ caml_bytes_unsafe_set(s$0, _K_, 110); + var n$2 = _K_; break a; case 13: - /*<>*/ caml_bytes_unsafe_set(s$0, n[1], 92); - /*<>*/ n[1]++; - /*<>*/ caml_bytes_unsafe_set(s$0, n[1], 114); + /*<>*/ caml_bytes_unsafe_set(s$0, n$1, 92); + var _L_ = /*<>*/ n$1 + 1 | 0; + /*<>*/ caml_bytes_unsafe_set(s$0, _L_, 114); + var n$2 = _L_; break a; default: break b; } } /*<>*/ if(34 > c) break c; } - /*<>*/ caml_bytes_unsafe_set(s$0, n[1], 92); - /*<>*/ n[1]++; - /*<>*/ caml_bytes_unsafe_set(s$0, n[1], c); + /*<>*/ caml_bytes_unsafe_set(s$0, n$1, 92); + var _P_ = /*<>*/ n$1 + 1 | 0; + /*<>*/ caml_bytes_unsafe_set(s$0, _P_, c); + var n$2 = _P_; break a; } - /*<>*/ caml_bytes_unsafe_set(s$0, n[1], c); + /*<>*/ caml_bytes_unsafe_set(s$0, n$1, c); + var n$2 = n$1; break a; } - /*<>*/ caml_bytes_unsafe_set(s$0, n[1], 92); - /*<>*/ n[1]++; + /*<>*/ caml_bytes_unsafe_set(s$0, n$1, 92); + var _M_ = /*<>*/ n$1 + 1 | 0; /*<>*/ caml_bytes_unsafe_set - (s$0, n[1], 48 + (c / 100 | 0) | 0); - /*<>*/ n[1]++; + (s$0, _M_, 48 + (c / 100 | 0) | 0); + var _N_ = /*<>*/ _M_ + 1 | 0; /*<>*/ caml_bytes_unsafe_set - (s$0, n[1], 48 + ((c / 10 | 0) % 10 | 0) | 0); - /*<>*/ n[1]++; + (s$0, _N_, 48 + ((c / 10 | 0) % 10 | 0) | 0); + var _O_ = /*<>*/ _N_ + 1 | 0; /*<>*/ caml_bytes_unsafe_set - (s$0, n[1], 48 + (c % 10 | 0) | 0); + (s$0, _O_, 48 + (c % 10 | 0) | 0); + var n$2 = _O_; } - /*<>*/ n[1]++; - var _G_ = i + 1 | 0; - if(_D_ === i) break; - i = _G_; + var _V_ = /*<>*/ n$2 + 1 | 0, _T_ = i + 1 | 0; + if(_G_ === i) break; + n$1 = _V_; + i = _T_; } } /*<>*/ return s$0; @@ -5242,19 +5251,19 @@ /*<>*/ if(0 === l) /*<>*/ return s; var r = /*<>*/ caml_create_bytes(l), - _y_ = /*<>*/ l - 1 | 0, - _z_ = 0; - if(_y_ >= 0){ - var i = _z_; + _A_ = /*<>*/ l - 1 | 0, + _B_ = 0; + if(_A_ >= 0){ + var i = _B_; for(;;){ /*<>*/ /*<>*/ caml_bytes_unsafe_set (r, i, /*<>*/ caml_call1 (f, /*<>*/ caml_bytes_unsafe_get(s, i))); - var _A_ = /*<>*/ i + 1 | 0; - if(_y_ === i) break; - i = _A_; + var _C_ = /*<>*/ i + 1 | 0; + if(_A_ === i) break; + i = _C_; } } /*<>*/ return r; @@ -5264,57 +5273,62 @@ /*<>*/ if(0 === l) /*<>*/ return s; var r = /*<>*/ caml_create_bytes(l), - _w_ = /*<>*/ l - 1 | 0, - _x_ = 0; - if(_w_ >= 0){ - var i = _x_; + _y_ = /*<>*/ l - 1 | 0, + _z_ = 0; + if(_y_ >= 0){ + var i = _z_; for(;;){ /*<>*/ /*<>*/ caml_bytes_unsafe_set (r, i, /*<>*/ caml_call2 (f, i, /*<>*/ caml_bytes_unsafe_get(s, i))); - var _y_ = /*<>*/ i + 1 | 0; - if(_w_ === i) break; - i = _y_; + var _A_ = /*<>*/ i + 1 | 0; + if(_y_ === i) break; + i = _A_; } } /*<>*/ return r; /*<>*/ } function fold_left(f, x, a){ var - r = /*<>*/ [0, x], - _u_ = /*<>*/ caml_ml_bytes_length(a) - 1 | 0, - _v_ = 0; - if(_u_ >= 0){ - var i = _v_; + _v_ = /*<>*/ caml_ml_bytes_length(a) - 1 | 0, + _x_ = 0; + if(_v_ < 0) + var r$0 = x; + else{ + var r = x, i = _x_; for(;;){ - /*<>*/ r[1] = - /*<>*/ caml_call2 - (f, r[1], /*<>*/ caml_bytes_unsafe_get(a, i)); - var _w_ = /*<>*/ i + 1 | 0; - if(_u_ === i) break; - i = _w_; + var + _w_ = + /*<>*/ /*<>*/ caml_call2 + (f, r, /*<>*/ caml_bytes_unsafe_get(a, i)), + _y_ = /*<>*/ i + 1 | 0; + if(_v_ === i){var r$0 = _w_; break;} + r = _w_; + i = _y_; } } - /*<>*/ return r[1]; + /*<>*/ return r$0; /*<>*/ } function fold_right(f, a, x){ - var - r = /*<>*/ [0, x], - _t_ = /*<>*/ caml_ml_bytes_length(a) - 1 | 0; - if(_t_ >= 0){ - var i = _t_; + var _t_ = /*<>*/ caml_ml_bytes_length(a) - 1 | 0; + if(_t_ < 0) + var r$0 = x; + else{ + var r = x, i = _t_; for(;;){ - /*<>*/ r[1] = - /*<>*/ caml_call2 - (f, /*<>*/ caml_bytes_unsafe_get(a, i), r[1]); - var _u_ = /*<>*/ i - 1 | 0; - if(0 === i) break; - i = _u_; + var + _u_ = + /*<>*/ /*<>*/ caml_call2 + (f, /*<>*/ caml_bytes_unsafe_get(a, i), r), + _v_ = /*<>*/ i - 1 | 0; + if(0 === i){var r$0 = _u_; break;} + r = _u_; + i = _v_; } } - /*<>*/ return r[1]; + /*<>*/ return r$0; /*<>*/ } function exists(p, s){ var @@ -5527,24 +5541,31 @@ cst_Bytes_of_seq_cannot_grow_b = "Bytes.of_seq: cannot grow bytes"; function split_on_char(sep, s){ var - r = /*<>*/ [0, 0], - j = /*<>*/ [0, caml_ml_bytes_length(s)], - _q_ = /*<>*/ caml_ml_bytes_length(s) - 1 | 0; - if(_q_ >= 0){ - var i = _q_; + _q_ = /*<>*/ 0, + _r_ = /*<>*/ caml_ml_bytes_length(s), + _s_ = /*<>*/ caml_ml_bytes_length(s) - 1 | 0; + if(_s_ < 0) + var j$1 = _r_, r$1 = _q_; + else{ + var j = _r_, r = _q_, i = _s_; for(;;){ - /*<>*/ if(caml_bytes_unsafe_get(s, i) === sep){ - var _s_ = /*<>*/ r[1]; - r[1] = [0, sub(s, i + 1 | 0, (j[1] - i | 0) - 1 | 0), _s_]; - /*<>*/ j[1] = i; - } - var _t_ = /*<>*/ i - 1 | 0; - if(0 === i) break; + /*<>*/ if(caml_bytes_unsafe_get(s, i) === sep) + var + j$0 = /*<>*/ i, + r$0 = + [0, + /*<>*/ sub(s, i + 1 | 0, (j - i | 0) - 1 | 0), + r]; + else + var j$0 = /*<>*/ j, r$0 = r; + var _t_ = i - 1 | 0; + if(0 === i){var j$1 = j$0, r$1 = r$0; break;} + j = j$0; + r = r$0; i = _t_; } } - var _r_ = /*<>*/ r[1]; - return [0, sub(s, 0, j[1]), _r_] /*<>*/ ; + /*<>*/ return [0, sub(s, 0, j$1), r$1] /*<>*/ ; /*<>*/ } function to_seq(s){ function aux(i, param){ @@ -6756,24 +6777,31 @@ } function split_on_char(sep, s){ var - r = /*<>*/ [0, 0], - j = /*<>*/ [0, caml_ml_string_length(s)], - _a_ = /*<>*/ caml_ml_string_length(s) - 1 | 0; - if(_a_ >= 0){ - var i = _a_; + _a_ = /*<>*/ 0, + _b_ = /*<>*/ caml_ml_string_length(s), + _c_ = /*<>*/ caml_ml_string_length(s) - 1 | 0; + if(_c_ < 0) + var j$1 = _b_, r$1 = _a_; + else{ + var j = _b_, r = _a_, i = _c_; for(;;){ - /*<>*/ if(caml_string_unsafe_get(s, i) === sep){ - var _c_ = /*<>*/ r[1]; - r[1] = [0, sub(s, i + 1 | 0, (j[1] - i | 0) - 1 | 0), _c_]; - /*<>*/ j[1] = i; - } - var _d_ = /*<>*/ i - 1 | 0; - if(0 === i) break; + /*<>*/ if(caml_string_unsafe_get(s, i) === sep) + var + j$0 = /*<>*/ i, + r$0 = + [0, + /*<>*/ sub(s, i + 1 | 0, (j - i | 0) - 1 | 0), + r]; + else + var j$0 = /*<>*/ j, r$0 = r; + var _d_ = i - 1 | 0; + if(0 === i){var j$1 = j$0, r$1 = r$0; break;} + j = j$0; + r = r$0; i = _d_; } } - var _b_ = /*<>*/ r[1]; - return [0, sub(s, 0, j[1]), _b_] /*<>*/ ; + /*<>*/ return [0, sub(s, 0, j$1), r$1] /*<>*/ ; /*<>*/ } var compare = /*<>*/ runtime.caml_string_compare; function to_seq(s){ @@ -7072,15 +7100,15 @@ res = /*<>*/ /*<>*/ caml_array_make (l, /*<>*/ caml_call1(f, 0)), - _am_ = /*<>*/ l - 1 | 0, - _an_ = 1; - if(_am_ >= 1){ - var i = _an_; + _al_ = /*<>*/ l - 1 | 0, + _am_ = 1; + if(_al_ >= 1){ + var i = _am_; for(;;){ /*<>*/ res[i + 1] = caml_call1(f, i); - var _ao_ = /*<>*/ i + 1 | 0; - if(_am_ === i) break; - i = _ao_; + var _an_ = /*<>*/ i + 1 | 0; + if(_al_ === i) break; + i = _an_; } } /*<>*/ return res; @@ -7090,14 +7118,14 @@ /*<>*/ Stdlib[1].call(null, cst_Array_make_matrix); var res = /*<>*/ caml_array_make(sx, [0]); /*<>*/ if(0 < sy){ - var _ak_ = /*<>*/ sx - 1 | 0, _al_ = 0; - if(_ak_ >= 0){ - var x = _al_; + var _aj_ = /*<>*/ sx - 1 | 0, _ak_ = 0; + if(_aj_ >= 0){ + var x = _ak_; for(;;){ /*<>*/ res[x + 1] = caml_array_make(sy, init); - var _am_ = /*<>*/ x + 1 | 0; - if(_ak_ === x) break; - x = _am_; + var _al_ = /*<>*/ x + 1 | 0; + if(_aj_ === x) break; + x = _al_; } } } @@ -7108,29 +7136,29 @@ /*<>*/ Stdlib[1].call(null, cst_Array_init_matrix); var res = /*<>*/ caml_array_make(sx, [0]); /*<>*/ if(0 < sy){ - var _af_ = /*<>*/ sx - 1 | 0, _ah_ = 0; - if(_af_ >= 0){ - var x = _ah_; + var _ae_ = /*<>*/ sx - 1 | 0, _ag_ = 0; + if(_ae_ >= 0){ + var x = _ag_; for(;;){ var row = /*<>*/ /*<>*/ caml_array_make (sy, /*<>*/ caml_call2(f, x, 0)), - _ag_ = /*<>*/ sy - 1 | 0, - _ai_ = 1; - if(_ag_ >= 1){ - var y = _ai_; + _af_ = /*<>*/ sy - 1 | 0, + _ah_ = 1; + if(_af_ >= 1){ + var y = _ah_; for(;;){ /*<>*/ row[y + 1] = caml_call2(f, x, y); - var _ak_ = /*<>*/ y + 1 | 0; - if(_ag_ === y) break; - y = _ak_; + var _aj_ = /*<>*/ y + 1 | 0; + if(_af_ === y) break; + y = _aj_; } } /*<>*/ res[x + 1] = row; - var _aj_ = x + 1 | 0; - if(_af_ === x) break; - x = _aj_; + var _ai_ = x + 1 | 0; + if(_ae_ === x) break; + x = _ai_; } } } @@ -7176,14 +7204,14 @@ /*<>*/ return Stdlib[1].call(null, cst_Array_blit) /*<>*/ ; } function iter(f, a){ - var _ad_ = /*<>*/ a.length - 2 | 0, _ae_ = 0; - if(_ad_ >= 0){ - var i = _ae_; + var _ac_ = /*<>*/ a.length - 2 | 0, _ad_ = 0; + if(_ac_ >= 0){ + var i = _ad_; for(;;){ /*<>*/ caml_call1(f, a[i + 1]); - var _af_ = /*<>*/ i + 1 | 0; - if(_ad_ === i) break; - i = _af_; + var _ae_ = /*<>*/ i + 1 | 0; + if(_ac_ === i) break; + i = _ae_; } } /*<>*/ return 0; @@ -7192,14 +7220,14 @@ /*<>*/ if(a.length - 1 !== b.length - 1) /*<>*/ return Stdlib[1].call (null, cst_Array_iter2_arrays_must_ha) /*<>*/ ; - var _ab_ = /*<>*/ a.length - 2 | 0, _ac_ = 0; - if(_ab_ >= 0){ - var i = _ac_; + var _aa_ = /*<>*/ a.length - 2 | 0, _ab_ = 0; + if(_aa_ >= 0){ + var i = _ab_; for(;;){ /*<>*/ caml_call2(f, a[i + 1], b[i + 1]); - var _ad_ = /*<>*/ i + 1 | 0; - if(_ab_ === i) break; - i = _ad_; + var _ac_ = /*<>*/ i + 1 | 0; + if(_aa_ === i) break; + i = _ac_; } } /*<>*/ return 0; @@ -7211,41 +7239,41 @@ r = /*<>*/ /*<>*/ caml_array_make (l, /*<>*/ caml_call1(f, a[1])), - _$_ = /*<>*/ l - 1 | 0, - _aa_ = 1; - if(_$_ >= 1){ - var i = _aa_; + ___ = /*<>*/ l - 1 | 0, + _$_ = 1; + if(___ >= 1){ + var i = _$_; for(;;){ /*<>*/ r[i + 1] = caml_call1(f, a[i + 1]); - var _ab_ = /*<>*/ i + 1 | 0; - if(_$_ === i) break; - i = _ab_; + var _aa_ = /*<>*/ i + 1 | 0; + if(___ === i) break; + i = _aa_; } } /*<>*/ return r; /*<>*/ } function map_inplace(f, a){ - var _Z_ = /*<>*/ a.length - 2 | 0, ___ = 0; - if(_Z_ >= 0){ - var i = ___; + var _Y_ = /*<>*/ a.length - 2 | 0, _Z_ = 0; + if(_Y_ >= 0){ + var i = _Z_; for(;;){ /*<>*/ a[i + 1] = caml_call1(f, a[i + 1]); - var _$_ = /*<>*/ i + 1 | 0; - if(_Z_ === i) break; - i = _$_; + var ___ = /*<>*/ i + 1 | 0; + if(_Y_ === i) break; + i = ___; } } /*<>*/ return 0; /*<>*/ } function mapi_inplace(f, a){ - var _X_ = /*<>*/ a.length - 2 | 0, _Y_ = 0; - if(_X_ >= 0){ - var i = _Y_; + var _W_ = /*<>*/ a.length - 2 | 0, _X_ = 0; + if(_W_ >= 0){ + var i = _X_; for(;;){ /*<>*/ a[i + 1] = caml_call2(f, i, a[i + 1]); - var _Z_ = /*<>*/ i + 1 | 0; - if(_X_ === i) break; - i = _Z_; + var _Y_ = /*<>*/ i + 1 | 0; + if(_W_ === i) break; + i = _Y_; } } /*<>*/ return 0; @@ -7262,28 +7290,28 @@ r = /*<>*/ /*<>*/ caml_array_make (la, /*<>*/ caml_call2(f, a[1], b[1])), - _V_ = /*<>*/ la - 1 | 0, - _W_ = 1; - if(_V_ >= 1){ - var i = _W_; + _U_ = /*<>*/ la - 1 | 0, + _V_ = 1; + if(_U_ >= 1){ + var i = _V_; for(;;){ /*<>*/ r[i + 1] = caml_call2(f, a[i + 1], b[i + 1]); - var _X_ = /*<>*/ i + 1 | 0; - if(_V_ === i) break; - i = _X_; + var _W_ = /*<>*/ i + 1 | 0; + if(_U_ === i) break; + i = _W_; } } /*<>*/ return r; /*<>*/ } function iteri(f, a){ - var _T_ = /*<>*/ a.length - 2 | 0, _U_ = 0; - if(_T_ >= 0){ - var i = _U_; + var _S_ = /*<>*/ a.length - 2 | 0, _T_ = 0; + if(_S_ >= 0){ + var i = _T_; for(;;){ /*<>*/ caml_call2(f, i, a[i + 1]); - var _V_ = /*<>*/ i + 1 | 0; - if(_T_ === i) break; - i = _V_; + var _U_ = /*<>*/ i + 1 | 0; + if(_S_ === i) break; + i = _U_; } } /*<>*/ return 0; @@ -7295,15 +7323,15 @@ r = /*<>*/ /*<>*/ caml_array_make (l, /*<>*/ caml_call2(f, 0, a[1])), - _R_ = /*<>*/ l - 1 | 0, - _S_ = 1; - if(_R_ >= 1){ - var i = _S_; + _Q_ = /*<>*/ l - 1 | 0, + _R_ = 1; + if(_Q_ >= 1){ + var i = _R_; for(;;){ /*<>*/ r[i + 1] = caml_call2(f, i, a[i + 1]); - var _T_ = /*<>*/ i + 1 | 0; - if(_R_ === i) break; - i = _T_; + var _S_ = /*<>*/ i + 1 | 0; + if(_Q_ === i) break; + i = _S_; } } /*<>*/ return r; @@ -7348,20 +7376,21 @@ } /*<>*/ } function fold_left(f, x, a){ - var - r = /*<>*/ [0, x], - _P_ = /*<>*/ a.length - 2 | 0, - _Q_ = 0; - if(_P_ >= 0){ - var i = _Q_; + var _N_ = /*<>*/ a.length - 2 | 0, _P_ = 0; + if(_N_ < 0) + var r$0 = x; + else{ + var r = x, i = _P_; for(;;){ - /*<>*/ r[1] = caml_call2(f, r[1], a[i + 1]); - var _R_ = /*<>*/ i + 1 | 0; - if(_P_ === i) break; - i = _R_; + var + _O_ = /*<>*/ caml_call2(f, r, a[i + 1]), + _Q_ = /*<>*/ i + 1 | 0; + if(_N_ === i){var r$0 = _O_; break;} + r = _O_; + i = _Q_; } } - /*<>*/ return r[1]; + /*<>*/ return r$0; /*<>*/ } function fold_left_map(f, acc, input_array){ var len = /*<>*/ input_array.length - 1; @@ -7372,40 +7401,43 @@ elt = /*<>*/ match[2], acc$0 = match[1], output_array = /*<>*/ caml_array_make(len, elt), - acc$1 = /*<>*/ [0, acc$0], - _N_ = /*<>*/ len - 1 | 0, - _O_ = 1; - if(_N_ >= 1){ - var i = _O_; + _L_ = /*<>*/ len - 1 | 0, + _M_ = 1; + if(_L_ < 1) + var acc$3 = acc$0; + else{ + var acc$2 = acc$0, i = _M_; for(;;){ var match$0 = - /*<>*/ caml_call2(f, acc$1[1], input_array[i + 1]), + /*<>*/ caml_call2(f, acc$2, input_array[i + 1]), elt$0 = /*<>*/ match$0[2], - acc$2 = match$0[1]; - /*<>*/ acc$1[1] = acc$2; - /*<>*/ output_array[i + 1] = elt$0; - var _P_ = /*<>*/ i + 1 | 0; - if(_N_ === i) break; - i = _P_; + acc$1 = match$0[1]; + /*<>*/ output_array[i + 1] = elt$0; + var _N_ = /*<>*/ i + 1 | 0; + if(_L_ === i){var acc$3 = acc$1; break;} + acc$2 = acc$1; + i = _N_; } } - /*<>*/ return [0, acc$1[1], output_array]; + /*<>*/ return [0, acc$3, output_array]; /*<>*/ } function fold_right(f, a, x){ - var - r = /*<>*/ [0, x], - _M_ = /*<>*/ a.length - 2 | 0; - if(_M_ >= 0){ - var i = _M_; + var _J_ = /*<>*/ a.length - 2 | 0; + if(_J_ < 0) + var r$0 = x; + else{ + var r = x, i = _J_; for(;;){ - /*<>*/ r[1] = caml_call2(f, a[i + 1], r[1]); - var _N_ = /*<>*/ i - 1 | 0; - if(0 === i) break; - i = _N_; + var + _K_ = /*<>*/ caml_call2(f, a[i + 1], r), + _L_ = /*<>*/ i - 1 | 0; + if(0 === i){var r$0 = _K_; break;} + r = _K_; + i = _L_; } } - /*<>*/ return r[1]; + /*<>*/ return r$0; /*<>*/ } function exists(p, a){ var @@ -7540,10 +7572,10 @@ n = /*<>*/ x.length - 1, a = /*<>*/ caml_array_make(n, a0), b = /*<>*/ caml_array_make(n, b0), - _K_ = /*<>*/ n - 1 | 0, - _L_ = 1; - if(_K_ >= 1){ - var i = _L_; + _H_ = /*<>*/ n - 1 | 0, + _I_ = 1; + if(_H_ >= 1){ + var i = _I_; for(;;){ var match$0 = /*<>*/ x[i + 1], @@ -7551,9 +7583,9 @@ ai = match$0[1]; /*<>*/ a[i + 1] = ai; /*<>*/ b[i + 1] = bi; - var _M_ = /*<>*/ i + 1 | 0; - if(_K_ === i) break; - i = _M_; + var _J_ = /*<>*/ i + 1 | 0; + if(_H_ === i) break; + i = _J_; } } /*<>*/ return [0, a, b]; @@ -7567,15 +7599,15 @@ /*<>*/ if(0 === na) /*<>*/ return [0]; var x = /*<>*/ caml_array_make(na, [0, a[1], b[1]]), - _I_ = /*<>*/ na - 1 | 0, - _J_ = 1; - if(_I_ >= 1){ - var i = _J_; + _F_ = /*<>*/ na - 1 | 0, + _G_ = 1; + if(_F_ >= 1){ + var i = _G_; for(;;){ /*<>*/ x[i + 1] = [0, a[i + 1], b[i + 1]]; - var _K_ = i + 1 | 0; - if(_I_ === i) break; - i = _K_; + var _H_ = i + 1 | 0; + if(_F_ === i) break; + i = _H_; } } /*<>*/ return x; @@ -7590,44 +7622,40 @@ cst_Array_shuffle_rand = "Array.shuffle: 'rand "; function sort(cmp, a){ function maxson(l, i){ - var - i31 = /*<>*/ ((i + i | 0) + i | 0) + 1 | 0, - x = /*<>*/ [0, i31]; - /*<>*/ if((i31 + 2 | 0) < l){ - var - _C_ = /*<>*/ i31 + 1 | 0, - _G_ = /*<>*/ caml_check_bound(a, _C_)[_C_ + 1]; - /*<>*/ if - ( /*<>*/ caml_call2 - (cmp, - /*<>*/ caml_check_bound(a, i31)[i31 + 1], - _G_) - < 0) - /*<>*/ x[1] = i31 + 1 | 0; + var i31 = /*<>*/ ((i + i | 0) + i | 0) + 1 | 0; + /*<>*/ if((i31 + 2 | 0) < l){ var - _D_ = /*<>*/ i31 + 2 | 0, - _H_ = /*<>*/ caml_check_bound(a, _D_)[_D_ + 1], - _E_ = /*<>*/ x[1]; - /*<>*/ if - ( /*<>*/ caml_call2 - (cmp, - /*<>*/ caml_check_bound(a, _E_)[_E_ + 1], - _H_) - < 0) - /*<>*/ x[1] = i31 + 2 | 0; - /*<>*/ return x[1]; + _A_ = /*<>*/ i31 + 1 | 0, + _D_ = /*<>*/ caml_check_bound(a, _A_)[_A_ + 1], + x = + /*<>*/ /*<>*/ caml_call2 + (cmp, + /*<>*/ caml_check_bound(a, i31)[i31 + 1], + _D_) + < 0 + ? i31 + 1 | 0 + : i31, + _B_ = /*<>*/ i31 + 2 | 0, + _E_ = /*<>*/ caml_check_bound(a, _B_)[_B_ + 1], + x$0 = + /*<>*/ /*<>*/ caml_call2 + (cmp, /*<>*/ caml_check_bound(a, x)[x + 1], _E_) + < 0 + ? i31 + 2 | 0 + : x; + /*<>*/ return x$0; } /*<>*/ if((i31 + 1 | 0) < l){ var - _F_ = i31 + 1 | 0, - _I_ = /*<>*/ caml_check_bound(a, _F_)[_F_ + 1]; + _C_ = i31 + 1 | 0, + _F_ = /*<>*/ caml_check_bound(a, _C_)[_C_ + 1]; /*<>*/ if (0 > /*<>*/ caml_call2 (cmp, /*<>*/ caml_check_bound(a, i31)[i31 + 1], - _I_)) + _F_)) /*<>*/ return i31 + 1 | 0; } /*<>*/ if(i31 < l) /*<>*/ return i31; @@ -7636,9 +7664,9 @@ /*<>*/ } var l = /*<>*/ a.length - 1, - _u_ = /*<>*/ ((l + 1 | 0) / 3 | 0) - 1 | 0; - if(_u_ >= 0){ - var i$6 = _u_; + _s_ = /*<>*/ ((l + 1 | 0) / 3 | 0) - 1 | 0; + if(_s_ >= 0){ + var i$6 = _s_; for(;;){ var e$1 = /*<>*/ caml_check_bound(a, i$6)[i$6 + 1]; /*<>*/ try{ @@ -7653,8 +7681,8 @@ /*<>*/ caml_check_bound(a, i)[i + 1] = e$1; break; } - var _y_ = /*<>*/ caml_check_bound(a, j)[j + 1]; - /*<>*/ caml_check_bound(a, i)[i + 1] = _y_; + var _w_ = /*<>*/ caml_check_bound(a, j)[j + 1]; + /*<>*/ caml_check_bound(a, i)[i + 1] = _w_; /*<>*/ i = j; } } @@ -7664,14 +7692,14 @@ var i$0 = exn[2]; /*<>*/ caml_check_bound(a, i$0)[i$0 + 1] = e$1; } - var _C_ = /*<>*/ i$6 - 1 | 0; + var _A_ = /*<>*/ i$6 - 1 | 0; if(0 === i$6) break; - i$6 = _C_; + i$6 = _A_; } } - var _v_ = /*<>*/ l - 1 | 0; - if(_v_ >= 2){ - var i$4 = _v_; + var _t_ = /*<>*/ l - 1 | 0; + if(_t_ >= 2){ + var i$4 = _t_; a: for(;;){ var e$0 = /*<>*/ caml_check_bound(a, i$4)[i$4 + 1]; @@ -7682,8 +7710,8 @@ for(;;){ var j$0 = /*<>*/ maxson(i$4, i$1), - _z_ = /*<>*/ caml_check_bound(a, j$0)[j$0 + 1]; - /*<>*/ caml_check_bound(a, i$1)[i$1 + 1] = _z_; + _x_ = /*<>*/ caml_check_bound(a, j$0)[j$0 + 1]; + /*<>*/ caml_check_bound(a, i$1)[i$1 + 1] = _x_; /*<>*/ i$1 = j$0; } } @@ -7705,30 +7733,30 @@ /*<>*/ caml_check_bound(a, i$3)[i$3 + 1] = e$0; else{ var - _A_ = + _y_ = /*<>*/ caml_check_bound(a, father)[father + 1]; - /*<>*/ caml_check_bound(a, i$3)[i$3 + 1] = _A_; + /*<>*/ caml_check_bound(a, i$3)[i$3 + 1] = _y_; /*<>*/ if(0 < father){i$3 = father; continue;} /*<>*/ caml_check_bound(a, 0)[1] = e$0; } - var _B_ = /*<>*/ i$4 - 1 | 0; + var _z_ = /*<>*/ i$4 - 1 | 0; if(2 === i$4) break a; - i$4 = _B_; + i$4 = _z_; break; } } } } - var _w_ = /*<>*/ 1 < l ? 1 : 0; - if(_w_){ + var _u_ = /*<>*/ 1 < l ? 1 : 0; + if(_u_){ var e = /*<>*/ caml_check_bound(a, 1)[2]; /*<>*/ a[2] = caml_check_bound(a, 0)[1]; /*<>*/ a[1] = e; - var _x_ = /*<>*/ 0; + var _v_ = /*<>*/ 0; } else - var _x_ = /*<>*/ _w_; - return _x_; + var _v_ = /*<>*/ _u_; + return _v_; /*<>*/ } function stable_sort(cmp, a){ function merge(src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs){ @@ -7773,39 +7801,37 @@ } /*<>*/ } function isortto(srcofs, dst, dstofs, len){ - var _m_ = /*<>*/ len - 1 | 0, _s_ = 0; + var _m_ = /*<>*/ len - 1 | 0, _q_ = 0; if(_m_ >= 0){ - var i = _s_; + var i = _q_; a: for(;;){ var _n_ = /*<>*/ srcofs + i | 0, e = /*<>*/ caml_check_bound(a, _n_)[_n_ + 1], - j = /*<>*/ [0, (dstofs + i | 0) - 1 | 0]; - /*<>*/ for(;;){ - if(dstofs <= j[1]){ - var _o_ = j[1]; - /*<>*/ if - (0 + j = /*<>*/ (dstofs + i | 0) - 1 | 0; + for(;;){ + if + (dstofs <= j + && + 0 < /*<>*/ caml_call2 (cmp, - /*<>*/ caml_check_bound(dst, _o_)[_o_ + 1], + /*<>*/ caml_check_bound(dst, j)[j + 1], e)){ - var - _p_ = /*<>*/ j[1], - _t_ = /*<>*/ caml_check_bound(dst, _p_)[_p_ + 1], - _q_ = /*<>*/ j[1] + 1 | 0; - /*<>*/ caml_check_bound(dst, _q_)[_q_ + 1] = _t_; - /*<>*/ j[1]--; - continue; - } + var + _o_ = /*<>*/ j + 1 | 0, + _r_ = /*<>*/ caml_check_bound(dst, j)[j + 1]; + /*<>*/ caml_check_bound(dst, _o_)[_o_ + 1] = _r_; + /*<>*/ j = j - 1 | 0; + continue; } - var _r_ = /*<>*/ j[1] + 1 | 0; - caml_check_bound(dst, _r_)[_r_ + 1] = e; - var _u_ = /*<>*/ i + 1 | 0; + var _p_ = /*<>*/ j + 1 | 0; + caml_check_bound(dst, _p_)[_p_ + 1] = e; + var _s_ = /*<>*/ i + 1 | 0; if(_m_ === i) break a; - i = _u_; + i = _s_; break; } } @@ -8036,8 +8062,8 @@ to_string = Stdlib[35]; function is_integer(x){ var - _ap_ = /*<>*/ x === runtime.caml_trunc_float(x) ? 1 : 0; - /*<>*/ return _ap_ ? is_finite(x) : _ap_ /*<>*/ ; + _ao_ = /*<>*/ x === runtime.caml_trunc_float(x) ? 1 : 0; + /*<>*/ return _ao_ ? is_finite(x) : _ao_ /*<>*/ ; } function succ(x){ /*<>*/ return caml_nextafter_float(x, infinity) /*<>*/ ; @@ -8134,19 +8160,19 @@ /*<>*/ return caml_hash(10, 100, 0, x) /*<>*/ ; } function check(a, ofs, len, msg){ - var _an_ = /*<>*/ ofs < 0 ? 1 : 0; - if(_an_) - var _am_ = _an_; + var _am_ = /*<>*/ ofs < 0 ? 1 : 0; + if(_am_) + var _al_ = _am_; else{ - var _ao_ = len < 0 ? 1 : 0; - if(_ao_) - var _am_ = _ao_; + var _an_ = len < 0 ? 1 : 0; + if(_an_) + var _al_ = _an_; else var - _ap_ = (ofs + len | 0) < 0 ? 1 : 0, - _am_ = _ap_ || (a.length - 1 < (ofs + len | 0) ? 1 : 0); + _ao_ = (ofs + len | 0) < 0 ? 1 : 0, + _al_ = _ao_ || (a.length - 1 < (ofs + len | 0) ? 1 : 0); } - return _am_ ? /*<>*/ Stdlib[1].call(null, msg) : _am_ /*<>*/ ; + return _al_ ? /*<>*/ Stdlib[1].call(null, msg) : _al_ /*<>*/ ; } var empty = /*<>*/ caml_floatarray_create(0), @@ -8169,15 +8195,15 @@ (null, cst_Float_Array_init) /*<>*/ ; var res = /*<>*/ caml_floatarray_create(l), - _ak_ = /*<>*/ l - 1 | 0, - _al_ = 0; - if(_ak_ >= 0){ - var i = _al_; + _aj_ = /*<>*/ l - 1 | 0, + _ak_ = 0; + if(_aj_ >= 0){ + var i = _ak_; for(;;){ /*<>*/ res[i + 1] = caml_call1(f, i); - var _am_ = /*<>*/ i + 1 | 0; - if(_ak_ === i) break; - i = _am_; + var _al_ = /*<>*/ i + 1 | 0; + if(_aj_ === i) break; + i = _al_; } } /*<>*/ return res; @@ -8191,14 +8217,14 @@ /*<>*/ /*<>*/ caml_array_make (sx, /*<>*/ caml_floatarray_create(0)); /*<>*/ if(0 < sy){ - var _ai_ = /*<>*/ sx - 1 | 0, _aj_ = 0; - if(_ai_ >= 0){ - var x = _aj_; + var _ah_ = /*<>*/ sx - 1 | 0, _ai_ = 0; + if(_ah_ >= 0){ + var x = _ai_; for(;;){ /*<>*/ res[x + 1] = caml_floatarray_make(sy, v); - var _ak_ = /*<>*/ x + 1 | 0; - if(_ai_ === x) break; - x = _ak_; + var _aj_ = /*<>*/ x + 1 | 0; + if(_ah_ === x) break; + x = _aj_; } } } @@ -8213,27 +8239,27 @@ /*<>*/ /*<>*/ caml_array_make (sx, /*<>*/ caml_floatarray_create(0)); /*<>*/ if(0 < sy){ - var _ad_ = /*<>*/ sx - 1 | 0, _af_ = 0; - if(_ad_ >= 0){ - var x = _af_; + var _ac_ = /*<>*/ sx - 1 | 0, _ae_ = 0; + if(_ac_ >= 0){ + var x = _ae_; for(;;){ var row = /*<>*/ caml_floatarray_create(sy), - _ae_ = /*<>*/ sy - 1 | 0, - _ag_ = 0; - if(_ae_ >= 0){ - var y = _ag_; + _ad_ = /*<>*/ sy - 1 | 0, + _af_ = 0; + if(_ad_ >= 0){ + var y = _af_; for(;;){ /*<>*/ row[y + 1] = caml_call2(f, x, y); - var _ai_ = /*<>*/ y + 1 | 0; - if(_ae_ === y) break; - y = _ai_; + var _ah_ = /*<>*/ y + 1 | 0; + if(_ad_ === y) break; + y = _ah_; } } /*<>*/ res[x + 1] = row; - var _ah_ = /*<>*/ x + 1 | 0; - if(_ad_ === x) break; - x = _ah_; + var _ag_ = /*<>*/ x + 1 | 0; + if(_ac_ === x) break; + x = _ag_; } } } @@ -8312,7 +8338,7 @@ /*<>*/ return Stdlib_List[11].call (null, a.length - 1, - function(_ad_){ /*<>*/ return a[_ad_ + 1];}) /*<>*/ ; + function(_ac_){ /*<>*/ return a[_ac_ + 1];}) /*<>*/ ; } function of_list(l){ var @@ -8331,14 +8357,14 @@ } /*<>*/ } function iter(f, a){ - var _ab_ = /*<>*/ a.length - 2 | 0, _ac_ = 0; - if(_ab_ >= 0){ - var i = _ac_; + var _aa_ = /*<>*/ a.length - 2 | 0, _ab_ = 0; + if(_aa_ >= 0){ + var i = _ab_; for(;;){ /*<>*/ caml_call1(f, a[i + 1]); - var _ad_ = /*<>*/ i + 1 | 0; - if(_ab_ === i) break; - i = _ad_; + var _ac_ = /*<>*/ i + 1 | 0; + if(_aa_ === i) break; + i = _ac_; } } /*<>*/ return 0; @@ -8347,14 +8373,14 @@ /*<>*/ if(a.length - 1 !== b.length - 1) /*<>*/ return Stdlib[1].call (null, cst_Float_Array_iter2_arrays_m) /*<>*/ ; - var _$_ = /*<>*/ a.length - 2 | 0, _aa_ = 0; - if(_$_ >= 0){ - var i = _aa_; + var ___ = /*<>*/ a.length - 2 | 0, _$_ = 0; + if(___ >= 0){ + var i = _$_; for(;;){ /*<>*/ caml_call2(f, a[i + 1], b[i + 1]); - var _ab_ = /*<>*/ i + 1 | 0; - if(_$_ === i) break; - i = _ab_; + var _aa_ = /*<>*/ i + 1 | 0; + if(___ === i) break; + i = _aa_; } } /*<>*/ return 0; @@ -8363,28 +8389,28 @@ var l = /*<>*/ a.length - 1, r = /*<>*/ caml_floatarray_create(l), - _Z_ = /*<>*/ l - 1 | 0, - ___ = 0; - if(_Z_ >= 0){ - var i = ___; + _Y_ = /*<>*/ l - 1 | 0, + _Z_ = 0; + if(_Y_ >= 0){ + var i = _Z_; for(;;){ /*<>*/ r[i + 1] = caml_call1(f, a[i + 1]); - var _$_ = /*<>*/ i + 1 | 0; - if(_Z_ === i) break; - i = _$_; + var ___ = /*<>*/ i + 1 | 0; + if(_Y_ === i) break; + i = ___; } } /*<>*/ return r; /*<>*/ } function map_inplace(f, a){ - var _X_ = /*<>*/ a.length - 2 | 0, _Y_ = 0; - if(_X_ >= 0){ - var i = _Y_; + var _W_ = /*<>*/ a.length - 2 | 0, _X_ = 0; + if(_W_ >= 0){ + var i = _X_; for(;;){ /*<>*/ a[i + 1] = caml_call1(f, a[i + 1]); - var _Z_ = /*<>*/ i + 1 | 0; - if(_X_ === i) break; - i = _Z_; + var _Y_ = /*<>*/ i + 1 | 0; + if(_W_ === i) break; + i = _Y_; } } /*<>*/ return 0; @@ -8398,28 +8424,28 @@ (null, cst_Float_Array_map2_arrays_mu) /*<>*/ ; var r = /*<>*/ caml_floatarray_create(la), - _V_ = /*<>*/ la - 1 | 0, - _W_ = 0; - if(_V_ >= 0){ - var i = _W_; + _U_ = /*<>*/ la - 1 | 0, + _V_ = 0; + if(_U_ >= 0){ + var i = _V_; for(;;){ /*<>*/ r[i + 1] = caml_call2(f, a[i + 1], b[i + 1]); - var _X_ = /*<>*/ i + 1 | 0; - if(_V_ === i) break; - i = _X_; + var _W_ = /*<>*/ i + 1 | 0; + if(_U_ === i) break; + i = _W_; } } /*<>*/ return r; /*<>*/ } function iteri(f, a){ - var _T_ = /*<>*/ a.length - 2 | 0, _U_ = 0; - if(_T_ >= 0){ - var i = _U_; + var _S_ = /*<>*/ a.length - 2 | 0, _T_ = 0; + if(_S_ >= 0){ + var i = _T_; for(;;){ /*<>*/ caml_call2(f, i, a[i + 1]); - var _V_ = /*<>*/ i + 1 | 0; - if(_T_ === i) break; - i = _V_; + var _U_ = /*<>*/ i + 1 | 0; + if(_S_ === i) break; + i = _U_; } } /*<>*/ return 0; @@ -8428,62 +8454,65 @@ var l = /*<>*/ a.length - 1, r = /*<>*/ caml_floatarray_create(l), - _R_ = /*<>*/ l - 1 | 0, - _S_ = 0; - if(_R_ >= 0){ - var i = _S_; + _Q_ = /*<>*/ l - 1 | 0, + _R_ = 0; + if(_Q_ >= 0){ + var i = _R_; for(;;){ /*<>*/ r[i + 1] = caml_call2(f, i, a[i + 1]); - var _T_ = /*<>*/ i + 1 | 0; - if(_R_ === i) break; - i = _T_; + var _S_ = /*<>*/ i + 1 | 0; + if(_Q_ === i) break; + i = _S_; } } /*<>*/ return r; /*<>*/ } function mapi_inplace(f, a){ - var _P_ = /*<>*/ a.length - 2 | 0, _Q_ = 0; - if(_P_ >= 0){ - var i = _Q_; + var _O_ = /*<>*/ a.length - 2 | 0, _P_ = 0; + if(_O_ >= 0){ + var i = _P_; for(;;){ /*<>*/ a[i + 1] = caml_call2(f, i, a[i + 1]); - var _R_ = /*<>*/ i + 1 | 0; - if(_P_ === i) break; - i = _R_; + var _Q_ = /*<>*/ i + 1 | 0; + if(_O_ === i) break; + i = _Q_; } } /*<>*/ return 0; /*<>*/ } function fold_left(f, x, a){ - var - r = /*<>*/ [0, x], - _N_ = /*<>*/ a.length - 2 | 0, - _O_ = 0; - if(_N_ >= 0){ - var i = _O_; + var _L_ = /*<>*/ a.length - 2 | 0, _N_ = 0; + if(_L_ < 0) + var r$0 = x; + else{ + var r = x, i = _N_; for(;;){ - /*<>*/ r[1] = caml_call2(f, r[1], a[i + 1]); - var _P_ = /*<>*/ i + 1 | 0; - if(_N_ === i) break; - i = _P_; + var + _M_ = /*<>*/ caml_call2(f, r, a[i + 1]), + _O_ = /*<>*/ i + 1 | 0; + if(_L_ === i){var r$0 = _M_; break;} + r = _M_; + i = _O_; } } - /*<>*/ return r[1]; + /*<>*/ return r$0; /*<>*/ } function fold_right(f, a, x){ - var - r = /*<>*/ [0, x], - _M_ = /*<>*/ a.length - 2 | 0; - if(_M_ >= 0){ - var i = _M_; + var _J_ = /*<>*/ a.length - 2 | 0; + if(_J_ < 0) + var r$0 = x; + else{ + var r = x, i = _J_; for(;;){ - /*<>*/ r[1] = caml_call2(f, a[i + 1], r[1]); - var _N_ = /*<>*/ i - 1 | 0; - if(0 === i) break; - i = _N_; + var + _K_ = /*<>*/ caml_call2(f, a[i + 1], r), + _L_ = /*<>*/ i - 1 | 0; + if(0 === i){var r$0 = _K_; break;} + r = _K_; + i = _L_; } } - /*<>*/ return r[1]; + /*<>*/ return r$0; /*<>*/ } function exists(p, a){ var @@ -8590,44 +8619,40 @@ _b_ = [0, cst_float_ml, 483, 6]; function sort(cmp, a){ function maxson(l, i){ - var - i31 = /*<>*/ ((i + i | 0) + i | 0) + 1 | 0, - x = /*<>*/ [0, i31]; - /*<>*/ if((i31 + 2 | 0) < l){ - var - _G_ = /*<>*/ i31 + 1 | 0, - _K_ = /*<>*/ caml_check_bound(a, _G_)[_G_ + 1]; - /*<>*/ if - ( /*<>*/ caml_call2 - (cmp, - /*<>*/ caml_check_bound(a, i31)[i31 + 1], - _K_) - < 0) - /*<>*/ x[1] = i31 + 1 | 0; + var i31 = /*<>*/ ((i + i | 0) + i | 0) + 1 | 0; + /*<>*/ if((i31 + 2 | 0) < l){ var - _H_ = /*<>*/ i31 + 2 | 0, - _L_ = /*<>*/ caml_check_bound(a, _H_)[_H_ + 1], - _I_ = /*<>*/ x[1]; - /*<>*/ if - ( /*<>*/ caml_call2 - (cmp, - /*<>*/ caml_check_bound(a, _I_)[_I_ + 1], - _L_) - < 0) - /*<>*/ x[1] = i31 + 2 | 0; - /*<>*/ return x[1]; + _E_ = /*<>*/ i31 + 1 | 0, + _H_ = /*<>*/ caml_check_bound(a, _E_)[_E_ + 1], + x = + /*<>*/ /*<>*/ caml_call2 + (cmp, + /*<>*/ caml_check_bound(a, i31)[i31 + 1], + _H_) + < 0 + ? i31 + 1 | 0 + : i31, + _F_ = /*<>*/ i31 + 2 | 0, + _I_ = /*<>*/ caml_check_bound(a, _F_)[_F_ + 1], + x$0 = + /*<>*/ /*<>*/ caml_call2 + (cmp, /*<>*/ caml_check_bound(a, x)[x + 1], _I_) + < 0 + ? i31 + 2 | 0 + : x; + /*<>*/ return x$0; } /*<>*/ if((i31 + 1 | 0) < l){ var - _J_ = i31 + 1 | 0, - _M_ = /*<>*/ caml_check_bound(a, _J_)[_J_ + 1]; + _G_ = i31 + 1 | 0, + _J_ = /*<>*/ caml_check_bound(a, _G_)[_G_ + 1]; /*<>*/ if (0 > /*<>*/ caml_call2 (cmp, /*<>*/ caml_check_bound(a, i31)[i31 + 1], - _M_)) + _J_)) /*<>*/ return i31 + 1 | 0; } /*<>*/ if(i31 < l) /*<>*/ return i31; @@ -8636,9 +8661,9 @@ /*<>*/ } var l = /*<>*/ a.length - 1, - _y_ = /*<>*/ ((l + 1 | 0) / 3 | 0) - 1 | 0; - if(_y_ >= 0){ - var i$6 = _y_; + _w_ = /*<>*/ ((l + 1 | 0) / 3 | 0) - 1 | 0; + if(_w_ >= 0){ + var i$6 = _w_; for(;;){ var e$1 = /*<>*/ caml_check_bound(a, i$6)[i$6 + 1]; /*<>*/ try{ @@ -8653,8 +8678,8 @@ /*<>*/ caml_check_bound(a, i)[i + 1] = e$1; break; } - var _C_ = /*<>*/ caml_check_bound(a, j)[j + 1]; - /*<>*/ caml_check_bound(a, i)[i + 1] = _C_; + var _A_ = /*<>*/ caml_check_bound(a, j)[j + 1]; + /*<>*/ caml_check_bound(a, i)[i + 1] = _A_; /*<>*/ i = j; } } @@ -8664,14 +8689,14 @@ var i$0 = exn[2]; /*<>*/ caml_check_bound(a, i$0)[i$0 + 1] = e$1; } - var _G_ = /*<>*/ i$6 - 1 | 0; + var _E_ = /*<>*/ i$6 - 1 | 0; if(0 === i$6) break; - i$6 = _G_; + i$6 = _E_; } } - var _z_ = /*<>*/ l - 1 | 0; - if(_z_ >= 2){ - var i$4 = _z_; + var _x_ = /*<>*/ l - 1 | 0; + if(_x_ >= 2){ + var i$4 = _x_; a: for(;;){ var e$0 = /*<>*/ caml_check_bound(a, i$4)[i$4 + 1]; @@ -8682,8 +8707,8 @@ for(;;){ var j$0 = /*<>*/ maxson(i$4, i$1), - _D_ = /*<>*/ caml_check_bound(a, j$0)[j$0 + 1]; - /*<>*/ caml_check_bound(a, i$1)[i$1 + 1] = _D_; + _B_ = /*<>*/ caml_check_bound(a, j$0)[j$0 + 1]; + /*<>*/ caml_check_bound(a, i$1)[i$1 + 1] = _B_; /*<>*/ i$1 = j$0; } } @@ -8705,30 +8730,30 @@ /*<>*/ caml_check_bound(a, i$3)[i$3 + 1] = e$0; else{ var - _E_ = + _C_ = /*<>*/ caml_check_bound(a, father)[father + 1]; - /*<>*/ caml_check_bound(a, i$3)[i$3 + 1] = _E_; + /*<>*/ caml_check_bound(a, i$3)[i$3 + 1] = _C_; /*<>*/ if(0 < father){i$3 = father; continue;} /*<>*/ caml_check_bound(a, 0)[1] = e$0; } - var _F_ = /*<>*/ i$4 - 1 | 0; + var _D_ = /*<>*/ i$4 - 1 | 0; if(2 === i$4) break a; - i$4 = _F_; + i$4 = _D_; break; } } } } - var _A_ = /*<>*/ 1 < l ? 1 : 0; - if(_A_){ + var _y_ = /*<>*/ 1 < l ? 1 : 0; + if(_y_){ var e = /*<>*/ caml_check_bound(a, 1)[2]; /*<>*/ a[2] = caml_check_bound(a, 0)[1]; /*<>*/ a[1] = e; - var _B_ = /*<>*/ 0; + var _z_ = /*<>*/ 0; } else - var _B_ = /*<>*/ _A_; - return _B_; + var _z_ = /*<>*/ _y_; + return _z_; /*<>*/ } function stable_sort(cmp, a){ function merge(src1ofs, src1len, src2, src2ofs, src2len, dst, dstofs){ @@ -8773,39 +8798,37 @@ } /*<>*/ } function isortto(srcofs, dst, dstofs, len){ - var _q_ = /*<>*/ len - 1 | 0, _w_ = 0; + var _q_ = /*<>*/ len - 1 | 0, _u_ = 0; if(_q_ >= 0){ - var i = _w_; + var i = _u_; a: for(;;){ var _r_ = /*<>*/ srcofs + i | 0, e = /*<>*/ caml_check_bound(a, _r_)[_r_ + 1], - j = /*<>*/ [0, (dstofs + i | 0) - 1 | 0]; - /*<>*/ for(;;){ - if(dstofs <= j[1]){ - var _s_ = j[1]; - /*<>*/ if - (0 + j = /*<>*/ (dstofs + i | 0) - 1 | 0; + for(;;){ + if + (dstofs <= j + && + 0 < /*<>*/ caml_call2 (cmp, - /*<>*/ caml_check_bound(dst, _s_)[_s_ + 1], + /*<>*/ caml_check_bound(dst, j)[j + 1], e)){ - var - _t_ = /*<>*/ j[1], - _x_ = /*<>*/ caml_check_bound(dst, _t_)[_t_ + 1], - _u_ = /*<>*/ j[1] + 1 | 0; - /*<>*/ caml_check_bound(dst, _u_)[_u_ + 1] = _x_; - /*<>*/ j[1]--; - continue; - } + var + _s_ = /*<>*/ j + 1 | 0, + _v_ = /*<>*/ caml_check_bound(dst, j)[j + 1]; + /*<>*/ caml_check_bound(dst, _s_)[_s_ + 1] = _v_; + /*<>*/ j = j - 1 | 0; + continue; } - var _v_ = /*<>*/ j[1] + 1 | 0; - caml_check_bound(dst, _v_)[_v_ + 1] = e; - var _y_ = /*<>*/ i + 1 | 0; + var _t_ = /*<>*/ j + 1 | 0; + caml_check_bound(dst, _t_)[_t_ + 1] = e; + var _w_ = /*<>*/ i + 1 | 0; if(_q_ === i) break a; - i = _y_; + i = _w_; break; } } @@ -12548,21 +12571,28 @@ var old_pos = /*<>*/ b[2], old_len = /*<>*/ b[1][2], - new_len = /*<>*/ [0, old_len]; - /*<>*/ for(;;){ - if(new_len[1] >= (old_pos + more | 0)) break; - /*<>*/ new_len[1] = 2 * new_len[1] | 0; - } - /*<>*/ if(Stdlib_Sys[12] < new_len[1]) - /*<>*/ if((old_pos + more | 0) <= Stdlib_Sys[12]) - /*<>*/ new_len[1] = Stdlib_Sys[12]; - else - /*<>*/ Stdlib[2].call - (null, cst_Buffer_add_cannot_grow_buf); - var new_buffer = /*<>*/ caml_create_bytes(new_len[1]); + new_len = /*<>*/ old_len; + for(;;){ + if(new_len >= (old_pos + more | 0)) break; + /*<>*/ new_len = 2 * new_len | 0; + } + var + new_len$0 = + /*<>*/ Stdlib_Sys[12] < new_len + ? (old_pos + + more + | 0) + <= Stdlib_Sys[12] + ? Stdlib_Sys[12] + : ( /*<>*/ Stdlib + [2].call + (null, cst_Buffer_add_cannot_grow_buf), + new_len) + : new_len, + new_buffer = /*<>*/ caml_create_bytes(new_len$0); /*<>*/ Stdlib_Bytes[11].call (null, b[1][1], 0, new_buffer, 0, b[2]); - /*<>*/ b[1] = [0, new_buffer, new_len[1]]; + /*<>*/ b[1] = [0, new_buffer, new_len$0]; /*<>*/ } function add_char(b, c){ var @@ -13676,14 +13706,14 @@ var str_ind = /*<>*/ c >>> 3 | 0, mask = 1 << (c & 7), - _a7_ = + _a9_ = /*<>*/ runtime.caml_bytes_get (char_set, str_ind) | mask; /*<>*/ return /*<>*/ caml_bytes_set (char_set, str_ind, - /*<>*/ Stdlib[29].call(null, _a7_)) /*<>*/ ; + /*<>*/ Stdlib[29].call(null, _a9_)) /*<>*/ ; } function freeze_char_set(char_set){ /*<>*/ return Stdlib_Bytes[6].call @@ -13695,18 +13725,18 @@ i = /*<>*/ 0; for(;;){ var - _a6_ = + _a8_ = /*<>*/ caml_string_get(char_set, i) ^ 255; /*<>*/ /*<>*/ caml_bytes_set (char_set$0, i, - /*<>*/ Stdlib[29].call(null, _a6_)); - var _a7_ = /*<>*/ i + 1 | 0; + /*<>*/ Stdlib[29].call(null, _a8_)); + var _a9_ = /*<>*/ i + 1 | 0; if(31 === i) /*<>*/ return Stdlib_Bytes[44].call (null, char_set$0) /*<>*/ ; - /*<>*/ i = _a7_; + /*<>*/ i = _a9_; } /*<>*/ } function is_in_char_set(char_set, c){ @@ -13775,11 +13805,11 @@ /*<>*/ if(prec_opt) var ndec = prec_opt[1], - _a6_ = /*<>*/ [0, ndec]; + _a8_ = /*<>*/ [0, ndec]; else - var _a6_ = /*<>*/ 0; + var _a8_ = /*<>*/ 0; /*<>*/ return [0, - [8, _a_, pad_of_pad_opt(pad_opt$5), _a6_, fmt]] /*<>*/ ; + [8, _a_, pad_of_pad_opt(pad_opt$5), _a8_, fmt]] /*<>*/ ; case 7: var pad_opt$6 = /*<>*/ ign[1]; /*<>*/ return [0, @@ -13925,19 +13955,19 @@ before = /*<>*/ Stdlib_Char[1].call (null, c - 1 | 0), - _a3_ = /*<>*/ is_in_char_set(set, c); - /*<>*/ if(_a3_) + _a5_ = /*<>*/ is_in_char_set(set, c); + /*<>*/ if(_a5_) var - _a4_ = - /*<>*/ is_in_char_set(set, before), _a6_ = - /*<>*/ _a4_ + /*<>*/ is_in_char_set(set, before), + _a8_ = + /*<>*/ _a6_ ? /*<>*/ is_in_char_set(set, after) - : _a4_, - _a5_ = /*<>*/ 1 - _a6_; + : _a6_, + _a7_ = /*<>*/ 1 - _a8_; else - var _a5_ = /*<>*/ _a3_; - return _a5_; + var _a7_ = /*<>*/ _a5_; + return _a7_; /*<>*/ } /*<>*/ if(is_alone(93)) /*<>*/ buffer_add_char(buf, 93); @@ -14155,11 +14185,11 @@ /*<>*/ if(2 === formatting_lit[0]){ var c = formatting_lit[1], - _a3_ = + _a5_ = /*<>*/ Stdlib_String[1].call (null, 1, c); /*<>*/ return Stdlib[28].call - (null, cst$7, _a3_); + (null, cst$7, _a5_); } var str = /*<>*/ formatting_lit[1]; return str; @@ -14172,17 +14202,17 @@ } function bprint_string_literal(buf, str){ var - _a1_ = + _a3_ = /*<>*/ caml_ml_string_length(str) - 1 | 0, - _a2_ = 0; - if(_a1_ >= 0){ - var i = _a2_; + _a4_ = 0; + if(_a3_ >= 0){ + var i = _a4_; for(;;){ /*<>*/ /*<>*/ bprint_char_literal (buf, /*<>*/ caml_string_get(str, i)); - var _a3_ = /*<>*/ i + 1 | 0; - if(_a1_ === i) break; - i = _a3_; + var _a5_ = /*<>*/ i + 1 | 0; + if(_a3_ === i) break; + i = _a5_; } } /*<>*/ } @@ -14542,12 +14572,12 @@ (buf, ign_flag); /*<>*/ switch(counter){ case 0: - var _aY_ = /*<>*/ 108; break; + var _a0_ = /*<>*/ 108; break; case 1: - var _aY_ = /*<>*/ 110; break; - default: var _aY_ = /*<>*/ 78; + var _a0_ = /*<>*/ 110; break; + default: var _a0_ = /*<>*/ 78; } - /*<>*/ buffer_add_char(buf, _aY_); + /*<>*/ buffer_add_char(buf, _a0_); /*<>*/ fmt = rest$20; ign_flag = 0; break; @@ -14576,19 +14606,19 @@ var rest$23 = /*<>*/ fmt[3], arity = fmt[1], - _aZ_ = + _a1_ = /*<>*/ int_of_custom_arity(arity), - _a0_ = /*<>*/ 1; - if(_aZ_ >= 1){ - var i = _a0_; + _a2_ = /*<>*/ 1; + if(_a1_ >= 1){ + var i = _a2_; for(;;){ /*<>*/ buffer_add_char(buf, 37); /*<>*/ bprint_ignored_flag (buf, ign_flag); /*<>*/ buffer_add_char(buf, 63); - var _a1_ = /*<>*/ i + 1 | 0; - if(_aZ_ === i) break; - i = _a1_; + var _a3_ = /*<>*/ i + 1 | 0; + if(_a1_ === i) break; + i = _a3_; } } /*<>*/ fmt = rest$23; @@ -15102,12 +15132,12 @@ var rest2$7 = ty2[2], ty2$0 = ty2[1], - _aY_ = + _a0_ = /*<>*/ trans (rest1$7, rest2$7); /*<>*/ return [8, trans(ty1$0, ty2$0), - _aY_] /*<>*/ ; + _a0_] /*<>*/ ; case 10: break a; case 11: @@ -15384,18 +15414,18 @@ var rest$11 = /*<>*/ fmtty[2], formatting_gen = fmtty[1], - _aX_ = /*<>*/ fmtty_of_fmt(rest$11); + _aZ_ = /*<>*/ fmtty_of_fmt(rest$11); /*<>*/ if(0 === formatting_gen[0]) var fmt = formatting_gen[1][1], - _aW_ = /*<>*/ fmtty_of_fmt(fmt); + _aY_ = /*<>*/ fmtty_of_fmt(fmt); else var fmt$0 = /*<>*/ formatting_gen[1][1], - _aW_ = /*<>*/ fmtty_of_fmt(fmt$0); + _aY_ = /*<>*/ fmtty_of_fmt(fmt$0); /*<>*/ return CamlinternalFormatBasics [1].call - (null, _aW_, _aX_) /*<>*/ ; + (null, _aY_, _aZ_) /*<>*/ ; case 19: var rest$12 = /*<>*/ fmtty[1]; /*<>*/ return [13, @@ -15422,10 +15452,10 @@ if(9 === ign[0]){ var fmtty$3 = ign[2], - _aY_ = /*<>*/ fmtty_of_fmt(fmtty$2); + _a0_ = /*<>*/ fmtty_of_fmt(fmtty$2); /*<>*/ return CamlinternalFormatBasics [1].call - (null, fmtty$3, _aY_) /*<>*/ ; + (null, fmtty$3, _a0_) /*<>*/ ; } /*<>*/ fmtty = fmtty$2; } @@ -15734,11 +15764,11 @@ /*<>*/ } function type_format(fmt, fmtty){ var - _aW_ = /*<>*/ type_format_gen(fmt, fmtty); - /*<>*/ if(typeof _aW_[2] !== "number") + _aY_ = /*<>*/ type_format_gen(fmt, fmtty); + /*<>*/ if(typeof _aY_[2] !== "number") /*<>*/ throw caml_maybe_attach_backtrace (Type_mismatch, 1); - var fmt$0 = /*<>*/ _aW_[1]; + var fmt$0 = /*<>*/ _aY_[1]; /*<>*/ return fmt$0; /*<>*/ } function type_format_gen(fmt, fmtty0){ @@ -16034,7 +16064,7 @@ fmt_rest$13 = fmt[3], sub_fmtty$1 = fmt[2], pad_opt$0 = fmt[1], - _aW_ = + _aY_ = /*<>*/ [0, CamlinternalFormatBasics[2].call(null, sub_fmtty1)]; /*<>*/ if @@ -16043,7 +16073,7 @@ /*<>*/ CamlinternalFormatBasics [2].call (null, sub_fmtty$1)], - _aW_)) + _aY_)) /*<>*/ throw caml_maybe_attach_backtrace (Type_mismatch, 1); var @@ -16207,13 +16237,13 @@ var sub_fmtty$3 = /*<>*/ ign[2], pad_opt$2 = ign[1], - _aV_ = + _aX_ = /*<>*/ type_ignored_format_substituti (sub_fmtty$3, rest, fmtty0), - match$43 = /*<>*/ _aV_[2], + match$43 = /*<>*/ _aX_[2], fmtty$21 = match$43[2], fmt$22 = match$43[1], - sub_fmtty$4 = _aV_[1]; + sub_fmtty$4 = _aX_[1]; /*<>*/ return [0, [23, [9, pad_opt$2, sub_fmtty$4], fmt$22], fmtty$21]; @@ -16418,7 +16448,7 @@ sub_fmtty_rest$17 = sub_fmtty[3], sub2_fmtty$2 = sub_fmtty[2], sub1_fmtty$0 = sub_fmtty[1], - _aU_ = + _aW_ = /*<>*/ [0, CamlinternalFormatBasics[2].call(null, sub1_fmtty)]; /*<>*/ if @@ -16427,11 +16457,11 @@ /*<>*/ CamlinternalFormatBasics [2].call (null, sub1_fmtty$0)], - _aU_)) + _aW_)) /*<>*/ throw caml_maybe_attach_backtrace (Type_mismatch, 1); var - _aV_ = + _aX_ = /*<>*/ [0, CamlinternalFormatBasics[2].call(null, sub2_fmtty$1)]; /*<>*/ if @@ -16440,7 +16470,7 @@ /*<>*/ CamlinternalFormatBasics [2].call (null, sub2_fmtty$2)], - _aV_)) + _aX_)) /*<>*/ throw caml_maybe_attach_backtrace (Type_mismatch, 1); var @@ -16538,12 +16568,12 @@ (Type_mismatch, 1); /*<>*/ } function recast(fmt, fmtty){ - var _aU_ = /*<>*/ symm(fmtty); + var _aW_ = /*<>*/ symm(fmtty); /*<>*/ return /*<>*/ type_format (fmt, /*<>*/ CamlinternalFormatBasics [2].call - (null, _aU_)) /*<>*/ ; + (null, _aW_)) /*<>*/ ; } function fix_padding(padty, width, str){ var @@ -16554,10 +16584,10 @@ /*<>*/ if(width$0 <= len) /*<>*/ return str; var - _aU_ = /*<>*/ 2 === padty$0 ? 48 : 32, + _aW_ = /*<>*/ 2 === padty$0 ? 48 : 32, res = /*<>*/ Stdlib_Bytes[1].call - (null, width$0, _aU_); + (null, width$0, _aW_); /*<>*/ switch(padty$0){ case 0: /*<>*/ Stdlib_String[6].call @@ -16722,23 +16752,28 @@ /*<>*/ if(13 > iconv) /*<>*/ return s; var - n = /*<>*/ [0, 0], - _aP_ = + _aP_ = /*<>*/ 0, + _aQ_ = /*<>*/ caml_ml_string_length(s) - 1 | 0, - _aR_ = 0; - if(_aP_ >= 0){ - var i$0 = _aR_; + _aS_ = 0; + if(_aQ_ < 0) + var digits = _aP_; + else{ + var n = _aP_, i$0 = _aS_; for(;;){ - /*<>*/ if - (9 >= caml_string_unsafe_get(s, i$0) - 48 >>> 0) - /*<>*/ n[1]++; - var _aU_ = /*<>*/ i$0 + 1 | 0; - if(_aP_ === i$0) break; - i$0 = _aU_; + var + n$0 = + /*<>*/ 9 + < caml_string_unsafe_get(s, i$0) - 48 >>> 0 + ? n + : n + 1 | 0, + _aW_ = i$0 + 1 | 0; + if(_aQ_ === i$0){var digits = n$0; break;} + n = n$0; + i$0 = _aW_; } } var - digits = /*<>*/ n[1], buf = /*<>*/ /*<>*/ caml_create_bytes ( /*<>*/ caml_ml_string_length(s) @@ -16750,30 +16785,32 @@ /*<>*/ pos[1]++; /*<>*/ } var - left = - /*<>*/ [0, - ((digits - 1 | 0) % 3 | 0) + 1 | 0], - _aQ_ = + _aR_ = /*<>*/ caml_ml_string_length(s) - 1 | 0, - _aS_ = 0; - if(_aQ_ >= 0){ - var i = _aS_; + _aT_ = ((digits - 1 | 0) % 3 | 0) + 1 | 0, + _aU_ = 0; + if(_aR_ >= 0){ + var left = _aT_, i = _aU_; for(;;){ var c = /*<>*/ caml_string_unsafe_get(s, i); - if(9 < c - 48 >>> 0) + if(9 < c - 48 >>> 0){ /*<>*/ put(c); + var left$1 = /*<>*/ left; + } else{ - /*<>*/ if(0 === left[1]){ - /*<>*/ put(95); - /*<>*/ left[1] = 3; - } - /*<>*/ left[1]--; + var + left$0 = + /*<>*/ 0 === left + ? ( /*<>*/ put(95), 3) + : left; /*<>*/ put(c); + var left$1 = /*<>*/ left$0 - 1 | 0; } - var _aT_ = /*<>*/ i + 1 | 0; - if(_aQ_ === i) break; - i = _aT_; + var _aV_ = /*<>*/ i + 1 | 0; + if(_aR_ === i) break; + left = left$1; + i = _aV_; } } /*<>*/ return Stdlib_Bytes[44].call @@ -21095,17 +21132,20 @@ case 13: var f$6 = /*<>*/ param[1]; /*<>*/ no_arg$0(0); - var acc = /*<>*/ [0, 0]; - /*<>*/ for(;;){ + var acc = /*<>*/ 0; + for(;;){ if(current[1] >= (argv[1].length - 2 | 0)) /*<>*/ return /*<>*/ caml_call1 (f$6, - /*<>*/ Stdlib_List[10].call(null, acc[1])) /*<>*/ ; + /*<>*/ Stdlib_List[10].call(null, acc)) /*<>*/ ; var _H_ = /*<>*/ current[1] + 1 | 0, - _K_ = /*<>*/ acc[1]; - acc[1] = [0, caml_check_bound(argv[1], _H_)[_H_ + 1], _K_]; + _K_ = + /*<>*/ [0, + caml_check_bound(argv[1], _H_)[_H_ + 1], + acc]; /*<>*/ consume_arg$0(0); + /*<>*/ acc = _K_; } break; default: @@ -22583,14 +22623,13 @@ var len = /*<>*/ caml_ml_bytes_length(buf); /*<>*/ if((ofs + n | 0) <= len) /*<>*/ return buf; - var new_len = /*<>*/ [0, len]; - /*<>*/ for(;;){ - if(new_len[1] >= (ofs + n | 0)) break; - /*<>*/ new_len[1] = (2 * new_len[1] | 0) + 1 | 0; + var new_len$0 = /*<>*/ len; + for(;;){ + if(new_len$0 >= (ofs + n | 0)) break; + /*<>*/ new_len$0 = (2 * new_len$0 | 0) + 1 | 0; } var - new_len$0 = /*<>*/ new_len[1], - new_len$1 = + new_len = /*<>*/ new_len$0 <= Stdlib_Sys[12] ? new_len$0 : ofs @@ -22599,7 +22638,7 @@ : /*<>*/ Stdlib [2].call (null, cst_In_channel_input_all_chann), - new_buf = /*<>*/ caml_create_bytes(new_len$1); + new_buf = /*<>*/ caml_create_bytes(new_len); /*<>*/ Stdlib_Bytes[11].call (null, buf, 0, new_buf, 0, ofs); /*<>*/ return new_buf; @@ -24400,9 +24439,9 @@ var Stdlib_String = global_data.Stdlib__String; function ongoing_traversal(h){ var - _K_ = /*<>*/ h.length - 1 < 4 ? 1 : 0, - _L_ = _K_ || (h[4] < 0 ? 1 : 0); - return _L_; + _J_ = /*<>*/ h.length - 1 < 4 ? 1 : 0, + _K_ = _J_ || (h[4] < 0 ? 1 : 0); + return _K_; /*<>*/ } function flip_ongoing_traversal(h){ /*<>*/ h[4] = - h[4] | 0; @@ -24466,24 +24505,24 @@ s = /*<>*/ power_2_above(16, initial_size); /*<>*/ if(random) var - _K_ = + _J_ = /*<>*/ caml_call1(Stdlib_Domain[11][2], prng_key), seed = /*<>*/ /*<>*/ caml_call1 - (Stdlib_Random[19][4], _K_); + (Stdlib_Random[19][4], _J_); else var seed = /*<>*/ 0; /*<>*/ return [0, 0, caml_array_make(s, 0), seed, s] /*<>*/ ; /*<>*/ } function clear(h){ - var _K_ = /*<>*/ 0 < h[1] ? 1 : 0; - return _K_ + var _J_ = /*<>*/ 0 < h[1] ? 1 : 0; + return _J_ ? (h [1] = 0, /*<>*/ Stdlib_Array[8].call (null, h[2], 0, h[2].length - 1, 0)) - : _K_ /*<>*/ ; + : _J_ /*<>*/ ; } function reset(h){ var len = /*<>*/ h[2].length - 1; @@ -24522,10 +24561,10 @@ /*<>*/ } function copy(h){ var - _I_ = /*<>*/ h[4], - _J_ = h[3], - _K_ = Stdlib_Array[14].call(null, copy_bucketlist, h[2]); - /*<>*/ return [0, h[1], _K_, _J_, _I_]; + _H_ = /*<>*/ h[4], + _I_ = h[3], + _J_ = Stdlib_Array[14].call(null, copy_bucketlist, h[2]); + /*<>*/ return [0, h[1], _J_, _I_, _H_]; /*<>*/ } function length(h){ /*<>*/ return h[1]; @@ -24534,10 +24573,10 @@ var nsize = /*<>*/ ndata.length - 1, ndata_tail = /*<>*/ caml_array_make(nsize, 0), - _C_ = /*<>*/ odata.length - 2 | 0, - _F_ = 0; - if(_C_ >= 0){ - var i$0 = _F_; + _B_ = /*<>*/ odata.length - 2 | 0, + _E_ = 0; + if(_B_ >= 0){ + var i$0 = _E_; a: for(;;){ var @@ -24546,9 +24585,9 @@ cell = /*<>*/ cell$1; for(;;){ /*<>*/ if(! cell){ - var _I_ = /*<>*/ i$0 + 1 | 0; - if(_C_ === i$0) break a; - i$0 = _I_; + var _H_ = /*<>*/ i$0 + 1 | 0; + if(_B_ === i$0) break a; + i$0 = _H_; break; } var @@ -24571,33 +24610,33 @@ } } /*<>*/ if(inplace){ - var _D_ = /*<>*/ nsize - 1 | 0, _G_ = 0; - if(_D_ >= 0){ - var i = _G_; + var _C_ = /*<>*/ nsize - 1 | 0, _F_ = 0; + if(_C_ >= 0){ + var i = _F_; for(;;){ var match$0 = /*<>*/ caml_check_bound(ndata_tail, i)[i + 1]; /*<>*/ if(match$0) /*<>*/ match$0[3] = 0; - var _H_ = /*<>*/ i + 1 | 0; - if(_D_ === i) break; - i = _H_; + var _G_ = /*<>*/ i + 1 | 0; + if(_C_ === i) break; + i = _G_; } } - var _E_ = /*<>*/ 0; + var _D_ = /*<>*/ 0; } else - var _E_ = /*<>*/ inplace; - return _E_; + var _D_ = /*<>*/ inplace; + return _D_; /*<>*/ } function resize(indexfun, h){ var odata = /*<>*/ h[2], osize = /*<>*/ odata.length - 1, nsize = /*<>*/ osize * 2 | 0, - _C_ = /*<>*/ nsize < Stdlib_Sys[13] ? 1 : 0; - if(! _C_) return _C_; + _B_ = /*<>*/ nsize < Stdlib_Sys[13] ? 1 : 0; + if(! _B_) return _B_; var ndata = /*<>*/ caml_array_make(nsize, 0), inplace = /*<>*/ 1 - ongoing_traversal(h); @@ -24613,9 +24652,9 @@ /*<>*/ if(1 - old_trav) /*<>*/ flip_ongoing_traversal(h); /*<>*/ try{ - var d = h[2], _y_ = /*<>*/ d.length - 2 | 0, _A_ = 0; - if(_y_ >= 0){ - var i = _A_; + var d = h[2], _x_ = /*<>*/ d.length - 2 | 0, _z_ = 0; + if(_x_ >= 0){ + var i = _z_; a: for(;;){ var @@ -24625,9 +24664,9 @@ [i + 1]; /*<>*/ for(;;){ /*<>*/ if(! param){ - var _C_ = /*<>*/ i + 1 | 0; - if(_y_ === i) break a; - i = _C_; + var _B_ = /*<>*/ i + 1 | 0; + if(_x_ === i) break a; + i = _B_; break; } var @@ -24640,9 +24679,9 @@ } } var - _z_ = /*<>*/ 1 - old_trav, - _B_ = _z_ ? /*<>*/ flip_ongoing_traversal(h) : _z_; - return _B_; + _y_ = /*<>*/ 1 - old_trav, + _A_ = _y_ ? /*<>*/ flip_ongoing_traversal(h) : _y_; + return _A_; } catch(exn$0){ var exn = /*<>*/ caml_wrap_exception(exn$0); @@ -24659,9 +24698,9 @@ /*<>*/ if(1 - old_trav) /*<>*/ flip_ongoing_traversal(h); /*<>*/ try{ - var _u_ = d.length - 2 | 0, _w_ = 0; - if(_u_ >= 0){ - var i = _w_; + var _t_ = d.length - 2 | 0, _v_ = 0; + if(_t_ >= 0){ + var i = _v_; a: for(;;){ var @@ -24674,9 +24713,9 @@ /*<>*/ prec[3] = 0; else /*<>*/ caml_check_bound(h[2], i)[i + 1] = 0; - var _y_ = /*<>*/ i + 1 | 0; - if(_u_ === i) break a; - i = _y_; + var _x_ = /*<>*/ i + 1 | 0; + if(_t_ === i) break a; + i = _x_; break; } var @@ -24702,9 +24741,9 @@ } } var - _v_ = /*<>*/ 1 - old_trav, - _x_ = _v_ ? /*<>*/ flip_ongoing_traversal(h) : _v_; - return _x_; + _u_ = /*<>*/ 1 - old_trav, + _w_ = _u_ ? /*<>*/ flip_ongoing_traversal(h) : _u_; + return _w_; } catch(exn$0){ var exn = /*<>*/ caml_wrap_exception(exn$0); @@ -24719,27 +24758,23 @@ /*<>*/ if(1 - old_trav) /*<>*/ flip_ongoing_traversal(h); /*<>*/ try{ - var - d = h[2], - accu$1 = /*<>*/ [0, init], - _r_ = /*<>*/ d.length - 2 | 0, - _s_ = 0; - if(_r_ >= 0){ - var i = _s_; + var d = h[2], _r_ = /*<>*/ d.length - 2 | 0, _s_ = 0; + if(_r_ < 0) + var accu$2 = init; + else{ + var accu$1 = init, i = _s_; a: for(;;){ var - accu$2 = /*<>*/ accu$1[1], b$0 = /*<>*/ caml_check_bound(d, i)[i + 1], b = /*<>*/ b$0, - accu = accu$2; + accu = accu$1; for(;;){ /*<>*/ if(! b){ - /*<>*/ accu$1[1] = accu; - var _u_ = i + 1 | 0; - if(_r_ === i) break a; - i = _u_; - break; + var _t_ = /*<>*/ i + 1 | 0; + if(_r_ !== i){accu$1 = accu; i = _t_; break;} + var accu$2 = accu; + break a; } var key = /*<>*/ b[1], @@ -24753,8 +24788,7 @@ } /*<>*/ if(1 - old_trav) /*<>*/ flip_ongoing_traversal(h); - var _t_ = /*<>*/ accu$1[1]; - return _t_; + return accu$2; } catch(exn$0){ var exn = /*<>*/ caml_wrap_exception(exn$0); @@ -28435,7 +28469,7 @@ /*<>*/ return create(1, next) /*<>*/ ; } var _a_ = /*<>*/ 0; - function from_function(_aw_){return create(_a_, _aw_);} + function from_function(_ax_){return create(_a_, _ax_);} var len = /*<>*/ 1024; function scan_close_at_end(ic){ /*<>*/ Stdlib[93].call(null, ic); @@ -28481,10 +28515,10 @@ (scan_close_at_end, [1, fname, ic], ic) /*<>*/ ; } var _b_ = /*<>*/ Stdlib[79]; - function open_in(_aw_){return open_in_file(_b_, _aw_);} + function open_in(_ax_){return open_in_file(_b_, _ax_);} var _c_ = /*<>*/ Stdlib[80]; - function open_in_bin(_aw_){ - /*<>*/ return open_in_file(_c_, _aw_); + function open_in_bin(_ax_){ + /*<>*/ return open_in_file(_c_, _ax_); } function from_channel(ic){ /*<>*/ return from_ic(scan_raise_at_end, [0, ic], ic) /*<>*/ ; @@ -28627,15 +28661,15 @@ /*<>*/ for(;;){ var c = /*<>*/ peek_char(ib), - _aw_ = /*<>*/ 1 - ib[1]; - if(! _aw_) return _aw_; - var _av_ = /*<>*/ c - 9 | 0; + _ax_ = /*<>*/ 1 - ib[1]; + if(! _ax_) return _ax_; + var _aw_ = /*<>*/ c - 9 | 0; a: { - if(4 < _av_ >>> 0){ - if(23 !== _av_) break a; + if(4 < _aw_ >>> 0){ + if(23 !== _aw_) break a; } - else if(1 >= _av_ - 2 >>> 0) break a; + else if(1 >= _aw_ - 2 >>> 0) break a; /*<>*/ invalidate_current_char(ib); continue; } @@ -28687,31 +28721,31 @@ /*<>*/ switch(conv){ case 0: var - _as_ = /*<>*/ token_string(ib), + _at_ = /*<>*/ token_string(ib), tok = /*<>*/ /*<>*/ Stdlib[28].call - (null, cst_0b, _as_); + (null, cst_0b, _at_); break; case 3: var - _at_ = /*<>*/ token_string(ib), + _au_ = /*<>*/ token_string(ib), tok = /*<>*/ /*<>*/ Stdlib[28].call - (null, cst_0o, _at_); + (null, cst_0o, _au_); break; case 4: var - _au_ = /*<>*/ token_string(ib), + _av_ = /*<>*/ token_string(ib), tok = /*<>*/ /*<>*/ Stdlib[28].call - (null, cst_0u, _au_); + (null, cst_0u, _av_); break; case 5: var - _av_ = /*<>*/ token_string(ib), + _aw_ = /*<>*/ token_string(ib), tok = /*<>*/ /*<>*/ Stdlib[28].call - (null, cst_0x, _av_); + (null, cst_0x, _aw_); break; default: var @@ -28796,13 +28830,13 @@ /*<>*/ return 7 < param - 48 >>> 0 ? 0 : 1 /*<>*/ ; } function is_hexa_digit(param){ - var _as_ = /*<>*/ param - 48 | 0; + var _at_ = /*<>*/ param - 48 | 0; a: { - if(22 < _as_ >>> 0){ - if(5 < _as_ - 49 >>> 0) break a; + if(22 < _at_ >>> 0){ + if(5 < _at_ - 49 >>> 0) break a; } - else if(6 >= _as_ - 10 >>> 0) break a; + else if(6 >= _at_ - 10 >>> 0) break a; /*<>*/ return 1; } /*<>*/ return 0; @@ -28933,28 +28967,31 @@ } var len = /*<>*/ caml_ml_string_length(str), - width$0 = /*<>*/ [0, width], _ap_ = /*<>*/ len - 1 | 0, - _aq_ = 0; - if(_ap_ >= 0){ - var i = _aq_; + _ar_ = 0; + if(_ap_ < 0) + var width$1 = width; + else{ + var width$0 = width, i = _ar_; for(;;){ var c = /*<>*/ peek_char(ib), - _ar_ = + _as_ = /*<>*/ /*<>*/ lowercase ( /*<>*/ caml_string_get(str, i)); - /*<>*/ if(lowercase(c) !== _ar_) + /*<>*/ if(lowercase(c) !== _as_) /*<>*/ caml_call1(error, 0); - /*<>*/ if(0 === width$0[1]) + /*<>*/ if(0 === width$0) /*<>*/ caml_call1(error, 0); - /*<>*/ width$0[1] = store_char(width$0[1], ib, c); - var _as_ = /*<>*/ i + 1 | 0; - if(_ap_ === i) break; - i = _as_; + var + _aq_ = /*<>*/ store_char(width$0, ib, c), + _at_ = /*<>*/ i + 1 | 0; + if(_ap_ === i){var width$1 = _aq_; break;} + width$0 = _aq_; + i = _at_; } } - /*<>*/ return width$0[1]; + /*<>*/ return width$1; /*<>*/ } function scan_hex_float(width, precision, ib){ var @@ -30508,28 +30545,33 @@ var params = /*<>*/ [0, 1, 1, 1, 3, 16]; function public_method_label(s){ var - accu = /*<>*/ [0, 0], - _C_ = + _C_ = /*<>*/ 0, + _D_ = /*<>*/ runtime.caml_ml_string_length(s) - 1 | 0, - _D_ = 0; - if(_C_ >= 0){ - var i = _D_; + _F_ = 0; + if(_D_ < 0) + var accu$1 = _C_; + else{ + var accu$0 = _C_, i = _F_; for(;;){ var - _E_ = /*<>*/ runtime.caml_string_get(s, i); - /*<>*/ accu[1] = (223 * accu[1] | 0) + _E_ | 0; - var _F_ = i + 1 | 0; - if(_C_ === i) break; - i = _F_; + _E_ = + /*<>*/ (223 * accu$0 | 0) + + runtime.caml_string_get(s, i) + | 0, + _G_ = /*<>*/ i + 1 | 0; + if(_D_ === i){var accu$1 = _E_; break;} + accu$0 = _E_; + i = _G_; } } - /*<>*/ accu[1] = accu[1] & 2147483647; var + accu = /*<>*/ accu$1 & 2147483647, tag = - /*<>*/ 1073741823 < accu[1] - ? accu[1] + 2147483648 | 0 - : accu[1]; + /*<>*/ 1073741823 < accu + ? accu + 2147483648 | 0 + : accu; /*<>*/ return tag; /*<>*/ } var @@ -31079,23 +31121,28 @@ function build_path(n, keys, tables){ var res = /*<>*/ [0, 0, 0, 0], - r = /*<>*/ [0, res], - _g_ = /*<>*/ 0; - if(n >= 0){ - var i = _g_; + _h_ = /*<>*/ 0; + if(n < 0) + var r$0 = res; + else{ + var r = res, i = _h_; for(;;){ - var _h_ = /*<>*/ r[1]; - r[1] = [0, caml_check_bound(keys, i)[i + 1], _h_, 0]; - var _i_ = /*<>*/ i + 1 | 0; - if(n === i) break; + var + _g_ = + /*<>*/ [0, + caml_check_bound(keys, i)[i + 1], + r, + 0], + _i_ = /*<>*/ i + 1 | 0; + if(n === i){var r$0 = _g_; break;} + r = _g_; i = _i_; } } - var v = /*<>*/ r[1]; /*<>*/ if(! tables) /*<>*/ throw caml_maybe_attach_backtrace ([0, Assert_failure, _b_], 1); - /*<>*/ tables[2] = v; + /*<>*/ tables[2] = r$0; /*<>*/ return res; /*<>*/ } function lookup_tables(root, keys){ @@ -31673,22 +31720,22 @@ CamlinternalOO = global_data.CamlinternalOO, _a_ = [0, 0]; function copy(a, dummy){ - var _af_ = /*<>*/ Stdlib_Obj[17]; - if(caml_obj_tag(a) !== _af_) + var _ai_ = /*<>*/ Stdlib_Obj[17]; + if(caml_obj_tag(a) !== _ai_) /*<>*/ return Stdlib_Array[7].call(null, a) /*<>*/ ; var n = /*<>*/ a.length - 1, arr = /*<>*/ caml_array_make(n, dummy), - _ae_ = /*<>*/ n - 1 | 0, - _ag_ = 0; - if(_ae_ >= 0){ - var i = _ag_; + _ah_ = /*<>*/ n - 1 | 0, + _aj_ = 0; + if(_ah_ >= 0){ + var i = _aj_; for(;;){ var v = /*<>*/ a[i + 1]; /*<>*/ arr[i + 1] = v; - var _ah_ = /*<>*/ i + 1 | 0; - if(_ae_ === i) break; - i = _ah_; + var _ak_ = /*<>*/ i + 1 | 0; + if(_ah_ === i) break; + i = _ak_; } } /*<>*/ return arr; @@ -31870,10 +31917,10 @@ _c_ = CamlinternalOO[3].call(null, _b_, cst_x); CamlinternalOO[17].call(null, _b_); _a_[1] = - function(_ae_){ - var _ad_ = /*<>*/ CamlinternalOO[24].call(null, 0, _b_); - _ad_[_c_ + 1] = _ae_[2]; - return _ad_; + function(_ah_){ + var _ag_ = /*<>*/ CamlinternalOO[24].call(null, 0, _b_); + _ag_[_c_ + 1] = _ah_[2]; + return _ag_; }; } var dummy = /*<>*/ caml_call1(_a_[1], [0, 0, r]); @@ -31906,26 +31953,26 @@ function check_same_length(f, param, expected){ var length_a = /*<>*/ param[1], - _ad_ = /*<>*/ expected !== length_a ? 1 : 0; - return _ad_ + _ag_ = /*<>*/ expected !== length_a ? 1 : 0; + return _ag_ ? /*<>*/ caml_call3 (Stdlib_Printf[10].call(null, Stdlib[1], _m_), f, expected, length_a) - : _ad_ /*<>*/ ; + : _ag_ /*<>*/ ; } function check_valid_length(length, arr){ var capacity = /*<>*/ arr.length - 1, - _ad_ = /*<>*/ capacity < length ? 1 : 0; - return _ad_ + _ag_ = /*<>*/ capacity < length ? 1 : 0; + return _ag_ ? /*<>*/ caml_call3 (Stdlib_Printf[10].call(null, Stdlib[1], _l_), invalid_state_description, length, capacity) - : _ad_ /*<>*/ ; + : _ag_ /*<>*/ ; } function unsafe_get(arr, dummy, i, length){ var v = /*<>*/ arr[i + 1]; @@ -31939,8 +31986,8 @@ function make(n, x){ /*<>*/ if(n < 0) /*<>*/ negative_length_requested(cst_make, n); - var _ad_ = /*<>*/ Stdlib_Obj[16]; - if(caml_obj_tag(x) !== _ad_) + var _ag_ = /*<>*/ Stdlib_Obj[16]; + if(caml_obj_tag(x) !== _ag_) var arr$0 = /*<>*/ /*<>*/ caml_array_make @@ -31957,16 +32004,16 @@ /*<>*/ negative_length_requested(cst_init, n); var arr = /*<>*/ caml_array_make(n, dummy), - _ab_ = /*<>*/ n - 1 | 0, - _ac_ = 0; - if(_ab_ >= 0){ - var i = _ac_; + _ae_ = /*<>*/ n - 1 | 0, + _af_ = 0; + if(_ae_ >= 0){ + var i = _af_; for(;;){ var v = /*<>*/ caml_call1(f, i); /*<>*/ arr[i + 1] = v; - var _ad_ = /*<>*/ i + 1 | 0; - if(_ab_ === i) break; - i = _ad_; + var _ag_ = /*<>*/ i + 1 | 0; + if(_ae_ === i) break; + i = _ag_; } } /*<>*/ return [0, n, arr, dummy]; @@ -32059,16 +32106,16 @@ function remove_last(a){ var last = /*<>*/ a[1] - 1 | 0, - _aa_ = /*<>*/ 0 <= last ? 1 : 0; - if(_aa_){ + _ad_ = /*<>*/ 0 <= last ? 1 : 0; + if(_ad_){ /*<>*/ a[1] = last; var dummy = /*<>*/ a[3]; caml_check_bound(a[2], last)[last + 1] = dummy; - var _ab_ = /*<>*/ 0; + var _ae_ = /*<>*/ 0; } else - var _ab_ = /*<>*/ _aa_; - return _ab_; + var _ae_ = /*<>*/ _ad_; + return _ae_; /*<>*/ } function truncate(a, n){ /*<>*/ if(n < 0) @@ -32098,24 +32145,24 @@ /*<>*/ if(capacity_request <= cur_capacity) /*<>*/ return 0; /*<>*/ if(Stdlib_Sys[13] < capacity_request){ - var _Z_ = /*<>*/ Stdlib_Sys[13]; + var _aa_ = /*<>*/ Stdlib_Sys[13]; caml_call3 (Stdlib_Printf[10].call(null, Stdlib[1], _j_), f$1, capacity_request, - _Z_); + _aa_); } var n = /*<>*/ 512 < cur_capacity ? cur_capacity + (cur_capacity / 2 | 0) | 0 : cur_capacity * 2 | 0, - ___ = /*<>*/ Stdlib_Sys[13], - _$_ = Stdlib[17].call(null, 8, n), - _aa_ = /*<>*/ Stdlib[16].call(null, _$_, ___), + _ab_ = /*<>*/ Stdlib_Sys[13], + _ac_ = Stdlib[17].call(null, 8, n), + _ad_ = /*<>*/ Stdlib[16].call(null, _ac_, _ab_), new_capacity = /*<>*/ Stdlib[17].call - (null, _aa_, capacity_request); + (null, _ad_, capacity_request); /*<>*/ if(0 >= new_capacity) throw caml_maybe_attach_backtrace([0, Assert_failure, _q_], 1); var @@ -32153,12 +32200,12 @@ /*<>*/ return 0; } var - _Y_ = /*<>*/ cur_capacity < n ? 1 : 0, - _Z_ = - _Y_ + _$_ = /*<>*/ cur_capacity < n ? 1 : 0, + _aa_ = + _$_ ? (a[2] = /*<>*/ extend(arr, a[1], a[3], n), 0) - : _Y_; - /*<>*/ return _Z_; + : _$_; + /*<>*/ return _aa_; /*<>*/ } function reset(param){ /*<>*/ param[1] = 0; @@ -32176,8 +32223,8 @@ /*<>*/ return 0; /*<>*/ for(;;){ /*<>*/ ensure_extra_capacity(a, 1); - var _Y_ = /*<>*/ 1 - add_last_if_room(a, x); - /*<>*/ if(! _Y_) return _Y_; + var _$_ = /*<>*/ 1 - add_last_if_room(a, x); + /*<>*/ if(! _$_) return _$_; } /*<>*/ } function append_list(a, li$0){ @@ -32218,47 +32265,47 @@ /*<>*/ if(src_dummy === dst_dummy) /*<>*/ return Stdlib_Array[9].call (null, src_arr, src_pos, dst_arr, dst_pos, blit_length) /*<>*/ ; - var _Q_ = /*<>*/ blit_length < 0 ? 1 : 0; - if(_Q_) - var _P_ = _Q_; + var _T_ = /*<>*/ blit_length < 0 ? 1 : 0; + if(_T_) + var _S_ = _T_; else{ - var _S_ = src_pos < 0 ? 1 : 0; - if(_S_) - var _P_ = _S_; + var _V_ = src_pos < 0 ? 1 : 0; + if(_V_) + var _S_ = _V_; else{ - var _T_ = (src_pos + blit_length | 0) < 0 ? 1 : 0; - if(_T_) - var _P_ = _T_; + var _W_ = (src_pos + blit_length | 0) < 0 ? 1 : 0; + if(_W_) + var _S_ = _W_; else{ - var _U_ = src_arr.length - 1 < (src_pos + blit_length | 0) ? 1 : 0; - if(_U_) - var _P_ = _U_; + var _X_ = src_arr.length - 1 < (src_pos + blit_length | 0) ? 1 : 0; + if(_X_) + var _S_ = _X_; else{ - var _V_ = dst_pos < 0 ? 1 : 0; - if(_V_) - var _P_ = _V_; + var _Y_ = dst_pos < 0 ? 1 : 0; + if(_Y_) + var _S_ = _Y_; else var - _Y_ = (dst_pos + blit_length | 0) < 0 ? 1 : 0, - _P_ = - _Y_ || (dst_arr.length - 1 < (dst_pos + blit_length | 0) ? 1 : 0); + _$_ = (dst_pos + blit_length | 0) < 0 ? 1 : 0, + _S_ = + _$_ || (dst_arr.length - 1 < (dst_pos + blit_length | 0) ? 1 : 0); } } } } - if(_P_) + if(_S_) /*<>*/ throw caml_maybe_attach_backtrace ([0, Assert_failure, _d_], 1); /*<>*/ if(src_arr === dst_arr) throw caml_maybe_attach_backtrace([0, Assert_failure, _e_], 1); - var _R_ = /*<>*/ blit_length - 1 | 0, _W_ = 0; - if(_R_ >= 0){ - var i = _W_; + var _U_ = /*<>*/ blit_length - 1 | 0, _Z_ = 0; + if(_U_ >= 0){ + var i = _Z_; for(;;){ /*<>*/ dst_arr[(dst_pos + i | 0) + 1] = src_arr[(src_pos + i | 0) + 1]; - var _X_ = /*<>*/ i + 1 | 0; - if(_R_ === i) break; - i = _X_; + var ___ = /*<>*/ i + 1 | 0; + if(_U_ === i) break; + i = ___; } } /*<>*/ return 0; @@ -32269,18 +32316,18 @@ /*<>*/ caml_call1 (Stdlib_Printf[10].call(null, Stdlib[1], _r_), len); var - _M_ = /*<>*/ src_pos < 0 ? 1 : 0, - _N_ = _M_ || (src_length < (src_pos + len | 0) ? 1 : 0); - if(_N_) + _P_ = /*<>*/ src_pos < 0 ? 1 : 0, + _Q_ = _P_ || (src_length < (src_pos + len | 0) ? 1 : 0); + if(_Q_) /*<>*/ caml_call3 (Stdlib_Printf[10].call(null, Stdlib[1], _s_), src_pos, src_pos + len | 0, src_length); var - _O_ = /*<>*/ dst_pos < 0 ? 1 : 0, - _P_ = _O_ || (dst_length < dst_pos ? 1 : 0); - if(_P_) + _R_ = /*<>*/ dst_pos < 0 ? 1 : 0, + _S_ = _R_ || (dst_length < dst_pos ? 1 : 0); + if(_S_) /*<>*/ caml_call3 (Stdlib_Printf[10].call(null, Stdlib[1], _t_), dst_pos, @@ -32298,23 +32345,23 @@ /*<>*/ if(arr.length - 1 < (length_a + length_b | 0)) /*<>*/ return 0; /*<>*/ param[1] = length_a + length_b | 0; - var _K_ = /*<>*/ Stdlib_Obj[17], src_pos = 0; - if(caml_obj_tag(src) !== _K_) + var _N_ = /*<>*/ Stdlib_Obj[17], src_pos = 0; + if(caml_obj_tag(src) !== _N_) /*<>*/ Stdlib_Array[9].call (null, src, src_pos, arr, length_a, length_b); else{ - var _H_ = /*<>*/ length_b - 1 | 0, _L_ = 0; - if(_H_ >= 0){ - var i = _L_; + var _K_ = /*<>*/ length_b - 1 | 0, _O_ = 0; + if(_K_ >= 0){ + var i = _O_; for(;;){ var - _I_ = /*<>*/ i | 0, - v = /*<>*/ caml_check_bound(src, _I_)[_I_ + 1], - _J_ = /*<>*/ length_a + i | 0; - /*<>*/ caml_check_bound(arr, _J_)[_J_ + 1] = v; - var _M_ = /*<>*/ i + 1 | 0; - if(_H_ === i) break; - i = _M_; + _L_ = /*<>*/ i | 0, + v = /*<>*/ caml_check_bound(src, _L_)[_L_ + 1], + _M_ = /*<>*/ length_a + i | 0; + /*<>*/ caml_check_bound(arr, _M_)[_M_ + 1] = v; + var _P_ = /*<>*/ i + 1 | 0; + if(_K_ === i) break; + i = _P_; } } } @@ -32325,8 +32372,8 @@ /*<>*/ return 0; /*<>*/ for(;;){ /*<>*/ ensure_extra_capacity(a, b.length - 1); - var _H_ = /*<>*/ 1 - append_array_if_room(a, b); - /*<>*/ if(! _H_) return _H_; + var _K_ = /*<>*/ 1 - append_array_if_room(a, b); + /*<>*/ if(! _K_) return _K_; } /*<>*/ } function append_if_room(param, b, length_b){ @@ -32347,22 +32394,22 @@ /*<>*/ for(;;){ /*<>*/ ensure_extra_capacity(a, length_b); /*<>*/ check_same_length(cst_append$0, b, length_b); - var _H_ = /*<>*/ 1 - append_if_room(a, b, length_b); - /*<>*/ if(! _H_) return _H_; + var _K_ = /*<>*/ 1 - append_if_room(a, b, length_b); + /*<>*/ if(! _K_) return _K_; } /*<>*/ } function iter(f, k, a){ var length = /*<>*/ a[1], arr = a[2], dummy = a[3]; /*<>*/ check_valid_length(length, arr); - var _F_ = /*<>*/ length - 1 | 0, _G_ = 0; - if(_F_ >= 0){ - var i = _G_; + var _I_ = /*<>*/ length - 1 | 0, _J_ = 0; + if(_I_ >= 0){ + var i = _J_; for(;;){ /*<>*/ /*<>*/ caml_call1 (k, /*<>*/ unsafe_get(arr, dummy, i, length)); - var _H_ = /*<>*/ i + 1 | 0; - if(_F_ === i) break; - i = _H_; + var _K_ = /*<>*/ i + 1 | 0; + if(_I_ === i) break; + i = _K_; } } /*<>*/ return check_same_length(f, a, length) /*<>*/ ; @@ -32373,15 +32420,15 @@ function iteri(k, a){ var length = /*<>*/ a[1], arr = a[2], dummy = a[3]; /*<>*/ check_valid_length(length, arr); - var _D_ = /*<>*/ length - 1 | 0, _E_ = 0; - if(_D_ >= 0){ - var i = _E_; + var _G_ = /*<>*/ length - 1 | 0, _H_ = 0; + if(_G_ >= 0){ + var i = _H_; for(;;){ /*<>*/ /*<>*/ caml_call2 (k, i, /*<>*/ unsafe_get(arr, dummy, i, length)); - var _F_ = /*<>*/ i + 1 | 0; - if(_D_ === i) break; - i = _F_; + var _I_ = /*<>*/ i + 1 | 0; + if(_G_ === i) break; + i = _I_; } } /*<>*/ return check_same_length(cst_iteri, a, length) /*<>*/ ; @@ -32391,10 +32438,10 @@ /*<>*/ check_valid_length(length, arr_in); var arr_out = /*<>*/ caml_array_make(length, dummy), - _B_ = /*<>*/ length - 1 | 0, - _C_ = 0; - if(_B_ >= 0){ - var i = _C_; + _E_ = /*<>*/ length - 1 | 0, + _F_ = 0; + if(_E_ >= 0){ + var i = _F_; for(;;){ var v = @@ -32402,9 +32449,9 @@ (f, /*<>*/ unsafe_get(arr_in, dummy, i, length)); /*<>*/ arr_out[i + 1] = v; - var _D_ = /*<>*/ i + 1 | 0; - if(_B_ === i) break; - i = _D_; + var _G_ = /*<>*/ i + 1 | 0; + if(_E_ === i) break; + i = _G_; } } var res = /*<>*/ [0, length, arr_out, dummy]; @@ -32416,10 +32463,10 @@ /*<>*/ check_valid_length(length, arr_in); var arr_out = /*<>*/ caml_array_make(length, dummy), - _z_ = /*<>*/ length - 1 | 0, - _A_ = 0; - if(_z_ >= 0){ - var i = _A_; + _C_ = /*<>*/ length - 1 | 0, + _D_ = 0; + if(_C_ >= 0){ + var i = _D_; for(;;){ var v = @@ -32428,9 +32475,9 @@ i, /*<>*/ unsafe_get(arr_in, dummy, i, length)); /*<>*/ arr_out[i + 1] = v; - var _B_ = /*<>*/ i + 1 | 0; - if(_z_ === i) break; - i = _B_; + var _E_ = /*<>*/ i + 1 | 0; + if(_C_ === i) break; + i = _E_; } } var res = /*<>*/ [0, length, arr_out, dummy]; @@ -32440,41 +32487,44 @@ function fold_left(f, acc, a){ var length = /*<>*/ a[1], arr = a[2], dummy = a[3]; /*<>*/ check_valid_length(length, arr); - var - r = /*<>*/ [0, acc], - _x_ = /*<>*/ length - 1 | 0, - _y_ = 0; - if(_x_ >= 0){ - var i = _y_; + var _z_ = /*<>*/ length - 1 | 0, _B_ = 0; + if(_z_ < 0) + var r$0 = acc; + else{ + var r = acc, i = _B_; for(;;){ - var v = /*<>*/ unsafe_get(arr, dummy, i, length); - /*<>*/ r[1] = caml_call2(f, r[1], v); - var _z_ = /*<>*/ i + 1 | 0; - if(_x_ === i) break; - i = _z_; + var + v = /*<>*/ unsafe_get(arr, dummy, i, length), + _A_ = /*<>*/ caml_call2(f, r, v), + _C_ = /*<>*/ i + 1 | 0; + if(_z_ === i){var r$0 = _A_; break;} + r = _A_; + i = _C_; } } /*<>*/ check_same_length(cst_fold_left, a, length); - /*<>*/ return r[1]; + /*<>*/ return r$0; /*<>*/ } function fold_right(f, a, acc){ var length = /*<>*/ a[1], arr = a[2], dummy = a[3]; /*<>*/ check_valid_length(length, arr); - var - r = /*<>*/ [0, acc], - _w_ = /*<>*/ length - 1 | 0; - if(_w_ >= 0){ - var i = _w_; + var _x_ = /*<>*/ length - 1 | 0; + if(_x_ < 0) + var r$0 = acc; + else{ + var r = acc, i = _x_; for(;;){ - var v = /*<>*/ unsafe_get(arr, dummy, i, length); - /*<>*/ r[1] = caml_call2(f, v, r[1]); - var _x_ = /*<>*/ i - 1 | 0; - if(0 === i) break; - i = _x_; + var + v = /*<>*/ unsafe_get(arr, dummy, i, length), + _y_ = /*<>*/ caml_call2(f, v, r), + _z_ = /*<>*/ i - 1 | 0; + if(0 === i){var r$0 = _y_; break;} + r = _y_; + i = _z_; } } /*<>*/ check_same_length(cst_fold_right, a, length); - /*<>*/ return r[1]; + /*<>*/ return r$0; /*<>*/ } function exists(p, a){ var length = /*<>*/ a[1], arr = a[2], dummy = a[3]; @@ -32485,15 +32535,15 @@ var res = /*<>*/ 0; else{ var - _w_ = + _x_ = /*<>*/ /*<>*/ caml_call1 (p, /*<>*/ unsafe_get(arr, dummy, i, length)); - /*<>*/ if(! _w_){ + /*<>*/ if(! _x_){ var i$0 = i + 1 | 0; i = i$0; continue; } - var res = _w_; + var res = _x_; } /*<>*/ check_same_length(cst_exists, a, length); /*<>*/ return res; @@ -32508,15 +32558,15 @@ var res = /*<>*/ 1; else{ var - _w_ = + _x_ = /*<>*/ /*<>*/ caml_call1 (p, /*<>*/ unsafe_get(arr, dummy, i, length)); - /*<>*/ if(_w_){ + /*<>*/ if(_x_){ var i$0 = i + 1 | 0; i = i$0; continue; } - var res = _w_; + var res = _x_; } /*<>*/ check_same_length(cst_for_all, a, length); /*<>*/ return res; @@ -32527,10 +32577,10 @@ /*<>*/ iter (cst_filter, function(x){ - var _w_ = /*<>*/ caml_call1(f, x); - /*<>*/ return _w_ + var _x_ = /*<>*/ caml_call1(f, x); + /*<>*/ return _x_ ? /*<>*/ add_last(b, x) - : _w_ /*<>*/ ; + : _x_ /*<>*/ ; }, a); /*<>*/ return b; @@ -32697,18 +32747,18 @@ var r = /*<>*/ 1; else{ var - _w_ = /*<>*/ unsafe_get(arr2, dum2, i, length), - _v_ = + _x_ = /*<>*/ unsafe_get(arr2, dum2, i, length), + _w_ = /*<>*/ /*<>*/ caml_call2 (eq, /*<>*/ unsafe_get(arr1, dum1, i, length), - _w_); - /*<>*/ if(_v_){ + _x_); + /*<>*/ if(_w_){ var i$0 = i + 1 | 0; i = i$0; continue; } - var r = _v_; + var r = _w_; } /*<>*/ check_same_length(cst_equal, a1, length); /*<>*/ check_same_length(cst_equal$0, a2, length); @@ -32733,12 +32783,12 @@ var r = /*<>*/ 0; else{ var - _v_ = /*<>*/ unsafe_get(arr2, dum2, i, length), + _w_ = /*<>*/ unsafe_get(arr2, dum2, i, length), c = /*<>*/ /*<>*/ caml_call2 (cmp, /*<>*/ unsafe_get(arr1, dum1, i, length), - _v_); + _w_); /*<>*/ if(0 === c){ var i$0 = /*<>*/ i + 1 | 0; i = i$0; @@ -32775,9 +32825,9 @@ var a = /*<>*/ Stdlib_Array[11].call(null, li), length = /*<>*/ a.length - 1, - _v_ = /*<>*/ Stdlib_Obj[17], + _w_ = /*<>*/ Stdlib_Obj[17], arr = - caml_obj_tag(a) !== _v_ + caml_obj_tag(a) !== _w_ ? a : /*<>*/ copy(a, dummy); /*<>*/ return [0, length, arr, dummy]; @@ -32786,20 +32836,24 @@ var length = /*<>*/ a[1], arr = a[2], dummy = a[3]; /*<>*/ check_valid_length(length, arr); var - l = /*<>*/ [0, 0], - _t_ = /*<>*/ length - 1 | 0; - if(_t_ >= 0){ - var i = _t_; + _t_ = /*<>*/ 0, + _u_ = /*<>*/ length - 1 | 0; + if(_u_ < 0) + var l$0 = _t_; + else{ + var l = _t_, i = _u_; for(;;){ - var _u_ = /*<>*/ l[1]; - l[1] = [0, unsafe_get(arr, dummy, i, length), _u_]; - var _v_ = /*<>*/ i - 1 | 0; - if(0 === i) break; - i = _v_; + var + _v_ = + /*<>*/ [0, unsafe_get(arr, dummy, i, length), l], + _w_ = /*<>*/ i - 1 | 0; + if(0 === i){var l$0 = _v_; break;} + l = _v_; + i = _w_; } } /*<>*/ check_same_length(cst_to_list, a, length); - /*<>*/ return l[1]; + /*<>*/ return l$0; /*<>*/ } function of_seq(seq){ var init = /*<>*/ create(0); @@ -32962,7 +33016,7 @@ Stdlib_Random = global_data.Stdlib__Random; function MakeSeeded(H){ var - prng = [246, function(_H_){return caml_call1(Stdlib_Random[19][2], 0);}]; + prng = [246, function(_I_){return caml_call1(Stdlib_Random[19][2], 0);}]; function create(opt, initial_size){ var random = @@ -32977,18 +33031,18 @@ x = x$0; } /*<>*/ if(random){ - var _G_ = /*<>*/ runtime.caml_obj_tag(prng); + var _H_ = /*<>*/ runtime.caml_obj_tag(prng); a: - if(250 === _G_) - var _H_ = prng[1]; + if(250 === _H_) + var _I_ = prng[1]; else{ - if(246 !== _G_ && 244 !== _G_){var _H_ = prng; break a;} - var _H_ = CamlinternalLazy[2].call(null, prng); + if(246 !== _H_ && 244 !== _H_){var _I_ = prng; break a;} + var _I_ = CamlinternalLazy[2].call(null, prng); } var seed = /*<>*/ /*<>*/ caml_call1 - (Stdlib_Random[19][4], _H_); + (Stdlib_Random[19][4], _I_); } else var seed = /*<>*/ 0; @@ -33002,15 +33056,15 @@ /*<>*/ h[1] = 0; var len = /*<>*/ h[2].length - 1, - _E_ = /*<>*/ len - 1 | 0, - _F_ = 0; - if(_E_ >= 0){ - var i = _F_; + _F_ = /*<>*/ len - 1 | 0, + _G_ = 0; + if(_F_ >= 0){ + var i = _G_; for(;;){ /*<>*/ caml_check_bound(h[2], i)[i + 1] = 0; - var _G_ = /*<>*/ i + 1 | 0; - if(_E_ === i) break; - i = _G_; + var _H_ = /*<>*/ i + 1 | 0; + if(_F_ === i) break; + i = _H_; } } /*<>*/ return 0; @@ -33027,10 +33081,10 @@ } function copy(h){ var - _C_ = /*<>*/ h[4], - _D_ = h[3], - _E_ = Stdlib_Array[7].call(null, h[2]); - /*<>*/ return [0, h[1], _E_, _D_, _C_]; + _D_ = /*<>*/ h[4], + _E_ = h[3], + _F_ = Stdlib_Array[7].call(null, h[2]); + /*<>*/ return [0, h[1], _F_, _E_, _D_]; /*<>*/ } function key_index(h, hkey){ /*<>*/ return hkey & (h[2].length - 2 | 0); @@ -33054,17 +33108,17 @@ /*<>*/ } var d = /*<>*/ h[2], - _A_ = /*<>*/ d.length - 2 | 0, - _B_ = 0; - if(_A_ >= 0){ - var i = _B_; + _B_ = /*<>*/ d.length - 2 | 0, + _C_ = 0; + if(_B_ >= 0){ + var i = _C_; for(;;){ /*<>*/ d[i + 1] = /*<>*/ do_bucket ( /*<>*/ caml_check_bound(d, i)[i + 1]); - var _C_ = /*<>*/ i + 1 | 0; - if(_A_ === i) break; - i = _C_; + var _D_ = /*<>*/ i + 1 | 0; + if(_B_ === i) break; + i = _D_; } } /*<>*/ return 0; @@ -33076,9 +33130,9 @@ nsize = /*<>*/ osize * 2 | 0; /*<>*/ clean(h); var - _v_ = /*<>*/ nsize < Stdlib_Sys[13] ? 1 : 0, - _w_ = _v_ ? (osize >>> 1 | 0) <= h[1] ? 1 : 0 : _v_; - if(_w_){ + _w_ = /*<>*/ nsize < Stdlib_Sys[13] ? 1 : 0, + _x_ = _w_ ? (osize >>> 1 | 0) <= h[1] ? 1 : 0 : _w_; + if(_x_){ var ndata = /*<>*/ caml_array_make(nsize, 0); /*<>*/ h[2] = ndata; var @@ -33095,23 +33149,23 @@ /*<>*/ ndata[nidx + 1] = [0, hkey, data, caml_check_bound(ndata, nidx)[nidx + 1]]; /*<>*/ }, - _x_ = /*<>*/ osize - 1 | 0, - _z_ = 0; - if(_x_ >= 0){ - var i = _z_; + _y_ = /*<>*/ osize - 1 | 0, + _A_ = 0; + if(_y_ >= 0){ + var i = _A_; for(;;){ /*<>*/ /*<>*/ insert_bucket ( /*<>*/ caml_check_bound(odata, i)[i + 1]); - var _A_ = /*<>*/ i + 1 | 0; - if(_x_ === i) break; - i = _A_; + var _B_ = /*<>*/ i + 1 | 0; + if(_y_ === i) break; + i = _B_; } } - var _y_ = /*<>*/ 0; + var _z_ = /*<>*/ 0; } else - var _y_ = /*<>*/ _w_; - return _y_; + var _z_ = /*<>*/ _x_; + return _z_; /*<>*/ } function add(h, key, info){ var @@ -33126,8 +33180,8 @@ /*<>*/ caml_check_bound(h[2], i)[i + 1] = bucket; /*<>*/ h[1] = h[1] + 1 | 0; var - _v_ = /*<>*/ h[2].length - 1 << 1 < h[1] ? 1 : 0; - return _v_ ? /*<>*/ resize(h) : _v_ /*<>*/ ; + _w_ = /*<>*/ h[2].length - 1 << 1 < h[1] ? 1 : 0; + return _w_ ? /*<>*/ resize(h) : _w_ /*<>*/ ; } function remove(h, key){ var hkey = /*<>*/ caml_call2(H[2], h[3], key); @@ -33160,20 +33214,20 @@ /*<>*/ } var i = /*<>*/ key_index(h, hkey), - _v_ = + _w_ = /*<>*/ /*<>*/ remove_bucket ( /*<>*/ caml_check_bound(h[2], i)[i + 1]); - /*<>*/ caml_check_bound(h[2], i)[i + 1] = _v_; + /*<>*/ caml_check_bound(h[2], i)[i + 1] = _w_; /*<>*/ return 0; } function find(h, key){ var hkey = /*<>*/ caml_call2(H[2], h[3], key), - _v_ = /*<>*/ key_index(h, hkey), + _w_ = /*<>*/ key_index(h, hkey), param = /*<>*/ /*<>*/ caml_check_bound - (h[2], _v_) - [_v_ + 1]; + (h[2], _w_) + [_w_ + 1]; /*<>*/ for(;;){ /*<>*/ if(! param) /*<>*/ throw caml_maybe_attach_backtrace @@ -33202,11 +33256,11 @@ function find_opt(h, key){ var hkey = /*<>*/ caml_call2(H[2], h[3], key), - _v_ = /*<>*/ key_index(h, hkey), + _w_ = /*<>*/ key_index(h, hkey), param = /*<>*/ /*<>*/ caml_check_bound - (h[2], _v_) - [_v_ + 1]; + (h[2], _w_) + [_w_ + 1]; /*<>*/ for(;;){ /*<>*/ if(! param) /*<>*/ return 0; @@ -33256,10 +33310,10 @@ } } /*<>*/ } - var _v_ = /*<>*/ key_index(h, hkey); + var _w_ = /*<>*/ key_index(h, hkey); /*<>*/ return /*<>*/ find_in_bucket - ( /*<>*/ caml_check_bound(h[2], _v_) - [_v_ + 1]) /*<>*/ ; + ( /*<>*/ caml_check_bound(h[2], _w_) + [_w_ + 1]) /*<>*/ ; } function replace(h, key, info){ var @@ -33279,8 +33333,8 @@ /*<>*/ if(hkey === hk){ /*<>*/ if(! caml_call2(H[3], c, key)){ var - _v_ = /*<>*/ caml_call3(H[5], c, key, info); - return _v_; + _w_ = /*<>*/ caml_call3(H[5], c, key, info); + return _w_; } /*<>*/ param = next; } @@ -33298,18 +33352,18 @@ /*<>*/ caml_check_bound(h[2], i)[i + 1] = [0, hkey, container, l]; /*<>*/ h[1] = h[1] + 1 | 0; var - _u_ = /*<>*/ h[2].length - 1 << 1 < h[1] ? 1 : 0; - return _u_ ? /*<>*/ resize(h) : _u_ /*<>*/ ; + _v_ = /*<>*/ h[2].length - 1 << 1 < h[1] ? 1 : 0; + return _v_ ? /*<>*/ resize(h) : _v_ /*<>*/ ; } } function mem(h, key){ var hkey = /*<>*/ caml_call2(H[2], h[3], key), - _u_ = /*<>*/ key_index(h, hkey), + _v_ = /*<>*/ key_index(h, hkey), param = /*<>*/ /*<>*/ caml_check_bound - (h[2], _u_) - [_u_ + 1]; + (h[2], _v_) + [_v_ + 1]; /*<>*/ for(;;){ /*<>*/ if(! param) /*<>*/ return 0; @@ -33348,9 +33402,9 @@ /*<>*/ Stdlib_Array[18].call (null, function(m, b){ - var _u_ = /*<>*/ bucket_length(0, b); + var _v_ = /*<>*/ bucket_length(0, b); /*<>*/ return Stdlib_Int[11].call - (null, m, _u_); + (null, m, _v_); }, 0, h[2]), @@ -33393,9 +33447,9 @@ /*<>*/ Stdlib_Array[18].call (null, function(m, b){ - var _u_ = /*<>*/ bucket_length_alive(0, b); + var _v_ = /*<>*/ bucket_length_alive(0, b); /*<>*/ return Stdlib_Int[11].call - (null, m, _u_); + (null, m, _v_); }, 0, h[2]), @@ -33530,7 +33584,7 @@ } var include = /*<>*/ MakeSeeded$0([0, equal, seeded_hash]), - _u_ = include[1], + _v_ = include[1], clear = include[2], reset = include[3], copy = include[4], @@ -33548,10 +33602,10 @@ clean = include[17], stats_alive = include[18]; function create(sz){ - /*<>*/ return caml_call2(_u_, _a_, sz) /*<>*/ ; + /*<>*/ return caml_call2(_v_, _a_, sz) /*<>*/ ; } function of_seq(i){ - var tbl = /*<>*/ caml_call2(_u_, _a_, 16); + var tbl = /*<>*/ caml_call2(_v_, _a_, 16); /*<>*/ caml_call2(replace_seq, tbl, i); /*<>*/ return tbl; /*<>*/ } @@ -33579,8 +33633,8 @@ /*<>*/ return [0, 0]; /*<>*/ } function add(b, k, d){ - var _u_ = /*<>*/ b[1]; - b[1] = [0, make(k, d), _u_]; + var _v_ = /*<>*/ b[1]; + b[1] = [0, make(k, d), _v_]; /*<>*/ return 0; /*<>*/ } function test_key(k, e){ @@ -33614,7 +33668,7 @@ match = /*<>*/ Stdlib_List[40].call (null, - function(_u_){ /*<>*/ return test_key(k, _u_);}, + function(_v_){ /*<>*/ return test_key(k, _v_);}, b[1]); /*<>*/ if(! match) /*<>*/ return 0; @@ -33689,9 +33743,9 @@ var k2 = /*<>*/ param[2], k1 = param[1], - _u_ = + _v_ = /*<>*/ caml_call2(H2[2], seed, k2) * 65599 | 0; - /*<>*/ return caml_call2(H1[2], seed, k1) + _u_ | 0 /*<>*/ ; + /*<>*/ return caml_call2(H1[2], seed, k1) + _v_ | 0 /*<>*/ ; /*<>*/ } function equal(c, param){ var @@ -33718,11 +33772,11 @@ } function check_key(c){ var - _u_ = /*<>*/ caml_call2(Stdlib_Obj[23][7], c, 0); - /*<>*/ return _u_ + _v_ = /*<>*/ caml_call2(Stdlib_Obj[23][7], c, 0); + /*<>*/ return _v_ ? /*<>*/ caml_call2 (Stdlib_Obj[23][7], c, 1) - : _u_ /*<>*/ ; + : _v_ /*<>*/ ; } /*<>*/ return MakeSeeded ([0, @@ -33746,7 +33800,7 @@ include = /*<>*/ MakeSeeded$1 ([0, equal$0, seeded_hash$0], [0, equal, seeded_hash]), - _u_ = include[1], + _v_ = include[1], clear = include[2], reset = include[3], copy = include[4], @@ -33764,10 +33818,10 @@ clean = include[17], stats_alive = include[18]; function create(sz){ - /*<>*/ return caml_call2(_u_, _b_, sz) /*<>*/ ; + /*<>*/ return caml_call2(_v_, _b_, sz) /*<>*/ ; } function of_seq(i){ - var tbl = /*<>*/ caml_call2(_u_, _b_, 16); + var tbl = /*<>*/ caml_call2(_v_, _b_, 16); /*<>*/ caml_call2(replace_seq, tbl, i); /*<>*/ return tbl; /*<>*/ } @@ -33795,8 +33849,8 @@ /*<>*/ return [0, 0]; /*<>*/ } function add$0(b, k1, k2, d){ - var _u_ = /*<>*/ b[1]; - b[1] = [0, make$1(k1, k2, d), _u_]; + var _v_ = /*<>*/ b[1]; + b[1] = [0, make$1(k1, k2, d), _v_]; /*<>*/ return 0; /*<>*/ } function test_keys(k1, k2, e){ @@ -33832,8 +33886,8 @@ match = /*<>*/ Stdlib_List[40].call (null, - function(_u_){ - /*<>*/ return test_keys(k1, k2, _u_); + function(_v_){ + /*<>*/ return test_keys(k1, k2, _v_); }, b[1]); /*<>*/ if(! match) @@ -33873,15 +33927,15 @@ l = /*<>*/ keys.length - 1, eph = /*<>*/ create$1(l); /*<>*/ set_data$1(eph, data); - var _s_ = /*<>*/ l - 1 | 0, _t_ = 0; - if(_s_ >= 0){ - var i = _t_; + var _t_ = /*<>*/ l - 1 | 0, _u_ = 0; + if(_t_ >= 0){ + var i = _u_; for(;;){ /*<>*/ /*<>*/ set_key$0 (eph, i, /*<>*/ caml_check_bound(keys, i)[i + 1]); - var _u_ = /*<>*/ i + 1 | 0; - if(_s_ === i) break; - i = _u_; + var _v_ = /*<>*/ i + 1 | 0; + if(_t_ === i) break; + i = _v_; } } /*<>*/ return eph; @@ -33892,9 +33946,9 @@ if(l !== keys.length - 1) /*<>*/ throw caml_maybe_attach_backtrace (Stdlib[3], 1); - var _p_ = /*<>*/ l - 1 | 0, _q_ = 0; - if(_p_ >= 0){ - var i = _q_; + var _q_ = /*<>*/ l - 1 | 0, _r_ = 0; + if(_q_ >= 0){ + var i = _r_; for(;;){ var match = /*<>*/ get_key$0(eph, i); /*<>*/ if(! match) @@ -33904,13 +33958,13 @@ /*<>*/ if(k !== caml_check_bound(keys, i)[i + 1]) /*<>*/ throw caml_maybe_attach_backtrace (Stdlib[3], 1); - var _s_ = /*<>*/ i + 1 | 0; - if(_p_ === i) break; - i = _s_; + var _t_ = /*<>*/ i + 1 | 0; + if(_q_ === i) break; + i = _t_; } } - var _r_ = /*<>*/ get_data$1(eph); - return _r_; + var _s_ = /*<>*/ get_data$1(eph); + return _s_; } catch(exn$0){ var exn = /*<>*/ caml_wrap_exception(exn$0); @@ -33922,38 +33976,43 @@ function create(k, d){ var c = /*<>*/ create$1(k.length - 1); /*<>*/ set_data$1(c, d); - var _n_ = /*<>*/ k.length - 2 | 0, _o_ = 0; - if(_n_ >= 0){ - var i = _o_; + var _o_ = /*<>*/ k.length - 2 | 0, _p_ = 0; + if(_o_ >= 0){ + var i = _p_; for(;;){ /*<>*/ /*<>*/ set_key$0 (c, i, /*<>*/ caml_check_bound(k, i)[i + 1]); - var _p_ = /*<>*/ i + 1 | 0; - if(_n_ === i) break; - i = _p_; + var _q_ = /*<>*/ i + 1 | 0; + if(_o_ === i) break; + i = _q_; } } /*<>*/ return c; /*<>*/ } function seeded_hash(seed, k){ var - h = /*<>*/ [0, 0], - _j_ = /*<>*/ k.length - 2 | 0, - _k_ = 0; - if(_j_ >= 0){ - var i = _k_; + _j_ = /*<>*/ 0, + _k_ = /*<>*/ k.length - 2 | 0, + _m_ = 0; + if(_k_ < 0) + var h$0 = _j_; + else{ + var h = _j_, i = _m_; for(;;){ var - _l_ = /*<>*/ h[1], - _m_ = caml_check_bound(k, i)[i + 1]; - /*<>*/ h[1] = - (caml_call2(H[2], seed, _m_) * 65599 | 0) + _l_ | 0; - var _n_ = /*<>*/ i + 1 | 0; - if(_j_ === i) break; - i = _n_; + _n_ = /*<>*/ caml_check_bound(k, i)[i + 1], + _l_ = + /*<>*/ (caml_call2(H[2], seed, _n_) * 65599 + | 0) + + h + | 0, + _o_ = /*<>*/ i + 1 | 0; + if(_k_ === i){var h$0 = _l_; break;} + h = _l_; + i = _o_; } } - /*<>*/ return h[1]; + /*<>*/ return h$0; /*<>*/ } function equal(c, k){ var diff --git a/runtime/js/compare.js b/runtime/js/compare.js index 0aa1289d93..7ccde88b71 100644 --- a/runtime/js/compare.js +++ b/runtime/js/compare.js @@ -251,7 +251,7 @@ function caml_compare_val(a, b, total) { b = b[i]; } } -//Provides: caml_compare (const, const) +//Provides: caml_compare mutable (const, const) //Requires: caml_compare_val function caml_compare(a, b) { return caml_compare_val(a, b, true); diff --git a/runtime/js/prng.js b/runtime/js/prng.js index f2a3b82f9c..0478bada3a 100644 --- a/runtime/js/prng.js +++ b/runtime/js/prng.js @@ -14,7 +14,7 @@ var caml_lxm_daba = caml_int64_of_string( caml_string_of_jsstring("0xdaba0b6eb09322e3"), ); -//Provides: caml_lxm_next const +//Provides: caml_lxm_next mutable //Requires: caml_int64_shift_left //Requires: caml_int64_shift_right_unsigned //Requires: caml_int64_or diff --git a/runtime/wasm/bigarray.wat b/runtime/wasm/bigarray.wat index 59cc22cd7f..df160a989c 100644 --- a/runtime/wasm/bigarray.wat +++ b/runtime/wasm/bigarray.wat @@ -172,7 +172,8 @@ (field $ba_kind i8) ;; kind (field $ba_layout i8)))) ;; layout - (func $double_to_float16 (param $f f64) (result i32) + (func $double_to_float16 (export "caml_double_to_float16") + (param $f f64) (result i32) (local $x i32) (local $sign i32) (local $o i32) (local.set $x (i32.reinterpret_f32 (f32.demote_f64 (local.get $f)))) (local.set $sign (i32.and (local.get $x) (i32.const 0x80000000))) @@ -202,7 +203,8 @@ (i32.const 13))))))) (i32.or (local.get $o) (i32.shr_u (local.get $sign) (i32.const 16)))) - (func $float16_to_double (param $d i32) (result f64) + (func $float16_to_double (export "caml_float16_to_double") + (param $d i32) (result f64) (local $f f32) (local.set $f (f32.mul @@ -1923,120 +1925,107 @@ (return (i32.const 0))) (func (export "caml_ba_uint8_get16") - (param $vba (ref eq)) (param $i (ref eq)) (result (ref eq)) + (param $vba (ref eq)) (param $i i32) (result i32) (local $ba (ref $bigarray)) (local $view (ref extern)) - (local $p i32) (local.set $ba (ref.cast (ref $bigarray) (local.get $vba))) (local.set $view (struct.get $bigarray $ba_view (local.get $ba))) - (local.set $p (i31.get_s (ref.cast (ref i31) (local.get $i)))) - (if (i32.lt_s (local.get $p) (i32.const 0)) + (if (i32.lt_s (local.get $i) (i32.const 0)) (then (call $caml_bound_error))) - (if (i32.ge_u (i32.add (local.get $p) (i32.const 1)) + (if (i32.ge_u (i32.add (local.get $i) (i32.const 1)) (array.get $int_array (struct.get $bigarray $ba_dim (local.get $ba)) (i32.const 0))) (then (call $caml_bound_error))) - (ref.i31 - (call $dv_get_ui16 (local.get $view) (local.get $p) (i32.const 1)))) + (call $dv_get_ui16 (local.get $view) (local.get $i) (i32.const 1))) (func (export "caml_ba_uint8_get32") - (param $vba (ref eq)) (param $i (ref eq)) (result i32) + (param $vba (ref eq)) (param $i i32) (result i32) (local $ba (ref $bigarray)) (local $view (ref extern)) - (local $p i32) (local.set $ba (ref.cast (ref $bigarray) (local.get $vba))) (local.set $view (struct.get $bigarray $ba_view (local.get $ba))) - (local.set $p (i31.get_s (ref.cast (ref i31) (local.get $i)))) - (if (i32.lt_s (local.get $p) (i32.const 0)) + (if (i32.lt_s (local.get $i) (i32.const 0)) (then (call $caml_bound_error))) - (if (i32.ge_u (i32.add (local.get $p) (i32.const 3)) + (if (i32.ge_u (i32.add (local.get $i) (i32.const 3)) (array.get $int_array (struct.get $bigarray $ba_dim (local.get $ba)) (i32.const 0))) (then (call $caml_bound_error))) - (return_call $dv_get_i32 (local.get $view) (local.get $p) (i32.const 1))) + (return_call $dv_get_i32 (local.get $view) (local.get $i) (i32.const 1))) (func (export "caml_ba_uint8_get64") - (param $vba (ref eq)) (param $i (ref eq)) (result i64) + (param $vba (ref eq)) (param $i i32) (result i64) (local $ba (ref $bigarray)) (local $view (ref extern)) - (local $p i32) (local.set $ba (ref.cast (ref $bigarray) (local.get $vba))) (local.set $view (struct.get $bigarray $ba_view (local.get $ba))) - (local.set $p (i31.get_s (ref.cast (ref i31) (local.get $i)))) - (if (i32.lt_s (local.get $p) (i32.const 0)) + (if (i32.lt_s (local.get $i) (i32.const 0)) (then (call $caml_bound_error))) - (if (i32.ge_u (i32.add (local.get $p) (i32.const 7)) + (if (i32.ge_u (i32.add (local.get $i) (i32.const 7)) (array.get $int_array (struct.get $bigarray $ba_dim (local.get $ba)) (i32.const 0))) (then (call $caml_bound_error))) (call $dv_get_i64 - (local.get $view) (local.get $p) (i32.const 1))) + (local.get $view) (local.get $i) (i32.const 1))) (func (export "caml_ba_uint8_set16") - (param $vba (ref eq)) (param $i (ref eq)) (param $v (ref eq)) + (param $vba (ref eq)) (param $i i32) (param $d i32) (result (ref eq)) (local $ba (ref $bigarray)) (local $view (ref extern)) - (local $p i32) (local $d i32) (local.set $ba (ref.cast (ref $bigarray) (local.get $vba))) (local.set $view (struct.get $bigarray $ba_view (local.get $ba))) - (local.set $p (i31.get_s (ref.cast (ref i31) (local.get $i)))) - (local.set $d (i31.get_s (ref.cast (ref i31) (local.get $v)))) - (if (i32.lt_s (local.get $p) (i32.const 0)) + (if (i32.lt_s (local.get $i) (i32.const 0)) (then (call $caml_bound_error))) - (if (i32.ge_u (i32.add (local.get $p) (i32.const 1)) + (if (i32.ge_u (i32.add (local.get $i) (i32.const 1)) (array.get $int_array (struct.get $bigarray $ba_dim (local.get $ba)) (i32.const 0))) (then (call $caml_bound_error))) (call $dv_set_i16 - (local.get $view) (local.get $p) (local.get $d) (i32.const 1)) + (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 (ref eq)) (param $d i32) + (param $vba (ref eq)) (param $i i32) (param $d i32) (result (ref eq)) (local $ba (ref $bigarray)) (local $view (ref extern)) - (local $p i32) (local.set $ba (ref.cast (ref $bigarray) (local.get $vba))) (local.set $view (struct.get $bigarray $ba_view (local.get $ba))) - (local.set $p (i31.get_s (ref.cast (ref i31) (local.get $i)))) - (if (i32.lt_s (local.get $p) (i32.const 0)) + (if (i32.lt_s (local.get $i) (i32.const 0)) (then (call $caml_bound_error))) - (if (i32.ge_u (i32.add (local.get $p) (i32.const 3)) + (if (i32.ge_u (i32.add (local.get $i) (i32.const 3)) (array.get $int_array (struct.get $bigarray $ba_dim (local.get $ba)) (i32.const 0))) (then (call $caml_bound_error))) (call $dv_set_i32 - (local.get $view) (local.get $p) (local.get $d) (i32.const 1)) + (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 (ref eq)) (param $d i64) + (param $vba (ref eq)) (param $i i32) (param $d i64) (result (ref eq)) (local $ba (ref $bigarray)) (local $view (ref extern)) - (local $p i32) (local.set $ba (ref.cast (ref $bigarray) (local.get $vba))) (local.set $view (struct.get $bigarray $ba_view (local.get $ba))) - (local.set $p (i31.get_s (ref.cast (ref i31) (local.get $i)))) - (if (i32.lt_s (local.get $p) (i32.const 0)) + (if (i32.lt_s (local.get $i) (i32.const 0)) (then (call $caml_bound_error))) - (if (i32.ge_u (i32.add (local.get $p) (i32.const 7)) + (if (i32.ge_u (i32.add (local.get $i) (i32.const 7)) (array.get $int_array (struct.get $bigarray $ba_dim (local.get $ba)) (i32.const 0))) (then (call $caml_bound_error))) (call $dv_set_i64 - (local.get $view) (local.get $p) (local.get $d) (i32.const 1)) + (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)) + (export "caml_string_of_array" (func $caml_string_of_uint8_array)) ;; Used by brr (func $caml_string_of_uint8_array (export "caml_string_of_uint8_array") (param (ref eq)) (result (ref eq)) ;; used to convert a typed array to a string diff --git a/runtime/wasm/compare.wat b/runtime/wasm/compare.wat index b6a48a62b7..a8b92f7e5c 100644 --- a/runtime/wasm/compare.wat +++ b/runtime/wasm/compare.wat @@ -556,53 +556,49 @@ (i32.const 0)) (func (export "caml_compare") - (param $v1 (ref eq)) (param $v2 (ref eq)) (result (ref eq)) + (param $v1 (ref eq)) (param $v2 (ref eq)) (result i32) (local $res i32) (local.set $res (call $compare_val (local.get $v1) (local.get $v2) (i32.const 1))) (if (i32.lt_s (local.get $res) (i32.const 0)) - (then (return (ref.i31 (i32.const -1))))) + (then (return (i32.const -1)))) (if (i32.gt_s (local.get $res) (i32.const 0)) - (then (return (ref.i31 (i32.const 1))))) - (ref.i31 (i32.const 0))) + (then (return (i32.const 1)))) + (i32.const 0)) (func (export "caml_equal") - (param $v1 (ref eq)) (param $v2 (ref eq)) (result (ref eq)) - (ref.i31 - (i32.eqz - (call $compare_val (local.get $v1) (local.get $v2) (i32.const 0))))) + (param $v1 (ref eq)) (param $v2 (ref eq)) (result i32) + (i32.eqz + (call $compare_val (local.get $v1) (local.get $v2) (i32.const 0)))) (func (export "caml_notequal") - (param $v1 (ref eq)) (param $v2 (ref eq)) (result (ref eq)) - (ref.i31 - (i32.ne (i32.const 0) - (call $compare_val (local.get $v1) (local.get $v2) (i32.const 0))))) + (param $v1 (ref eq)) (param $v2 (ref eq)) (result i32) + (i32.ne (i32.const 0) + (call $compare_val (local.get $v1) (local.get $v2) (i32.const 0)))) (func (export "caml_lessthan") - (param $v1 (ref eq)) (param $v2 (ref eq)) (result (ref eq)) + (param $v1 (ref eq)) (param $v2 (ref eq)) (result i32) (local $res i32) (local.set $res (call $compare_val (local.get $v1) (local.get $v2) (i32.const 0))) - (ref.i31 - (i32.and (i32.lt_s (local.get $res) (i32.const 0)) - (i32.ne (local.get $res) (global.get $unordered))))) + (i32.and (i32.lt_s (local.get $res) (i32.const 0)) + (i32.ne (local.get $res) (global.get $unordered)))) (func (export "caml_lessequal") - (param $v1 (ref eq)) (param $v2 (ref eq)) (result (ref eq)) + (param $v1 (ref eq)) (param $v2 (ref eq)) (result i32) (local $res i32) (local.set $res (call $compare_val (local.get $v1) (local.get $v2) (i32.const 0))) - (ref.i31 - (i32.and (i32.le_s (local.get $res) (i32.const 0)) - (i32.ne (local.get $res) (global.get $unordered))))) + (i32.and (i32.le_s (local.get $res) (i32.const 0)) + (i32.ne (local.get $res) (global.get $unordered)))) (func (export "caml_greaterthan") - (param $v1 (ref eq)) (param $v2 (ref eq)) (result (ref eq)) - (ref.i31 (i32.lt_s (i32.const 0) - (call $compare_val (local.get $v1) (local.get $v2) (i32.const 0))))) + (param $v1 (ref eq)) (param $v2 (ref eq)) (result i32) + (i32.lt_s (i32.const 0) + (call $compare_val (local.get $v1) (local.get $v2) (i32.const 0)))) (func (export "caml_greaterequal") - (param $v1 (ref eq)) (param $v2 (ref eq)) (result (ref eq)) - (ref.i31 (i32.le_s (i32.const 0) - (call $compare_val (local.get $v1) (local.get $v2) (i32.const 0))))) + (param $v1 (ref eq)) (param $v2 (ref eq)) (result i32) + (i32.le_s (i32.const 0) + (call $compare_val (local.get $v1) (local.get $v2) (i32.const 0)))) ) diff --git a/runtime/wasm/effect.wat b/runtime/wasm/effect.wat index 05bc0ad9c2..40aa1dc7c1 100644 --- a/runtime/wasm/effect.wat +++ b/runtime/wasm/effect.wat @@ -45,7 +45,7 @@ (type $block (array (mut (ref eq)))) (type $bytes (array (mut i8))) (type $function_1 (func (param (ref eq) (ref eq)) (result (ref eq)))) - (type $closure (sub (struct (;(field i32);) (field (ref $function_1))))) + (type $closure (sub (struct (field (ref $function_1))))) (type $function_3 (func (param (ref eq) (ref eq) (ref eq) (ref eq)) (result (ref eq)))) (type $closure_3 diff --git a/runtime/wasm/float.wat b/runtime/wasm/float.wat index b0bf76e609..295a358cfe 100644 --- a/runtime/wasm/float.wat +++ b/runtime/wasm/float.wat @@ -717,7 +717,8 @@ (array.new_fixed $block 3 (ref.i31 (i32.const 0)) (struct.new $float (local.get $f)) (struct.new $float (local.get $i)))) - (func $ldexp (param $x f64) (param $n i32) (result f64) + (func $ldexp (export "caml_ldexp_float") + (param $x f64) (param $n i32) (result f64) (if (i32.gt_s (local.get $n) (i32.const 1023)) (then (local.set $x (f64.mul (local.get $x) (f64.const 0x1p1023))) @@ -747,12 +748,6 @@ (i64.const 0x3ff)) (i64.const 52))))) - (func (export "caml_ldexp_float") - (param $x f64) (param $i (ref eq)) (result f64) - (call $ldexp - (local.get $x) - (i31.get_s (ref.cast (ref i31) (local.get $i))))) - (func $frexp (param $x f64) (result f64 i32) (local $y i64) (local $e i32) @@ -1132,13 +1127,12 @@ (struct.new $float (local.get $y))) (func (export "caml_float_compare") - (param $x f64) (param $y f64) (result (ref eq)) - (ref.i31 - (i32.add - (i32.sub (f64.gt (local.get $x) (local.get $y)) - (f64.lt (local.get $x) (local.get $y))) - (i32.sub (f64.eq (local.get $x) (local.get $x)) - (f64.eq (local.get $y) (local.get $y)))))) + (param $x f64) (param $y f64) (result i32) + (i32.add + (i32.sub (f64.gt (local.get $x) (local.get $y)) + (f64.lt (local.get $x) (local.get $y))) + (i32.sub (f64.eq (local.get $x) (local.get $x)) + (f64.eq (local.get $y) (local.get $y))))) (func (export "caml_round") (param $x f64) (result f64) (local $y f64) diff --git a/runtime/wasm/int32.wat b/runtime/wasm/int32.wat index bb3126fb53..8f1caac309 100644 --- a/runtime/wasm/int32.wat +++ b/runtime/wasm/int32.wat @@ -126,9 +126,9 @@ (export "caml_nativeint_compare" (func $caml_int32_compare)) (func $caml_int32_compare (export "caml_int32_compare") - (param $i1 i32) (param $i2 i32) (result (ref eq)) - (ref.i31 (i32.sub (i32.gt_s (local.get $i1) (local.get $i2)) - (i32.lt_s (local.get $i1) (local.get $i2))))) + (param $i1 i32) (param $i2 i32) (result i32) + (i32.sub (i32.gt_s (local.get $i1) (local.get $i2)) + (i32.lt_s (local.get $i1) (local.get $i2)))) (global $nativeint_ops (export "nativeint_ops") (ref $custom_operations) (struct.new $custom_operations diff --git a/runtime/wasm/int64.wat b/runtime/wasm/int64.wat index 6b2a4fb964..3d4c39260e 100644 --- a/runtime/wasm/int64.wat +++ b/runtime/wasm/int64.wat @@ -124,9 +124,9 @@ (i64.const 8))))) (func (export "caml_int64_compare") - (param $i1 i64) (param $i2 i64) (result (ref eq)) - (ref.i31 (i32.sub (i64.gt_s (local.get $i1) (local.get $i2)) - (i64.lt_s (local.get $i1) (local.get $i2))))) + (param $i1 i64) (param $i2 i64) (result i32) + (i32.sub (i64.gt_s (local.get $i1) (local.get $i2)) + (i64.lt_s (local.get $i1) (local.get $i2)))) (@string $INT64_ERRMSG "Int64.of_string") diff --git a/runtime/wasm/obj.wat b/runtime/wasm/obj.wat index 5e6a96ea5f..4fc39ee904 100644 --- a/runtime/wasm/obj.wat +++ b/runtime/wasm/obj.wat @@ -34,11 +34,9 @@ (type $float (struct (field f64))) (type $float_array (array (mut f64))) (type $function_1 (func (param (ref eq) (ref eq)) (result (ref eq)))) - (type $closure (sub (struct (;(field i32);) (field (ref $function_1))))) - (type $closure_last_arg - (sub $closure (struct (;(field i32);) (field (ref $function_1))))) - (type $function_2 - (func (param (ref eq) (ref eq) (ref eq)) (result (ref eq)))) + (type $closure (sub (struct (field (ref $function_1))))) + (type $closure_last_arg (sub $closure (struct (field (ref $function_1))))) + (type $function_2 (func (param (ref eq) (ref eq) (ref eq)) (result (ref eq)))) (type $cps_closure (sub (struct (field (ref $function_2))))) (type $cps_closure_last_arg (sub $cps_closure (struct (field (ref $function_2))))) diff --git a/runtime/wasm/string.wat b/runtime/wasm/string.wat index 66183061b4..b594de1206 100644 --- a/runtime/wasm/string.wat +++ b/runtime/wasm/string.wat @@ -154,27 +154,25 @@ (export "caml_string_get16" (func $caml_bytes_get16)) (func $caml_bytes_get16 (export "caml_bytes_get16") - (param $v (ref eq)) (param $i (ref eq)) (result (ref eq)) - (local $s (ref $bytes)) (local $p i32) + (param $v (ref eq)) (param $p i32) (result i32) + (local $s (ref $bytes)) (local.set $s (ref.cast (ref $bytes) (local.get $v))) - (local.set $p (i31.get_s (ref.cast (ref i31) (local.get $i)))) (if (i32.lt_s (local.get $p) (i32.const 0)) (then (call $caml_bound_error))) (if (i32.ge_u (i32.add (local.get $p) (i32.const 1)) (array.len (local.get $s))) (then (call $caml_bound_error))) - (ref.i31 (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 + (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 $i (ref eq)) (result i32) - (local $s (ref $bytes)) (local $p i32) + (param $v (ref eq)) (param $p i32) (result i32) + (local $s (ref $bytes)) (local.set $s (ref.cast (ref $bytes) (local.get $v))) - (local.set $p (i31.get_s (ref.cast (ref i31) (local.get $i)))) (if (i32.lt_s (local.get $p) (i32.const 0)) (then (call $caml_bound_error))) (if (i32.ge_u (i32.add (local.get $p) (i32.const 3)) @@ -196,10 +194,9 @@ (export "caml_string_get64" (func $caml_bytes_get64)) (func $caml_bytes_get64 (export "caml_bytes_get64") - (param $v (ref eq)) (param $i (ref eq)) (result i64) - (local $s (ref $bytes)) (local $p i32) + (param $v (ref eq)) (param $p i32) (result i64) + (local $s (ref $bytes)) (local.set $s (ref.cast (ref $bytes) (local.get $v))) - (local.set $p (i31.get_s (ref.cast (ref i31) (local.get $i)))) (if (i32.lt_s (local.get $p) (i32.const 0)) (then (call $caml_bound_error))) (if (i32.ge_u (i32.add (local.get $p) (i32.const 7)) @@ -244,11 +241,9 @@ (i64.const 56)))))) (func (export "caml_bytes_set16") - (param (ref eq) (ref eq) (ref eq)) (result (ref eq)) - (local $s (ref $bytes)) (local $p i32) (local $v i32) + (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))) - (local.set $p (i31.get_s (ref.cast (ref i31) (local.get 1)))) - (local.set $v (i31.get_s (ref.cast (ref i31) (local.get 2)))) (if (i32.lt_s (local.get $p) (i32.const 0)) (then (call $caml_bound_error))) (if (i32.ge_u (i32.add (local.get $p) (i32.const 1)) @@ -261,10 +256,9 @@ (ref.i31 (i32.const 0))) (func (export "caml_bytes_set32") - (param (ref eq)) (param (ref eq)) (param $v i32) (result (ref eq)) - (local $s (ref $bytes)) (local $p i32) + (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))) - (local.set $p (i31.get_s (ref.cast (ref i31) (local.get 1)))) (if (i32.lt_s (local.get $p) (i32.const 0)) (then (call $caml_bound_error))) (if (i32.ge_u (i32.add (local.get $p) (i32.const 3)) @@ -283,10 +277,9 @@ (ref.i31 (i32.const 0))) (func (export "caml_bytes_set64") - (param (ref eq)) (param (ref eq)) (param $v i64) (result (ref eq)) - (local $s (ref $bytes)) (local $p i32) + (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))) - (local.set $p (i31.get_s (ref.cast (ref i31) (local.get 1)))) (if (i32.lt_s (local.get $p) (i32.const 0)) (then (call $caml_bound_error))) (if (i32.ge_u (i32.add (local.get $p) (i32.const 7))