336 lines
9.6 KiB
OCaml
336 lines
9.6 KiB
OCaml
(**************************************************************************)
|
|
(* *)
|
|
(* OCaml *)
|
|
(* *)
|
|
(* 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 GNU Lesser General Public License version 2.1, with the *)
|
|
(* special exception on linking described in the file LICENSE. *)
|
|
(* *)
|
|
(**************************************************************************)
|
|
|
|
type machtype_component =
|
|
| Val
|
|
| Addr
|
|
| Int
|
|
| Float
|
|
|
|
type machtype = machtype_component array
|
|
|
|
let typ_void = ([||] : machtype_component array)
|
|
let typ_val = [|Val|]
|
|
let typ_addr = [|Addr|]
|
|
let typ_int = [|Int|]
|
|
let typ_float = [|Float|]
|
|
|
|
(** [machtype_component]s are partially ordered as follows:
|
|
|
|
Addr Float
|
|
^
|
|
|
|
|
Val
|
|
^
|
|
|
|
|
Int
|
|
|
|
In particular, [Addr] must be above [Val], to ensure that if there is
|
|
a join point between a code path yielding [Addr] and one yielding [Val]
|
|
then the result is treated as a derived pointer into the heap (i.e. [Addr]).
|
|
(Such a result may not be live across any call site or a fatal compiler
|
|
error will result.)
|
|
*)
|
|
|
|
let lub_component comp1 comp2 =
|
|
match comp1, comp2 with
|
|
| Int, Int -> Int
|
|
| Int, Val -> Val
|
|
| Int, Addr -> Addr
|
|
| Val, Int -> Val
|
|
| Val, Val -> Val
|
|
| Val, Addr -> Addr
|
|
| Addr, Int -> Addr
|
|
| Addr, Addr -> Addr
|
|
| Addr, Val -> Addr
|
|
| Float, Float -> Float
|
|
| (Int | Addr | Val), Float
|
|
| Float, (Int | Addr | Val) ->
|
|
(* Float unboxing code must be sure to avoid this case. *)
|
|
assert false
|
|
|
|
let ge_component comp1 comp2 =
|
|
match comp1, comp2 with
|
|
| Int, Int -> true
|
|
| Int, Addr -> false
|
|
| Int, Val -> false
|
|
| Val, Int -> true
|
|
| Val, Val -> true
|
|
| Val, Addr -> false
|
|
| Addr, Int -> true
|
|
| Addr, Addr -> true
|
|
| Addr, Val -> true
|
|
| Float, Float -> true
|
|
| (Int | Addr | Val), Float
|
|
| Float, (Int | Addr | Val) ->
|
|
assert false
|
|
|
|
type exttype =
|
|
| XInt
|
|
| XInt32
|
|
| XInt64
|
|
| XFloat
|
|
|
|
let machtype_of_exttype = function
|
|
| XInt -> typ_int
|
|
| XInt32 -> typ_int
|
|
| XInt64 -> if Arch.size_int = 4 then [|Int;Int|] else typ_int
|
|
| XFloat -> typ_float
|
|
|
|
let machtype_of_exttype_list xtl =
|
|
Array.concat (List.map machtype_of_exttype xtl)
|
|
|
|
type integer_comparison = Lambda.integer_comparison =
|
|
| Ceq | Cne | Clt | Cgt | Cle | Cge
|
|
|
|
let negate_integer_comparison = Lambda.negate_integer_comparison
|
|
|
|
let swap_integer_comparison = Lambda.swap_integer_comparison
|
|
|
|
(* With floats [not (x < y)] is not the same as [x >= y] due to NaNs,
|
|
so we provide additional comparisons to represent the negations.*)
|
|
type float_comparison = Lambda.float_comparison =
|
|
| CFeq | CFneq | CFlt | CFnlt | CFgt | CFngt | CFle | CFnle | CFge | CFnge
|
|
|
|
let negate_float_comparison = Lambda.negate_float_comparison
|
|
|
|
let swap_float_comparison = Lambda.swap_float_comparison
|
|
type label = int
|
|
|
|
let init_label = 99
|
|
|
|
let label_counter = ref init_label
|
|
|
|
let set_label l =
|
|
if (l < !label_counter) then begin
|
|
Misc.fatal_errorf "Cannot set label counter to %d, it must be >= %d"
|
|
l !label_counter ()
|
|
end;
|
|
label_counter := l
|
|
|
|
let cur_label () = !label_counter
|
|
|
|
let new_label() = incr label_counter; !label_counter
|
|
|
|
type rec_flag = Nonrecursive | Recursive
|
|
|
|
type phantom_defining_expr =
|
|
| Cphantom_const_int of Targetint.t
|
|
| Cphantom_const_symbol of string
|
|
| Cphantom_var of Backend_var.t
|
|
| Cphantom_offset_var of { var : Backend_var.t; offset_in_words : int; }
|
|
| Cphantom_read_field of { var : Backend_var.t; field : int; }
|
|
| Cphantom_read_symbol_field of { sym : string; field : int; }
|
|
| Cphantom_block of { tag : int; fields : Backend_var.t list; }
|
|
|
|
type memory_chunk =
|
|
Byte_unsigned
|
|
| Byte_signed
|
|
| Sixteen_unsigned
|
|
| Sixteen_signed
|
|
| Thirtytwo_unsigned
|
|
| Thirtytwo_signed
|
|
| Word_int
|
|
| Word_val
|
|
| Single
|
|
| Double
|
|
| Double_u
|
|
|
|
and operation =
|
|
Capply of machtype
|
|
| Cextcall of string * machtype * exttype list * bool
|
|
| Cload of memory_chunk * Asttypes.mutable_flag
|
|
| Calloc
|
|
| Cstore of memory_chunk * Lambda.initialization_or_assignment
|
|
| Caddi | Csubi | Cmuli | Cmulhi | Cdivi | Cmodi
|
|
| Cand | Cor | Cxor | Clsl | Clsr | Casr
|
|
| Ccmpi of integer_comparison
|
|
| Caddv | Cadda
|
|
| Ccmpa of integer_comparison
|
|
| Cnegf | Cabsf
|
|
| Caddf | Csubf | Cmulf | Cdivf
|
|
| Cfloatofint | Cintoffloat
|
|
| Ccmpf of float_comparison
|
|
| Craise of Lambda.raise_kind
|
|
| Ccheckbound
|
|
|
|
type expression =
|
|
Cconst_int of int * Debuginfo.t
|
|
| Cconst_natint of nativeint * Debuginfo.t
|
|
| Cconst_float of float * Debuginfo.t
|
|
| Cconst_symbol of string * Debuginfo.t
|
|
| Cvar of Backend_var.t
|
|
| Clet of Backend_var.With_provenance.t * expression * expression
|
|
| Clet_mut of Backend_var.With_provenance.t * machtype
|
|
* expression * expression
|
|
| Cphantom_let of Backend_var.With_provenance.t
|
|
* phantom_defining_expr option * expression
|
|
| Cassign of Backend_var.t * expression
|
|
| Ctuple of expression list
|
|
| Cop of operation * expression list * Debuginfo.t
|
|
| Csequence of expression * expression
|
|
| Cifthenelse of expression * Debuginfo.t * expression
|
|
* Debuginfo.t * expression * Debuginfo.t
|
|
| Cswitch of expression * int array * (expression * Debuginfo.t) array
|
|
* Debuginfo.t
|
|
| Ccatch of
|
|
rec_flag
|
|
* (int * (Backend_var.With_provenance.t * machtype) list
|
|
* expression * Debuginfo.t) list
|
|
* expression
|
|
| Cexit of int * expression list
|
|
| Ctrywith of expression * Backend_var.With_provenance.t * expression
|
|
* Debuginfo.t
|
|
|
|
type codegen_option =
|
|
| Reduce_code_size
|
|
| No_CSE
|
|
|
|
type fundecl =
|
|
{ fun_name: string;
|
|
fun_args: (Backend_var.With_provenance.t * machtype) list;
|
|
fun_body: expression;
|
|
fun_codegen_options : codegen_option list;
|
|
fun_dbg : Debuginfo.t;
|
|
}
|
|
|
|
type data_item =
|
|
Cdefine_symbol of string
|
|
| Cglobal_symbol of string
|
|
| Cint8 of int
|
|
| Cint16 of int
|
|
| Cint32 of nativeint
|
|
| Cint of nativeint
|
|
| Csingle of float
|
|
| Cdouble of float
|
|
| Csymbol_address of string
|
|
| Cstring of string
|
|
| Cskip of int
|
|
| Calign of int
|
|
|
|
type phrase =
|
|
Cfunction of fundecl
|
|
| Cdata of data_item list
|
|
|
|
let ccatch (i, ids, e1, e2, dbg) =
|
|
Ccatch(Nonrecursive, [i, ids, e2, dbg], e1)
|
|
|
|
let reset () =
|
|
label_counter := init_label
|
|
|
|
let iter_shallow_tail f = function
|
|
| Clet(_, _, body) | Cphantom_let (_, _, body) | Clet_mut(_, _, _, body) ->
|
|
f body;
|
|
true
|
|
| Cifthenelse(_cond, _ifso_dbg, ifso, _ifnot_dbg, ifnot, _dbg) ->
|
|
f ifso;
|
|
f ifnot;
|
|
true
|
|
| Csequence(_e1, e2) ->
|
|
f e2;
|
|
true
|
|
| Cswitch(_e, _tbl, el, _dbg') ->
|
|
Array.iter (fun (e, _dbg) -> f e) el;
|
|
true
|
|
| Ccatch(_rec_flag, handlers, body) ->
|
|
List.iter (fun (_, _, h, _dbg) -> f h) handlers;
|
|
f body;
|
|
true
|
|
| Ctrywith(e1, _id, e2, _dbg) ->
|
|
f e1;
|
|
f e2;
|
|
true
|
|
| Cexit _ | Cop (Craise _, _, _) ->
|
|
true
|
|
| Cconst_int _
|
|
| Cconst_natint _
|
|
| Cconst_float _
|
|
| Cconst_symbol _
|
|
| Cvar _
|
|
| Cassign _
|
|
| Ctuple _
|
|
| Cop _ ->
|
|
false
|
|
|
|
let rec map_tail f = function
|
|
| Clet(id, exp, body) ->
|
|
Clet(id, exp, map_tail f body)
|
|
| Clet_mut(id, kind, exp, body) ->
|
|
Clet_mut(id, kind, exp, map_tail f body)
|
|
| Cphantom_let(id, exp, body) ->
|
|
Cphantom_let (id, exp, map_tail f body)
|
|
| Cifthenelse(cond, ifso_dbg, ifso, ifnot_dbg, ifnot, dbg) ->
|
|
Cifthenelse
|
|
(
|
|
cond,
|
|
ifso_dbg, map_tail f ifso,
|
|
ifnot_dbg, map_tail f ifnot,
|
|
dbg
|
|
)
|
|
| Csequence(e1, e2) ->
|
|
Csequence(e1, map_tail f e2)
|
|
| Cswitch(e, tbl, el, dbg') ->
|
|
Cswitch(e, tbl, Array.map (fun (e, dbg) -> map_tail f e, dbg) el, dbg')
|
|
| Ccatch(rec_flag, handlers, body) ->
|
|
let map_h (n, ids, handler, dbg) = (n, ids, map_tail f handler, dbg) in
|
|
Ccatch(rec_flag, List.map map_h handlers, map_tail f body)
|
|
| Ctrywith(e1, id, e2, dbg) ->
|
|
Ctrywith(map_tail f e1, id, map_tail f e2, dbg)
|
|
| Cexit _ | Cop (Craise _, _, _) as cmm ->
|
|
cmm
|
|
| Cconst_int _
|
|
| Cconst_natint _
|
|
| Cconst_float _
|
|
| Cconst_symbol _
|
|
| Cvar _
|
|
| Cassign _
|
|
| Ctuple _
|
|
| Cop _ as c ->
|
|
f c
|
|
|
|
let map_shallow f = function
|
|
| Clet (id, e1, e2) ->
|
|
Clet (id, f e1, f e2)
|
|
| Clet_mut (id, kind, e1, e2) ->
|
|
Clet_mut (id, kind, f e1, f e2)
|
|
| Cphantom_let (id, de, e) ->
|
|
Cphantom_let (id, de, f e)
|
|
| Cassign (id, e) ->
|
|
Cassign (id, f e)
|
|
| Ctuple el ->
|
|
Ctuple (List.map f el)
|
|
| Cop (op, el, dbg) ->
|
|
Cop (op, List.map f el, dbg)
|
|
| Csequence (e1, e2) ->
|
|
Csequence (f e1, f e2)
|
|
| Cifthenelse(cond, ifso_dbg, ifso, ifnot_dbg, ifnot, dbg) ->
|
|
Cifthenelse(f cond, ifso_dbg, f ifso, ifnot_dbg, f ifnot, dbg)
|
|
| Cswitch (e, ia, ea, dbg) ->
|
|
Cswitch (e, ia, Array.map (fun (e, dbg) -> f e, dbg) ea, dbg)
|
|
| Ccatch (rf, hl, body) ->
|
|
let map_h (n, ids, handler, dbg) = (n, ids, f handler, dbg) in
|
|
Ccatch (rf, List.map map_h hl, f body)
|
|
| Cexit (n, el) ->
|
|
Cexit (n, List.map f el)
|
|
| Ctrywith (e1, id, e2, dbg) ->
|
|
Ctrywith (f e1, id, f e2, dbg)
|
|
| Cconst_int _
|
|
| Cconst_natint _
|
|
| Cconst_float _
|
|
| Cconst_symbol _
|
|
| Cvar _
|
|
as c ->
|
|
c
|