ocaml/asmcomp/cmm.ml

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