diff --git a/compiler/lib-wasm/code_generation.ml b/compiler/lib-wasm/code_generation.ml index 4efeb11a1b..2ea78e58b0 100644 --- a/compiler/lib-wasm/code_generation.ml +++ b/compiler/lib-wasm/code_generation.ml @@ -368,6 +368,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) diff --git a/compiler/lib-wasm/gc_target.ml b/compiler/lib-wasm/gc_target.ml index 36ca054e4c..6ab6d56142 100644 --- a/compiler/lib-wasm/gc_target.ml +++ b/compiler/lib-wasm/gc_target.ml @@ -419,6 +419,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 @@ -1360,6 +1392,237 @@ 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 + Memory.box_float (return (W.F64PromoteF32 x)) ) + | Float64 -> "dv_get_f64", F64, 3, Memory.box_float + | Int8_signed -> "dv_get_i8", I32, 0, Fun.id + | Int8_unsigned | Char -> "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, Memory.box_int32 + | Nativeint -> "dv_get_i32", I32, 2, Memory.box_nativeint + | Int64 -> "dv_get_i64", I64, 3, Memory.box_int64 + | 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 + Memory.box_float (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 + | Char + | 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* e = Memory.unbox_float x in + return (W.F32DemoteF64 e) ) + | Float64 -> "dv_set_f64", F64, 3, Memory.unbox_float + | Int8_signed | Int8_unsigned | Char -> "dv_set_i8", I32, 0, Fun.id + | Int16_signed | Int16_unsigned -> "dv_set_i16", I32, 1, Fun.id + | Int32 -> "dv_set_i32", I32, 2, Memory.unbox_int32 + | Nativeint -> "dv_set_i32", I32, 2, Memory.unbox_nativeint + | Int64 -> "dv_set_i64", I64, 3, Memory.unbox_int64 + | 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 = Memory.unbox_float 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 + | Char + | 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 fa196e8571..2ac6de6863 100644 --- a/compiler/lib-wasm/generate.ml +++ b/compiler/lib-wasm/generate.ml @@ -68,6 +68,7 @@ module Generate (Target : Target_sig.S) = struct type repr = | Value | Float + | Int | Int32 | Nativeint | Int64 @@ -76,8 +77,7 @@ 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) = @@ -85,7 +85,7 @@ module Generate (Target : Target_sig.S) = struct let box_value r e = match r with - | Value -> e + | Value | Int -> e | Float -> Memory.box_float e | Int32 -> Memory.box_int32 e | Nativeint -> Memory.box_nativeint e @@ -93,7 +93,7 @@ module Generate (Target : Target_sig.S) = struct let unbox_value r e = match r with - | Value -> e + | Value | Int -> e | Float -> Memory.unbox_float e | Int32 -> Memory.unbox_int32 e | Nativeint -> Memory.unbox_nativeint e @@ -106,9 +106,9 @@ 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_int32_compare", (`Pure, [ Int32; Int32 ], Int) + ; "caml_nativeint_compare", (`Pure, [ Nativeint; Nativeint ], Int) + ; "caml_int64_compare", (`Pure, [ Int64; Int64 ], Int) ; "caml_string_get32", (`Mutator, [ Value; Value ], Int32) ; "caml_string_get64", (`Mutator, [ Value; Value ], Int64) ; "caml_bytes_get32", (`Mutator, [ Value; Value ], Int32) @@ -116,16 +116,18 @@ module Generate (Target : Target_sig.S) = struct ; "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_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_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 @@ -236,7 +238,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,6 +303,38 @@ 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 ] -> ( + let x' = transl_prim_arg ctx x in + let y' = transl_prim_arg ctx y in + match get_type ctx x, get_type ctx y with + | Int _, Int _ -> cmp_int ctx x y + | Number Int32, Number Int32 -> + let* x' = Memory.unbox_int32 x' in + let* y' = Memory.unbox_int32 y' in + return (W.BinOp (I32 cmp_boxed_int, x', y')) + | Number Nativeint, Number Nativeint -> + let* x' = Memory.unbox_nativeint x' in + let* y' = Memory.unbox_nativeint y' in + return (W.BinOp (I32 cmp_boxed_int, x', y')) + | Number Int64, Number Int64 -> + let* x' = Memory.unbox_int64 x' in + let* y' = Memory.unbox_int64 y' in + return (W.BinOp (I64 cmp_boxed_int, x', y')) + | Number Float, Number Float -> float_comparison cmp_float x' y' + | _ -> + let* f = + register_import + ~name + (Fun { W.params = [ Type.value; Type.value ]; result = [ I32 ] }) + in + let* x' = x' in + let* y' = y' in + return (W.Call (f, [ x'; y' ]))) + | _ -> invalid_arity name l ~expected:2) + let () = register_bin_prim "caml_array_unsafe_get" @@ -781,7 +816,235 @@ module Generate (Target : Target_sig.S) = struct l ~init:(return []) in - Memory.allocate ~tag:0 ~deadcode_sentinal:ctx.deadcode_sentinal ~load l) + Memory.allocate ~tag:0 ~deadcode_sentinal:ctx.deadcode_sentinal ~load 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 ] -> ( + let x' = transl_prim_arg ctx x in + let y' = transl_prim_arg ctx y in + match get_type ctx x, get_type ctx y with + | Int _, Int _ -> + Arith.( + (Value.int_val y' < Value.int_val x') + - (Value.int_val x' < Value.int_val y')) + | Number Int32, Number Int32 -> + let* f = + register_import + ~name:"caml_int32_compare" + (Fun { W.params = [ Type.value; Type.value ]; result = [ I32 ] }) + in + let* x' = Memory.unbox_int32 x' in + let* y' = Memory.unbox_int32 y' in + return (W.Call (f, [ x'; y' ])) + | Number Nativeint, Number Nativeint -> + let* f = + register_import + ~name:"caml_nativeint_compare" + (Fun (Type.primitive_type 2)) + in + let* x' = Memory.unbox_nativeint x' in + let* y' = Memory.unbox_nativeint y' in + return (W.Call (f, [ x'; y' ])) + | Number Int64, Number Int64 -> + let* f = + register_import + ~name:"caml_int64_compare" + (Fun { W.params = [ Type.value; Type.value ]; result = [ I32 ] }) + in + let* x' = Memory.unbox_int64 x' in + let* y' = Memory.unbox_int64 y' in + return (W.Call (f, [ x'; y' ])) + | Number Float, Number Float -> + let* f = + register_import + ~name:"caml_float_compare" + (Fun { W.params = [ Type.value; Type.value ]; result = [ I32 ] }) + in + let* x' = Memory.unbox_int64 x' in + let* y' = Memory.unbox_int64 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' = x' in + let* y' = 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: + (match (kind : Typing.Bigarray.kind) with + | Int8_signed | Int8_unsigned | Int16_signed | Int16_unsigned | Char -> + Some (Int Unnormalized) + | Int -> Some (Int Normalized) + | _ -> None) + 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 rec translate_expr ctx context x e = match e with @@ -900,36 +1163,45 @@ module Generate (Target : Target_sig.S) = struct match p with | Extern name when String.Hashtbl.mem internal_primitives name -> snd (String.Hashtbl.find internal_primitives name) ctx context l + | Extern name when String.Hashtbl.mem specialized_primitives name -> + 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 + (transl_prim_arg + ctx + ?typ: + (match repr with + | Int -> Some (Int Normalized) + | _ -> None) + x) + in + loop (x :: acc) rem r + | [], _ :: _ | _ :: _, [] -> assert false + in + loop [] arg_typ l | _ -> ( 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), _ -> @@ -1055,7 +1327,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 ( _ diff --git a/compiler/lib-wasm/target_sig.ml b/compiler/lib-wasm/target_sig.ml index 053e3be066..399db05590 100644 --- a/compiler/lib-wasm/target_sig.ml +++ b/compiler/lib-wasm/target_sig.ml @@ -255,6 +255,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 1e7253fb6c..9c90cfd29a 100644 --- a/compiler/lib-wasm/typing.ml +++ b/compiler/lib-wasm/typing.ml @@ -23,11 +23,93 @@ type boxed_number = | Nativeint | Float +module Bigarray = struct + type kind = + | Float32 + | Float64 + | Int8_signed + | Int8_unsigned + | Int16_signed + | Int16_unsigned + | Int32 + | Int64 + | Int + | Nativeint + | Complex32 + | Complex64 + | Char + | Float16 + + 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 -> Char + | 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" + | Char -> "char" + | 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 | 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 @@ -47,8 +129,11 @@ module Domain = struct else Array.init (max l l') ~f:(fun i -> 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 @@ -60,7 +145,8 @@ module Domain = struct | Number t, Number t' -> Poly.equal t t' | 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 @@ -68,12 +154,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 @@ -102,6 +188,7 @@ module Domain = struct | Number Int64 -> Format.fprintf f "int64" | Number Nativeint -> Format.fprintf f "nativeint" | Number Float -> Format.fprintf f "float" + | Bigarray b -> Bigarray.print f b | Tuple t -> Format.fprintf f @@ -117,7 +204,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 -> @@ -161,7 +259,22 @@ 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_type ~approx ba = + match arg_type ~approx ba with + | Bot -> Bot + | Bigarray { kind; _ } -> ( + match kind with + | Float16 | Float32 | Float64 -> Number Float + | Int8_signed | Int8_unsigned | Int16_signed | Int16_unsigned | Char -> + Int Normalized + | Int -> Int Unnormalized + | Int32 -> Number Int32 + | Int64 -> Number Int64 + | Nativeint -> Number Nativeint + | Complex32 | Complex64 -> Tuple [| Number Float; Number Float |]) + | _ -> 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 @@ -186,22 +299,25 @@ let prim_type ~approx prim args = | "caml_lessthan" | "caml_lessequal" | "caml_equal" - | "caml_compare" -> Int Ref + | "caml_notequal" + | "caml_compare" -> Int Normalized | "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_int32_compare" | "caml_nativeint_compare" | "caml_int64_compare" -> + Int Normalized | "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_get16" -> Int Normalized | "caml_ba_uint8_get32" -> Number Int32 | "caml_ba_uint8_get64" -> Number Int64 | "caml_nextafter_float" -> Number Float | "caml_classify_float" -> Int Ref | "caml_ldexp_float" | "caml_erf_float" | "caml_erfc_float" -> Number Float - | "caml_float_compare" -> Int Ref + | "caml_float_compare" -> Int Normalized | "caml_floatarray_unsafe_get" -> Number Float | "caml_bytes_unsafe_get" | "caml_string_unsafe_get" @@ -316,6 +432,25 @@ let prim_type ~approx prim args = | "caml_nativeint_to_int" -> Int Unnormalized | "caml_nativeint_of_int" -> Number Nativeint | "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.state.defs.(Var.idx indices) with + | Expr (Block _) -> bigarray_type ~approx ba + | _ -> Top) + | [] | [ _ ] | _ :: Pc _ :: _ -> Top) | _ -> Top let propagate st approx x : Domain.t = @@ -374,7 +509,7 @@ 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 @@ -387,7 +522,32 @@ let propagate st approx x : Domain.t = when List.length args = List.length params -> Domain.box (Domain.join_set - (fun y -> Var.Tbl.get approx y) + (fun y -> + match st.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.state.defs.(Var.idx (Var.Map.find kind m)) + , st.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.state.return_values)) | Expr (Closure (_, _, _)) -> (* The function is partially applied or over applied *) @@ -414,10 +574,48 @@ let solver st = in Solver.f () g (propagate st) +let print_opt st typ f e = + match e with + | Prim + ( Extern + ( "caml_greaterthan" + | "caml_greaterequal" + | "caml_lessthan" + | "caml_lessequal" + | "caml_equal" + | "caml_compare" ) + , l ) -> ( + match List.map ~f:(arg_type ~approx:typ) l with + | [ Int _; Int _ ] + | [ Number Int32; Number Int32 ] + | [ Number Int64; Number Int64 ] + | [ Number Nativeint; Number Nativeint ] + | [ Number Float; Number Float ] -> Format.fprintf f " OPT" + | _ -> ()) + | Prim + ( Extern + ( "caml_ba_get_1" + | "caml_ba_get_2" + | "caml_ba_get_3" + | "caml_ba_set_1" + | "caml_ba_set_2" + | "caml_ba_set_3" ) + , Pv x :: _ ) -> ( + match Var.Tbl.get typ x with + | Bigarray _ -> Format.fprintf f " OPT" + | _ -> ()) + | Prim (Extern ("caml_ba_get_generic" | "caml_ba_set_generic"), Pv x :: Pv indices :: _) + -> ( + match Var.Tbl.get typ x, st.state.defs.(Var.idx indices) with + | Bigarray _, Expr (Block _) -> Format.fprintf f " OPT" + | _ -> ()) + | _ -> () + 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 + let st = { state; info; function_parameters } in + let typ = solver st in Var.Tbl.set typ deadcode_sentinal (Int Normalized); if debug () then ( @@ -434,7 +632,8 @@ let f ~state ~info ~deadcode_sentinal p = 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 typ x) (print_opt st typ) e | _ -> "") p); typ diff --git a/compiler/lib-wasm/typing.mli b/compiler/lib-wasm/typing.mli index 1860b4ac7c..a5690157b3 100644 --- a/compiler/lib-wasm/typing.mli +++ b/compiler/lib-wasm/typing.mli @@ -11,11 +11,39 @@ type boxed_number = | Nativeint | Float +module Bigarray : sig + type kind = + | Float32 + | Float64 + | Int8_signed + | Int8_unsigned + | Int16_signed + | Int16_unsigned + | Int32 + | Int64 + | Int + | Nativeint + | Complex32 + | Complex64 + | Char + | Float16 + + type layout = + | C + | Fortran + + type t = + { kind : kind + ; layout : layout + } +end + type typ = | Top | Int of Integer.kind | Number of boxed_number | Tuple of typ array + | Bigarray of Bigarray.t | Bot val constant_type : Code.constant -> typ 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/wasm/bigarray.wat b/runtime/wasm/bigarray.wat index 59cc22cd7f..6141bea257 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,117 +1925,103 @@ (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)) 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/float.wat b/runtime/wasm/float.wat index b0bf76e609..3256113e54 100644 --- a/runtime/wasm/float.wat +++ b/runtime/wasm/float.wat @@ -1132,13 +1132,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")