diff options
author | Tom Kelly <ctk21@cl.cam.ac.uk> | 2020-04-29 16:47:18 +0100 |
---|---|---|
committer | Tom Kelly <ctk21@cl.cam.ac.uk> | 2020-04-29 16:47:18 +0100 |
commit | de137da19d78ab3610bc1d02de7885d7074b31f7 (patch) | |
tree | 55590f81226add0ad528717ebce0bc64617cfb69 /asmcomp/cmmgen.ml | |
parent | 92a5eeb1e7f3e24c03fc4c3195783fc1e2b3dade (diff) | |
parent | dbd717e817307dc6a527dd54cc1c9765b30cfad2 (diff) | |
download | ocaml-de137da19d78ab3610bc1d02de7885d7074b31f7.tar.gz |
Merge commit 'dbd717e817307dc6a527dd54cc1c9765b30cfad2' into parallel_minor_gc_4_10
Diffstat (limited to 'asmcomp/cmmgen.ml')
-rw-r--r-- | asmcomp/cmmgen.ml | 2761 |
1 files changed, 112 insertions, 2649 deletions
diff --git a/asmcomp/cmmgen.ml b/asmcomp/cmmgen.ml index cfb48cffb9..4762df1b83 100644 --- a/asmcomp/cmmgen.ml +++ b/asmcomp/cmmgen.ml @@ -26,13 +26,12 @@ open Lambda open Clambda open Clambda_primitives open Cmm -open Cmx_format -open Cmxs_format module String = Misc.Stdlib.String module IntMap = Map.Make(Int) module V = Backend_var module VP = Backend_var.With_provenance +open Cmm_helpers (* Environments used for translation to Cmm. *) @@ -92,240 +91,6 @@ let notify_catch i env l = | Some f -> f l | None -> () -let structured_constant_of_sym s = - match Compilenv.structured_constant_of_symbol s with - | None -> Cmmgen_state.get_structured_constant s - | Some _ as r -> r - -(* Local binding of complex expressions *) - -let bind name arg fn = - match arg with - Cvar _ | Cconst_int _ | Cconst_natint _ | Cconst_symbol _ - | Cconst_pointer _ | Cconst_natpointer _ - | Cblockheader _ -> fn arg - | _ -> let id = V.create_local name in Clet(VP.create id, arg, fn (Cvar id)) - -let bind_load name arg fn = - match arg with - | Cop(Cload _, [Cvar _], _) -> fn arg - | _ -> bind name arg fn - -let bind_nonvar name arg fn = - match arg with - Cconst_int _ | Cconst_natint _ | Cconst_symbol _ - | Cconst_pointer _ | Cconst_natpointer _ - | Cblockheader _ -> fn arg - | _ -> let id = V.create_local name in Clet(VP.create id, arg, fn (Cvar id)) - -let caml_black = Nativeint.shift_left (Nativeint.of_int 3) 8 - (* cf. runtime/caml/gc.h *) - -let mk_load_mut memory_chunk = Cload {memory_chunk; mutability=Mutable; is_atomic=false} - -(* Block headers. Meaning of the tag field: see stdlib/obj.ml *) - -let floatarray_tag dbg = Cconst_int (Obj.double_array_tag, dbg) - -let block_header tag sz = - Nativeint.add (Nativeint.shift_left (Nativeint.of_int sz) 10) - (Nativeint.of_int tag) -(* Static data corresponding to "value"s must be marked black in case we are - in no-naked-pointers mode. See [caml_darken] and the code below that emits - structured constants and static module definitions. *) -let black_block_header tag sz = Nativeint.logor (block_header tag sz) caml_black -let white_closure_header sz = block_header Obj.closure_tag sz -let black_closure_header sz = black_block_header Obj.closure_tag sz -let infix_header ofs = block_header Obj.infix_tag ofs -let float_header = block_header Obj.double_tag (size_float / size_addr) -let floatarray_header len = - (* Zero-sized float arrays have tag zero for consistency with - [caml_alloc_float_array]. *) - assert (len >= 0); - if len = 0 then block_header 0 0 - else block_header Obj.double_array_tag (len * size_float / size_addr) -let string_header len = - block_header Obj.string_tag ((len + size_addr) / size_addr) -let boxedint32_header = block_header Obj.custom_tag 2 -let boxedint64_header = block_header Obj.custom_tag (1 + 8 / size_addr) -let boxedintnat_header = block_header Obj.custom_tag 2 -let caml_nativeint_ops = "caml_nativeint_ops" -let caml_int32_ops = "caml_int32_ops" -let caml_int64_ops = "caml_int64_ops" - - -let alloc_float_header dbg = Cblockheader (float_header, dbg) -let alloc_floatarray_header len dbg = Cblockheader (floatarray_header len, dbg) -let alloc_closure_header sz dbg = Cblockheader (white_closure_header sz, dbg) -let alloc_infix_header ofs dbg = Cblockheader (infix_header ofs, dbg) -let alloc_boxedint32_header dbg = Cblockheader (boxedint32_header, dbg) -let alloc_boxedint64_header dbg = Cblockheader (boxedint64_header, dbg) -let alloc_boxedintnat_header dbg = Cblockheader (boxedintnat_header, dbg) - -(* Integers *) - -let max_repr_int = max_int asr 1 -let min_repr_int = min_int asr 1 - -let int_const dbg n = - if n <= max_repr_int && n >= min_repr_int - then Cconst_int((n lsl 1) + 1, dbg) - else Cconst_natint - (Nativeint.add (Nativeint.shift_left (Nativeint.of_int n) 1) 1n, dbg) - -let natint_const_untagged dbg n = - if n > Nativeint.of_int max_int - || n < Nativeint.of_int min_int - then Cconst_natint (n,dbg) - else Cconst_int (Nativeint.to_int n, dbg) - -let cint_const n = - Cint(Nativeint.add (Nativeint.shift_left (Nativeint.of_int n) 1) 1n) - -let targetint_const n = - Targetint.add (Targetint.shift_left (Targetint.of_int n) 1) - Targetint.one - -let add_no_overflow n x c dbg = - let d = n + x in - if d = 0 then c else Cop(Caddi, [c; Cconst_int (d, dbg)], dbg) - -let rec add_const c n dbg = - if n = 0 then c - else match c with - | Cconst_int (x, _) when no_overflow_add x n -> Cconst_int (x + n, dbg) - | Cop(Caddi, [Cconst_int (x, _); c], _) - when no_overflow_add n x -> - add_no_overflow n x c dbg - | Cop(Caddi, [c; Cconst_int (x, _)], _) - when no_overflow_add n x -> - add_no_overflow n x c dbg - | Cop(Csubi, [Cconst_int (x, _); c], _) when no_overflow_add n x -> - Cop(Csubi, [Cconst_int (n + x, dbg); c], dbg) - | Cop(Csubi, [c; Cconst_int (x, _)], _) when no_overflow_sub n x -> - add_const c (n - x) dbg - | c -> Cop(Caddi, [c; Cconst_int (n, dbg)], dbg) - -let incr_int c dbg = add_const c 1 dbg -let decr_int c dbg = add_const c (-1) dbg - -let rec add_int c1 c2 dbg = - match (c1, c2) with - | (Cconst_int (n, _), c) | (c, Cconst_int (n, _)) -> - add_const c n dbg - | (Cop(Caddi, [c1; Cconst_int (n1, _)], _), c2) -> - add_const (add_int c1 c2 dbg) n1 dbg - | (c1, Cop(Caddi, [c2; Cconst_int (n2, _)], _)) -> - add_const (add_int c1 c2 dbg) n2 dbg - | (_, _) -> - Cop(Caddi, [c1; c2], dbg) - -let rec sub_int c1 c2 dbg = - match (c1, c2) with - | (c1, Cconst_int (n2, _)) when n2 <> min_int -> - add_const c1 (-n2) dbg - | (c1, Cop(Caddi, [c2; Cconst_int (n2, _)], _)) when n2 <> min_int -> - add_const (sub_int c1 c2 dbg) (-n2) dbg - | (Cop(Caddi, [c1; Cconst_int (n1, _)], _), c2) -> - add_const (sub_int c1 c2 dbg) n1 dbg - | (c1, c2) -> - Cop(Csubi, [c1; c2], dbg) - -let rec lsl_int c1 c2 dbg = - match (c1, c2) with - | (Cop(Clsl, [c; Cconst_int (n1, _)], _), Cconst_int (n2, _)) - when n1 > 0 && n2 > 0 && n1 + n2 < size_int * 8 -> - Cop(Clsl, [c; Cconst_int (n1 + n2, dbg)], dbg) - | (Cop(Caddi, [c1; Cconst_int (n1, _)], _), Cconst_int (n2, _)) - when no_overflow_lsl n1 n2 -> - add_const (lsl_int c1 c2 dbg) (n1 lsl n2) dbg - | (_, _) -> - Cop(Clsl, [c1; c2], dbg) - -let is_power2 n = n = 1 lsl Misc.log2 n - -and mult_power2 c n dbg = lsl_int c (Cconst_int (Misc.log2 n, dbg)) dbg - -let rec mul_int c1 c2 dbg = - match (c1, c2) with - | (c, Cconst_int (0, _)) | (Cconst_int (0, _), c) -> - Csequence (c, Cconst_int (0, dbg)) - | (c, Cconst_int (1, _)) | (Cconst_int (1, _), c) -> - c - | (c, Cconst_int(-1, _)) | (Cconst_int(-1, _), c) -> - sub_int (Cconst_int (0, dbg)) c dbg - | (c, Cconst_int (n, _)) when is_power2 n -> mult_power2 c n dbg - | (Cconst_int (n, _), c) when is_power2 n -> mult_power2 c n dbg - | (Cop(Caddi, [c; Cconst_int (n, _)], _), Cconst_int (k, _)) | - (Cconst_int (k, _), Cop(Caddi, [c; Cconst_int (n, _)], _)) - when no_overflow_mul n k -> - add_const (mul_int c (Cconst_int (k, dbg)) dbg) (n * k) dbg - | (c1, c2) -> - Cop(Cmuli, [c1; c2], dbg) - - -let ignore_low_bit_int = function - Cop(Caddi, - [(Cop(Clsl, [_; Cconst_int (n, _)], _) as c); Cconst_int (1, _)], _) - when n > 0 - -> c - | Cop(Cor, [c; Cconst_int (1, _)], _) -> c - | c -> c - -let lsr_int c1 c2 dbg = - match c2 with - Cconst_int (0, _) -> - c1 - | Cconst_int (n, _) when n > 0 -> - Cop(Clsr, [ignore_low_bit_int c1; c2], dbg) - | _ -> - Cop(Clsr, [c1; c2], dbg) - -let asr_int c1 c2 dbg = - match c2 with - Cconst_int (0, _) -> - c1 - | Cconst_int (n, _) when n > 0 -> - Cop(Casr, [ignore_low_bit_int c1; c2], dbg) - | _ -> - Cop(Casr, [c1; c2], dbg) - -let tag_int i dbg = - match i with - | Cconst_int (n, _) -> - int_const dbg n - | Cop(Casr, [c; Cconst_int (n, _)], _) when n > 0 -> - Cop(Cor, - [asr_int c (Cconst_int (n - 1, dbg)) dbg; Cconst_int (1, dbg)], - dbg) - | c -> - incr_int (lsl_int c (Cconst_int (1, dbg)) dbg) dbg - -let force_tag_int i dbg = - match i with - Cconst_int (n, _) -> - int_const dbg n - | Cop(Casr, [c; Cconst_int (n, _)], dbg') when n > 0 -> - Cop(Cor, [asr_int c (Cconst_int (n - 1, dbg)) dbg'; Cconst_int (1, dbg)], - dbg) - | c -> - Cop(Cor, [lsl_int c (Cconst_int (1, dbg)) dbg; Cconst_int (1, dbg)], dbg) - -let untag_int i dbg = - match i with - Cconst_int (n, _) -> Cconst_int(n asr 1, dbg) - | Cop(Caddi, [Cop(Clsl, [c; Cconst_int (1, _)], _); Cconst_int (1, _)], _) -> - c - | Cop(Cor, [Cop(Casr, [c; Cconst_int (n, _)], _); Cconst_int (1, _)], _) - when n > 0 && n < size_int * 8 -> - Cop(Casr, [c; Cconst_int (n+1, dbg)], dbg) - | Cop(Cor, [Cop(Clsr, [c; Cconst_int (n, _)], _); Cconst_int (1, _)], _) - when n > 0 && n < size_int * 8 -> - Cop(Clsr, [c; Cconst_int (n+1, dbg)], dbg) - | Cop(Cor, [c; Cconst_int (1, _)], _) -> - Cop(Casr, [c; Cconst_int (1, dbg)], dbg) - | c -> Cop(Casr, [c; Cconst_int (1, dbg)], dbg) - (* Description of the "then" and "else" continuations in [transl_if]. If the "then" continuation is true and the "else" continuation is false then we can use the condition directly as the result. Similarly, if the "then" @@ -341,587 +106,23 @@ let invert_then_else = function | Then_false_else_true -> Then_true_else_false | Unknown -> Unknown -let mk_if_then_else dbg cond ifso_dbg ifso ifnot_dbg ifnot = - match cond with - | Cconst_int (0, _) -> ifnot - | Cconst_int (1, _) -> ifso - | _ -> - Cifthenelse(cond, ifso_dbg, ifso, ifnot_dbg, ifnot, dbg) - -let mk_not dbg cmm = - match cmm with - | Cop(Caddi, - [Cop(Clsl, [c; Cconst_int (1, _)], _); Cconst_int (1, _)], dbg') -> - begin - match c with - | Cop(Ccmpi cmp, [c1; c2], dbg'') -> - tag_int - (Cop(Ccmpi (negate_integer_comparison cmp), [c1; c2], dbg'')) dbg' - | Cop(Ccmpa cmp, [c1; c2], dbg'') -> - tag_int - (Cop(Ccmpa (negate_integer_comparison cmp), [c1; c2], dbg'')) dbg' - | Cop(Ccmpf cmp, [c1; c2], dbg'') -> - tag_int - (Cop(Ccmpf (negate_float_comparison cmp), [c1; c2], dbg'')) dbg' - | _ -> - (* 0 -> 3, 1 -> 1 *) - Cop(Csubi, - [Cconst_int (3, dbg); Cop(Clsl, [c; Cconst_int (1, dbg)], dbg)], dbg) - end - | Cconst_int (3, _) -> Cconst_int (1, dbg) - | Cconst_int (1, _) -> Cconst_int (3, dbg) - | c -> - (* 1 -> 3, 3 -> 1 *) - Cop(Csubi, [Cconst_int (4, dbg); c], dbg) - - -let create_loop body dbg = - let cont = next_raise_count () in - let call_cont = Cexit (cont, []) in - let body = Csequence (body, call_cont) in - Ccatch (Recursive, [cont, [], body, dbg], call_cont) - -(* Turning integer divisions into multiply-high then shift. - The [division_parameters] function is used in module Emit for - those target platforms that support this optimization. *) - -(* Unsigned comparison between native integers. *) - -let ucompare x y = Nativeint.(compare (add x min_int) (add y min_int)) - -(* Unsigned division and modulus at type nativeint. - Algorithm: Hacker's Delight section 9.3 *) - -let udivmod n d = Nativeint.( - if d < 0n then - if ucompare n d < 0 then (0n, n) else (1n, sub n d) - else begin - let q = shift_left (div (shift_right_logical n 1) d) 1 in - let r = sub n (mul q d) in - if ucompare r d >= 0 then (succ q, sub r d) else (q, r) - end) - -(* Compute division parameters. - Algorithm: Hacker's Delight chapter 10, fig 10-1. *) - -let divimm_parameters d = Nativeint.( - assert (d > 0n); - let twopsm1 = min_int in (* 2^31 for 32-bit archs, 2^63 for 64-bit archs *) - let nc = sub (pred twopsm1) (snd (udivmod twopsm1 d)) in - let rec loop p (q1, r1) (q2, r2) = - let p = p + 1 in - let q1 = shift_left q1 1 and r1 = shift_left r1 1 in - let (q1, r1) = - if ucompare r1 nc >= 0 then (succ q1, sub r1 nc) else (q1, r1) in - let q2 = shift_left q2 1 and r2 = shift_left r2 1 in - let (q2, r2) = - if ucompare r2 d >= 0 then (succ q2, sub r2 d) else (q2, r2) in - let delta = sub d r2 in - if ucompare q1 delta < 0 || (q1 = delta && r1 = 0n) - then loop p (q1, r1) (q2, r2) - else (succ q2, p - size) - in loop (size - 1) (udivmod twopsm1 nc) (udivmod twopsm1 d)) - -(* The result [(m, p)] of [divimm_parameters d] satisfies the following - inequality: - - 2^(wordsize + p) < m * d <= 2^(wordsize + p) + 2^(p + 1) (i) - - from which it follows that - - floor(n / d) = floor(n * m / 2^(wordsize+p)) - if 0 <= n < 2^(wordsize-1) - ceil(n / d) = floor(n * m / 2^(wordsize+p)) + 1 - if -2^(wordsize-1) <= n < 0 - - The correctness condition (i) above can be checked by the code below. - It was exhaustively tested for values of d from 2 to 10^9 in the - wordsize = 64 case. - -let add2 (xh, xl) (yh, yl) = - let zl = add xl yl and zh = add xh yh in - ((if ucompare zl xl < 0 then succ zh else zh), zl) - -let shl2 (xh, xl) n = - assert (0 < n && n < size + size); - if n < size - then (logor (shift_left xh n) (shift_right_logical xl (size - n)), - shift_left xl n) - else (shift_left xl (n - size), 0n) - -let mul2 x y = - let halfsize = size / 2 in - let halfmask = pred (shift_left 1n halfsize) in - let xl = logand x halfmask and xh = shift_right_logical x halfsize in - let yl = logand y halfmask and yh = shift_right_logical y halfsize in - add2 (mul xh yh, 0n) - (add2 (shl2 (0n, mul xl yh) halfsize) - (add2 (shl2 (0n, mul xh yl) halfsize) - (0n, mul xl yl))) - -let ucompare2 (xh, xl) (yh, yl) = - let c = ucompare xh yh in if c = 0 then ucompare xl yl else c - -let validate d m p = - let md = mul2 m d in - let one2 = (0n, 1n) in - let twoszp = shl2 one2 (size + p) in - let twop1 = shl2 one2 (p + 1) in - ucompare2 twoszp md < 0 && ucompare2 md (add2 twoszp twop1) <= 0 -*) - -let raise_symbol dbg symb = - Cop(Craise Lambda.Raise_regular, [Cconst_symbol (symb, dbg)], dbg) - -let rec div_int c1 c2 is_safe dbg = - match (c1, c2) with - (c1, Cconst_int (0, _)) -> - Csequence(c1, raise_symbol dbg "caml_exn_Division_by_zero") - | (c1, Cconst_int (1, _)) -> - c1 - | (Cconst_int (n1, _), Cconst_int (n2, _)) -> - Cconst_int (n1 / n2, dbg) - | (c1, Cconst_int (n, _)) when n <> min_int -> - let l = Misc.log2 n in - if n = 1 lsl l then - (* Algorithm: - t = shift-right-signed(c1, l - 1) - t = shift-right(t, W - l) - t = c1 + t - res = shift-right-signed(c1 + t, l) - *) - Cop(Casr, [bind "dividend" c1 (fun c1 -> - let t = asr_int c1 (Cconst_int (l - 1, dbg)) dbg in - let t = - lsr_int t (Cconst_int (Nativeint.size - l, dbg)) dbg - in - add_int c1 t dbg); - Cconst_int (l, dbg)], dbg) - else if n < 0 then - sub_int (Cconst_int (0, dbg)) - (div_int c1 (Cconst_int (-n, dbg)) is_safe dbg) - dbg - else begin - let (m, p) = divimm_parameters (Nativeint.of_int n) in - (* Algorithm: - t = multiply-high-signed(c1, m) - if m < 0, t = t + c1 - if p > 0, t = shift-right-signed(t, p) - res = t + sign-bit(c1) - *) - bind "dividend" c1 (fun c1 -> - let t = Cop(Cmulhi, [c1; Cconst_natint (m, dbg)], dbg) in - let t = if m < 0n then Cop(Caddi, [t; c1], dbg) else t in - let t = - if p > 0 then Cop(Casr, [t; Cconst_int (p, dbg)], dbg) else t - in - add_int t (lsr_int c1 (Cconst_int (Nativeint.size - 1, dbg)) dbg) dbg) - end - | (c1, c2) when !Clflags.unsafe || is_safe = Lambda.Unsafe -> - Cop(Cdivi, [c1; c2], dbg) - | (c1, c2) -> - bind "divisor" c2 (fun c2 -> - bind "dividend" c1 (fun c1 -> - Cifthenelse(c2, - dbg, - Cop(Cdivi, [c1; c2], dbg), - dbg, - raise_symbol dbg "caml_exn_Division_by_zero", - dbg))) - -let mod_int c1 c2 is_safe dbg = - match (c1, c2) with - (c1, Cconst_int (0, _)) -> - Csequence(c1, raise_symbol dbg "caml_exn_Division_by_zero") - | (c1, Cconst_int ((1 | (-1)), _)) -> - Csequence(c1, Cconst_int (0, dbg)) - | (Cconst_int (n1, _), Cconst_int (n2, _)) -> - Cconst_int (n1 mod n2, dbg) - | (c1, (Cconst_int (n, _) as c2)) when n <> min_int -> - let l = Misc.log2 n in - if n = 1 lsl l then - (* Algorithm: - t = shift-right-signed(c1, l - 1) - t = shift-right(t, W - l) - t = c1 + t - t = bit-and(t, -n) - res = c1 - t - *) - bind "dividend" c1 (fun c1 -> - let t = asr_int c1 (Cconst_int (l - 1, dbg)) dbg in - let t = lsr_int t (Cconst_int (Nativeint.size - l, dbg)) dbg in - let t = add_int c1 t dbg in - let t = Cop(Cand, [t; Cconst_int (-n, dbg)], dbg) in - sub_int c1 t dbg) - else - bind "dividend" c1 (fun c1 -> - sub_int c1 (mul_int (div_int c1 c2 is_safe dbg) c2 dbg) dbg) - | (c1, c2) when !Clflags.unsafe || is_safe = Lambda.Unsafe -> - (* Flambda already generates that test *) - Cop(Cmodi, [c1; c2], dbg) - | (c1, c2) -> - bind "divisor" c2 (fun c2 -> - bind "dividend" c1 (fun c1 -> - Cifthenelse(c2, - dbg, - Cop(Cmodi, [c1; c2], dbg), - dbg, - raise_symbol dbg "caml_exn_Division_by_zero", - dbg))) - -(* Division or modulo on boxed integers. The overflow case min_int / -1 - can occur, in which case we force x / -1 = -x and x mod -1 = 0. (PR#5513). *) - -let is_different_from x = function - Cconst_int (n, _) -> n <> x - | Cconst_natint (n, _) -> n <> Nativeint.of_int x - | _ -> false - -let safe_divmod_bi mkop is_safe mkm1 c1 c2 bi dbg = - bind "dividend" c1 (fun c1 -> - bind "divisor" c2 (fun c2 -> - let c = mkop c1 c2 is_safe dbg in - if Arch.division_crashes_on_overflow - && (size_int = 4 || bi <> Pint32) - && not (is_different_from (-1) c2) - then - Cifthenelse(Cop(Ccmpi Cne, [c2; Cconst_int (-1, dbg)], dbg), - dbg, c, - dbg, mkm1 c1 dbg, - dbg) - else - c)) - -let safe_div_bi is_safe = - safe_divmod_bi div_int is_safe - (fun c1 dbg -> Cop(Csubi, [Cconst_int (0, dbg); c1], dbg)) - -let safe_mod_bi is_safe = - safe_divmod_bi mod_int is_safe (fun _ dbg -> Cconst_int (0, dbg)) - -(* Bool *) - -let test_bool dbg cmm = - match cmm with - | Cop(Caddi, [Cop(Clsl, [c; Cconst_int (1, _)], _); Cconst_int (1, _)], _) -> - c - | Cconst_int (n, dbg) -> - if n = 1 then - Cconst_int (0, dbg) - else - Cconst_int (1, dbg) - | c -> Cop(Ccmpi Cne, [c; Cconst_int (1, dbg)], dbg) - -(* Float *) - -let box_float dbg c = Cop(Calloc, [alloc_float_header dbg; c], dbg) - -let unbox_float dbg = - map_tail - (function - | Cop(Calloc, [Cblockheader (hdr, _); c], _) - when Nativeint.equal hdr float_header -> - c - | Cconst_symbol (s, _dbg) as cmm -> - begin match structured_constant_of_sym s with - | Some (Uconst_float x) -> - Cconst_float (x, dbg) (* or keep _dbg? *) - | _ -> - Cop(Cload {memory_chunk=Double_u; mutability=Immutable; - is_atomic=false}, - [cmm], dbg) - end - | cmm -> Cop(Cload {memory_chunk=Double_u; mutability=Immutable; - is_atomic=false}, - [cmm], dbg) - ) - -(* Complex *) - -let box_complex dbg c_re c_im = - Cop(Calloc, [alloc_floatarray_header 2 dbg; c_re; c_im], dbg) - -let complex_re c dbg = Cop(Cload {memory_chunk=Double_u; mutability=Immutable; is_atomic=false}, [c], dbg) -let complex_im c dbg = Cop(Cload {memory_chunk=Double_u; mutability=Immutable; is_atomic=false}, - [Cop(Cadda, [c; Cconst_int (size_float, dbg)], dbg)], - dbg) - -(* Unit *) - -let return_unit dbg c = Csequence(c, Cconst_pointer (1, dbg)) - -let rec remove_unit = function - Cconst_pointer (1, _) -> Ctuple [] - | Csequence(c, Cconst_pointer (1, _)) -> c - | Csequence(c1, c2) -> - Csequence(c1, remove_unit c2) - | Cifthenelse(cond, ifso_dbg, ifso, ifnot_dbg, ifnot, dbg) -> - Cifthenelse(cond, - ifso_dbg, remove_unit ifso, - ifnot_dbg, - remove_unit ifnot, dbg) - | Cswitch(sel, index, cases, dbg) -> - Cswitch(sel, index, - Array.map (fun (case, dbg) -> remove_unit case, dbg) cases, - dbg) - | Ccatch(rec_flag, handlers, body) -> - let map_h (n, ids, handler, dbg) = (n, ids, remove_unit handler, dbg) in - Ccatch(rec_flag, List.map map_h handlers, remove_unit body) - | Ctrywith(body, exn, handler, dbg) -> - Ctrywith(remove_unit body, exn, remove_unit handler, dbg) - | Clet(id, c1, c2) -> - Clet(id, c1, remove_unit c2) - | Cop(Capply _mty, args, dbg) -> - Cop(Capply typ_void, args, dbg) - | Cop(Cextcall(proc, _mty, alloc, label_after), args, dbg) -> - Cop(Cextcall(proc, typ_void, alloc, label_after), args, dbg) - | Cexit (_,_) as c -> c - | Ctuple [] as c -> c - | c -> Csequence(c, Ctuple []) - -(* Access to block fields *) - -let field_address ptr n dbg = - if n = 0 - then ptr - else Cop(Cadda, [ptr; Cconst_int(n * size_addr, dbg)], dbg) +let mut_from_env env ptr = + match env.environment_param with + | None -> Mutable + | Some environment_param -> + match ptr with + | Cvar ptr -> + (* Loads from the current function's closure are immutable. *) + if V.same environment_param ptr then Immutable + else Mutable + | _ -> Mutable let get_mut_field ptr n dbg = Cop (Cloadmut {is_atomic=false}, [ptr; n], dbg) let get_field env ptr n dbg = - let mutability = - match env.environment_param with - | None -> Mutable - | Some environment_param -> - match ptr with - | Cvar ptr -> - (* Loads from the current function's closure are immutable. *) - if V.same environment_param ptr then Immutable - else Mutable - | _ -> Mutable - in - Cop(Cload {memory_chunk=Word_val; mutability; is_atomic=false}, [field_address ptr n dbg], dbg) - -let set_field ptr n newval init dbg = - Cop(Cstore (Word_val, init), [field_address ptr n dbg; newval], dbg) - -let non_profinfo_mask = - if Config.profinfo - then (1 lsl (64 - Config.profinfo_width)) - 1 - else 0 (* [non_profinfo_mask] is unused in this case *) - -let get_header ptr dbg = - (* We cannot deem this as [Immutable] due to the presence of [Obj.truncate] - and [Obj.set_tag]. *) - Cop(mk_load_mut Word_int, - [Cop(Cadda, [ptr; Cconst_int(-size_int, dbg)], dbg)], dbg) - -let get_header_without_profinfo ptr dbg = - if Config.profinfo then - Cop(Cand, [get_header ptr dbg; Cconst_int (non_profinfo_mask, dbg)], dbg) - else - get_header ptr dbg - -let tag_offset = - if big_endian then -1 else -size_int - -let get_tag ptr dbg = - if Proc.word_addressed then (* If byte loads are slow *) - Cop(Cand, [get_header ptr dbg; Cconst_int (255, dbg)], dbg) - else (* If byte loads are efficient *) - Cop(mk_load_mut Byte_unsigned, (* Same comment as [get_header] above *) - [Cop(Cadda, [ptr; Cconst_int(tag_offset, dbg)], dbg)], dbg) - -let get_size ptr dbg = - Cop(Clsr, [get_header_without_profinfo ptr dbg; Cconst_int (10, dbg)], dbg) - -(* Array indexing *) - -let log2_size_addr = Misc.log2 size_addr -let log2_size_float = Misc.log2 size_float - -let wordsize_shift = 9 -let numfloat_shift = 9 + log2_size_float - log2_size_addr - -let is_addr_array_hdr hdr dbg = - Cop(Ccmpi Cne, - [Cop(Cand, [hdr; Cconst_int (255, dbg)], dbg); floatarray_tag dbg], - dbg) - -let is_addr_array_ptr ptr dbg = - Cop(Ccmpi Cne, [get_tag ptr dbg; floatarray_tag dbg], dbg) - -let addr_array_length hdr dbg = - Cop(Clsr, [hdr; Cconst_int (wordsize_shift, dbg)], dbg) -let float_array_length hdr dbg = - Cop(Clsr, [hdr; Cconst_int (numfloat_shift, dbg)], dbg) - -let lsl_const c n dbg = - if n = 0 then c - else Cop(Clsl, [c; Cconst_int (n, dbg)], dbg) - -(* Produces a pointer to the element of the array [ptr] on the position [ofs] - with the given element [log2size] log2 element size. [ofs] is given as a - tagged int expression. - The optional ?typ argument is the C-- type of the result. - By default, it is Addr, meaning we are constructing a derived pointer - into the heap. If we know the pointer is outside the heap - (this is the case for bigarray indexing), we give type Int instead. *) - -let array_indexing ?typ log2size ptr ofs dbg = - let add = - match typ with - | None | Some Addr -> Cadda - | Some Int -> Caddi - | _ -> assert false in - match ofs with - | Cconst_int (n, _) -> - let i = n asr 1 in - if i = 0 then ptr - else Cop(add, [ptr; Cconst_int(i lsl log2size, dbg)], dbg) - | Cop(Caddi, - [Cop(Clsl, [c; Cconst_int (1, _)], _); Cconst_int (1, _)], dbg') -> - Cop(add, [ptr; lsl_const c log2size dbg], dbg') - | Cop(Caddi, [c; Cconst_int (n, _)], dbg') when log2size = 0 -> - Cop(add, - [Cop(add, [ptr; untag_int c dbg], dbg); Cconst_int (n asr 1, dbg)], - dbg') - | Cop(Caddi, [c; Cconst_int (n, _)], _) -> - Cop(add, [Cop(add, [ptr; lsl_const c (log2size - 1) dbg], dbg); - Cconst_int((n-1) lsl (log2size - 1), dbg)], dbg) - | _ when log2size = 0 -> - Cop(add, [ptr; untag_int ofs dbg], dbg) - | _ -> - Cop(add, [Cop(add, [ptr; lsl_const ofs (log2size - 1) dbg], dbg); - Cconst_int((-1) lsl (log2size - 1), dbg)], dbg) - -let addr_array_ref arr ofs dbg = - Cop(Cloadmut {is_atomic=false}, [arr; untag_int ofs dbg], dbg) -let int_array_ref arr ofs dbg = - Cop(mk_load_mut Word_int, - [array_indexing log2_size_addr arr ofs dbg], dbg) -let unboxed_float_array_ref arr ofs dbg = - Cop(mk_load_mut Double_u, - [array_indexing log2_size_float arr ofs dbg], dbg) -let float_array_ref dbg arr ofs = - box_float dbg (unboxed_float_array_ref arr ofs dbg) - -let addr_array_set arr ofs newval dbg = - Cop(Cextcall("caml_modify_field_asm", typ_void, false, None), - [arr; untag_int ofs dbg; newval], dbg) -let addr_array_initialize arr ofs newval dbg = - Cop(Cextcall("caml_initialize_field", typ_void, false, None), - [arr; untag_int ofs dbg; newval], dbg) -let int_array_set arr ofs newval dbg = - Cop(Cstore (Word_int, Assignment), - [array_indexing log2_size_addr arr ofs dbg; newval], dbg) -let float_array_set arr ofs newval dbg = - Cop(Cstore (Double_u, Assignment), - [array_indexing log2_size_float arr ofs dbg; newval], dbg) - -(* String length *) - -(* Length of string block *) - -let string_length exp dbg = - bind "str" exp (fun str -> - let tmp_var = V.create_local "*tmp*" in - Clet(VP.create tmp_var, - Cop(Csubi, - [Cop(Clsl, - [get_size str dbg; - Cconst_int (log2_size_addr, dbg)], - dbg); - Cconst_int (1, dbg)], - dbg), - Cop(Csubi, - [Cvar tmp_var; - Cop(mk_load_mut Byte_unsigned, - [Cop(Cadda, [str; Cvar tmp_var], dbg)], dbg)], dbg))) - -let bigstring_length ba dbg = - Cop(mk_load_mut Word_int, [field_address ba 5 dbg], dbg) - -(* Message sending *) - -let lookup_tag obj tag dbg = - bind "tag" tag (fun tag -> - Cop(Cextcall("caml_get_public_method", typ_val, false, None), - [obj; tag], - dbg)) - -let lookup_label obj lab dbg = - bind "lab" lab (fun lab -> - let table = Cop (Cloadmut {is_atomic=false}, [obj; Cconst_int (0, dbg)], dbg) in - (* Should this be Cloadmut? *) - addr_array_ref table lab dbg) - -let call_cached_method obj tag cache pos args dbg = - let arity = List.length args in - let cache = array_indexing log2_size_addr cache pos dbg in - Compilenv.need_send_fun arity; - Cop(Capply typ_val, - Cconst_symbol("caml_send" ^ Int.to_string arity, dbg) :: - obj :: tag :: cache :: args, - dbg) - -(* Allocation *) - -let make_alloc_generic set_fn dbg tag wordsize args = - if wordsize <= Config.max_young_wosize then - Cop(Calloc, Cblockheader(block_header tag wordsize, dbg) :: args, dbg) - else begin - let id = V.create_local "*alloc*" in - let rec fill_fields idx = function - [] -> Cvar id - | e1::el -> Csequence(set_fn (Cvar id) (Cconst_int (idx, dbg)) e1 dbg, - fill_fields (idx + 2) el) in - Clet(VP.create id, - Cop(Cextcall("caml_alloc", typ_val, true, None), - [Cconst_int (wordsize, dbg); Cconst_int (tag, dbg)], dbg), - fill_fields 1 args) - end - -let make_alloc dbg tag args = - let addr_array_init arr ofs newval dbg = - Cop(Cextcall("caml_initialize_field", typ_void, false, None), - [arr; untag_int ofs dbg; newval], dbg) - in - make_alloc_generic addr_array_init dbg tag (List.length args) args - -let make_float_alloc dbg tag args = - make_alloc_generic float_array_set dbg tag - (List.length args * size_float / size_addr) args - -(* Bounds checking *) - -let make_checkbound dbg = function - | [Cop(Clsr, [a1; Cconst_int (n, _)], _); Cconst_int (m, _)] - when (m lsl n) > n -> - Cop(Ccheckbound, [a1; Cconst_int(m lsl n + 1 lsl n - 1, dbg)], dbg) - | args -> - Cop(Ccheckbound, args, dbg) - -(* To compile "let rec" over values *) - -let fundecls_size fundecls = - let sz = ref (-1) in - List.iter - (fun f -> - let indirect_call_code_pointer_size = - match f.arity with - | 0 | 1 -> 0 - (* arity 1 does not need an indirect call handler. - arity 0 cannot be indirect called *) - | _ -> 1 - (* For other arities there is an indirect call handler. - if arity >= 2 it is caml_curry... - if arity < 0 it is caml_tuplify... *) - in - sz := !sz + 1 + 2 + indirect_call_code_pointer_size) - fundecls; - !sz + let mut = mut_from_env env ptr in + get_field_gen mut ptr n dbg type rhs_kind = | RHS_block of int @@ -929,6 +130,7 @@ type rhs_kind = | RHS_floatblock of int | RHS_nonrec ;; + let rec expr_size env = function | Uvar id -> begin try V.find_same id env with Not_found -> RHS_nonrec end @@ -974,22 +176,6 @@ let rec expr_size env = function | _ -> assert false) | _ -> RHS_nonrec -(* Record application and currying functions *) - -let apply_function n = - Compilenv.need_apply_fun n; "caml_apply" ^ Int.to_string n -let curry_function n = - Compilenv.need_curry_fun n; - if n >= 0 - then "caml_curry" ^ Int.to_string n - else "caml_tuplify" ^ Int.to_string (-n) - -(* Comparisons *) - -let transl_int_comparison cmp = cmp - -let transl_float_comparison cmp = cmp - (* Translate structured constants to Cmm data items *) let transl_constant dbg = function @@ -1004,105 +190,48 @@ let transl_constant dbg = function | Uconst_ref (label, _) -> Cconst_symbol (label, dbg) -let cdefine_symbol (symb, (global : Cmmgen_state.is_global)) = - match global with - | Global -> [Cglobal_symbol symb; Cdefine_symbol symb] - | Local -> [Cdefine_symbol symb] - -let emit_block symb is_global white_header cont = - (* Headers for structured constants must be marked black in case we - are in no-naked-pointers mode. See [caml_darken]. *) - let black_header = Nativeint.logor white_header caml_black in - Cint black_header :: cdefine_symbol (symb, is_global) @ cont +let emit_constant cst cont = + match cst with + | Uconst_int n | Uconst_ptr n -> + cint_const n + :: cont + | Uconst_ref (sym, _) -> + Csymbol_address sym :: cont -let rec emit_structured_constant (sym, is_global) cst cont = +let emit_structured_constant ((_sym, is_global) as symb) cst cont = match cst with | Uconst_float s -> - emit_block sym is_global float_header (Cdouble s :: cont) + emit_float_constant symb s cont | Uconst_string s -> - emit_block sym is_global (string_header (String.length s)) - (emit_string_constant s cont) + emit_string_constant symb s cont | Uconst_int32 n -> - emit_block sym is_global boxedint32_header - (emit_boxed_int32_constant n cont) + emit_int32_constant symb n cont | Uconst_int64 n -> - emit_block sym is_global boxedint64_header - (emit_boxed_int64_constant n cont) + emit_int64_constant symb n cont | Uconst_nativeint n -> - emit_block sym is_global boxedintnat_header - (emit_boxed_nativeint_constant n cont) + emit_nativeint_constant symb n cont | Uconst_block (tag, csts) -> let cont = List.fold_right emit_constant csts cont in - emit_block sym is_global (block_header tag (List.length csts)) cont + emit_block symb (block_header tag (List.length csts)) cont | Uconst_float_array fields -> - emit_block sym is_global (floatarray_header (List.length fields)) - (Misc.map_end (fun f -> Cdouble f) fields cont) + emit_float_array_constant symb fields cont | Uconst_closure(fundecls, lbl, fv) -> Cmmgen_state.add_constant lbl (Const_closure (is_global, fundecls, fv)); List.iter (fun f -> Cmmgen_state.add_function f) fundecls; cont -and emit_constant cst cont = - match cst with - | Uconst_int n | Uconst_ptr n -> - cint_const n - :: cont - | Uconst_ref (sym, _) -> - Csymbol_address sym :: cont - -and emit_string_constant s cont = - let n = size_int - 1 - (String.length s) mod size_int in - Cstring s :: Cskip n :: Cint8 n :: cont - -and emit_boxed_int32_constant n cont = - let n = Nativeint.of_int32 n in - if size_int = 8 then - Csymbol_address caml_int32_ops :: Cint32 n :: Cint32 0n :: cont - else - Csymbol_address caml_int32_ops :: Cint n :: cont - -and emit_boxed_nativeint_constant n cont = - Csymbol_address caml_nativeint_ops :: Cint n :: cont - -and emit_boxed_int64_constant n cont = - let lo = Int64.to_nativeint n in - if size_int = 8 then - Csymbol_address caml_int64_ops :: Cint lo :: cont - else begin - let hi = Int64.to_nativeint (Int64.shift_right n 32) in - if big_endian then - Csymbol_address caml_int64_ops :: Cint hi :: Cint lo :: cont - else - Csymbol_address caml_int64_ops :: Cint lo :: Cint hi :: cont - end - (* Boxed integers *) let box_int_constant sym bi n = match bi with Pnativeint -> - emit_block sym Local boxedintnat_header - (emit_boxed_nativeint_constant n []) + emit_nativeint_constant (sym, Local) n [] | Pint32 -> let n = Nativeint.to_int32 n in - emit_block sym Local boxedint32_header - (emit_boxed_int32_constant n []) + emit_int32_constant (sym, Local) n [] | Pint64 -> let n = Int64.of_nativeint n in - emit_block sym Local boxedint64_header - (emit_boxed_int64_constant n []) - -let operations_boxed_int bi = - match bi with - Pnativeint -> caml_nativeint_ops - | Pint32 -> caml_int32_ops - | Pint64 -> caml_int64_ops - -let alloc_header_boxed_int bi = - match bi with - Pnativeint -> alloc_boxedintnat_header - | Pint32 -> alloc_boxedint32_header - | Pint64 -> alloc_boxedint64_header + emit_int64_constant (sym, Local) n [] let box_int dbg bi arg = match arg with @@ -1117,96 +246,7 @@ let box_int dbg bi arg = Cmmgen_state.add_data_items data_items; Cconst_symbol (sym, dbg) | _ -> - let arg' = - if bi = Pint32 && size_int = 8 && big_endian - then Cop(Clsl, [arg; Cconst_int (32, dbg)], dbg) - else arg in - Cop(Calloc, [alloc_header_boxed_int bi dbg; - Cconst_symbol(operations_boxed_int bi, dbg); - arg'], dbg) - -let split_int64_for_32bit_target arg dbg = - bind "split_int64" arg (fun arg -> - let first = Cop (Cadda, [Cconst_int (size_int, dbg); arg], dbg) in - let second = Cop (Cadda, [Cconst_int (2 * size_int, dbg); arg], dbg) in - Ctuple [Cop (mk_load_mut Thirtytwo_unsigned, [first], dbg); - Cop (mk_load_mut Thirtytwo_unsigned, [second], dbg)]) - -let alloc_matches_boxed_int bi ~hdr ~ops = - match bi, hdr, ops with - | Pnativeint, Cblockheader (hdr, _dbg), Cconst_symbol (sym, _) -> - Nativeint.equal hdr boxedintnat_header - && String.equal sym caml_nativeint_ops - | Pint32, Cblockheader (hdr, _dbg), Cconst_symbol (sym, _) -> - Nativeint.equal hdr boxedint32_header - && String.equal sym caml_int32_ops - | Pint64, Cblockheader (hdr, _dbg), Cconst_symbol (sym, _) -> - Nativeint.equal hdr boxedint64_header - && String.equal sym caml_int64_ops - | (Pnativeint | Pint32 | Pint64), _, _ -> false - -let unbox_int dbg bi = - let default arg = - if size_int = 4 && bi = Pint64 then - split_int64_for_32bit_target arg dbg - else - let memory_chunk = if bi = Pint32 then Thirtytwo_signed else Word_int - in - Cop( - Cload {memory_chunk; mutability=Immutable; is_atomic=false}, - [Cop(Cadda, [arg; Cconst_int (size_addr, dbg)], dbg)], dbg) - in - map_tail - (function - | Cop(Calloc, - [hdr; ops; - Cop(Clsl, [contents; Cconst_int (32, _)], dbg')], _dbg) - when bi = Pint32 && size_int = 8 && big_endian - && alloc_matches_boxed_int bi ~hdr ~ops -> - (* Force sign-extension of low 32 bits *) - Cop(Casr, [Cop(Clsl, [contents; Cconst_int (32, dbg)], dbg'); - Cconst_int (32, dbg)], - dbg) - | Cop(Calloc, - [hdr; ops; contents], _dbg) - when bi = Pint32 && size_int = 8 && not big_endian - && alloc_matches_boxed_int bi ~hdr ~ops -> - (* Force sign-extension of low 32 bits *) - Cop(Casr, [Cop(Clsl, [contents; Cconst_int (32, dbg)], dbg); - Cconst_int (32, dbg)], - dbg) - | Cop(Calloc, [hdr; ops; contents], _dbg) - when alloc_matches_boxed_int bi ~hdr ~ops -> - contents - | Cconst_symbol (s, _dbg) as cmm -> - begin match structured_constant_of_sym s, bi with - | Some (Uconst_nativeint n), Pnativeint -> - Cconst_natint (n, dbg) - | Some (Uconst_int32 n), Pint32 -> - Cconst_natint (Nativeint.of_int32 n, dbg) - | Some (Uconst_int64 n), Pint64 -> - if size_int = 8 then - Cconst_natint (Int64.to_nativeint n, dbg) - else - let low = Int64.to_nativeint n in - let high = - Int64.to_nativeint (Int64.shift_right_logical n 32) - in - if big_endian then - Ctuple [Cconst_natint (high, dbg); Cconst_natint (low, dbg)] - else - Ctuple [Cconst_natint (low, dbg); Cconst_natint (high, dbg)] - | _ -> - default cmm - end - | cmm -> - default cmm - ) - -let make_unsigned_int bi arg dbg = - if bi = Pint32 && size_int = 8 - then Cop(Cand, [arg; Cconst_natint (0xFFFFFFFFn, dbg)], dbg) - else arg + box_int_gen dbg bi arg (* Boxed numbers *) @@ -1234,657 +274,6 @@ let unbox_number dbg bn arg = | Boxed_float _ -> unbox_float dbg arg | Boxed_integer (bi, _) -> unbox_int dbg bi arg -(* Big arrays *) - -let bigarray_elt_size = function - Pbigarray_unknown -> assert false - | Pbigarray_float32 -> 4 - | Pbigarray_float64 -> 8 - | Pbigarray_sint8 -> 1 - | Pbigarray_uint8 -> 1 - | Pbigarray_sint16 -> 2 - | Pbigarray_uint16 -> 2 - | Pbigarray_int32 -> 4 - | Pbigarray_int64 -> 8 - | Pbigarray_caml_int -> size_int - | Pbigarray_native_int -> size_int - | Pbigarray_complex32 -> 8 - | Pbigarray_complex64 -> 16 - -(* Produces a pointer to the element of the bigarray [b] on the position - [args]. [args] is given as a list of tagged int expressions, one per array - dimension. *) -let bigarray_indexing unsafe elt_kind layout b args dbg = - let check_ba_bound bound idx v = - Csequence(make_checkbound dbg [bound;idx], v) in - (* Validates the given multidimensional offset against the array bounds and - transforms it into a one dimensional offset. The offsets are expressions - evaluating to tagged int. *) - let rec ba_indexing dim_ofs delta_ofs = function - [] -> assert false - | [arg] -> - if unsafe then arg - else - bind "idx" arg (fun idx -> - (* Load the untagged int bound for the given dimension *) - let bound = - Cop(mk_load_mut Word_int,[field_address b dim_ofs dbg], dbg) - in - let idxn = untag_int idx dbg in - check_ba_bound bound idxn idx) - | arg1 :: argl -> - (* The remainder of the list is transformed into a one dimensional offset - *) - let rem = ba_indexing (dim_ofs + delta_ofs) delta_ofs argl in - (* Load the untagged int bound for the given dimension *) - let bound = - Cop(mk_load_mut Word_int, [field_address b dim_ofs dbg], dbg) - in - if unsafe then add_int (mul_int (decr_int rem dbg) bound dbg) arg1 dbg - else - bind "idx" arg1 (fun idx -> - bind "bound" bound (fun bound -> - let idxn = untag_int idx dbg in - (* [offset = rem * (tag_int bound) + idx] *) - let offset = - add_int (mul_int (decr_int rem dbg) bound dbg) idx dbg - in - check_ba_bound bound idxn offset)) in - (* The offset as an expression evaluating to int *) - let offset = - match layout with - Pbigarray_unknown_layout -> - assert false - | Pbigarray_c_layout -> - ba_indexing (4 + List.length args) (-1) (List.rev args) - | Pbigarray_fortran_layout -> - ba_indexing 5 1 - (List.map (fun idx -> sub_int idx (Cconst_int (2, dbg)) dbg) args) - and elt_size = - bigarray_elt_size elt_kind in - (* [array_indexing] can simplify the given expressions *) - array_indexing ~typ:Addr (log2 elt_size) - (Cop(mk_load_mut Word_int, - [field_address b 1 dbg], dbg)) offset dbg - -let bigarray_word_kind = function - Pbigarray_unknown -> assert false - | Pbigarray_float32 -> Single - | Pbigarray_float64 -> Double - | Pbigarray_sint8 -> Byte_signed - | Pbigarray_uint8 -> Byte_unsigned - | Pbigarray_sint16 -> Sixteen_signed - | Pbigarray_uint16 -> Sixteen_unsigned - | Pbigarray_int32 -> Thirtytwo_signed - | Pbigarray_int64 -> Word_int - | Pbigarray_caml_int -> Word_int - | Pbigarray_native_int -> Word_int - | Pbigarray_complex32 -> Single - | Pbigarray_complex64 -> Double - -let bigarray_get unsafe elt_kind layout b args dbg = - bind "ba" b (fun b -> - match elt_kind with - Pbigarray_complex32 | Pbigarray_complex64 -> - let kind = bigarray_word_kind elt_kind in - let sz = bigarray_elt_size elt_kind / 2 in - bind "addr" - (bigarray_indexing unsafe elt_kind layout b args dbg) (fun addr -> - bind "reval" - (Cop(mk_load_mut kind, [addr], dbg)) (fun reval -> - bind "imval" - (Cop(mk_load_mut kind, - [Cop(Cadda, [addr; Cconst_int (sz, dbg)], dbg)], dbg)) - (fun imval -> box_complex dbg reval imval))) - | _ -> - Cop(mk_load_mut (bigarray_word_kind elt_kind), - [bigarray_indexing unsafe elt_kind layout b args dbg], - dbg)) - -let bigarray_set unsafe elt_kind layout b args newval dbg = - bind "ba" b (fun b -> - match elt_kind with - Pbigarray_complex32 | Pbigarray_complex64 -> - let kind = bigarray_word_kind elt_kind in - let sz = bigarray_elt_size elt_kind / 2 in - bind "newval" newval (fun newv -> - bind "addr" (bigarray_indexing unsafe elt_kind layout b args dbg) - (fun addr -> - Csequence( - Cop(Cstore (kind, Assignment), [addr; complex_re newv dbg], dbg), - Cop(Cstore (kind, Assignment), - [Cop(Cadda, [addr; Cconst_int (sz, dbg)], dbg); - complex_im newv dbg], - dbg)))) - | _ -> - Cop(Cstore (bigarray_word_kind elt_kind, Assignment), - [bigarray_indexing unsafe elt_kind layout b args dbg; newval], - dbg)) - -let unaligned_load_16 ptr idx dbg = - if Arch.allow_unaligned_access - then Cop(mk_load_mut Sixteen_unsigned, [add_int ptr idx dbg], dbg) - else - let cconst_int i = Cconst_int (i, dbg) in - let v1 = Cop(mk_load_mut Byte_unsigned, [add_int ptr idx dbg], dbg) in - let v2 = Cop(mk_load_mut Byte_unsigned, - [add_int (add_int ptr idx dbg) (cconst_int 1) dbg], dbg) in - let b1, b2 = if Arch.big_endian then v1, v2 else v2, v1 in - Cop(Cor, [lsl_int b1 (cconst_int 8) dbg; b2], dbg) - -let unaligned_set_16 ptr idx newval dbg = - if Arch.allow_unaligned_access - then - Cop(Cstore (Sixteen_unsigned, Assignment), - [add_int ptr idx dbg; newval], dbg) - else - let cconst_int i = Cconst_int (i, dbg) in - let v1 = - Cop(Cand, [Cop(Clsr, [newval; cconst_int 8], dbg); - cconst_int 0xFF], dbg) - in - let v2 = Cop(Cand, [newval; cconst_int 0xFF], dbg) in - let b1, b2 = if Arch.big_endian then v1, v2 else v2, v1 in - Csequence( - Cop(Cstore (Byte_unsigned, Assignment), [add_int ptr idx dbg; b1], dbg), - Cop(Cstore (Byte_unsigned, Assignment), - [add_int (add_int ptr idx dbg) (cconst_int 1) dbg; b2], dbg)) - -let unaligned_load_32 ptr idx dbg = - if Arch.allow_unaligned_access - then Cop(mk_load_mut Thirtytwo_unsigned, [add_int ptr idx dbg], dbg) - else - let cconst_int i = Cconst_int (i, dbg) in - let v1 = Cop(mk_load_mut Byte_unsigned, [add_int ptr idx dbg], dbg) in - let v2 = Cop(mk_load_mut Byte_unsigned, - [add_int (add_int ptr idx dbg) (cconst_int 1) dbg], dbg) in - let v3 = Cop(mk_load_mut Byte_unsigned, - [add_int (add_int ptr idx dbg) (cconst_int 2) dbg], dbg) in - let v4 = Cop(mk_load_mut Byte_unsigned, - [add_int (add_int ptr idx dbg) (cconst_int 3) dbg], dbg) in - let b1, b2, b3, b4 = - if Arch.big_endian - then v1, v2, v3, v4 - else v4, v3, v2, v1 in - Cop(Cor, - [Cop(Cor, [lsl_int b1 (cconst_int 24) dbg; - lsl_int b2 (cconst_int 16) dbg], dbg); - Cop(Cor, [lsl_int b3 (cconst_int 8) dbg; b4], dbg)], - dbg) - -let unaligned_set_32 ptr idx newval dbg = - if Arch.allow_unaligned_access - then - Cop(Cstore (Thirtytwo_unsigned, Assignment), [add_int ptr idx dbg; newval], - dbg) - else - let cconst_int i = Cconst_int (i, dbg) in - let v1 = - Cop(Cand, [Cop(Clsr, [newval; cconst_int 24], dbg); cconst_int 0xFF], dbg) - in - let v2 = - Cop(Cand, [Cop(Clsr, [newval; cconst_int 16], dbg); cconst_int 0xFF], dbg) - in - let v3 = - Cop(Cand, [Cop(Clsr, [newval; cconst_int 8], dbg); cconst_int 0xFF], dbg) - in - let v4 = Cop(Cand, [newval; cconst_int 0xFF], dbg) in - let b1, b2, b3, b4 = - if Arch.big_endian - then v1, v2, v3, v4 - else v4, v3, v2, v1 in - Csequence( - Csequence( - Cop(Cstore (Byte_unsigned, Assignment), - [add_int ptr idx dbg; b1], dbg), - Cop(Cstore (Byte_unsigned, Assignment), - [add_int (add_int ptr idx dbg) (cconst_int 1) dbg; b2], - dbg)), - Csequence( - Cop(Cstore (Byte_unsigned, Assignment), - [add_int (add_int ptr idx dbg) (cconst_int 2) dbg; b3], - dbg), - Cop(Cstore (Byte_unsigned, Assignment), - [add_int (add_int ptr idx dbg) (cconst_int 3) dbg; b4], - dbg))) - -let unaligned_load_64 ptr idx dbg = - assert(size_int = 8); - if Arch.allow_unaligned_access - then Cop(mk_load_mut Word_int, [add_int ptr idx dbg], dbg) - else - let cconst_int i = Cconst_int (i, dbg) in - let v1 = Cop(mk_load_mut Byte_unsigned, [add_int ptr idx dbg], dbg) in - let v2 = Cop(mk_load_mut Byte_unsigned, - [add_int (add_int ptr idx dbg) (cconst_int 1) dbg], dbg) in - let v3 = Cop(mk_load_mut Byte_unsigned, - [add_int (add_int ptr idx dbg) (cconst_int 2) dbg], dbg) in - let v4 = Cop(mk_load_mut Byte_unsigned, - [add_int (add_int ptr idx dbg) (cconst_int 3) dbg], dbg) in - let v5 = Cop(mk_load_mut Byte_unsigned, - [add_int (add_int ptr idx dbg) (cconst_int 4) dbg], dbg) in - let v6 = Cop(mk_load_mut Byte_unsigned, - [add_int (add_int ptr idx dbg) (cconst_int 5) dbg], dbg) in - let v7 = Cop(mk_load_mut Byte_unsigned, - [add_int (add_int ptr idx dbg) (cconst_int 6) dbg], dbg) in - let v8 = Cop(mk_load_mut Byte_unsigned, - [add_int (add_int ptr idx dbg) (cconst_int 7) dbg], dbg) in - let b1, b2, b3, b4, b5, b6, b7, b8 = - if Arch.big_endian - then v1, v2, v3, v4, v5, v6, v7, v8 - else v8, v7, v6, v5, v4, v3, v2, v1 in - Cop(Cor, - [Cop(Cor, - [Cop(Cor, [lsl_int b1 (cconst_int (8*7)) dbg; - lsl_int b2 (cconst_int (8*6)) dbg], dbg); - Cop(Cor, [lsl_int b3 (cconst_int (8*5)) dbg; - lsl_int b4 (cconst_int (8*4)) dbg], dbg)], - dbg); - Cop(Cor, - [Cop(Cor, [lsl_int b5 (cconst_int (8*3)) dbg; - lsl_int b6 (cconst_int (8*2)) dbg], dbg); - Cop(Cor, [lsl_int b7 (cconst_int 8) dbg; - b8], dbg)], - dbg)], dbg) - -let unaligned_set_64 ptr idx newval dbg = - assert(size_int = 8); - if Arch.allow_unaligned_access - then Cop(Cstore (Word_int, Assignment), [add_int ptr idx dbg; newval], dbg) - else - let cconst_int i = Cconst_int (i, dbg) in - let v1 = - Cop(Cand, [Cop(Clsr, [newval; cconst_int (8*7)], dbg); cconst_int 0xFF], - dbg) - in - let v2 = - Cop(Cand, [Cop(Clsr, [newval; cconst_int (8*6)], dbg); cconst_int 0xFF], - dbg) - in - let v3 = - Cop(Cand, [Cop(Clsr, [newval; cconst_int (8*5)], dbg); cconst_int 0xFF], - dbg) - in - let v4 = - Cop(Cand, [Cop(Clsr, [newval; cconst_int (8*4)], dbg); cconst_int 0xFF], - dbg) - in - let v5 = - Cop(Cand, [Cop(Clsr, [newval; cconst_int (8*3)], dbg); cconst_int 0xFF], - dbg) - in - let v6 = - Cop(Cand, [Cop(Clsr, [newval; cconst_int (8*2)], dbg); cconst_int 0xFF], - dbg) - in - let v7 = - Cop(Cand, [Cop(Clsr, [newval; cconst_int 8], dbg); cconst_int 0xFF], - dbg) - in - let v8 = Cop(Cand, [newval; cconst_int 0xFF], dbg) in - let b1, b2, b3, b4, b5, b6, b7, b8 = - if Arch.big_endian - then v1, v2, v3, v4, v5, v6, v7, v8 - else v8, v7, v6, v5, v4, v3, v2, v1 in - Csequence( - Csequence( - Csequence( - Cop(Cstore (Byte_unsigned, Assignment), - [add_int ptr idx dbg; b1], - dbg), - Cop(Cstore (Byte_unsigned, Assignment), - [add_int (add_int ptr idx dbg) (cconst_int 1) dbg; b2], - dbg)), - Csequence( - Cop(Cstore (Byte_unsigned, Assignment), - [add_int (add_int ptr idx dbg) (cconst_int 2) dbg; b3], - dbg), - Cop(Cstore (Byte_unsigned, Assignment), - [add_int (add_int ptr idx dbg) (cconst_int 3) dbg; b4], - dbg))), - Csequence( - Csequence( - Cop(Cstore (Byte_unsigned, Assignment), - [add_int (add_int ptr idx dbg) (cconst_int 4) dbg; b5], - dbg), - Cop(Cstore (Byte_unsigned, Assignment), - [add_int (add_int ptr idx dbg) (cconst_int 5) dbg; b6], - dbg)), - Csequence( - Cop(Cstore (Byte_unsigned, Assignment), - [add_int (add_int ptr idx dbg) (cconst_int 6) dbg; b7], - dbg), - Cop(Cstore (Byte_unsigned, Assignment), - [add_int (add_int ptr idx dbg) (cconst_int 7) dbg; b8], - dbg)))) - -let max_or_zero a dbg = - bind "size" a (fun a -> - (* equivalent to - Cifthenelse(Cop(Ccmpi Cle, [a; cconst_int 0]), cconst_int 0, a) - - if a is positive, sign is 0 hence sign_negation is full of 1 - so sign_negation&a = a - if a is negative, sign is full of 1 hence sign_negation is 0 - so sign_negation&a = 0 *) - let sign = Cop(Casr, [a; Cconst_int (size_int * 8 - 1, dbg)], dbg) in - let sign_negation = Cop(Cxor, [sign; Cconst_int (-1, dbg)], dbg) in - Cop(Cand, [sign_negation; a], dbg)) - -let check_bound safety access_size dbg length a2 k = - match safety with - | Unsafe -> k - | Safe -> - let offset = - match access_size with - | Sixteen -> 1 - | Thirty_two -> 3 - | Sixty_four -> 7 - in - let a1 = - sub_int length (Cconst_int (offset, dbg)) dbg - in - Csequence(make_checkbound dbg [max_or_zero a1 dbg; a2], k) - -let unaligned_set size ptr idx newval dbg = - match size with - | Sixteen -> unaligned_set_16 ptr idx newval dbg - | Thirty_two -> unaligned_set_32 ptr idx newval dbg - | Sixty_four -> unaligned_set_64 ptr idx newval dbg - -let unaligned_load size ptr idx dbg = - match size with - | Sixteen -> unaligned_load_16 ptr idx dbg - | Thirty_two -> unaligned_load_32 ptr idx dbg - | Sixty_four -> unaligned_load_64 ptr idx dbg - -let box_sized size dbg exp = - match size with - | Sixteen -> tag_int exp dbg - | Thirty_two -> box_int dbg Pint32 exp - | Sixty_four -> box_int dbg Pint64 exp - -(* Simplification of some primitives into C calls *) - -let default_prim name = - Primitive.simple ~name ~arity:0(*ignored*) ~alloc:true - -let int64_native_prim name arity ~alloc = - let u64 = Unboxed_integer Pint64 in - let rec make_args = function 0 -> [] | n -> u64 :: make_args (n - 1) in - Primitive.make ~name ~native_name:(name ^ "_native") - ~alloc - ~native_repr_args:(make_args arity) - ~native_repr_res:u64 - -let simplif_primitive_32bits = function - Pbintofint Pint64 -> Pccall (default_prim "caml_int64_of_int") - | Pintofbint Pint64 -> Pccall (default_prim "caml_int64_to_int") - | Pcvtbint(Pint32, Pint64) -> Pccall (default_prim "caml_int64_of_int32") - | Pcvtbint(Pint64, Pint32) -> Pccall (default_prim "caml_int64_to_int32") - | Pcvtbint(Pnativeint, Pint64) -> - Pccall (default_prim "caml_int64_of_nativeint") - | Pcvtbint(Pint64, Pnativeint) -> - Pccall (default_prim "caml_int64_to_nativeint") - | Pnegbint Pint64 -> Pccall (int64_native_prim "caml_int64_neg" 1 - ~alloc:false) - | Paddbint Pint64 -> Pccall (int64_native_prim "caml_int64_add" 2 - ~alloc:false) - | Psubbint Pint64 -> Pccall (int64_native_prim "caml_int64_sub" 2 - ~alloc:false) - | Pmulbint Pint64 -> Pccall (int64_native_prim "caml_int64_mul" 2 - ~alloc:false) - | Pdivbint {size=Pint64} -> Pccall (int64_native_prim "caml_int64_div" 2 - ~alloc:true) - | Pmodbint {size=Pint64} -> Pccall (int64_native_prim "caml_int64_mod" 2 - ~alloc:true) - | Pandbint Pint64 -> Pccall (int64_native_prim "caml_int64_and" 2 - ~alloc:false) - | Porbint Pint64 -> Pccall (int64_native_prim "caml_int64_or" 2 - ~alloc:false) - | Pxorbint Pint64 -> Pccall (int64_native_prim "caml_int64_xor" 2 - ~alloc:false) - | Plslbint Pint64 -> Pccall (default_prim "caml_int64_shift_left") - | Plsrbint Pint64 -> Pccall (default_prim "caml_int64_shift_right_unsigned") - | Pasrbint Pint64 -> Pccall (default_prim "caml_int64_shift_right") - | Pbintcomp(Pint64, Lambda.Ceq) -> Pccall (default_prim "caml_equal") - | Pbintcomp(Pint64, Lambda.Cne) -> Pccall (default_prim "caml_notequal") - | Pbintcomp(Pint64, Lambda.Clt) -> Pccall (default_prim "caml_lessthan") - | Pbintcomp(Pint64, Lambda.Cgt) -> Pccall (default_prim "caml_greaterthan") - | Pbintcomp(Pint64, Lambda.Cle) -> Pccall (default_prim "caml_lessequal") - | Pbintcomp(Pint64, Lambda.Cge) -> Pccall (default_prim "caml_greaterequal") - | Pbigarrayref(_unsafe, n, Pbigarray_int64, _layout) -> - Pccall (default_prim ("caml_ba_get_" ^ Int.to_string n)) - | Pbigarrayset(_unsafe, n, Pbigarray_int64, _layout) -> - Pccall (default_prim ("caml_ba_set_" ^ Int.to_string n)) - | Pstring_load(Sixty_four, _) -> Pccall (default_prim "caml_string_get64") - | Pbytes_load(Sixty_four, _) -> Pccall (default_prim "caml_bytes_get64") - | Pbytes_set(Sixty_four, _) -> Pccall (default_prim "caml_bytes_set64") - | Pbigstring_load(Sixty_four,_) -> Pccall (default_prim "caml_ba_uint8_get64") - | Pbigstring_set(Sixty_four,_) -> Pccall (default_prim "caml_ba_uint8_set64") - | Pbbswap Pint64 -> Pccall (default_prim "caml_int64_bswap") - | p -> p - -let simplif_primitive p = - match p with - | Pduprecord _ -> - Pccall (default_prim "caml_obj_dup") - | Pbigarrayref(_unsafe, n, Pbigarray_unknown, _layout) -> - Pccall (default_prim ("caml_ba_get_" ^ Int.to_string n)) - | Pbigarrayset(_unsafe, n, Pbigarray_unknown, _layout) -> - Pccall (default_prim ("caml_ba_set_" ^ Int.to_string n)) - | Pbigarrayref(_unsafe, n, _kind, Pbigarray_unknown_layout) -> - Pccall (default_prim ("caml_ba_get_" ^ Int.to_string n)) - | Pbigarrayset(_unsafe, n, _kind, Pbigarray_unknown_layout) -> - Pccall (default_prim ("caml_ba_set_" ^ Int.to_string n)) - | p -> - if size_int = 8 then p else simplif_primitive_32bits p - -(* Build switchers both for constants and blocks *) - -let transl_isout h arg dbg = tag_int (Cop(Ccmpa Clt, [h ; arg], dbg)) dbg - -(* Build an actual switch (ie jump table) *) - -let make_switch arg cases actions dbg = - let extract_uconstant = - function - (* Constant integers loaded from a table should end in 1, - so that Cload never produces untagged integers *) - | Cconst_int (n, _), _dbg - | Cconst_pointer (n, _), _dbg when (n land 1) = 1 -> - Some (Cint (Nativeint.of_int n)) - | Cconst_natint (n, _), _dbg - | Cconst_natpointer (n, _), _dbg - when Nativeint.(to_int (logand n one) = 1) -> - Some (Cint n) - | Cconst_symbol (s,_), _dbg -> - Some (Csymbol_address s) - | _ -> None - in - let extract_affine ~cases ~const_actions = - let length = Array.length cases in - if length >= 2 - then begin - match const_actions.(cases.(0)), const_actions.(cases.(1)) with - | Cint v0, Cint v1 -> - let slope = Nativeint.sub v1 v0 in - let check i = function - | Cint v -> v = Nativeint.(add (mul (of_int i) slope) v0) - | _ -> false - in - if Misc.Stdlib.Array.for_alli - (fun i idx -> check i const_actions.(idx)) cases - then Some (v0, slope) - else None - | _, _ -> - None - end - else None - in - let make_table_lookup ~cases ~const_actions arg dbg = - let table = Compilenv.new_const_symbol () in - Cmmgen_state.add_constant table (Const_table (Local, - Array.to_list (Array.map (fun act -> - const_actions.(act)) cases))); - addr_array_ref (Cconst_symbol (table, dbg)) (tag_int arg dbg) dbg - in - let make_affine_computation ~offset ~slope arg dbg = - (* In case the resulting integers are an affine function of the index, we - don't emit a table, and just compute the result directly *) - add_int - (mul_int arg (natint_const_untagged dbg slope) dbg) - (natint_const_untagged dbg offset) - dbg - in - match Misc.Stdlib.Array.all_somes (Array.map extract_uconstant actions) with - | None -> - Cswitch (arg,cases,actions,dbg) - | Some const_actions -> - match extract_affine ~cases ~const_actions with - | Some (offset, slope) -> - make_affine_computation ~offset ~slope arg dbg - | None -> make_table_lookup ~cases ~const_actions arg dbg - -module SArgBlocks = -struct - type primitive = operation - - let eqint = Ccmpi Ceq - let neint = Ccmpi Cne - let leint = Ccmpi Cle - let ltint = Ccmpi Clt - let geint = Ccmpi Cge - let gtint = Ccmpi Cgt - - type act = expression - - (* CR mshinwell: GPR#2294 will fix the Debuginfo here *) - - let make_const i = Cconst_int (i, Debuginfo.none) - let make_prim p args = Cop (p,args, Debuginfo.none) - let make_offset arg n = add_const arg n Debuginfo.none - let make_isout h arg = Cop (Ccmpa Clt, [h ; arg], Debuginfo.none) - let make_isin h arg = Cop (Ccmpa Cge, [h ; arg], Debuginfo.none) - let make_if cond ifso ifnot = - Cifthenelse (cond, Debuginfo.none, ifso, Debuginfo.none, ifnot, - Debuginfo.none) - let make_switch loc arg cases actions = - let dbg = Debuginfo.from_location loc in - let actions = Array.map (fun expr -> expr, dbg) actions in - make_switch arg cases actions dbg - let bind arg body = bind "switcher" arg body - - let make_catch handler = - match handler with - | Cexit (i,[]) -> i,fun e -> e - | _ -> - let dbg = Debuginfo.none in - let i = next_raise_count () in -(* - Printf.eprintf "SHARE CMM: %i\n" i ; - Printcmm.expression Format.str_formatter handler ; - Printf.eprintf "%s\n" (Format.flush_str_formatter ()) ; -*) - i, - (fun body -> match body with - | Cexit (j,_) -> - if i=j then handler - else body - | _ -> ccatch (i,[],body,handler, dbg)) - - let make_exit i = Cexit (i,[]) - -end - -(* cmm store, as sharing as normally been detected in previous - phases, we only share exits *) -(* Some specific patterns can lead to switches where several cases - point to the same action, but this action is not an exit (see GPR#1370). - The addition of the index in the action array as context allows - sharing them correctly without duplication. *) -module StoreExpForSwitch = - Switch.CtxStore - (struct - type t = expression - type key = int option * int - type context = int - let make_key index expr = - let continuation = - match expr with - | Cexit (i,[]) -> Some i - | _ -> None - in - Some (continuation, index) - let compare_key (cont, index) (cont', index') = - match cont, cont' with - | Some i, Some i' when i = i' -> 0 - | _, _ -> Stdlib.compare index index' - end) - -(* For string switches, we can use a generic store *) -module StoreExp = - Switch.Store - (struct - type t = expression - type key = int - let make_key = function - | Cexit (i,[]) -> Some i - | _ -> None - let compare_key = Stdlib.compare - end) - -module SwitcherBlocks = Switch.Make(SArgBlocks) - -(* Int switcher, arg in [low..high], - cases is list of individual cases, and is sorted by first component *) - -let transl_int_switch loc arg low high cases default = match cases with -| [] -> assert false -| _::_ -> - let store = StoreExp.mk_store () in - assert (store.Switch.act_store () default = 0) ; - let cases = - List.map - (fun (i,act) -> i,store.Switch.act_store () act) - cases in - let rec inters plow phigh pact = function - | [] -> - if phigh = high then [plow,phigh,pact] - else [(plow,phigh,pact); (phigh+1,high,0) ] - | (i,act)::rem -> - if i = phigh+1 then - if pact = act then - inters plow i pact rem - else - (plow,phigh,pact)::inters i i act rem - else (* insert default *) - if pact = 0 then - if act = 0 then - inters plow i 0 rem - else - (plow,i-1,pact):: - inters i i act rem - else (* pact <> 0 *) - (plow,phigh,pact):: - begin - if act = 0 then inters (phigh+1) i 0 rem - else (phigh+1,i-1,0)::inters i i act rem - end in - let inters = match cases with - | [] -> assert false - | (k0,act0)::rem -> - if k0 = low then inters k0 k0 act0 rem - else inters low (k0-1) 0 cases in - bind "switcher" arg - (fun a -> - SwitcherBlocks.zyva - loc - (low,high) - a - (Array.of_list inters) store) - - (* Auxiliary functions for optimizing "let" of boxed numbers (floats and boxed integers *) @@ -1941,7 +330,7 @@ let is_unboxed_number_cmm ~strict cmm = else notify No_unboxing | Cconst_symbol (s, _) -> - begin match structured_constant_of_sym s with + begin match Cmmgen_state.structured_constant_of_sym s with | Some (Uconst_float _) -> notify (Boxed (Boxed_float Debuginfo.none, true)) | Some (Uconst_nativeint _) -> @@ -1960,30 +349,8 @@ let is_unboxed_number_cmm ~strict cmm = aux cmm; !r -(* Helper for compilation of initialization and assignment operations *) - -type assignment_kind = Caml_modify | Caml_initialize | Simple - -let assignment_kind ptr init = - match init, ptr with - | Assignment, Pointer -> Caml_modify - | Heap_initialization, Pointer - | Root_initialization, Pointer -> Caml_initialize - | Assignment, Immediate - | Heap_initialization, Immediate - | Root_initialization, Immediate -> Simple - (* Translate an expression *) -let strmatch_compile = - let module S = - Strmatch.Make - (struct - let string_block_length ptr = get_size ptr Debuginfo.none - let transl_switch = transl_int_switch - end) in - S.compile - let rec transl env e = match e with Uvar id -> @@ -2016,7 +383,7 @@ let rec transl env e = int_const dbg f.arity :: transl_fundecls (pos + 3) rem else - Cconst_symbol (curry_function f.arity, dbg) :: + Cconst_symbol (curry_function_sym f.arity, dbg) :: int_const dbg f.arity :: Cconst_symbol (f.label, dbg) :: transl_fundecls (pos + 4) rem @@ -2034,46 +401,19 @@ let rec transl env e = (* produces a valid Caml value, pointing just after an infix header *) let ptr = transl env arg in let dbg = Debuginfo.none in - if offset = 0 - then ptr - else Cop(Caddv, [ptr; Cconst_int(offset * size_addr, dbg)], dbg) + ptr_offset ptr offset dbg | Udirect_apply(lbl, args, dbg) -> - Cop(Capply typ_val, - Cconst_symbol (lbl, dbg) :: List.map (transl env) args, - dbg) - | Ugeneric_apply(clos, [arg], dbg) -> - bind "fun" (transl env clos) (fun clos -> - Cop(Capply typ_val, - [get_field env clos 0 dbg; transl env arg; clos], - dbg)) + let args = List.map (transl env) args in + direct_apply lbl args dbg | Ugeneric_apply(clos, args, dbg) -> - let arity = List.length args in - let cargs = Cconst_symbol(apply_function arity, dbg) :: - List.map (transl env) (args @ [clos]) in - Cop(Capply typ_val, cargs, dbg) + let clos = transl env clos in + let args = List.map (transl env) args in + generic_apply (mut_from_env env clos) clos args dbg | Usend(kind, met, obj, args, dbg) -> - let call_met obj args clos = - if args = [] then - Cop(Capply typ_val, - [get_field env clos 0 dbg; obj; clos], dbg) - else - let arity = List.length args + 1 in - let cargs = Cconst_symbol(apply_function arity, dbg) :: obj :: - (List.map (transl env) args) @ [clos] in - Cop(Capply typ_val, cargs, dbg) - in - bind "obj" (transl env obj) (fun obj -> - match kind, args with - Self, _ -> - bind "met" (lookup_label obj (transl env met) dbg) - (call_met obj args) - | Cached, cache :: pos :: args -> - call_cached_method obj - (transl env met) (transl env cache) (transl env pos) - (List.map (transl env) args) dbg - | _ -> - bind "met" (lookup_tag obj (transl env met) dbg) - (call_met obj args)) + let met = transl env met in + let obj = transl env obj in + let args = List.map (transl env) args in + send kind met obj args dbg | Ulet(str, kind, id, exp, body) -> transl_let env str kind id exp body | Uphantom_let (var, defining_expr, body) -> @@ -2433,37 +773,19 @@ and transl_prim_1 env p arg dbg = get_field env (transl env arg) n dbg | Pfloatfield n -> let ptr = transl env arg in - box_float dbg ( - Cop(mk_load_mut Double_u, - [if n = 0 then ptr - else Cop(Cadda, [ptr; Cconst_int(n * size_float, dbg)], dbg)], - dbg)) + box_float dbg (floatfield n ptr dbg) | Pint_as_pointer -> - Cop(Caddi, [transl env arg; Cconst_int (-1, dbg)], dbg) - (* always a pointer outside the heap *) - | Ppoll -> - Cop(Cpoll, [transl env arg], dbg) + int_as_pointer (transl env arg) dbg (* Exceptions *) - | Praise _ when not (!Clflags.debug) -> - Cop(Craise Lambda.Raise_notrace, [transl env arg], dbg) - | Praise raise_kind -> - Cop(Craise raise_kind, [transl env arg], dbg) + | Praise rkind -> + raise_prim rkind (transl env arg) dbg (* Integer operations *) | Pnegint -> - Cop(Csubi, [Cconst_int (2, dbg); transl env arg], dbg) + negint (transl env arg) dbg | Poffsetint n -> - if no_overflow_lsl n 1 then - add_const (transl env arg) (n lsl 1) dbg - else - transl_prim_2 env Paddint arg (Uconst (Uconst_int n)) dbg + offsetint n (transl env arg) dbg | Poffsetref n -> - return_unit dbg - (bind "ref" (transl env arg) (fun arg -> - Cop(Cstore (Word_int, Assignment), - [arg; - add_const (Cop(mk_load_mut Word_int, [arg], dbg)) - (n lsl 1) dbg], - dbg))) + offsetref n (transl env arg) dbg (* Floating-point operations *) | Pfloatofint -> box_float dbg (Cop(Cfloatofint, [untag_int(transl env arg) dbg], dbg)) @@ -2478,29 +800,7 @@ and transl_prim_1 env p arg dbg = tag_int(string_length (transl env arg) dbg) dbg (* Array operations *) | Parraylength kind -> - let hdr = get_header_without_profinfo (transl env arg) dbg in - begin match kind with - Pgenarray -> - let len = - if wordsize_shift = numfloat_shift then - Cop(Clsr, [hdr; Cconst_int (wordsize_shift, dbg)], dbg) - else - bind "header" hdr (fun hdr -> - Cifthenelse(is_addr_array_hdr hdr dbg, - dbg, - Cop(Clsr, - [hdr; Cconst_int (wordsize_shift, dbg)], dbg), - dbg, - Cop(Clsr, - [hdr; Cconst_int (numfloat_shift, dbg)], dbg), - dbg)) - in - Cop(Cor, [len; Cconst_int (1, dbg)], dbg) - | Paddrarray | Pintarray -> - Cop(Cor, [addr_array_length hdr dbg; Cconst_int (1, dbg)], dbg) - | Pfloatarray -> - Cop(Cor, [float_array_length hdr dbg; Cconst_int (1, dbg)], dbg) - end + arraylength kind (transl env arg) dbg (* Boolean operations *) | Pnot -> transl_if env Then_false_else_true @@ -2522,25 +822,22 @@ and transl_prim_1 env p arg dbg = (Cop(Csubi, [Cconst_int (0, dbg); transl_unbox_int dbg env bi arg], dbg)) | Pbbswap bi -> - let prim = match bi with - | Pnativeint -> "nativeint" - | Pint32 -> "int32" - | Pint64 -> "int64" in - box_int dbg bi (Cop(Cextcall(Printf.sprintf "caml_%s_direct_bswap" prim, - typ_int, false, None), - [transl_unbox_int dbg env bi arg], - dbg)) + box_int dbg bi (bbswap bi (transl_unbox_int dbg env bi arg) dbg) | Pbswap16 -> - tag_int (Cop(Cextcall("caml_bswap16_direct", typ_int, false, None), - [untag_int (transl env arg) dbg], - dbg)) - dbg + tag_int (bswap16 (untag_int (transl env arg) dbg) dbg) dbg + | Ppoll -> + Cop(Cpoll, [transl env arg], dbg) | Patomic_load {immediate_or_pointer} -> let ptr = transl env arg in ( match immediate_or_pointer with - | Immediate -> Cop (Cload {memory_chunk=Word_int ; mutability=Mutable ; is_atomic=true} , [ptr], dbg) - | Pointer -> Cop (Cloadmut {is_atomic=true}, [ptr; Cconst_int (0, dbg)], dbg) ) + | Immediate -> + Cop (Cload {memory_chunk=Word_int ; + mutability=Mutable ; is_atomic=true}, + [ptr], dbg) + | Pointer -> + Cop (Cloadmut {is_atomic=true}, + [ptr; Cconst_int (0, dbg)], dbg)) | (Pfield_computed | Psequand | Psequor | Prunstack | Pperform | Presume | Preperform | Patomic_exchange | Patomic_cas | Patomic_fetch_add @@ -2569,27 +866,11 @@ and transl_prim_2 env p arg1 arg2 dbg = | Pfield_computed -> addr_array_ref (transl env arg1) (transl env arg2) dbg | Psetfield(n, ptr, init) -> - begin match assignment_kind ptr init with - | Caml_modify -> - return_unit dbg (Cop(Cextcall("caml_modify_field_asm", typ_void, false, None), - [transl env arg1; Cconst_int (n, dbg); transl env arg2], - dbg)) - | Caml_initialize -> - return_unit dbg (Cop(Cextcall("caml_initialize_field", typ_void, false, None), - [transl env arg1; Cconst_int (n, dbg); transl env arg2], - dbg)) - | Simple -> - return_unit dbg - (set_field (transl env arg1) n (transl env arg2) init dbg) - end + setfield n ptr init (transl env arg1) (transl env arg2) dbg | Psetfloatfield (n, init) -> let ptr = transl env arg1 in - return_unit dbg ( - Cop(Cstore (Double_u, init), - [if n = 0 then ptr - else - Cop(Cadda, [ptr; Cconst_int(n * size_float, dbg)], dbg); - transl_unbox_float dbg env arg2], dbg)) + let float_val = transl_unbox_float dbg env arg2 in + setfloatfield n init ptr float_val dbg (* Boolean operations *) | Psequand -> @@ -2611,50 +892,29 @@ and transl_prim_2 env p arg1 arg2 dbg = dbg' (Cconst_pointer (1, dbg)) (* Integer operations *) | Paddint -> - decr_int(add_int (transl env arg1) (transl env arg2) dbg) dbg + add_int_caml (transl env arg1) (transl env arg2) dbg | Psubint -> - incr_int(sub_int (transl env arg1) (transl env arg2) dbg) dbg + sub_int_caml (transl env arg1) (transl env arg2) dbg | Pmulint -> - begin - (* decrementing the non-constant part helps when the multiplication is - followed by an addition; - for example, using this trick compiles (100 * a + 7) into - (+ ( * a 100) -85) - rather than - (+ ( * 200 (>>s a 1)) 15) - *) - match transl env arg1, transl env arg2 with - | Cconst_int _ as c1, c2 -> - incr_int (mul_int (untag_int c1 dbg) (decr_int c2 dbg) dbg) dbg - | c1, c2 -> - incr_int (mul_int (decr_int c1 dbg) (untag_int c2 dbg) dbg) dbg - end + mul_int_caml (transl env arg1) (transl env arg2) dbg | Pdivint is_safe -> - tag_int(div_int (untag_int(transl env arg1) dbg) - (untag_int(transl env arg2) dbg) is_safe dbg) dbg + div_int_caml is_safe (transl env arg1) (transl env arg2) dbg | Pmodint is_safe -> - tag_int(mod_int (untag_int(transl env arg1) dbg) - (untag_int(transl env arg2) dbg) is_safe dbg) dbg + mod_int_caml is_safe (transl env arg1) (transl env arg2) dbg | Pandint -> - Cop(Cand, [transl env arg1; transl env arg2], dbg) + and_int_caml (transl env arg1) (transl env arg2) dbg | Porint -> - Cop(Cor, [transl env arg1; transl env arg2], dbg) + or_int_caml (transl env arg1) (transl env arg2) dbg | Pxorint -> - Cop(Cor, [Cop(Cxor, [ignore_low_bit_int(transl env arg1); - ignore_low_bit_int(transl env arg2)], dbg); - Cconst_int (1, dbg)], dbg) + xor_int_caml (transl env arg1) (transl env arg2) dbg | Plslint -> - incr_int(lsl_int (decr_int(transl env arg1) dbg) - (untag_int(transl env arg2) dbg) dbg) dbg + lsl_int_caml (transl env arg1) (transl env arg2) dbg | Plsrint -> - Cop(Cor, [lsr_int (transl env arg1) (untag_int(transl env arg2) dbg) dbg; - Cconst_int (1, dbg)], dbg) + lsr_int_caml (transl env arg1) (transl env arg2) dbg | Pasrint -> - Cop(Cor, [asr_int (transl env arg1) (untag_int(transl env arg2) dbg) dbg; - Cconst_int (1, dbg)], dbg) + asr_int_caml (transl env arg1) (transl env arg2) dbg | Pintcomp cmp -> - tag_int(Cop(Ccmpi(transl_int_comparison cmp), - [transl env arg1; transl env arg2], dbg)) dbg + int_comp_caml cmp (transl env arg1) (transl env arg2) dbg | Pisout -> transl_isout (transl env arg1) (transl env arg2) dbg (* Float operations *) @@ -2679,110 +939,26 @@ and transl_prim_2 env p arg1 arg2 dbg = transl_unbox_float dbg env arg2], dbg)) | Pfloatcomp cmp -> - tag_int(Cop(Ccmpf(transl_float_comparison cmp), + tag_int(Cop(Ccmpf cmp, [transl_unbox_float dbg env arg1; transl_unbox_float dbg env arg2], dbg)) dbg (* String operations *) | Pstringrefu | Pbytesrefu -> - tag_int(Cop(mk_load_mut Byte_unsigned, - [add_int (transl env arg1) (untag_int(transl env arg2) dbg) - dbg], - dbg)) dbg + stringref_unsafe (transl env arg1) (transl env arg2) dbg | Pstringrefs | Pbytesrefs -> - tag_int - (bind "str" (transl env arg1) (fun str -> - bind "index" (untag_int (transl env arg2) dbg) (fun idx -> - Csequence( - make_checkbound dbg [string_length str dbg; idx], - Cop(mk_load_mut Byte_unsigned, - [add_int str idx dbg], dbg))))) dbg - + stringref_safe (transl env arg1) (transl env arg2) dbg | Pstring_load(size, unsafe) | Pbytes_load(size, unsafe) -> - box_sized size dbg - (bind "str" (transl env arg1) (fun str -> - bind "index" (untag_int (transl env arg2) dbg) (fun idx -> - check_bound unsafe size dbg - (string_length str dbg) - idx (unaligned_load size str idx dbg)))) - + string_load size unsafe (transl env arg1) (transl env arg2) dbg | Pbigstring_load(size, unsafe) -> - box_sized size dbg - (bind "ba" (transl env arg1) (fun ba -> - bind "index" (untag_int (transl env arg2) dbg) (fun idx -> - bind "ba_data" - (Cop(mk_load_mut Word_int, [field_address ba 1 dbg], dbg)) - (fun ba_data -> - check_bound unsafe size dbg - (bigstring_length ba dbg) - idx - (unaligned_load size ba_data idx dbg))))) + bigstring_load size unsafe (transl env arg1) (transl env arg2) dbg (* Array operations *) | Parrayrefu kind -> - begin match kind with - Pgenarray -> - bind "arr" (transl env arg1) (fun arr -> - bind "index" (transl env arg2) (fun idx -> - Cifthenelse(is_addr_array_ptr arr dbg, - dbg, - addr_array_ref arr idx dbg, - dbg, - float_array_ref dbg arr idx, - dbg))) - | Paddrarray -> - addr_array_ref (transl env arg1) (transl env arg2) dbg - | Pintarray -> - (* CR mshinwell: for int/addr_array_ref move "dbg" to first arg *) - int_array_ref (transl env arg1) (transl env arg2) dbg - | Pfloatarray -> - float_array_ref dbg (transl env arg1) (transl env arg2) - end + arrayref_unsafe kind (transl env arg1) (transl env arg2) dbg | Parrayrefs kind -> - begin match kind with - | Pgenarray -> - bind "index" (transl env arg2) (fun idx -> - bind "arr" (transl env arg1) (fun arr -> - bind "header" (get_header_without_profinfo arr dbg) (fun hdr -> - if wordsize_shift = numfloat_shift then - Csequence(make_checkbound dbg [addr_array_length hdr dbg; idx], - Cifthenelse(is_addr_array_hdr hdr dbg, - dbg, - addr_array_ref arr idx dbg, - dbg, - float_array_ref dbg arr idx, - dbg)) - else - Cifthenelse(is_addr_array_hdr hdr dbg, - dbg, - Csequence(make_checkbound dbg [addr_array_length hdr dbg; idx], - addr_array_ref arr idx dbg), - dbg, - Csequence(make_checkbound dbg [float_array_length hdr dbg; idx], - float_array_ref dbg arr idx), - dbg)))) - | Paddrarray -> - bind "index" (transl env arg2) (fun idx -> - bind "arr" (transl env arg1) (fun arr -> - Csequence(make_checkbound dbg [ - addr_array_length(get_header_without_profinfo arr dbg) dbg; idx], - addr_array_ref arr idx dbg))) - | Pintarray -> - bind "index" (transl env arg2) (fun idx -> - bind "arr" (transl env arg1) (fun arr -> - Csequence(make_checkbound dbg [ - addr_array_length(get_header_without_profinfo arr dbg) dbg; idx], - int_array_ref arr idx dbg))) - | Pfloatarray -> - box_float dbg ( - bind "index" (transl env arg2) (fun idx -> - bind "arr" (transl env arg1) (fun arr -> - Csequence(make_checkbound dbg - [float_array_length(get_header_without_profinfo arr dbg) dbg; - idx], - unboxed_float_array_ref arr idx dbg)))) - end + arrayref_safe kind (transl env arg1) (transl env arg2) dbg (* Boxed integers *) | Paddbint bi -> @@ -2833,7 +1009,7 @@ and transl_prim_2 env p arg1 arg2 dbg = [transl_unbox_int dbg env bi arg1; untag_int(transl env arg2) dbg], dbg)) | Pbintcomp(bi, cmp) -> - tag_int (Cop(Ccmpi(transl_int_comparison cmp), + tag_int (Cop(Ccmpi cmp, [transl_unbox_int dbg env bi arg1; transl_unbox_int dbg env bi arg2], dbg)) dbg | Patomic_exchange -> @@ -2861,130 +1037,39 @@ and transl_prim_3 env p arg1 arg2 arg3 dbg = match p with (* Heap operations *) | Psetfield_computed(ptr, init) -> - begin match assignment_kind ptr init with - | Caml_modify -> - return_unit dbg ( - addr_array_set (transl env arg1) (transl env arg2) (transl env arg3) - dbg) - | Caml_initialize -> - return_unit dbg ( - addr_array_initialize (transl env arg1) (transl env arg2) - (transl env arg3) dbg) - | Simple -> - return_unit dbg ( - int_array_set (transl env arg1) (transl env arg2) (transl env arg3) - dbg) - end + setfield_computed ptr init + (transl env arg1) (transl env arg2) (transl env arg3) dbg (* String operations *) | Pbytessetu -> - return_unit dbg (Cop(Cstore (Byte_unsigned, Assignment), - [add_int (transl env arg1) - (untag_int(transl env arg2) dbg) - dbg; - untag_int(transl env arg3) dbg], dbg)) + bytesset_unsafe + (transl env arg1) (transl env arg2) (transl env arg3) dbg | Pbytessets -> - return_unit dbg - (bind "str" (transl env arg1) (fun str -> - bind "index" (untag_int (transl env arg2) dbg) (fun idx -> - Csequence( - make_checkbound dbg [string_length str dbg; idx], - Cop(Cstore (Byte_unsigned, Assignment), - [add_int str idx dbg; untag_int(transl env arg3) dbg], - dbg))))) + bytesset_safe + (transl env arg1) (transl env arg2) (transl env arg3) dbg (* Array operations *) | Parraysetu kind -> - return_unit dbg (begin match kind with - Pgenarray -> - bind "newval" (transl env arg3) (fun newval -> - bind "index" (transl env arg2) (fun index -> - bind "arr" (transl env arg1) (fun arr -> - Cifthenelse(is_addr_array_ptr arr dbg, - dbg, - addr_array_set arr index newval dbg, - dbg, - float_array_set arr index (unbox_float dbg newval) - dbg, - dbg)))) - | Paddrarray -> - addr_array_set (transl env arg1) (transl env arg2) (transl env arg3) - dbg - | Pintarray -> - int_array_set (transl env arg1) (transl env arg2) (transl env arg3) - dbg - | Pfloatarray -> - float_array_set (transl env arg1) (transl env arg2) - (transl_unbox_float dbg env arg3) - dbg - end) + let newval = + match kind with + | Pfloatarray -> transl_unbox_float dbg env arg3 + | _ -> transl env arg3 + in + arrayset_unsafe kind (transl env arg1) (transl env arg2) newval dbg | Parraysets kind -> - return_unit dbg (begin match kind with - | Pgenarray -> - bind "newval" (transl env arg3) (fun newval -> - bind "index" (transl env arg2) (fun idx -> - bind "arr" (transl env arg1) (fun arr -> - bind "header" (get_header_without_profinfo arr dbg) (fun hdr -> - if wordsize_shift = numfloat_shift then - Csequence(make_checkbound dbg [addr_array_length hdr dbg; idx], - Cifthenelse(is_addr_array_hdr hdr dbg, - dbg, - addr_array_set arr idx newval dbg, - dbg, - float_array_set arr idx - (unbox_float dbg newval) - dbg, - dbg)) - else - Cifthenelse(is_addr_array_hdr hdr dbg, - dbg, - Csequence(make_checkbound dbg [addr_array_length hdr dbg; idx], - addr_array_set arr idx newval dbg), - dbg, - Csequence(make_checkbound dbg [float_array_length hdr dbg; idx], - float_array_set arr idx - (unbox_float dbg newval) dbg), - dbg))))) - | Paddrarray -> - bind "newval" (transl env arg3) (fun newval -> - bind "index" (transl env arg2) (fun idx -> - bind "arr" (transl env arg1) (fun arr -> - Csequence(make_checkbound dbg [ - addr_array_length(get_header_without_profinfo arr dbg) dbg; idx], - addr_array_set arr idx newval dbg)))) - | Pintarray -> - bind "newval" (transl env arg3) (fun newval -> - bind "index" (transl env arg2) (fun idx -> - bind "arr" (transl env arg1) (fun arr -> - Csequence(make_checkbound dbg [ - addr_array_length(get_header_without_profinfo arr dbg) dbg; idx], - int_array_set arr idx newval dbg)))) - | Pfloatarray -> - bind_load "newval" (transl_unbox_float dbg env arg3) (fun newval -> - bind "index" (transl env arg2) (fun idx -> - bind "arr" (transl env arg1) (fun arr -> - Csequence(make_checkbound dbg [ - float_array_length (get_header_without_profinfo arr dbg) dbg;idx], - float_array_set arr idx newval dbg)))) - end) + let newval = + match kind with + | Pfloatarray -> transl_unbox_float dbg env arg3 + | _ -> transl env arg3 + in + arrayset_safe kind (transl env arg1) (transl env arg2) newval dbg | Pbytes_set(size, unsafe) -> - return_unit dbg - (bind "str" (transl env arg1) (fun str -> - bind "index" (untag_int (transl env arg2) dbg) (fun idx -> - bind "newval" (transl_unbox_sized size dbg env arg3) (fun newval -> - check_bound unsafe size dbg (string_length str dbg) - idx (unaligned_set size str idx newval dbg))))) + bytes_set size unsafe (transl env arg1) (transl env arg2) + (transl_unbox_sized size dbg env arg3) dbg | Pbigstring_set(size, unsafe) -> - return_unit dbg - (bind "ba" (transl env arg1) (fun ba -> - bind "index" (untag_int (transl env arg2) dbg) (fun idx -> - bind "newval" (transl_unbox_sized size dbg env arg3) (fun newval -> - bind "ba_data" - (Cop(mk_load_mut Word_int, [field_address ba 1 dbg], dbg)) - (fun ba_data -> - check_bound unsafe size dbg (bigstring_length ba dbg) - idx (unaligned_set size ba_data idx newval dbg)))))) + bigstring_set size unsafe (transl env arg1) (transl env arg2) + (transl_unbox_sized size dbg env arg3) dbg | Patomic_cas -> Cop (Cextcall ("caml_atomic_cas", typ_int, false, None), @@ -3206,38 +1291,7 @@ and transl_switch loc env arg index cases = match Array.length cases with | 1 -> transl env cases.(0) | _ -> let cases = Array.map (transl env) cases in - let store = StoreExpForSwitch.mk_store () in - let index = - Array.map - (fun j -> store.Switch.act_store j cases.(j)) - index in - let n_index = Array.length index in - let inters = ref [] - and this_high = ref (n_index-1) - and this_low = ref (n_index-1) - and this_act = ref index.(n_index-1) in - for i = n_index-2 downto 0 do - let act = index.(i) in - if act = !this_act then - decr this_low - else begin - inters := (!this_low, !this_high, !this_act) :: !inters ; - this_high := i ; - this_low := i ; - this_act := act - end - done ; - inters := (0, !this_high, !this_act) :: !inters ; - match !inters with - | [_] -> cases.(0) - | inters -> - bind "switcher" arg - (fun a -> - SwitcherBlocks.zyva - loc - (0,n_index-1) - a - (Array.of_list inters) store) + transl_switch_clambda loc arg index cases and transl_letrec env bindings cont = let dbg = Debuginfo.none in @@ -3316,55 +1370,6 @@ let rec transl_all_functions already_translated cont = ((f.dbg, transl_function f) :: cont) end -(* Emit constant closures *) - -let emit_constant_closure ((_, global_symb) as symb) fundecls clos_vars cont = - let closure_symbol f = - if Config.flambda then - cdefine_symbol (f.label ^ "_closure", global_symb) - else - [] - in - match fundecls with - [] -> - (* This should probably not happen: dead code has normally been - eliminated and a closure cannot be accessed without going through - a [Project_closure], which depends on the function. *) - assert (clos_vars = []); - cdefine_symbol symb @ - List.fold_right emit_constant clos_vars cont - | f1 :: remainder -> - let rec emit_others pos = function - [] -> - List.fold_right emit_constant clos_vars cont - | f2 :: rem -> - if f2.arity = 1 || f2.arity = 0 then - Cint(infix_header pos) :: - (closure_symbol f2) @ - Csymbol_address f2.label :: - cint_const f2.arity :: - emit_others (pos + 3) rem - else - Cint(infix_header pos) :: - (closure_symbol f2) @ - Csymbol_address(curry_function f2.arity) :: - cint_const f2.arity :: - Csymbol_address f2.label :: - emit_others (pos + 4) rem in - Cint(black_closure_header (fundecls_size fundecls - + List.length clos_vars)) :: - cdefine_symbol symb @ - (closure_symbol f1) @ - if f1.arity = 1 || f1.arity = 0 then - Csymbol_address f1.label :: - cint_const f1.arity :: - emit_others 3 remainder - else - Csymbol_address(curry_function f1.arity) :: - cint_const f1.arity :: - Csymbol_address f1.label :: - emit_others 4 remainder - (* Emit constant blocks *) let emit_constant_table symb elems = @@ -3395,7 +1400,8 @@ let emit_cmm_data_items_for_constants cont = match cst with | Const_closure (global, fundecls, clos_vars) -> let cmm = - emit_constant_closure (symbol, global) fundecls clos_vars [] + emit_constant_closure (symbol, global) fundecls + (List.fold_right emit_constant clos_vars []) [] in c := (Cdata cmm) :: !c | Const_table (global, elems) -> @@ -3424,53 +1430,6 @@ let transl_all_functions cont = in translated_functions @ cont -(* Build the NULL terminated array of gc roots *) - -let emit_gc_roots_table ~symbols cont = - let table_symbol = Compilenv.make_symbol (Some "gc_roots") in - Cdata(Cglobal_symbol table_symbol :: - Cdefine_symbol table_symbol :: - List.map (fun s -> Csymbol_address s) symbols @ - [Cint 0n]) - :: cont - -(* Build preallocated blocks (used for Flambda [Initialize_symbol] - constructs, and Clambda global module) *) - -let preallocate_block cont { Clambda.symbol; exported; tag; fields } = - let space = - (* These words will be registered as roots and as such must contain - valid values, in case we are in no-naked-pointers mode. Likewise - the block header must be black, below (see [caml_darken]), since - the overall record may be referenced. *) - List.map (fun field -> - match field with - | None -> - Cint (Nativeint.of_int 1 (* Val_unit *)) - | Some (Uconst_field_int n) -> - cint_const n - | Some (Uconst_field_ref label) -> - Csymbol_address label) - fields - in - let data = - Cint(black_block_header tag (List.length fields)) :: - if exported then - Cglobal_symbol symbol :: - Cdefine_symbol symbol :: space - else - Cdefine_symbol symbol :: space - in - Cdata data :: cont - -let emit_preallocated_blocks preallocated_blocks cont = - let symbols = - List.map (fun ({ Clambda.symbol }:Clambda.preallocated_block) -> symbol) - preallocated_blocks - in - let c1 = emit_gc_roots_table ~symbols cont in - List.fold_left preallocate_block c1 preallocated_blocks - (* Translate a compilation unit *) let compunit (ulam, preallocated_blocks, constants) = @@ -3501,499 +1460,3 @@ let compunit (ulam, preallocated_blocks, constants) = Cmmgen_state.set_structured_constants []; let c4 = emit_preallocated_blocks preallocated_blocks c3 in emit_cmm_data_items_for_constants c4 - -(* -CAMLprim value caml_cache_public_method (value meths, value tag, value *cache) -{ - int li = 3, hi = Field_imm(meths,0), mi; - while (li < hi) { // no need to check the 1st time - mi = ((li+hi) >> 1) | 1; - if (tag < Field_imm(meths,mi)) hi = mi-2; - else li = mi; - } - *cache = (li-3)*sizeof(value)+1; - return Field_imm (meths, li-1); -} -*) - -let cache_public_method meths tag cache dbg = - let raise_num = next_raise_count () in - let cconst_int i = Cconst_int (i, dbg) in - let li = V.create_local "*li*" and hi = V.create_local "*hi*" - and mi = V.create_local "*mi*" and tagged = V.create_local "*tagged*" in - Clet ( - VP.create li, cconst_int 3, - Clet ( - VP.create hi, Cop(mk_load_mut Word_int, [meths], dbg), - Csequence( - ccatch - (raise_num, [], - create_loop - (Clet( - VP.create mi, - Cop(Cor, - [Cop(Clsr, [Cop(Caddi, [Cvar li; Cvar hi], dbg); cconst_int 1], - dbg); - cconst_int 1], - dbg), - Csequence( - Cifthenelse - (Cop (Ccmpi Clt, - [tag; - Cop(mk_load_mut Word_int, - [Cop(Cadda, - [meths; lsl_const (Cvar mi) log2_size_addr dbg], - dbg)], - dbg)], dbg), - dbg, Cassign(hi, Cop(Csubi, [Cvar mi; cconst_int 2], dbg)), - dbg, Cassign(li, Cvar mi), - dbg), - Cifthenelse - (Cop(Ccmpi Cge, [Cvar li; Cvar hi], dbg), - dbg, Cexit (raise_num, []), - dbg, Ctuple [], - dbg)))) - dbg, - Ctuple [], - dbg), - Clet ( - VP.create tagged, - Cop(Cadda, [lsl_const (Cvar li) log2_size_addr dbg; - cconst_int(1 - 3 * size_addr)], dbg), - Csequence(Cop (Cstore (Word_int, Assignment), [cache; Cvar tagged], dbg), - Cvar tagged))))) - -(* CR mshinwell: These will be filled in by later pull requests. *) -let placeholder_dbg () = Debuginfo.none -let placeholder_fun_dbg ~human_name:_ = Debuginfo.none - -(* Generate an application function: - (defun caml_applyN (a1 ... aN clos) - (if (= clos.arity N) - (app clos.direct a1 ... aN clos) - (let (clos1 (app clos.code a1 clos) - clos2 (app clos1.code a2 clos) - ... - closN-1 (app closN-2.code aN-1 closN-2)) - (app closN-1.code aN closN-1)))) -*) - -let apply_function_body arity = - let dbg = placeholder_dbg in - let arg = Array.make arity (V.create_local "arg") in - for i = 1 to arity - 1 do arg.(i) <- V.create_local "arg" done; - let clos = V.create_local "clos" in - let env = empty_env in - let rec app_fun clos n = - if n = arity-1 then - Cop(Capply typ_val, - [get_field env (Cvar clos) 0 (dbg ()); Cvar arg.(n); Cvar clos], - dbg ()) - else begin - let newclos = V.create_local "clos" in - Clet(VP.create newclos, - Cop(Capply typ_val, - [get_field env (Cvar clos) 0 (dbg ()); Cvar arg.(n); Cvar clos], - dbg ()), - app_fun newclos (n+1)) - end in - let args = Array.to_list arg in - let all_args = args @ [clos] in - (args, clos, - if arity = 1 then app_fun clos 0 else - Cifthenelse( - Cop(Ccmpi Ceq, - [get_field env (Cvar clos) 1 (dbg ()); int_const (dbg ()) arity], dbg ()), - dbg (), - Cop(Capply typ_val, - get_field env (Cvar clos) 2 (dbg ()) - :: List.map (fun s -> Cvar s) all_args, - dbg ()), - dbg (), - app_fun clos 0, - dbg ())) - -let send_function arity = - let dbg = placeholder_dbg in - let cconst_int i = Cconst_int (i, dbg ()) in - let (args, clos', body) = apply_function_body (1+arity) in - let cache = V.create_local "cache" - and obj = List.hd args - and tag = V.create_local "tag" in - let clos = - let cache = Cvar cache and obj = Cvar obj and tag = Cvar tag in - let meths = V.create_local "meths" and cached = V.create_local "cached" in - let real = V.create_local "real" in - let mask = get_mut_field (Cvar meths) (cconst_int (1)) (dbg ()) in - let cached_pos = Cvar cached in - let tag_pos = Cop(Cadda, [Cop (Cadda, [cached_pos; Cvar meths], dbg ()); - cconst_int(3*size_addr-1)], dbg ()) in - let tag' = Cop(mk_load_mut Word_int, [tag_pos], dbg ()) in - Clet ( - VP.create meths, get_mut_field obj (cconst_int (0)) (dbg ()), - Clet ( - VP.create cached, - Cop(Cand, [Cop(mk_load_mut Word_int, [cache], dbg ()); mask], - dbg ()), - Clet ( - VP.create real, - Cifthenelse(Cop(Ccmpa Cne, [tag'; tag], dbg ()), - dbg (), - cache_public_method (Cvar meths) tag cache (dbg ()), - dbg (), - cached_pos, - dbg ()), - get_mut_field - (Cvar meths) - (Cop(Casr, [Cop (Cadda, [Cvar real; - cconst_int (2*size_addr - 1)], dbg ()); - cconst_int log2_size_addr], dbg ())) (dbg ())))) - in - let body = Clet(VP.create clos', clos, body) in - let cache = cache in - let fun_name = "caml_send" ^ Int.to_string arity in - let fun_args = - [obj, typ_val; tag, typ_int; cache, typ_val] - @ List.map (fun id -> (id, typ_val)) (List.tl args) in - let fun_dbg = placeholder_fun_dbg ~human_name:fun_name in - Cfunction - {fun_name; - fun_args = List.map (fun (arg, ty) -> VP.create arg, ty) fun_args; - fun_body = body; - fun_codegen_options = []; - fun_dbg; - } - -let apply_function arity = - let (args, clos, body) = apply_function_body arity in - let all_args = args @ [clos] in - let fun_name = "caml_apply" ^ Int.to_string arity in - let fun_dbg = placeholder_fun_dbg ~human_name:fun_name in - Cfunction - {fun_name; - fun_args = List.map (fun arg -> (VP.create arg, typ_val)) all_args; - fun_body = body; - fun_codegen_options = []; - fun_dbg; - } - -(* Generate tuplifying functions: - (defun caml_tuplifyN (arg clos) - (app clos.direct #0(arg) ... #N-1(arg) clos)) *) - -let tuplify_function arity = - let dbg = placeholder_dbg in - let arg = V.create_local "arg" in - let clos = V.create_local "clos" in - let env = empty_env in - let rec access_components i = - if i >= arity - then [] - else get_field env (Cvar arg) i (dbg ()) :: access_components(i+1) in - let fun_name = "caml_tuplify" ^ Int.to_string arity in - let fun_dbg = placeholder_fun_dbg ~human_name:fun_name in - Cfunction - {fun_name; - fun_args = [VP.create arg, typ_val; VP.create clos, typ_val]; - fun_body = - Cop(Capply typ_val, - get_field env (Cvar clos) 2 (dbg ()) - :: access_components 0 @ [Cvar clos], - dbg ()); - fun_codegen_options = []; - fun_dbg; - } - -(* Generate currying functions: - (defun caml_curryN (arg clos) - (alloc HDR caml_curryN_1 <arity (N-1)> caml_curry_N_1_app arg clos)) - (defun caml_curryN_1 (arg clos) - (alloc HDR caml_curryN_2 <arity (N-2)> caml_curry_N_2_app arg clos)) - ... - (defun caml_curryN_N-1 (arg clos) - (let (closN-2 clos.vars[1] - closN-3 closN-2.vars[1] - ... - clos1 clos2.vars[1] - clos clos1.vars[1]) - (app clos.direct - clos1.vars[0] ... closN-2.vars[0] clos.vars[0] arg clos))) - - Special "shortcut" functions are also generated to handle the - case where a partially applied function is applied to all remaining - arguments in one go. For instance: - (defun caml_curry_N_1_app (arg2 ... argN clos) - (let clos' clos.vars[1] - (app clos'.direct clos.vars[0] arg2 ... argN clos'))) - - Those shortcuts may lead to a quadratic number of application - primitives being generated in the worst case, which resulted in - linking time blowup in practice (PR#5933), so we only generate and - use them when below a fixed arity 'max_arity_optimized'. -*) - -let max_arity_optimized = 15 -let final_curry_function arity = - let dbg = placeholder_dbg in - let last_arg = V.create_local "arg" in - let last_clos = V.create_local "clos" in - let env = empty_env in - let rec curry_fun args clos n = - if n = 0 then - Cop(Capply typ_val, - get_field env (Cvar clos) 2 (dbg ()) :: - args @ [Cvar last_arg; Cvar clos], - dbg ()) - else - if n = arity - 1 || arity > max_arity_optimized then - begin - let newclos = V.create_local "clos" in - Clet(VP.create newclos, - get_field env (Cvar clos) 3 (dbg ()), - curry_fun (get_field env (Cvar clos) 2 (dbg ()) :: args) - newclos (n-1)) - end else - begin - let newclos = V.create_local "clos" in - Clet(VP.create newclos, - get_field env (Cvar clos) 4 (dbg ()), - curry_fun (get_field env (Cvar clos) 3 (dbg ()) :: args) - newclos (n-1)) - end in - let fun_name = - "caml_curry" ^ Int.to_string arity ^ "_" ^ Int.to_string (arity-1) - in - let fun_dbg = placeholder_fun_dbg ~human_name:fun_name in - Cfunction - {fun_name; - fun_args = [VP.create last_arg, typ_val; VP.create last_clos, typ_val]; - fun_body = curry_fun [] last_clos (arity-1); - fun_codegen_options = []; - fun_dbg; - } - -let rec intermediate_curry_functions arity num = - let dbg = placeholder_dbg in - let env = empty_env in - if num = arity - 1 then - [final_curry_function arity] - else begin - let name1 = "caml_curry" ^ Int.to_string arity in - let name2 = if num = 0 then name1 else name1 ^ "_" ^ Int.to_string num in - let arg = V.create_local "arg" and clos = V.create_local "clos" in - let fun_dbg = placeholder_fun_dbg ~human_name:name2 in - Cfunction - {fun_name = name2; - fun_args = [VP.create arg, typ_val; VP.create clos, typ_val]; - fun_body = - if arity - num > 2 && arity <= max_arity_optimized then - Cop(Calloc, - [alloc_closure_header 5 Debuginfo.none; - Cconst_symbol(name1 ^ "_" ^ Int.to_string (num+1), dbg ()); - int_const (dbg ()) (arity - num - 1); - Cconst_symbol(name1 ^ "_" ^ Int.to_string (num+1) ^ "_app", - dbg ()); - Cvar arg; Cvar clos], - dbg ()) - else - Cop(Calloc, - [alloc_closure_header 4 (dbg ()); - Cconst_symbol(name1 ^ "_" ^ Int.to_string (num+1), dbg ()); - int_const (dbg ()) 1; Cvar arg; Cvar clos], - dbg ()); - fun_codegen_options = []; - fun_dbg; - } - :: - (if arity <= max_arity_optimized && arity - num > 2 then - let rec iter i = - if i <= arity then - let arg = V.create_local (Printf.sprintf "arg%d" i) in - (arg, typ_val) :: iter (i+1) - else [] - in - let direct_args = iter (num+2) in - let rec iter i args clos = - if i = 0 then - Cop(Capply typ_val, - (get_field env (Cvar clos) 2 (dbg ())) :: args @ [Cvar clos], - dbg ()) - else - let newclos = V.create_local "clos" in - Clet(VP.create newclos, - get_field env (Cvar clos) 4 (dbg ()), - iter (i-1) (get_field env (Cvar clos) 3 (dbg ()) :: args) - newclos) - in - let fun_args = - List.map (fun (arg, ty) -> VP.create arg, ty) - (direct_args @ [clos, typ_val]) - in - let fun_name = name1 ^ "_" ^ Int.to_string (num+1) ^ "_app" in - let fun_dbg = placeholder_fun_dbg ~human_name:fun_name in - let cf = - Cfunction - {fun_name; - fun_args; - fun_body = iter (num+1) - (List.map (fun (arg,_) -> Cvar arg) direct_args) clos; - fun_codegen_options = []; - fun_dbg; - } - in - cf :: intermediate_curry_functions arity (num+1) - else - intermediate_curry_functions arity (num+1)) - end - -let curry_function arity = - assert(arity <> 0); - (* Functions with arity = 0 does not have a curry_function *) - if arity > 0 - then intermediate_curry_functions arity 0 - else [tuplify_function (-arity)] - -module Int = Numbers.Int - -let default_apply = Int.Set.add 2 (Int.Set.add 3 Int.Set.empty) - (* These apply funs are always present in the main program because - the run-time system needs them (cf. runtime/<arch>.S) . *) - -let generic_functions shared units = - let (apply,send,curry) = - List.fold_left - (fun (apply,send,curry) ui -> - List.fold_right Int.Set.add ui.ui_apply_fun apply, - List.fold_right Int.Set.add ui.ui_send_fun send, - List.fold_right Int.Set.add ui.ui_curry_fun curry) - (Int.Set.empty,Int.Set.empty,Int.Set.empty) - units in - let apply = if shared then apply else Int.Set.union apply default_apply in - let accu = Int.Set.fold (fun n accu -> apply_function n :: accu) apply [] in - let accu = Int.Set.fold (fun n accu -> send_function n :: accu) send accu in - Int.Set.fold (fun n accu -> curry_function n @ accu) curry accu - -(* Generate the entry point *) - -let entry_point namelist = - let dbg = placeholder_dbg in - let cconst_int i = Cconst_int (i, dbg ()) in - let cconst_symbol sym = Cconst_symbol (sym, dbg ()) in - let incr_global_inited () = - Cop(Cstore (Word_int, Assignment), - [cconst_symbol "caml_globals_inited"; - Cop(Caddi, [Cop(mk_load_mut Word_int, - [cconst_symbol "caml_globals_inited"], dbg ()); - cconst_int 1], dbg ())], dbg ()) in - let body = - List.fold_right - (fun name next -> - let entry_sym = Compilenv.make_symbol ~unitname:name (Some "entry") in - Csequence(Cop(Capply typ_void, - [cconst_symbol entry_sym], dbg ()), - Csequence(incr_global_inited (), next))) - namelist (cconst_int 1) in - let fun_name = "caml_program" in - let fun_dbg = placeholder_fun_dbg ~human_name:fun_name in - Cfunction {fun_name; - fun_args = []; - fun_body = body; - fun_codegen_options = [Reduce_code_size]; - fun_dbg; - } - -(* Generate the table of globals *) - -let cint_zero = Cint 0n - -let global_table namelist = - let mksym name = - Csymbol_address (Compilenv.make_symbol ~unitname:name (Some "gc_roots")) - in - Cdata(Cglobal_symbol "caml_globals" :: - Cdefine_symbol "caml_globals" :: - List.map mksym namelist @ - [cint_zero]) - -let reference_symbols namelist = - let mksym name = Csymbol_address name in - Cdata(List.map mksym namelist) - -let global_data name v = - Cdata(emit_structured_constant (name, Global) - (Uconst_string (Marshal.to_string v [])) []) - -let globals_map v = global_data "caml_globals_map" v - -(* Generate the master table of frame descriptors *) - -let frame_table namelist = - let mksym name = - Csymbol_address (Compilenv.make_symbol ~unitname:name (Some "frametable")) - in - Cdata(Cglobal_symbol "caml_frametable" :: - Cdefine_symbol "caml_frametable" :: - List.map mksym namelist - @ [cint_zero]) - -(* Generate the master table of Spacetime shapes *) - -let spacetime_shapes namelist = - let mksym name = - Csymbol_address ( - Compilenv.make_symbol ~unitname:name (Some "spacetime_shapes")) - in - Cdata(Cglobal_symbol "caml_spacetime_shapes" :: - Cdefine_symbol "caml_spacetime_shapes" :: - List.map mksym namelist - @ [cint_zero]) - -(* Generate the table of module data and code segments *) - -let segment_table namelist symbol begname endname = - let addsyms name lst = - Csymbol_address (Compilenv.make_symbol ~unitname:name (Some begname)) :: - Csymbol_address (Compilenv.make_symbol ~unitname:name (Some endname)) :: - lst - in - Cdata(Cglobal_symbol symbol :: - Cdefine_symbol symbol :: - List.fold_right addsyms namelist [cint_zero]) - -let data_segment_table namelist = - segment_table namelist "caml_data_segments" "data_begin" "data_end" - -let code_segment_table namelist = - segment_table namelist "caml_code_segments" "code_begin" "code_end" - -(* Initialize a predefined exception *) - -let predef_exception i name = - let name_sym = Compilenv.new_const_symbol () in - let data_items = - emit_block name_sym Local (string_header (String.length name)) - (emit_string_constant name []) - in - let exn_sym = "caml_exn_" ^ name in - let tag = Obj.object_tag in - let size = 2 in - let fields = - (Csymbol_address name_sym) - :: (cint_const (-i - 1)) - :: data_items - in - let data_items = emit_block exn_sym Global (block_header tag size) fields in - Cdata data_items - -(* Header for a plugin *) - -let plugin_header units = - let mk (ui,crc) = - { dynu_name = ui.ui_name; - dynu_crc = crc; - dynu_imports_cmi = ui.ui_imports_cmi; - dynu_imports_cmx = ui.ui_imports_cmx; - dynu_defines = ui.ui_defines - } in - global_data "caml_plugin_header" - { dynu_magic = Config.cmxs_magic_number; dynu_units = List.map mk units } |