summaryrefslogtreecommitdiff
path: root/ocaml-binary-annot/asmcomp/cmmgen.ml
diff options
context:
space:
mode:
Diffstat (limited to 'ocaml-binary-annot/asmcomp/cmmgen.ml')
-rw-r--r--ocaml-binary-annot/asmcomp/cmmgen.ml2073
1 files changed, 2073 insertions, 0 deletions
diff --git a/ocaml-binary-annot/asmcomp/cmmgen.ml b/ocaml-binary-annot/asmcomp/cmmgen.ml
new file mode 100644
index 0000000000..bb96153fa4
--- /dev/null
+++ b/ocaml-binary-annot/asmcomp/cmmgen.ml
@@ -0,0 +1,2073 @@
+(***********************************************************************)
+(* *)
+(* Objective Caml *)
+(* *)
+(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
+(* *)
+(* Copyright 1996 Institut National de Recherche en Informatique et *)
+(* en Automatique. All rights reserved. This file is distributed *)
+(* under the terms of the Q Public License version 1.0. *)
+(* *)
+(***********************************************************************)
+
+(* $Id$ *)
+
+(* Translation from closed lambda to C-- *)
+
+open Misc
+open Arch
+open Asttypes
+open Primitive
+open Types
+open Lambda
+open Clambda
+open Cmm
+open Cmx_format
+
+(* Local binding of complex expressions *)
+
+let bind name arg fn =
+ match arg with
+ Cvar _ | Cconst_int _ | Cconst_natint _ | Cconst_symbol _
+ | Cconst_pointer _ | Cconst_natpointer _ -> fn arg
+ | _ -> let id = Ident.create name in Clet(id, arg, fn (Cvar id))
+
+let bind_nonvar name arg fn =
+ match arg with
+ Cconst_int _ | Cconst_natint _ | Cconst_symbol _
+ | Cconst_pointer _ | Cconst_natpointer _ -> fn arg
+ | _ -> let id = Ident.create name in Clet(id, arg, fn (Cvar id))
+
+(* Block headers. Meaning of the tag field: see stdlib/obj.ml *)
+
+let float_tag = Cconst_int Obj.double_tag
+let floatarray_tag = Cconst_int Obj.double_array_tag
+
+let block_header tag sz =
+ Nativeint.add (Nativeint.shift_left (Nativeint.of_int sz) 10)
+ (Nativeint.of_int tag)
+let closure_header sz = 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 =
+ 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 alloc_block_header tag sz = Cconst_natint(block_header tag sz)
+let alloc_float_header = Cconst_natint(float_header)
+let alloc_floatarray_header len = Cconst_natint(floatarray_header len)
+let alloc_closure_header sz = Cconst_natint(closure_header sz)
+let alloc_infix_header ofs = Cconst_natint(infix_header ofs)
+let alloc_boxedint32_header = Cconst_natint(boxedint32_header)
+let alloc_boxedint64_header = Cconst_natint(boxedint64_header)
+let alloc_boxedintnat_header = Cconst_natint(boxedintnat_header)
+
+(* Integers *)
+
+let max_repr_int = max_int asr 1
+let min_repr_int = min_int asr 1
+
+let int_const n =
+ if n <= max_repr_int && n >= min_repr_int
+ then Cconst_int((n lsl 1) + 1)
+ else Cconst_natint
+ (Nativeint.add (Nativeint.shift_left (Nativeint.of_int n) 1) 1n)
+
+let add_const c n =
+ if n = 0 then c else Cop(Caddi, [c; Cconst_int n])
+
+let incr_int = function
+ Cconst_int n when n < max_int -> Cconst_int(n+1)
+ | Cop(Caddi, [c; Cconst_int n]) when n < max_int -> add_const c (n + 1)
+ | c -> add_const c 1
+
+let decr_int = function
+ Cconst_int n when n > min_int -> Cconst_int(n-1)
+ | Cop(Caddi, [c; Cconst_int n]) when n > min_int -> add_const c (n - 1)
+ | c -> add_const c (-1)
+
+let add_int c1 c2 =
+ match (c1, c2) with
+ (Cop(Caddi, [c1; Cconst_int n1]),
+ Cop(Caddi, [c2; Cconst_int n2])) when no_overflow_add n1 n2 ->
+ add_const (Cop(Caddi, [c1; c2])) (n1 + n2)
+ | (Cop(Caddi, [c1; Cconst_int n1]), c2) ->
+ add_const (Cop(Caddi, [c1; c2])) n1
+ | (c1, Cop(Caddi, [c2; Cconst_int n2])) ->
+ add_const (Cop(Caddi, [c1; c2])) n2
+ | (Cconst_int _, _) ->
+ Cop(Caddi, [c2; c1])
+ | (_, _) ->
+ Cop(Caddi, [c1; c2])
+
+let sub_int c1 c2 =
+ match (c1, c2) with
+ (Cop(Caddi, [c1; Cconst_int n1]),
+ Cop(Caddi, [c2; Cconst_int n2])) when no_overflow_sub n1 n2 ->
+ add_const (Cop(Csubi, [c1; c2])) (n1 - n2)
+ | (Cop(Caddi, [c1; Cconst_int n1]), c2) ->
+ add_const (Cop(Csubi, [c1; c2])) n1
+ | (c1, Cop(Caddi, [c2; Cconst_int n2])) when n2 <> min_int ->
+ add_const (Cop(Csubi, [c1; c2])) (-n2)
+ | (c1, Cconst_int n) when n <> min_int ->
+ add_const c1 (-n)
+ | (c1, c2) ->
+ Cop(Csubi, [c1; c2])
+
+let mul_int c1 c2 =
+ match (c1, c2) with
+ (Cconst_int 0, _) -> c1
+ | (Cconst_int 1, _) -> c2
+ | (_, Cconst_int 0) -> c2
+ | (_, Cconst_int 1) -> c1
+ | (_, _) -> Cop(Cmuli, [c1; c2])
+
+let tag_int = function
+ Cconst_int n -> int_const n
+ | c -> Cop(Caddi, [Cop(Clsl, [c; Cconst_int 1]); Cconst_int 1])
+
+let force_tag_int = function
+ Cconst_int n -> int_const n
+ | c -> Cop(Cor, [Cop(Clsl, [c; Cconst_int 1]); Cconst_int 1])
+
+let untag_int = function
+ Cconst_int n -> Cconst_int(n asr 1)
+ | 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)])
+ | 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)])
+ | Cop(Cor, [c; Cconst_int 1]) -> Cop(Casr, [c; Cconst_int 1])
+ | c -> Cop(Casr, [c; Cconst_int 1])
+
+let lsl_int c1 c2 =
+ 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)])
+ | (_, _) ->
+ Cop(Clsl, [c1; c2])
+
+let ignore_low_bit_int = function
+ Cop(Caddi, [(Cop(Clsl, [_; Cconst_int 1]) as c); Cconst_int 1]) -> c
+ | Cop(Cor, [c; Cconst_int 1]) -> c
+ | c -> c
+
+let is_nonzero_constant = function
+ Cconst_int n -> n <> 0
+ | Cconst_natint n -> n <> 0n
+ | _ -> false
+
+let safe_divmod op c1 c2 dbg =
+ if !Clflags.fast || is_nonzero_constant c2 then
+ Cop(op, [c1; c2])
+ else
+ bind "divisor" c2 (fun c2 ->
+ Cifthenelse(c2,
+ Cop(op, [c1; c2]),
+ Cop(Craise dbg,
+ [Cconst_symbol "caml_bucket_Division_by_zero"])))
+
+(* Bool *)
+
+let test_bool = function
+ Cop(Caddi, [Cop(Clsl, [c; Cconst_int 1]); Cconst_int 1]) -> c
+ | Cop(Clsl, [c; Cconst_int 1]) -> c
+ | c -> Cop(Ccmpi Cne, [c; Cconst_int 1])
+
+(* Float *)
+
+let box_float c = Cop(Calloc, [alloc_float_header; c])
+
+let rec unbox_float = function
+ Cop(Calloc, [header; c]) -> c
+ | Clet(id, exp, body) -> Clet(id, exp, unbox_float body)
+ | Cifthenelse(cond, e1, e2) ->
+ Cifthenelse(cond, unbox_float e1, unbox_float e2)
+ | Csequence(e1, e2) -> Csequence(e1, unbox_float e2)
+ | Cswitch(e, tbl, el) -> Cswitch(e, tbl, Array.map unbox_float el)
+ | Ccatch(n, ids, e1, e2) -> Ccatch(n, ids, unbox_float e1, unbox_float e2)
+ | Ctrywith(e1, id, e2) -> Ctrywith(unbox_float e1, id, unbox_float e2)
+ | c -> Cop(Cload Double_u, [c])
+
+(* Complex *)
+
+let box_complex c_re c_im =
+ Cop(Calloc, [alloc_floatarray_header 2; c_re; c_im])
+
+let complex_re c = Cop(Cload Double_u, [c])
+let complex_im c = Cop(Cload Double_u,
+ [Cop(Cadda, [c; Cconst_int size_float])])
+
+(* Unit *)
+
+let return_unit c = Csequence(c, Cconst_pointer 1)
+
+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, ifnot) ->
+ Cifthenelse(cond, remove_unit ifso, remove_unit ifnot)
+ | Cswitch(sel, index, cases) ->
+ Cswitch(sel, index, Array.map remove_unit cases)
+ | Ccatch(io, ids, body, handler) ->
+ Ccatch(io, ids, remove_unit body, remove_unit handler)
+ | Ctrywith(body, exn, handler) ->
+ Ctrywith(remove_unit body, exn, remove_unit handler)
+ | Clet(id, c1, c2) ->
+ Clet(id, c1, remove_unit c2)
+ | Cop(Capply (mty, dbg), args) ->
+ Cop(Capply (typ_void, dbg), args)
+ | Cop(Cextcall(proc, mty, alloc, dbg), args) ->
+ Cop(Cextcall(proc, typ_void, alloc, dbg), args)
+ | Cexit (_,_) as c -> c
+ | Ctuple [] as c -> c
+ | c -> Csequence(c, Ctuple [])
+
+(* Access to block fields *)
+
+let field_address ptr n =
+ if n = 0
+ then ptr
+ else Cop(Cadda, [ptr; Cconst_int(n * size_addr)])
+
+let get_field ptr n =
+ Cop(Cload Word, [field_address ptr n])
+
+let set_field ptr n newval =
+ Cop(Cstore Word, [field_address ptr n; newval])
+
+let header ptr =
+ Cop(Cload Word, [Cop(Cadda, [ptr; Cconst_int(-size_int)])])
+
+let tag_offset =
+ if big_endian then -1 else -size_int
+
+let get_tag ptr =
+ if Proc.word_addressed then (* If byte loads are slow *)
+ Cop(Cand, [header ptr; Cconst_int 255])
+ else (* If byte loads are efficient *)
+ Cop(Cload Byte_unsigned,
+ [Cop(Cadda, [ptr; Cconst_int(tag_offset)])])
+
+let get_size ptr =
+ Cop(Clsr, [header ptr; Cconst_int 10])
+
+(* 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 =
+ Cop(Ccmpi Cne, [Cop(Cand, [hdr; Cconst_int 255]); floatarray_tag])
+
+let is_addr_array_ptr ptr =
+ Cop(Ccmpi Cne, [get_tag ptr; floatarray_tag])
+
+let addr_array_length hdr = Cop(Clsr, [hdr; Cconst_int wordsize_shift])
+let float_array_length hdr = Cop(Clsr, [hdr; Cconst_int numfloat_shift])
+
+let lsl_const c n =
+ Cop(Clsl, [c; Cconst_int n])
+
+let array_indexing log2size ptr ofs =
+ match ofs with
+ Cconst_int n ->
+ let i = n asr 1 in
+ if i = 0 then ptr else Cop(Cadda, [ptr; Cconst_int(i lsl log2size)])
+ | Cop(Caddi, [Cop(Clsl, [c; Cconst_int 1]); Cconst_int 1]) ->
+ Cop(Cadda, [ptr; lsl_const c log2size])
+ | Cop(Caddi, [c; Cconst_int n]) ->
+ Cop(Cadda, [Cop(Cadda, [ptr; lsl_const c (log2size - 1)]);
+ Cconst_int((n-1) lsl (log2size - 1))])
+ | _ ->
+ Cop(Cadda, [Cop(Cadda, [ptr; lsl_const ofs (log2size - 1)]);
+ Cconst_int((-1) lsl (log2size - 1))])
+
+let addr_array_ref arr ofs =
+ Cop(Cload Word, [array_indexing log2_size_addr arr ofs])
+let unboxed_float_array_ref arr ofs =
+ Cop(Cload Double_u, [array_indexing log2_size_float arr ofs])
+let float_array_ref arr ofs =
+ box_float(unboxed_float_array_ref arr ofs)
+
+let addr_array_set arr ofs newval =
+ Cop(Cextcall("caml_modify", typ_void, false, Debuginfo.none),
+ [array_indexing log2_size_addr arr ofs; newval])
+let int_array_set arr ofs newval =
+ Cop(Cstore Word, [array_indexing log2_size_addr arr ofs; newval])
+let float_array_set arr ofs newval =
+ Cop(Cstore Double_u, [array_indexing log2_size_float arr ofs; newval])
+
+(* String length *)
+
+let string_length exp =
+ bind "str" exp (fun str ->
+ let tmp_var = Ident.create "tmp" in
+ Clet(tmp_var,
+ Cop(Csubi,
+ [Cop(Clsl,
+ [Cop(Clsr, [header str; Cconst_int 10]);
+ Cconst_int log2_size_addr]);
+ Cconst_int 1]),
+ Cop(Csubi,
+ [Cvar tmp_var;
+ Cop(Cload Byte_unsigned,
+ [Cop(Cadda, [str; Cvar tmp_var])])])))
+
+(* Message sending *)
+
+let lookup_tag obj tag =
+ bind "tag" tag (fun tag ->
+ Cop(Cextcall("caml_get_public_method", typ_addr, false, Debuginfo.none),
+ [obj; tag]))
+
+let lookup_label obj lab =
+ bind "lab" lab (fun lab ->
+ let table = Cop (Cload Word, [obj]) in
+ addr_array_ref table lab)
+
+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 in
+ Compilenv.need_send_fun arity;
+ Cop(Capply (typ_addr, dbg),
+ Cconst_symbol("caml_send" ^ string_of_int arity) ::
+ obj :: tag :: cache :: args)
+
+(* Allocation *)
+
+let make_alloc_generic set_fn tag wordsize args =
+ if wordsize <= Config.max_young_wosize then
+ Cop(Calloc, Cconst_natint(block_header tag wordsize) :: args)
+ else begin
+ let id = Ident.create "alloc" in
+ let rec fill_fields idx = function
+ [] -> Cvar id
+ | e1::el -> Csequence(set_fn (Cvar id) (Cconst_int idx) e1,
+ fill_fields (idx + 2) el) in
+ Clet(id,
+ Cop(Cextcall("caml_alloc", typ_addr, true, Debuginfo.none),
+ [Cconst_int wordsize; Cconst_int tag]),
+ fill_fields 1 args)
+ end
+
+let make_alloc tag args =
+ make_alloc_generic addr_array_set tag (List.length args) args
+let make_float_alloc tag args =
+ make_alloc_generic float_array_set tag
+ (List.length args * size_float / size_addr) args
+
+(* To compile "let rec" over values *)
+
+let fundecls_size fundecls =
+ let sz = ref (-1) in
+ List.iter
+ (fun (label, arity, params, body) ->
+ sz := !sz + 1 + (if arity = 1 then 2 else 3))
+ fundecls;
+ !sz
+
+type rhs_kind =
+ | RHS_block of int
+ | RHS_nonrec
+;;
+let rec expr_size = function
+ | Uclosure(fundecls, clos_vars) ->
+ RHS_block (fundecls_size fundecls + List.length clos_vars)
+ | Ulet(id, exp, body) ->
+ expr_size body
+ | Uletrec(bindings, body) ->
+ expr_size body
+ | Uprim(Pmakeblock(tag, mut), args, _) ->
+ RHS_block (List.length args)
+ | Uprim(Pmakearray(Paddrarray | Pintarray), args, _) ->
+ RHS_block (List.length args)
+ | Usequence(exp, exp') ->
+ expr_size exp'
+ | _ -> RHS_nonrec
+
+(* Record application and currying functions *)
+
+let apply_function n =
+ Compilenv.need_apply_fun n; "caml_apply" ^ string_of_int n
+let curry_function n =
+ Compilenv.need_curry_fun n;
+ if n >= 0
+ then "caml_curry" ^ string_of_int n
+ else "caml_tuplify" ^ string_of_int (-n)
+
+(* Comparisons *)
+
+let transl_comparison = function
+ Lambda.Ceq -> Ceq
+ | Lambda.Cneq -> Cne
+ | Lambda.Cge -> Cge
+ | Lambda.Cgt -> Cgt
+ | Lambda.Cle -> Cle
+ | Lambda.Clt -> Clt
+
+(* Translate structured constants *)
+
+let const_label = ref 0
+
+let new_const_label () =
+ incr const_label;
+ !const_label
+
+let new_const_symbol () =
+ incr const_label;
+ Compilenv.make_symbol (Some (string_of_int !const_label))
+
+let structured_constants = ref ([] : (string * structured_constant) list)
+
+let transl_constant = function
+ Const_base(Const_int n) ->
+ int_const n
+ | Const_base(Const_char c) ->
+ Cconst_int(((Char.code c) lsl 1) + 1)
+ | Const_pointer n ->
+ if n <= max_repr_int && n >= min_repr_int
+ then Cconst_pointer((n lsl 1) + 1)
+ else Cconst_natpointer
+ (Nativeint.add (Nativeint.shift_left (Nativeint.of_int n) 1) 1n)
+ | cst ->
+ let lbl = new_const_symbol() in
+ structured_constants := (lbl, cst) :: !structured_constants;
+ Cconst_symbol lbl
+
+(* Translate constant closures *)
+
+let constant_closures =
+ ref ([] : (string * (string * int * Ident.t list * ulambda) list) list)
+
+(* Boxed integers *)
+
+let box_int_constant bi n =
+ match bi with
+ Pnativeint -> Const_base(Const_nativeint n)
+ | Pint32 -> Const_base(Const_int32 (Nativeint.to_int32 n))
+ | Pint64 -> Const_base(Const_int64 (Int64.of_nativeint 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
+
+let box_int bi arg =
+ match arg with
+ Cconst_int n ->
+ transl_constant (box_int_constant bi (Nativeint.of_int n))
+ | Cconst_natint n ->
+ transl_constant (box_int_constant bi n)
+ | _ ->
+ let arg' =
+ if bi = Pint32 && size_int = 8 && big_endian
+ then Cop(Clsl, [arg; Cconst_int 32])
+ else arg in
+ Cop(Calloc, [alloc_header_boxed_int bi;
+ Cconst_symbol(operations_boxed_int bi);
+ arg'])
+
+let rec unbox_int bi arg =
+ match arg with
+ Cop(Calloc, [hdr; ops; Cop(Clsl, [contents; Cconst_int 32])])
+ when bi = Pint32 && size_int = 8 && big_endian ->
+ (* Force sign-extension of low 32 bits *)
+ Cop(Casr, [Cop(Clsl, [contents; Cconst_int 32]); Cconst_int 32])
+ | Cop(Calloc, [hdr; ops; contents])
+ when bi = Pint32 && size_int = 8 && not big_endian ->
+ (* Force sign-extension of low 32 bits *)
+ Cop(Casr, [Cop(Clsl, [contents; Cconst_int 32]); Cconst_int 32])
+ | Cop(Calloc, [hdr; ops; contents]) ->
+ contents
+ | Clet(id, exp, body) -> Clet(id, exp, unbox_int bi body)
+ | Cifthenelse(cond, e1, e2) ->
+ Cifthenelse(cond, unbox_int bi e1, unbox_int bi e2)
+ | Csequence(e1, e2) -> Csequence(e1, unbox_int bi e2)
+ | Cswitch(e, tbl, el) -> Cswitch(e, tbl, Array.map (unbox_int bi) el)
+ | Ccatch(n, ids, e1, e2) -> Ccatch(n, ids, unbox_int bi e1, unbox_int bi e2)
+ | Ctrywith(e1, id, e2) -> Ctrywith(unbox_int bi e1, id, unbox_int bi e2)
+ | _ ->
+ Cop(Cload(if bi = Pint32 then Thirtytwo_signed else Word),
+ [Cop(Cadda, [arg; Cconst_int size_addr])])
+
+let make_unsigned_int bi arg =
+ if bi = Pint32 && size_int = 8
+ then Cop(Cand, [arg; Cconst_natint 0xFFFFFFFFn])
+ else 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
+
+let bigarray_indexing unsafe elt_kind layout b args dbg =
+ let check_bound a1 a2 k =
+ if unsafe then k else Csequence(Cop(Ccheckbound dbg, [a1;a2]), k) in
+ let rec ba_indexing dim_ofs delta_ofs = function
+ [] -> assert false
+ | [arg] ->
+ bind "idx" (untag_int arg)
+ (fun idx ->
+ check_bound (Cop(Cload Word,[field_address b dim_ofs])) idx idx)
+ | arg1 :: argl ->
+ let rem = ba_indexing (dim_ofs + delta_ofs) delta_ofs argl in
+ bind "idx" (untag_int arg1)
+ (fun idx ->
+ bind "bound" (Cop(Cload Word, [field_address b dim_ofs]))
+ (fun bound ->
+ check_bound bound idx (add_int (mul_int rem bound) idx))) in
+ 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)) args)
+ and elt_size =
+ bigarray_elt_size elt_kind in
+ let byte_offset =
+ if elt_size = 1
+ then offset
+ else Cop(Clsl, [offset; Cconst_int(log2 elt_size)]) in
+ Cop(Cadda, [Cop(Cload Word, [field_address b 1]); byte_offset])
+
+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
+ | Pbigarray_caml_int -> Word
+ | Pbigarray_native_int -> Word
+ | Pbigarray_complex32 -> Single
+ | Pbigarray_complex64 -> Double
+
+let bigarray_get unsafe elt_kind layout b args dbg =
+ 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 ->
+ box_complex
+ (Cop(Cload kind, [addr]))
+ (Cop(Cload kind, [Cop(Cadda, [addr; Cconst_int sz])])))
+ | _ ->
+ Cop(Cload (bigarray_word_kind elt_kind),
+ [bigarray_indexing unsafe elt_kind layout b args dbg])
+
+let bigarray_set unsafe elt_kind layout b args newval dbg =
+ 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, [addr; complex_re newv]),
+ Cop(Cstore kind,
+ [Cop(Cadda, [addr; Cconst_int sz]); complex_im newv]))))
+ | _ ->
+ Cop(Cstore (bigarray_word_kind elt_kind),
+ [bigarray_indexing unsafe elt_kind layout b args dbg; newval])
+
+(* Simplification of some primitives into C calls *)
+
+let default_prim name =
+ { prim_name = name; prim_arity = 0 (*ignored*);
+ prim_alloc = true; prim_native_name = ""; prim_native_float = false }
+
+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 (default_prim "caml_int64_neg")
+ | Paddbint Pint64 -> Pccall (default_prim "caml_int64_add")
+ | Psubbint Pint64 -> Pccall (default_prim "caml_int64_sub")
+ | Pmulbint Pint64 -> Pccall (default_prim "caml_int64_mul")
+ | Pdivbint Pint64 -> Pccall (default_prim "caml_int64_div")
+ | Pmodbint Pint64 -> Pccall (default_prim "caml_int64_mod")
+ | Pandbint Pint64 -> Pccall (default_prim "caml_int64_and")
+ | Porbint Pint64 -> Pccall (default_prim "caml_int64_or")
+ | Pxorbint Pint64 -> Pccall (default_prim "caml_int64_xor")
+ | 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.Cneq) -> 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_" ^ string_of_int n))
+ | Pbigarrayset(unsafe, n, Pbigarray_int64, layout) ->
+ Pccall (default_prim ("caml_ba_set_" ^ string_of_int n))
+ | 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_" ^ string_of_int n))
+ | Pbigarrayset(unsafe, n, Pbigarray_unknown, layout) ->
+ Pccall (default_prim ("caml_ba_set_" ^ string_of_int n))
+ | Pbigarrayref(unsafe, n, kind, Pbigarray_unknown_layout) ->
+ Pccall (default_prim ("caml_ba_get_" ^ string_of_int n))
+ | Pbigarrayset(unsafe, n, kind, Pbigarray_unknown_layout) ->
+ Pccall (default_prim ("caml_ba_set_" ^ string_of_int n))
+ | p ->
+ if size_int = 8 then p else simplif_primitive_32bits p
+
+(* Build switchers both for constants and blocks *)
+
+(* constants first *)
+
+let transl_isout h arg = tag_int (Cop(Ccmpa Clt, [h ; arg]))
+
+exception Found of int
+
+let make_switch_gen arg cases acts =
+ let lcases = Array.length cases in
+ let new_cases = Array.create lcases 0 in
+ let store = Switch.mk_store (=) in
+
+ for i = 0 to Array.length cases-1 do
+ let act = cases.(i) in
+ let new_act = store.Switch.act_store act in
+ new_cases.(i) <- new_act
+ done ;
+ Cswitch
+ (arg, new_cases,
+ Array.map
+ (fun n -> acts.(n))
+ (store.Switch.act_get ()))
+
+
+(* Then for blocks *)
+
+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
+
+ let default = Cexit (0,[])
+ let make_prim p args = Cop (p,args)
+ let make_offset arg n = add_const arg n
+ let make_isout h arg = Cop (Ccmpa Clt, [h ; arg])
+ let make_isin h arg = Cop (Ccmpa Cge, [h ; arg])
+ let make_if cond ifso ifnot = Cifthenelse (cond, ifso, ifnot)
+ let make_switch arg cases actions =
+ make_switch_gen arg cases actions
+ let bind arg body = bind "switcher" arg body
+
+end
+
+module SwitcherBlocks = Switch.Make(SArgBlocks)
+
+(* Auxiliary functions for optimizing "let" of boxed numbers (floats and
+ boxed integers *)
+
+type unboxed_number_kind =
+ No_unboxing
+ | Boxed_float
+ | Boxed_integer of boxed_integer
+
+let is_unboxed_number = function
+ Uconst(Const_base(Const_float f)) ->
+ Boxed_float
+ | Uprim(p, _, _) ->
+ begin match simplif_primitive p with
+ Pccall p -> if p.prim_native_float then Boxed_float else No_unboxing
+ | Pfloatfield _ -> Boxed_float
+ | Pfloatofint -> Boxed_float
+ | Pnegfloat -> Boxed_float
+ | Pabsfloat -> Boxed_float
+ | Paddfloat -> Boxed_float
+ | Psubfloat -> Boxed_float
+ | Pmulfloat -> Boxed_float
+ | Pdivfloat -> Boxed_float
+ | Parrayrefu Pfloatarray -> Boxed_float
+ | Parrayrefs Pfloatarray -> Boxed_float
+ | Pbintofint bi -> Boxed_integer bi
+ | Pcvtbint(src, dst) -> Boxed_integer dst
+ | Pnegbint bi -> Boxed_integer bi
+ | Paddbint bi -> Boxed_integer bi
+ | Psubbint bi -> Boxed_integer bi
+ | Pmulbint bi -> Boxed_integer bi
+ | Pdivbint bi -> Boxed_integer bi
+ | Pmodbint bi -> Boxed_integer bi
+ | Pandbint bi -> Boxed_integer bi
+ | Porbint bi -> Boxed_integer bi
+ | Pxorbint bi -> Boxed_integer bi
+ | Plslbint bi -> Boxed_integer bi
+ | Plsrbint bi -> Boxed_integer bi
+ | Pasrbint bi -> Boxed_integer bi
+ | Pbigarrayref(_, _, (Pbigarray_float32 | Pbigarray_float64), _) ->
+ Boxed_float
+ | Pbigarrayref(_, _, Pbigarray_int32, _) -> Boxed_integer Pint32
+ | Pbigarrayref(_, _, Pbigarray_int64, _) -> Boxed_integer Pint64
+ | Pbigarrayref(_, _, Pbigarray_native_int, _) -> Boxed_integer Pnativeint
+ | _ -> No_unboxing
+ end
+ | _ -> No_unboxing
+
+let subst_boxed_number unbox_fn boxed_id unboxed_id exp =
+ let need_boxed = ref false in
+ let assigned = ref false in
+ let rec subst = function
+ Cvar id as e ->
+ if Ident.same id boxed_id then need_boxed := true; e
+ | Clet(id, arg, body) -> Clet(id, subst arg, subst body)
+ | Cassign(id, arg) ->
+ if Ident.same id boxed_id then begin
+ assigned := true;
+ Cassign(unboxed_id, subst(unbox_fn arg))
+ end else
+ Cassign(id, subst arg)
+ | Ctuple argv -> Ctuple(List.map subst argv)
+ | Cop(Cload _, [Cvar id]) as e ->
+ if Ident.same id boxed_id then Cvar unboxed_id else e
+ | Cop(Cload _, [Cop(Cadda, [Cvar id; _])]) as e ->
+ if Ident.same id boxed_id then Cvar unboxed_id else e
+ | Cop(op, argv) -> Cop(op, List.map subst argv)
+ | Csequence(e1, e2) -> Csequence(subst e1, subst e2)
+ | Cifthenelse(e1, e2, e3) -> Cifthenelse(subst e1, subst e2, subst e3)
+ | Cswitch(arg, index, cases) ->
+ Cswitch(subst arg, index, Array.map subst cases)
+ | Cloop e -> Cloop(subst e)
+ | Ccatch(nfail, ids, e1, e2) -> Ccatch(nfail, ids, subst e1, subst e2)
+ | Cexit (nfail, el) -> Cexit (nfail, List.map subst el)
+ | Ctrywith(e1, id, e2) -> Ctrywith(subst e1, id, subst e2)
+ | e -> e in
+ let res = subst exp in
+ (res, !need_boxed, !assigned)
+
+(* Translate an expression *)
+
+let functions = (Queue.create() : (string * Ident.t list * ulambda) Queue.t)
+
+let rec transl = function
+ Uvar id ->
+ Cvar id
+ | Uconst sc ->
+ transl_constant sc
+ | Uclosure(fundecls, []) ->
+ let lbl = new_const_symbol() in
+ constant_closures := (lbl, fundecls) :: !constant_closures;
+ List.iter
+ (fun (label, arity, params, body) ->
+ Queue.add (label, params, body) functions)
+ fundecls;
+ Cconst_symbol lbl
+ | Uclosure(fundecls, clos_vars) ->
+ let block_size =
+ fundecls_size fundecls + List.length clos_vars in
+ let rec transl_fundecls pos = function
+ [] ->
+ List.map transl clos_vars
+ | (label, arity, params, body) :: rem ->
+ Queue.add (label, params, body) functions;
+ let header =
+ if pos = 0
+ then alloc_closure_header block_size
+ else alloc_infix_header pos in
+ if arity = 1 then
+ header ::
+ Cconst_symbol label ::
+ int_const 1 ::
+ transl_fundecls (pos + 3) rem
+ else
+ header ::
+ Cconst_symbol(curry_function arity) ::
+ int_const arity ::
+ Cconst_symbol label ::
+ transl_fundecls (pos + 4) rem in
+ Cop(Calloc, transl_fundecls 0 fundecls)
+ | Uoffset(arg, offset) ->
+ field_address (transl arg) offset
+ | Udirect_apply(lbl, args, dbg) ->
+ Cop(Capply(typ_addr, dbg), Cconst_symbol lbl :: List.map transl args)
+ | Ugeneric_apply(clos, [arg], dbg) ->
+ bind "fun" (transl clos) (fun clos ->
+ Cop(Capply(typ_addr, dbg), [get_field clos 0; transl arg; clos]))
+ | Ugeneric_apply(clos, args, dbg) ->
+ let arity = List.length args in
+ let cargs = Cconst_symbol(apply_function arity) ::
+ List.map transl (args @ [clos]) in
+ Cop(Capply(typ_addr, dbg), cargs)
+ | Usend(kind, met, obj, args, dbg) ->
+ let call_met obj args clos =
+ if args = [] then
+ Cop(Capply(typ_addr, dbg), [get_field clos 0;obj;clos])
+ else
+ let arity = List.length args + 1 in
+ let cargs = Cconst_symbol(apply_function arity) :: obj ::
+ (List.map transl args) @ [clos] in
+ Cop(Capply(typ_addr, dbg), cargs)
+ in
+ bind "obj" (transl obj) (fun obj ->
+ match kind, args with
+ Self, _ ->
+ bind "met" (lookup_label obj (transl met)) (call_met obj args)
+ | Cached, cache :: pos :: args ->
+ call_cached_method obj (transl met) (transl cache) (transl pos)
+ (List.map transl args) dbg
+ | _ ->
+ bind "met" (lookup_tag obj (transl met)) (call_met obj args))
+ | Ulet(id, exp, body) ->
+ begin match is_unboxed_number exp with
+ No_unboxing ->
+ Clet(id, transl exp, transl body)
+ | Boxed_float ->
+ transl_unbox_let box_float unbox_float transl_unbox_float
+ id exp body
+ | Boxed_integer bi ->
+ transl_unbox_let (box_int bi) (unbox_int bi) (transl_unbox_int bi)
+ id exp body
+ end
+ | Uletrec(bindings, body) ->
+ transl_letrec bindings (transl body)
+
+ (* Primitives *)
+ | Uprim(prim, args, dbg) ->
+ begin match (simplif_primitive prim, args) with
+ (Pgetglobal id, []) ->
+ Cconst_symbol (Ident.name id)
+ | (Pmakeblock(tag, mut), []) ->
+ transl_constant(Const_block(tag, []))
+ | (Pmakeblock(tag, mut), args) ->
+ make_alloc tag (List.map transl args)
+ | (Pccall prim, args) ->
+ if prim.prim_native_float then
+ box_float
+ (Cop(Cextcall(prim.prim_native_name, typ_float, false, dbg),
+ List.map transl_unbox_float args))
+ else
+ Cop(Cextcall(Primitive.native_name prim, typ_addr, prim.prim_alloc, dbg),
+ List.map transl args)
+ | (Pmakearray kind, []) ->
+ transl_constant(Const_block(0, []))
+ | (Pmakearray kind, args) ->
+ begin match kind with
+ Pgenarray ->
+ Cop(Cextcall("caml_make_array", typ_addr, true, Debuginfo.none),
+ [make_alloc 0 (List.map transl args)])
+ | Paddrarray | Pintarray ->
+ make_alloc 0 (List.map transl args)
+ | Pfloatarray ->
+ make_float_alloc Obj.double_array_tag
+ (List.map transl_unbox_float args)
+ end
+ | (Pbigarrayref(unsafe, num_dims, elt_kind, layout), arg1 :: argl) ->
+ let elt =
+ bigarray_get unsafe elt_kind layout
+ (transl arg1) (List.map transl argl) dbg in
+ begin match elt_kind with
+ Pbigarray_float32 | Pbigarray_float64 -> box_float elt
+ | Pbigarray_complex32 | Pbigarray_complex64 -> elt
+ | Pbigarray_int32 -> box_int Pint32 elt
+ | Pbigarray_int64 -> box_int Pint64 elt
+ | Pbigarray_native_int -> box_int Pnativeint elt
+ | Pbigarray_caml_int -> force_tag_int elt
+ | _ -> tag_int elt
+ end
+ | (Pbigarrayset(unsafe, num_dims, elt_kind, layout), arg1 :: argl) ->
+ let (argidx, argnewval) = split_last argl in
+ return_unit(bigarray_set unsafe elt_kind layout
+ (transl arg1)
+ (List.map transl argidx)
+ (match elt_kind with
+ Pbigarray_float32 | Pbigarray_float64 ->
+ transl_unbox_float argnewval
+ | Pbigarray_complex32 | Pbigarray_complex64 -> transl argnewval
+ | Pbigarray_int32 -> transl_unbox_int Pint32 argnewval
+ | Pbigarray_int64 -> transl_unbox_int Pint64 argnewval
+ | Pbigarray_native_int -> transl_unbox_int Pnativeint argnewval
+ | _ -> untag_int (transl argnewval))
+ dbg)
+ | (p, [arg]) ->
+ transl_prim_1 p arg dbg
+ | (p, [arg1; arg2]) ->
+ transl_prim_2 p arg1 arg2 dbg
+ | (p, [arg1; arg2; arg3]) ->
+ transl_prim_3 p arg1 arg2 arg3 dbg
+ | (_, _) ->
+ fatal_error "Cmmgen.transl:prim"
+ end
+
+ (* Control structures *)
+ | Uswitch(arg, s) ->
+ (* As in the bytecode interpreter, only matching against constants
+ can be checked *)
+ if Array.length s.us_index_blocks = 0 then
+ Cswitch
+ (untag_int (transl arg),
+ s.us_index_consts,
+ Array.map transl s.us_actions_consts)
+ else if Array.length s.us_index_consts = 0 then
+ transl_switch (get_tag (transl arg))
+ s.us_index_blocks s.us_actions_blocks
+ else
+ bind "switch" (transl arg) (fun arg ->
+ Cifthenelse(
+ Cop(Cand, [arg; Cconst_int 1]),
+ transl_switch
+ (untag_int arg) s.us_index_consts s.us_actions_consts,
+ transl_switch
+ (get_tag arg) s.us_index_blocks s.us_actions_blocks))
+ | Ustaticfail (nfail, args) ->
+ Cexit (nfail, List.map transl args)
+ | Ucatch(nfail, [], body, handler) ->
+ make_catch nfail (transl body) (transl handler)
+ | Ucatch(nfail, ids, body, handler) ->
+ Ccatch(nfail, ids, transl body, transl handler)
+ | Utrywith(body, exn, handler) ->
+ Ctrywith(transl body, exn, transl handler)
+ | Uifthenelse(Uprim(Pnot, [arg], _), ifso, ifnot) ->
+ transl (Uifthenelse(arg, ifnot, ifso))
+ | Uifthenelse(cond, ifso, Ustaticfail (nfail, [])) ->
+ exit_if_false cond (transl ifso) nfail
+ | Uifthenelse(cond, Ustaticfail (nfail, []), ifnot) ->
+ exit_if_true cond nfail (transl ifnot)
+ | Uifthenelse(Uprim(Psequand, _, _) as cond, ifso, ifnot) ->
+ let raise_num = next_raise_count () in
+ make_catch
+ raise_num
+ (exit_if_false cond (transl ifso) raise_num)
+ (transl ifnot)
+ | Uifthenelse(Uprim(Psequor, _, _) as cond, ifso, ifnot) ->
+ let raise_num = next_raise_count () in
+ make_catch
+ raise_num
+ (exit_if_true cond raise_num (transl ifnot))
+ (transl ifso)
+ | Uifthenelse (Uifthenelse (cond, condso, condnot), ifso, ifnot) ->
+ let num_true = next_raise_count () in
+ make_catch
+ num_true
+ (make_catch2
+ (fun shared_false ->
+ Cifthenelse
+ (test_bool (transl cond),
+ exit_if_true condso num_true shared_false,
+ exit_if_true condnot num_true shared_false))
+ (transl ifnot))
+ (transl ifso)
+ | Uifthenelse(cond, ifso, ifnot) ->
+ Cifthenelse(test_bool(transl cond), transl ifso, transl ifnot)
+ | Usequence(exp1, exp2) ->
+ Csequence(remove_unit(transl exp1), transl exp2)
+ | Uwhile(cond, body) ->
+ let raise_num = next_raise_count () in
+ return_unit
+ (Ccatch
+ (raise_num, [],
+ Cloop(exit_if_false cond (remove_unit(transl body)) raise_num),
+ Ctuple []))
+ | Ufor(id, low, high, dir, body) ->
+ let tst = match dir with Upto -> Cgt | Downto -> Clt in
+ let inc = match dir with Upto -> Caddi | Downto -> Csubi in
+ let raise_num = next_raise_count () in
+ let id_prev = Ident.rename id in
+ return_unit
+ (Clet
+ (id, transl low,
+ bind_nonvar "bound" (transl high) (fun high ->
+ Ccatch
+ (raise_num, [],
+ Cifthenelse
+ (Cop(Ccmpi tst, [Cvar id; high]), Cexit (raise_num, []),
+ Cloop
+ (Csequence
+ (remove_unit(transl body),
+ Clet(id_prev, Cvar id,
+ Csequence
+ (Cassign(id,
+ Cop(inc, [Cvar id; Cconst_int 2])),
+ Cifthenelse
+ (Cop(Ccmpi Ceq, [Cvar id_prev; high]),
+ Cexit (raise_num,[]), Ctuple [])))))),
+ Ctuple []))))
+ | Uassign(id, exp) ->
+ return_unit(Cassign(id, transl exp))
+
+and transl_prim_1 p arg dbg =
+ match p with
+ (* Generic operations *)
+ Pidentity ->
+ transl arg
+ | Pignore ->
+ return_unit(remove_unit (transl arg))
+ (* Heap operations *)
+ | Pfield n ->
+ get_field (transl arg) n
+ | Pfloatfield n ->
+ let ptr = transl arg in
+ box_float(
+ Cop(Cload Double_u,
+ [if n = 0 then ptr
+ else Cop(Cadda, [ptr; Cconst_int(n * size_float)])]))
+ (* Exceptions *)
+ | Praise ->
+ Cop(Craise dbg, [transl arg])
+ (* Integer operations *)
+ | Pnegint ->
+ Cop(Csubi, [Cconst_int 2; transl arg])
+ | Poffsetint n ->
+ if no_overflow_lsl n then
+ add_const (transl arg) (n lsl 1)
+ else
+ transl_prim_2 Paddint arg (Uconst (Const_base(Const_int n))) Debuginfo.none
+ | Poffsetref n ->
+ return_unit
+ (bind "ref" (transl arg) (fun arg ->
+ Cop(Cstore Word,
+ [arg; add_const (Cop(Cload Word, [arg])) (n lsl 1)])))
+ (* Floating-point operations *)
+ | Pfloatofint ->
+ box_float(Cop(Cfloatofint, [untag_int(transl arg)]))
+ | Pintoffloat ->
+ tag_int(Cop(Cintoffloat, [transl_unbox_float arg]))
+ | Pnegfloat ->
+ box_float(Cop(Cnegf, [transl_unbox_float arg]))
+ | Pabsfloat ->
+ box_float(Cop(Cabsf, [transl_unbox_float arg]))
+ (* String operations *)
+ | Pstringlength ->
+ tag_int(string_length (transl arg))
+ (* Array operations *)
+ | Parraylength kind ->
+ begin match kind with
+ Pgenarray ->
+ let len =
+ if wordsize_shift = numfloat_shift then
+ Cop(Clsr, [header(transl arg); Cconst_int wordsize_shift])
+ else
+ bind "header" (header(transl arg)) (fun hdr ->
+ Cifthenelse(is_addr_array_hdr hdr,
+ Cop(Clsr, [hdr; Cconst_int wordsize_shift]),
+ Cop(Clsr, [hdr; Cconst_int numfloat_shift]))) in
+ Cop(Cor, [len; Cconst_int 1])
+ | Paddrarray | Pintarray ->
+ Cop(Cor, [addr_array_length(header(transl arg)); Cconst_int 1])
+ | Pfloatarray ->
+ Cop(Cor, [float_array_length(header(transl arg)); Cconst_int 1])
+ end
+ (* Boolean operations *)
+ | Pnot ->
+ Cop(Csubi, [Cconst_int 4; transl arg]) (* 1 -> 3, 3 -> 1 *)
+ (* Test integer/block *)
+ | Pisint ->
+ tag_int(Cop(Cand, [transl arg; Cconst_int 1]))
+ (* Boxed integers *)
+ | Pbintofint bi ->
+ box_int bi (untag_int (transl arg))
+ | Pintofbint bi ->
+ force_tag_int (transl_unbox_int bi arg)
+ | Pcvtbint(bi1, bi2) ->
+ box_int bi2 (transl_unbox_int bi1 arg)
+ | Pnegbint bi ->
+ box_int bi (Cop(Csubi, [Cconst_int 0; transl_unbox_int bi arg]))
+ | _ ->
+ fatal_error "Cmmgen.transl_prim_1"
+
+and transl_prim_2 p arg1 arg2 dbg =
+ match p with
+ (* Heap operations *)
+ Psetfield(n, ptr) ->
+ if ptr then
+ return_unit(Cop(Cextcall("caml_modify", typ_void, false, Debuginfo.none),
+ [field_address (transl arg1) n; transl arg2]))
+ else
+ return_unit(set_field (transl arg1) n (transl arg2))
+ | Psetfloatfield n ->
+ let ptr = transl arg1 in
+ return_unit(
+ Cop(Cstore Double_u,
+ [if n = 0 then ptr
+ else Cop(Cadda, [ptr; Cconst_int(n * size_float)]);
+ transl_unbox_float arg2]))
+
+ (* Boolean operations *)
+ | Psequand ->
+ Cifthenelse(test_bool(transl arg1), transl arg2, Cconst_int 1)
+ (* let id = Ident.create "res1" in
+ Clet(id, transl arg1,
+ Cifthenelse(test_bool(Cvar id), transl arg2, Cvar id)) *)
+ | Psequor ->
+ Cifthenelse(test_bool(transl arg1), Cconst_int 3, transl arg2)
+
+ (* Integer operations *)
+ | Paddint ->
+ decr_int(add_int (transl arg1) (transl arg2))
+ | Psubint ->
+ incr_int(sub_int (transl arg1) (transl arg2))
+ | Pmulint ->
+ incr_int(Cop(Cmuli, [decr_int(transl arg1); untag_int(transl arg2)]))
+ | Pdivint ->
+ tag_int(safe_divmod Cdivi (untag_int(transl arg1)) (untag_int(transl arg2)) dbg)
+ | Pmodint ->
+ tag_int(safe_divmod Cmodi (untag_int(transl arg1)) (untag_int(transl arg2)) dbg)
+ | Pandint ->
+ Cop(Cand, [transl arg1; transl arg2])
+ | Porint ->
+ Cop(Cor, [transl arg1; transl arg2])
+ | Pxorint ->
+ Cop(Cor, [Cop(Cxor, [ignore_low_bit_int(transl arg1);
+ ignore_low_bit_int(transl arg2)]);
+ Cconst_int 1])
+ | Plslint ->
+ incr_int(lsl_int (decr_int(transl arg1)) (untag_int(transl arg2)))
+ | Plsrint ->
+ Cop(Cor, [Cop(Clsr, [transl arg1; untag_int(transl arg2)]);
+ Cconst_int 1])
+ | Pasrint ->
+ Cop(Cor, [Cop(Casr, [transl arg1; untag_int(transl arg2)]);
+ Cconst_int 1])
+ | Pintcomp cmp ->
+ tag_int(Cop(Ccmpi(transl_comparison cmp), [transl arg1; transl arg2]))
+ | Pisout ->
+ transl_isout (transl arg1) (transl arg2)
+ (* Float operations *)
+ | Paddfloat ->
+ box_float(Cop(Caddf,
+ [transl_unbox_float arg1; transl_unbox_float arg2]))
+ | Psubfloat ->
+ box_float(Cop(Csubf,
+ [transl_unbox_float arg1; transl_unbox_float arg2]))
+ | Pmulfloat ->
+ box_float(Cop(Cmulf,
+ [transl_unbox_float arg1; transl_unbox_float arg2]))
+ | Pdivfloat ->
+ box_float(Cop(Cdivf,
+ [transl_unbox_float arg1; transl_unbox_float arg2]))
+ | Pfloatcomp cmp ->
+ tag_int(Cop(Ccmpf(transl_comparison cmp),
+ [transl_unbox_float arg1; transl_unbox_float arg2]))
+
+ (* String operations *)
+ | Pstringrefu ->
+ tag_int(Cop(Cload Byte_unsigned,
+ [add_int (transl arg1) (untag_int(transl arg2))]))
+ | Pstringrefs ->
+ tag_int
+ (bind "str" (transl arg1) (fun str ->
+ bind "index" (untag_int (transl arg2)) (fun idx ->
+ Csequence(
+ Cop(Ccheckbound dbg, [string_length str; idx]),
+ Cop(Cload Byte_unsigned, [add_int str idx])))))
+
+ (* Array operations *)
+ | Parrayrefu kind ->
+ begin match kind with
+ Pgenarray ->
+ bind "arr" (transl arg1) (fun arr ->
+ bind "index" (transl arg2) (fun idx ->
+ Cifthenelse(is_addr_array_ptr arr,
+ addr_array_ref arr idx,
+ float_array_ref arr idx)))
+ | Paddrarray | Pintarray ->
+ addr_array_ref (transl arg1) (transl arg2)
+ | Pfloatarray ->
+ float_array_ref (transl arg1) (transl arg2)
+ end
+ | Parrayrefs kind ->
+ begin match kind with
+ Pgenarray ->
+ bind "index" (transl arg2) (fun idx ->
+ bind "arr" (transl arg1) (fun arr ->
+ bind "header" (header arr) (fun hdr ->
+ Cifthenelse(is_addr_array_hdr hdr,
+ Csequence(Cop(Ccheckbound dbg, [addr_array_length hdr; idx]),
+ addr_array_ref arr idx),
+ Csequence(Cop(Ccheckbound dbg, [float_array_length hdr; idx]),
+ float_array_ref arr idx)))))
+ | Paddrarray | Pintarray ->
+ bind "index" (transl arg2) (fun idx ->
+ bind "arr" (transl arg1) (fun arr ->
+ Csequence(Cop(Ccheckbound dbg, [addr_array_length(header arr); idx]),
+ addr_array_ref arr idx)))
+ | Pfloatarray ->
+ box_float(
+ bind "index" (transl arg2) (fun idx ->
+ bind "arr" (transl arg1) (fun arr ->
+ Csequence(Cop(Ccheckbound dbg,
+ [float_array_length(header arr); idx]),
+ unboxed_float_array_ref arr idx))))
+ end
+
+ (* Operations on bitvects *)
+ | Pbittest ->
+ bind "index" (untag_int(transl arg2)) (fun idx ->
+ tag_int(
+ Cop(Cand, [Cop(Clsr, [Cop(Cload Byte_unsigned,
+ [add_int (transl arg1)
+ (Cop(Clsr, [idx; Cconst_int 3]))]);
+ Cop(Cand, [idx; Cconst_int 7])]);
+ Cconst_int 1])))
+
+ (* Boxed integers *)
+ | Paddbint bi ->
+ box_int bi (Cop(Caddi,
+ [transl_unbox_int bi arg1; transl_unbox_int bi arg2]))
+ | Psubbint bi ->
+ box_int bi (Cop(Csubi,
+ [transl_unbox_int bi arg1; transl_unbox_int bi arg2]))
+ | Pmulbint bi ->
+ box_int bi (Cop(Cmuli,
+ [transl_unbox_int bi arg1; transl_unbox_int bi arg2]))
+ | Pdivbint bi ->
+ box_int bi (safe_divmod Cdivi
+ (transl_unbox_int bi arg1) (transl_unbox_int bi arg2)
+ dbg)
+ | Pmodbint bi ->
+ box_int bi (safe_divmod Cmodi
+ (transl_unbox_int bi arg1) (transl_unbox_int bi arg2)
+ dbg)
+ | Pandbint bi ->
+ box_int bi (Cop(Cand,
+ [transl_unbox_int bi arg1; transl_unbox_int bi arg2]))
+ | Porbint bi ->
+ box_int bi (Cop(Cor,
+ [transl_unbox_int bi arg1; transl_unbox_int bi arg2]))
+ | Pxorbint bi ->
+ box_int bi (Cop(Cxor,
+ [transl_unbox_int bi arg1; transl_unbox_int bi arg2]))
+ | Plslbint bi ->
+ box_int bi (Cop(Clsl,
+ [transl_unbox_int bi arg1; untag_int(transl arg2)]))
+ | Plsrbint bi ->
+ box_int bi (Cop(Clsr,
+ [make_unsigned_int bi (transl_unbox_int bi arg1);
+ untag_int(transl arg2)]))
+ | Pasrbint bi ->
+ box_int bi (Cop(Casr,
+ [transl_unbox_int bi arg1; untag_int(transl arg2)]))
+ | Pbintcomp(bi, cmp) ->
+ tag_int (Cop(Ccmpi(transl_comparison cmp),
+ [transl_unbox_int bi arg1; transl_unbox_int bi arg2]))
+ | _ ->
+ fatal_error "Cmmgen.transl_prim_2"
+
+and transl_prim_3 p arg1 arg2 arg3 dbg =
+ match p with
+ (* String operations *)
+ Pstringsetu ->
+ return_unit(Cop(Cstore Byte_unsigned,
+ [add_int (transl arg1) (untag_int(transl arg2));
+ untag_int(transl arg3)]))
+ | Pstringsets ->
+ return_unit
+ (bind "str" (transl arg1) (fun str ->
+ bind "index" (untag_int (transl arg2)) (fun idx ->
+ Csequence(
+ Cop(Ccheckbound dbg, [string_length str; idx]),
+ Cop(Cstore Byte_unsigned,
+ [add_int str idx; untag_int(transl arg3)])))))
+
+ (* Array operations *)
+ | Parraysetu kind ->
+ return_unit(begin match kind with
+ Pgenarray ->
+ bind "newval" (transl arg3) (fun newval ->
+ bind "index" (transl arg2) (fun index ->
+ bind "arr" (transl arg1) (fun arr ->
+ Cifthenelse(is_addr_array_ptr arr,
+ addr_array_set arr index newval,
+ float_array_set arr index (unbox_float newval)))))
+ | Paddrarray ->
+ addr_array_set (transl arg1) (transl arg2) (transl arg3)
+ | Pintarray ->
+ int_array_set (transl arg1) (transl arg2) (transl arg3)
+ | Pfloatarray ->
+ float_array_set (transl arg1) (transl arg2) (transl_unbox_float arg3)
+ end)
+ | Parraysets kind ->
+ return_unit(begin match kind with
+ Pgenarray ->
+ bind "newval" (transl arg3) (fun newval ->
+ bind "index" (transl arg2) (fun idx ->
+ bind "arr" (transl arg1) (fun arr ->
+ bind "header" (header arr) (fun hdr ->
+ Cifthenelse(is_addr_array_hdr hdr,
+ Csequence(Cop(Ccheckbound dbg, [addr_array_length hdr; idx]),
+ addr_array_set arr idx newval),
+ Csequence(Cop(Ccheckbound dbg, [float_array_length hdr; idx]),
+ float_array_set arr idx
+ (unbox_float newval)))))))
+ | Paddrarray ->
+ bind "index" (transl arg2) (fun idx ->
+ bind "arr" (transl arg1) (fun arr ->
+ Csequence(Cop(Ccheckbound dbg, [addr_array_length(header arr); idx]),
+ addr_array_set arr idx (transl arg3))))
+ | Pintarray ->
+ bind "index" (transl arg2) (fun idx ->
+ bind "arr" (transl arg1) (fun arr ->
+ Csequence(Cop(Ccheckbound dbg, [addr_array_length(header arr); idx]),
+ int_array_set arr idx (transl arg3))))
+ | Pfloatarray ->
+ bind "index" (transl arg2) (fun idx ->
+ bind "arr" (transl arg1) (fun arr ->
+ Csequence(Cop(Ccheckbound dbg, [float_array_length(header arr);idx]),
+ float_array_set arr idx (transl_unbox_float arg3))))
+ end)
+ | _ ->
+ fatal_error "Cmmgen.transl_prim_3"
+
+and transl_unbox_float = function
+ Uconst(Const_base(Const_float f)) -> Cconst_float f
+ | exp -> unbox_float(transl exp)
+
+and transl_unbox_int bi = function
+ Uconst(Const_base(Const_int32 n)) ->
+ Cconst_natint (Nativeint.of_int32 n)
+ | Uconst(Const_base(Const_nativeint n)) ->
+ Cconst_natint n
+ | Uconst(Const_base(Const_int64 n)) ->
+ assert (size_int = 8); Cconst_natint (Int64.to_nativeint n)
+ | Uprim(Pbintofint bi', [Uconst(Const_base(Const_int i))], _) when bi = bi' ->
+ Cconst_int i
+ | exp -> unbox_int bi (transl exp)
+
+and transl_unbox_let box_fn unbox_fn transl_unbox_fn id exp body =
+ let unboxed_id = Ident.create (Ident.name id) in
+ let trbody1 = transl body in
+ let (trbody2, need_boxed, is_assigned) =
+ subst_boxed_number unbox_fn id unboxed_id trbody1 in
+ if need_boxed && is_assigned then
+ Clet(id, transl exp, trbody1)
+ else
+ Clet(unboxed_id, transl_unbox_fn exp,
+ if need_boxed
+ then Clet(id, box_fn(Cvar unboxed_id), trbody2)
+ else trbody2)
+
+and make_catch ncatch body handler = match body with
+| Cexit (nexit,[]) when nexit=ncatch -> handler
+| _ -> Ccatch (ncatch, [], body, handler)
+
+and make_catch2 mk_body handler = match handler with
+| Cexit (_,[])|Ctuple []|Cconst_int _|Cconst_pointer _ ->
+ mk_body handler
+| _ ->
+ let nfail = next_raise_count () in
+ make_catch
+ nfail
+ (mk_body (Cexit (nfail,[])))
+ handler
+
+and exit_if_true cond nfail otherwise =
+ match cond with
+ | Uconst (Const_pointer 0) -> otherwise
+ | Uconst (Const_pointer 1) -> Cexit (nfail,[])
+ | Uprim(Psequor, [arg1; arg2], _) ->
+ exit_if_true arg1 nfail (exit_if_true arg2 nfail otherwise)
+ | Uprim(Psequand, _, _) ->
+ begin match otherwise with
+ | Cexit (raise_num,[]) ->
+ exit_if_false cond (Cexit (nfail,[])) raise_num
+ | _ ->
+ let raise_num = next_raise_count () in
+ make_catch
+ raise_num
+ (exit_if_false cond (Cexit (nfail,[])) raise_num)
+ otherwise
+ end
+ | Uprim(Pnot, [arg], _) ->
+ exit_if_false arg otherwise nfail
+ | Uifthenelse (cond, ifso, ifnot) ->
+ make_catch2
+ (fun shared ->
+ Cifthenelse
+ (test_bool (transl cond),
+ exit_if_true ifso nfail shared,
+ exit_if_true ifnot nfail shared))
+ otherwise
+ | _ ->
+ Cifthenelse(test_bool(transl cond), Cexit (nfail, []), otherwise)
+
+and exit_if_false cond otherwise nfail =
+ match cond with
+ | Uconst (Const_pointer 0) -> Cexit (nfail,[])
+ | Uconst (Const_pointer 1) -> otherwise
+ | Uprim(Psequand, [arg1; arg2], _) ->
+ exit_if_false arg1 (exit_if_false arg2 otherwise nfail) nfail
+ | Uprim(Psequor, _, _) ->
+ begin match otherwise with
+ | Cexit (raise_num,[]) ->
+ exit_if_true cond raise_num (Cexit (nfail,[]))
+ | _ ->
+ let raise_num = next_raise_count () in
+ make_catch
+ raise_num
+ (exit_if_true cond raise_num (Cexit (nfail,[])))
+ otherwise
+ end
+ | Uprim(Pnot, [arg], _) ->
+ exit_if_true arg nfail otherwise
+ | Uifthenelse (cond, ifso, ifnot) ->
+ make_catch2
+ (fun shared ->
+ Cifthenelse
+ (test_bool (transl cond),
+ exit_if_false ifso shared nfail,
+ exit_if_false ifnot shared nfail))
+ otherwise
+ | _ ->
+ Cifthenelse(test_bool(transl cond), otherwise, Cexit (nfail, []))
+
+and transl_switch arg index cases = match Array.length cases with
+| 0 -> fatal_error "Cmmgen.transl_switch"
+| 1 -> transl cases.(0)
+| _ ->
+ let n_index = Array.length index in
+ let actions = Array.map transl cases 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 ;
+ bind "switcher" arg
+ (fun a ->
+ SwitcherBlocks.zyva
+ (0,n_index-1)
+ (fun i -> Cconst_int i)
+ a
+ (Array.of_list !inters) actions)
+
+and transl_letrec bindings cont =
+ let bsz = List.map (fun (id, exp) -> (id, exp, expr_size exp)) bindings in
+ let rec init_blocks = function
+ | [] -> fill_nonrec bsz
+ | (id, exp, RHS_block sz) :: rem ->
+ Clet(id, Cop(Cextcall("caml_alloc_dummy", typ_addr, true, Debuginfo.none),
+ [int_const sz]),
+ init_blocks rem)
+ | (id, exp, RHS_nonrec) :: rem ->
+ Clet (id, Cconst_int 0, init_blocks rem)
+ and fill_nonrec = function
+ | [] -> fill_blocks bsz
+ | (id, exp, RHS_block sz) :: rem -> fill_nonrec rem
+ | (id, exp, RHS_nonrec) :: rem ->
+ Clet (id, transl exp, fill_nonrec rem)
+ and fill_blocks = function
+ | [] -> cont
+ | (id, exp, RHS_block _) :: rem ->
+ Csequence(Cop(Cextcall("caml_update_dummy", typ_void, false, Debuginfo.none),
+ [Cvar id; transl exp]),
+ fill_blocks rem)
+ | (id, exp, RHS_nonrec) :: rem ->
+ fill_blocks rem
+ in init_blocks bsz
+
+(* Translate a function definition *)
+
+let transl_function lbl params body =
+ Cfunction {fun_name = lbl;
+ fun_args = List.map (fun id -> (id, typ_addr)) params;
+ fun_body = transl body;
+ fun_fast = !Clflags.optimize_for_speed}
+
+(* Translate all function definitions *)
+
+module StringSet =
+ Set.Make(struct
+ type t = string
+ let compare = compare
+ end)
+
+let rec transl_all_functions already_translated cont =
+ try
+ let (lbl, params, body) = Queue.take functions in
+ if StringSet.mem lbl already_translated then
+ transl_all_functions already_translated cont
+ else begin
+ transl_all_functions (StringSet.add lbl already_translated)
+ (transl_function lbl params body :: cont)
+ end
+ with Queue.Empty ->
+ cont
+
+(* Emit structured constants *)
+
+let immstrings = Hashtbl.create 17
+
+let rec emit_constant symb cst cont =
+ match cst with
+ Const_base(Const_float s) ->
+ Cint(float_header) :: Cdefine_symbol symb :: Cdouble s :: cont
+ | Const_base(Const_string s) | Const_immstring s ->
+ Cint(string_header (String.length s)) ::
+ Cdefine_symbol symb ::
+ emit_string_constant s cont
+ | Const_base(Const_int32 n) ->
+ Cint(boxedint32_header) :: Cdefine_symbol symb ::
+ emit_boxed_int32_constant n cont
+ | Const_base(Const_int64 n) ->
+ Cint(boxedint64_header) :: Cdefine_symbol symb ::
+ emit_boxed_int64_constant n cont
+ | Const_base(Const_nativeint n) ->
+ Cint(boxedintnat_header) :: Cdefine_symbol symb ::
+ emit_boxed_nativeint_constant n cont
+ | Const_block(tag, fields) ->
+ let (emit_fields, cont1) = emit_constant_fields fields cont in
+ Cint(block_header tag (List.length fields)) ::
+ Cdefine_symbol symb ::
+ emit_fields @ cont1
+ | Const_float_array(fields) ->
+ Cint(floatarray_header (List.length fields)) ::
+ Cdefine_symbol symb ::
+ Misc.map_end (fun f -> Cdouble f) fields cont
+ | _ -> fatal_error "gencmm.emit_constant"
+
+and emit_constant_fields fields cont =
+ match fields with
+ [] -> ([], cont)
+ | f1 :: fl ->
+ let (data1, cont1) = emit_constant_field f1 cont in
+ let (datal, contl) = emit_constant_fields fl cont1 in
+ (data1 :: datal, contl)
+
+and emit_constant_field field cont =
+ match field with
+ Const_base(Const_int n) ->
+ (Cint(Nativeint.add (Nativeint.shift_left (Nativeint.of_int n) 1) 1n),
+ cont)
+ | Const_base(Const_char c) ->
+ (Cint(Nativeint.of_int(((Char.code c) lsl 1) + 1)), cont)
+ | Const_base(Const_float s) ->
+ let lbl = new_const_label() in
+ (Clabel_address lbl,
+ Cint(float_header) :: Cdefine_label lbl :: Cdouble s :: cont)
+ | Const_base(Const_string s) ->
+ let lbl = new_const_label() in
+ (Clabel_address lbl,
+ Cint(string_header (String.length s)) :: Cdefine_label lbl ::
+ emit_string_constant s cont)
+ | Const_immstring s ->
+ begin try
+ (Clabel_address (Hashtbl.find immstrings s), cont)
+ with Not_found ->
+ let lbl = new_const_label() in
+ Hashtbl.add immstrings s lbl;
+ (Clabel_address lbl,
+ Cint(string_header (String.length s)) :: Cdefine_label lbl ::
+ emit_string_constant s cont)
+ end
+ | Const_base(Const_int32 n) ->
+ let lbl = new_const_label() in
+ (Clabel_address lbl,
+ Cint(boxedint32_header) :: Cdefine_label lbl ::
+ emit_boxed_int32_constant n cont)
+ | Const_base(Const_int64 n) ->
+ let lbl = new_const_label() in
+ (Clabel_address lbl,
+ Cint(boxedint64_header) :: Cdefine_label lbl ::
+ emit_boxed_int64_constant n cont)
+ | Const_base(Const_nativeint n) ->
+ let lbl = new_const_label() in
+ (Clabel_address lbl,
+ Cint(boxedintnat_header) :: Cdefine_label lbl ::
+ emit_boxed_nativeint_constant n cont)
+ | Const_pointer n ->
+ (Cint(Nativeint.add (Nativeint.shift_left (Nativeint.of_int n) 1) 1n),
+ cont)
+ | Const_block(tag, fields) ->
+ let lbl = new_const_label() in
+ let (emit_fields, cont1) = emit_constant_fields fields cont in
+ (Clabel_address lbl,
+ Cint(block_header tag (List.length fields)) :: Cdefine_label lbl ::
+ emit_fields @ cont1)
+ | Const_float_array(fields) ->
+ let lbl = new_const_label() in
+ (Clabel_address lbl,
+ Cint(floatarray_header (List.length fields)) :: Cdefine_label lbl ::
+ Misc.map_end (fun f -> Cdouble f) fields 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
+
+(* Emit constant closures *)
+
+let emit_constant_closure symb fundecls cont =
+ match fundecls with
+ [] -> assert false
+ | (label, arity, params, body) :: remainder ->
+ let rec emit_others pos = function
+ [] -> cont
+ | (label, arity, params, body) :: rem ->
+ if arity = 1 then
+ Cint(infix_header pos) ::
+ Csymbol_address label ::
+ Cint 3n ::
+ emit_others (pos + 3) rem
+ else
+ Cint(infix_header pos) ::
+ Csymbol_address(curry_function arity) ::
+ Cint(Nativeint.of_int (arity lsl 1 + 1)) ::
+ Csymbol_address label ::
+ emit_others (pos + 4) rem in
+ Cint(closure_header (fundecls_size fundecls)) ::
+ Cdefine_symbol symb ::
+ if arity = 1 then
+ Csymbol_address label ::
+ Cint 3n ::
+ emit_others 3 remainder
+ else
+ Csymbol_address(curry_function arity) ::
+ Cint(Nativeint.of_int (arity lsl 1 + 1)) ::
+ Csymbol_address label ::
+ emit_others 4 remainder
+
+(* Emit all structured constants *)
+
+let emit_all_constants cont =
+ let c = ref cont in
+ List.iter
+ (fun (lbl, cst) -> c := Cdata(emit_constant lbl cst []) :: !c)
+ !structured_constants;
+ structured_constants := [];
+ Hashtbl.clear immstrings; (* PR#3979 *)
+ List.iter
+ (fun (symb, fundecls) ->
+ c := Cdata(emit_constant_closure symb fundecls []) :: !c)
+ !constant_closures;
+ constant_closures := [];
+ !c
+
+(* Translate a compilation unit *)
+
+let compunit size ulam =
+ let glob = Compilenv.make_symbol None in
+ let init_code = transl ulam in
+ let c1 = [Cfunction {fun_name = Compilenv.make_symbol (Some "entry");
+ fun_args = [];
+ fun_body = init_code; fun_fast = false}] in
+ let c2 = transl_all_functions StringSet.empty c1 in
+ let c3 = emit_all_constants c2 in
+ Cdata [Cint(block_header 0 size);
+ Cglobal_symbol glob;
+ Cdefine_symbol glob;
+ Cskip(size * size_addr)] :: c3
+
+(*
+CAMLprim value caml_cache_public_method (value meths, value tag, value *cache)
+{
+ int li = 3, hi = Field(meths,0), mi;
+ while (li < hi) { // no need to check the 1st time
+ mi = ((li+hi) >> 1) | 1;
+ if (tag < Field(meths,mi)) hi = mi-2;
+ else li = mi;
+ }
+ *cache = (li-3)*sizeof(value)+1;
+ return Field (meths, li-1);
+}
+*)
+
+let cache_public_method meths tag cache =
+ let raise_num = next_raise_count () in
+ let li = Ident.create "li" and hi = Ident.create "hi"
+ and mi = Ident.create "mi" and tagged = Ident.create "tagged" in
+ Clet (
+ li, Cconst_int 3,
+ Clet (
+ hi, Cop(Cload Word, [meths]),
+ Csequence(
+ Ccatch
+ (raise_num, [],
+ Cloop
+ (Clet(
+ mi,
+ Cop(Cor,
+ [Cop(Clsr, [Cop(Caddi, [Cvar li; Cvar hi]); Cconst_int 1]);
+ Cconst_int 1]),
+ Csequence(
+ Cifthenelse
+ (Cop (Ccmpi Clt,
+ [tag;
+ Cop(Cload Word,
+ [Cop(Cadda,
+ [meths; lsl_const (Cvar mi) log2_size_addr])])]),
+ Cassign(hi, Cop(Csubi, [Cvar mi; Cconst_int 2])),
+ Cassign(li, Cvar mi)),
+ Cifthenelse
+ (Cop(Ccmpi Cge, [Cvar li; Cvar hi]), Cexit (raise_num, []),
+ Ctuple [])))),
+ Ctuple []),
+ Clet (
+ tagged, Cop(Cadda, [lsl_const (Cvar li) log2_size_addr;
+ Cconst_int(1 - 3 * size_addr)]),
+ Csequence(Cop (Cstore Word, [cache; Cvar tagged]),
+ Cvar tagged)))))
+
+(* 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 arg = Array.create arity (Ident.create "arg") in
+ for i = 1 to arity - 1 do arg.(i) <- Ident.create "arg" done;
+ let clos = Ident.create "clos" in
+ let rec app_fun clos n =
+ if n = arity-1 then
+ Cop(Capply(typ_addr, Debuginfo.none),
+ [get_field (Cvar clos) 0; Cvar arg.(n); Cvar clos])
+ else begin
+ let newclos = Ident.create "clos" in
+ Clet(newclos,
+ Cop(Capply(typ_addr, Debuginfo.none),
+ [get_field (Cvar clos) 0; Cvar arg.(n); Cvar clos]),
+ 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 (Cvar clos) 1; int_const arity]),
+ Cop(Capply(typ_addr, Debuginfo.none),
+ get_field (Cvar clos) 2 :: List.map (fun s -> Cvar s) all_args),
+ app_fun clos 0))
+
+let send_function arity =
+ let (args, clos', body) = apply_function_body (1+arity) in
+ let cache = Ident.create "cache"
+ and obj = List.hd args
+ and tag = Ident.create "tag" in
+ let clos =
+ let cache = Cvar cache and obj = Cvar obj and tag = Cvar tag in
+ let meths = Ident.create "meths" and cached = Ident.create "cached" in
+ let real = Ident.create "real" in
+ let mask = get_field (Cvar meths) 1 in
+ let cached_pos = Cvar cached in
+ let tag_pos = Cop(Cadda, [Cop (Cadda, [cached_pos; Cvar meths]);
+ Cconst_int(3*size_addr-1)]) in
+ let tag' = Cop(Cload Word, [tag_pos]) in
+ Clet (
+ meths, Cop(Cload Word, [obj]),
+ Clet (
+ cached, Cop(Cand, [Cop(Cload Word, [cache]); mask]),
+ Clet (
+ real,
+ Cifthenelse(Cop(Ccmpa Cne, [tag'; tag]),
+ cache_public_method (Cvar meths) tag cache,
+ cached_pos),
+ Cop(Cload Word, [Cop(Cadda, [Cop (Cadda, [Cvar real; Cvar meths]);
+ Cconst_int(2*size_addr-1)])]))))
+
+ in
+ let body = Clet(clos', clos, body) in
+ let fun_args =
+ [obj, typ_addr; tag, typ_int; cache, typ_addr]
+ @ List.map (fun id -> (id, typ_addr)) (List.tl args) in
+ Cfunction
+ {fun_name = "caml_send" ^ string_of_int arity;
+ fun_args = fun_args;
+ fun_body = body;
+ fun_fast = true}
+
+let apply_function arity =
+ let (args, clos, body) = apply_function_body arity in
+ let all_args = args @ [clos] in
+ Cfunction
+ {fun_name = "caml_apply" ^ string_of_int arity;
+ fun_args = List.map (fun id -> (id, typ_addr)) all_args;
+ fun_body = body;
+ fun_fast = true}
+
+(* Generate tuplifying functions:
+ (defun caml_tuplifyN (arg clos)
+ (app clos.direct #0(arg) ... #N-1(arg) clos)) *)
+
+let tuplify_function arity =
+ let arg = Ident.create "arg" in
+ let clos = Ident.create "clos" in
+ let rec access_components i =
+ if i >= arity
+ then []
+ else get_field (Cvar arg) i :: access_components(i+1) in
+ Cfunction
+ {fun_name = "caml_tuplify" ^ string_of_int arity;
+ fun_args = [arg, typ_addr; clos, typ_addr];
+ fun_body =
+ Cop(Capply(typ_addr, Debuginfo.none),
+ get_field (Cvar clos) 2 :: access_components 0 @ [Cvar clos]);
+ fun_fast = true}
+
+(* Generate currying functions:
+ (defun caml_curryN (arg clos)
+ (alloc HDR caml_curryN_1 arg clos))
+ (defun caml_curryN_1 (arg clos)
+ (alloc HDR caml_curryN_2 arg clos))
+ ...
+ (defun caml_curryN_N-1 (arg clos)
+ (let (closN-2 clos.cdr
+ closN-3 closN-2.cdr
+ ...
+ clos1 clos2.cdr
+ clos clos1.cdr)
+ (app clos.direct
+ clos1.car clos2.car ... closN-2.car clos.car arg clos))) *)
+
+let final_curry_function arity =
+ let last_arg = Ident.create "arg" in
+ let last_clos = Ident.create "clos" in
+ let rec curry_fun args clos n =
+ if n = 0 then
+ Cop(Capply(typ_addr, Debuginfo.none),
+ get_field (Cvar clos) 2 ::
+ args @ [Cvar last_arg; Cvar clos])
+ else begin
+ let newclos = Ident.create "clos" in
+ Clet(newclos,
+ get_field (Cvar clos) 3,
+ curry_fun (get_field (Cvar clos) 2 :: args) newclos (n-1))
+ end in
+ Cfunction
+ {fun_name = "caml_curry" ^ string_of_int arity ^
+ "_" ^ string_of_int (arity-1);
+ fun_args = [last_arg, typ_addr; last_clos, typ_addr];
+ fun_body = curry_fun [] last_clos (arity-1);
+ fun_fast = true}
+
+let rec intermediate_curry_functions arity num =
+ if num = arity - 1 then
+ [final_curry_function arity]
+ else begin
+ let name1 = "caml_curry" ^ string_of_int arity in
+ let name2 = if num = 0 then name1 else name1 ^ "_" ^ string_of_int num in
+ let arg = Ident.create "arg" and clos = Ident.create "clos" in
+ Cfunction
+ {fun_name = name2;
+ fun_args = [arg, typ_addr; clos, typ_addr];
+ fun_body = Cop(Calloc,
+ [alloc_closure_header 4;
+ Cconst_symbol(name1 ^ "_" ^ string_of_int (num+1));
+ int_const 1; Cvar arg; Cvar clos]);
+ fun_fast = true}
+ :: intermediate_curry_functions arity (num+1)
+ end
+
+let curry_function arity =
+ if arity >= 0
+ then intermediate_curry_functions arity 0
+ else [tuplify_function (-arity)]
+
+
+module IntSet = Set.Make(
+ struct
+ type t = int
+ let compare = compare
+ end)
+
+let default_apply = IntSet.add 2 (IntSet.add 3 IntSet.empty)
+ (* These apply funs are always present in the main program because
+ the run-time system needs them (cf. asmrun/<arch>.S) . *)
+
+let generic_functions shared units =
+ let (apply,send,curry) =
+ List.fold_left
+ (fun (apply,send,curry) ui ->
+ List.fold_right IntSet.add ui.ui_apply_fun apply,
+ List.fold_right IntSet.add ui.ui_send_fun send,
+ List.fold_right IntSet.add ui.ui_curry_fun curry)
+ (IntSet.empty,IntSet.empty,IntSet.empty)
+ units in
+ let apply = if shared then apply else IntSet.union apply default_apply in
+ let accu = IntSet.fold (fun n accu -> apply_function n :: accu) apply [] in
+ let accu = IntSet.fold (fun n accu -> send_function n :: accu) send accu in
+ IntSet.fold (fun n accu -> curry_function n @ accu) curry accu
+
+(* Generate the entry point *)
+
+let entry_point namelist =
+ let incr_global_inited =
+ Cop(Cstore Word,
+ [Cconst_symbol "caml_globals_inited";
+ Cop(Caddi, [Cop(Cload Word, [Cconst_symbol "caml_globals_inited"]);
+ Cconst_int 1])]) 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, Debuginfo.none),
+ [Cconst_symbol entry_sym]),
+ Csequence(incr_global_inited, next)))
+ namelist (Cconst_int 1) in
+ Cfunction {fun_name = "caml_program";
+ fun_args = [];
+ fun_body = body;
+ fun_fast = false}
+
+(* Generate the table of globals *)
+
+let cint_zero = Cint 0n
+
+let global_table namelist =
+ let mksym name =
+ Csymbol_address (Compilenv.make_symbol ~unitname:name None)
+ 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(Cglobal_symbol name ::
+ emit_constant name
+ (Const_base (Const_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 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 name =
+ let bucketname = "caml_bucket_" ^ name in
+ let symname = "caml_exn_" ^ name in
+ Cdata(Cglobal_symbol symname ::
+ emit_constant symname (Const_block(0,[Const_base(Const_string name)]))
+ [ Cglobal_symbol bucketname;
+ Cint(block_header 0 1);
+ Cdefine_symbol bucketname;
+ Csymbol_address symname ])
+
+(* Header for a plugin *)
+
+let mapflat f l = List.flatten (List.map f l)
+
+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 }