summaryrefslogtreecommitdiff
path: root/src/c_backend.ml
diff options
context:
space:
mode:
authorJon French2018-06-11 15:25:02 +0100
committerJon French2018-06-11 15:25:02 +0100
commit826e94548a86a88d8fefeb1edef177c02bf5d68d (patch)
treefc9a5484440e030cc479101c5cab345c1c77468e /src/c_backend.ml
parent5717bb3d0cef5932cb2b33bc66b3b2f0c0552164 (diff)
parent4336409f923c10a8c5e4acc91fa7e6ef5551a88f (diff)
Merge branch 'sail2' into mappings
(involved some manual tinkering with gitignore, type_check, riscv)
Diffstat (limited to 'src/c_backend.ml')
-rw-r--r--src/c_backend.ml1152
1 files changed, 513 insertions, 639 deletions
diff --git a/src/c_backend.ml b/src/c_backend.ml
index 23a8c92e..06e92f3a 100644
--- a/src/c_backend.ml
+++ b/src/c_backend.ml
@@ -51,6 +51,7 @@
open Ast
open Ast_util
open Bytecode
+open Bytecode_util
open Type_check
open PPrint
open Value2
@@ -61,13 +62,12 @@ let opt_ddump_flow_graphs = ref false
(* Optimization flags *)
let optimize_primops = ref false
+let optimize_z3 = ref false
let optimize_hoist_allocations = ref false
-let optimize_struct_undefined = ref false
let optimize_struct_updates = ref false
-let optimize_enum_undefined = ref false
let c_debug str =
- if !c_verbosity > 0 then prerr_endline str else ()
+ if !c_verbosity > 0 then prerr_endline (Lazy.force str) else ()
let c_error ?loc:(l=Parse_ast.Unknown) message =
raise (Reporting_basic.err_general l ("\nC backend: " ^ message))
@@ -82,40 +82,6 @@ let lvar_typ = function
| Enum typ -> typ
| _ -> assert false
-let string_of_value = function
- | V_bits bs -> Sail_values.show_bitlist bs ^ "ul"
- | V_int i -> Big_int.to_string i ^ "l"
- | V_bool true -> "true"
- | V_bool false -> "false"
- | V_null -> "NULL"
- | V_unit -> "UNIT"
- | V_bit Sail_values.B0 -> "0ul"
- | V_bit Sail_values.B1 -> "1ul"
- | V_string str -> "\"" ^ str ^ "\""
- | V_ctor_kind str -> "Kind_" ^ Util.zencode_string str
- | _ -> failwith "Cannot convert value to string"
-
-let rec string_of_fragment ?zencode:(zencode=true) = function
- | F_id id when zencode -> Util.zencode_string (string_of_id id)
- | F_id id -> string_of_id id
- | F_ref id when zencode -> "&" ^ Util.zencode_string (string_of_id id)
- | F_ref id -> "&" ^ string_of_id id
- | F_lit v -> string_of_value v
- | F_call (str, frags) ->
- Printf.sprintf "%s(%s)" str (Util.string_of_list ", " (string_of_fragment ~zencode:zencode) frags)
- | F_field (f, field) ->
- Printf.sprintf "%s.%s" (string_of_fragment' ~zencode:zencode f) field
- | F_op (f1, op, f2) ->
- Printf.sprintf "%s %s %s" (string_of_fragment' ~zencode:zencode f1) op (string_of_fragment' ~zencode:zencode f2)
- | F_unary (op, f) ->
- op ^ string_of_fragment' ~zencode:zencode f
- | F_have_exception -> "have_exception"
- | F_current_exception -> "(*current_exception)"
-and string_of_fragment' ?zencode:(zencode=true) f =
- match f with
- | F_op _ | F_unary _ -> "(" ^ string_of_fragment ~zencode:zencode f ^ ")"
- | _ -> string_of_fragment ~zencode:zencode f
-
(**************************************************************************)
(* 1. Conversion to A-normal form (ANF) *)
(**************************************************************************)
@@ -132,21 +98,22 @@ and string_of_fragment' ?zencode:(zencode=true) f =
while/until loops). The aexp datatype represents these expressions,
while aval represents the trivial values.
- The X_aux construct in ast.ml isn't used here, but the typing
- information is collapsed into the aexp and aval types. The
- convention is that the type of an aexp is given by last argument to
- a constructor. It is omitted where it is obvious - for example all
- for loops have unit as their type. If some constituent part of the
- aexp has an annotation, the it refers to the previous argument, so
- in
+ The convention is that the type of an aexp is given by last
+ argument to a constructor. It is omitted where it is obvious - for
+ example all for loops have unit as their type. If some constituent
+ part of the aexp has an annotation, the it refers to the previous
+ argument, so in
AE_let (id, typ1, _, body, typ2)
typ1 is the type of the bound identifer, whereas typ2 is the type
of the whole let expression (and therefore also the body).
- See Flanagan et al's 'The Essence of Compiling with Continuations' *)
-type aexp =
+ See Flanagan et al's 'The Essence of Compiling with Continuations'
+ *)
+type aexp = AE_aux of aexp_aux * Env.t * l
+
+and aexp_aux =
| AE_val of aval
| AE_app of id * aval list * typ
| AE_cast of aexp * typ
@@ -166,7 +133,9 @@ type aexp =
and sc_op = SC_and | SC_or
-and apat =
+and apat = AP_aux of apat_aux * Env.t * l
+
+and apat_aux =
| AP_tup of apat list
| AP_id of id * typ
| AP_global of id * typ
@@ -191,7 +160,7 @@ let rec frag_rename from_id to_id = function
| F_id id when Id.compare id from_id = 0 -> F_id to_id
| F_id id -> F_id id
| F_ref id when Id.compare id from_id = 0 -> F_ref to_id
- | F_ref id -> F_id id
+ | F_ref id -> F_ref id
| F_lit v -> F_lit v
| F_have_exception -> F_have_exception
| F_current_exception -> F_current_exception
@@ -199,8 +168,10 @@ let rec frag_rename from_id to_id = function
| F_op (f1, op, f2) -> F_op (frag_rename from_id to_id f1, op, frag_rename from_id to_id f2)
| F_unary (op, f) -> F_unary (op, frag_rename from_id to_id f)
| F_field (f, field) -> F_field (frag_rename from_id to_id f, field)
+ | F_raw raw -> F_raw raw
-let rec apat_bindings = function
+let rec apat_bindings (AP_aux (apat_aux, _, _)) =
+ match apat_aux with
| AP_tup apats -> List.fold_left IdSet.union IdSet.empty (List.map apat_bindings apats)
| AP_id (id, _) -> IdSet.singleton id
| AP_global (id, _) -> IdSet.empty
@@ -209,15 +180,18 @@ let rec apat_bindings = function
| AP_nil -> IdSet.empty
| AP_wild -> IdSet.empty
-let rec apat_rename from_id to_id = function
- | AP_tup apats -> AP_tup (List.map (apat_rename from_id to_id) apats)
- | AP_id (id, typ) when Id.compare id from_id = 0 -> AP_id (to_id, typ)
- | AP_id (id, typ) -> AP_id (id, typ)
- | AP_global (id, typ) -> AP_global (id, typ)
- | AP_app (ctor, apat) -> AP_app (ctor, apat_rename from_id to_id apat)
- | AP_cons (apat1, apat2) -> AP_cons (apat_rename from_id to_id apat1, apat_rename from_id to_id apat2)
- | AP_nil -> AP_nil
- | AP_wild -> AP_wild
+let rec apat_rename from_id to_id (AP_aux (apat_aux, env, l)) =
+ let apat_aux = match apat_aux with
+ | AP_tup apats -> AP_tup (List.map (apat_rename from_id to_id) apats)
+ | AP_id (id, typ) when Id.compare id from_id = 0 -> AP_id (to_id, typ)
+ | AP_id (id, typ) -> AP_id (id, typ)
+ | AP_global (id, typ) -> AP_global (id, typ)
+ | AP_app (ctor, apat) -> AP_app (ctor, apat_rename from_id to_id apat)
+ | AP_cons (apat1, apat2) -> AP_cons (apat_rename from_id to_id apat1, apat_rename from_id to_id apat2)
+ | AP_nil -> AP_nil
+ | AP_wild -> AP_wild
+ in
+ AP_aux (apat_aux, env, l)
let rec aval_rename from_id to_id = function
| AV_lit (lit, typ) -> AV_lit (lit, typ)
@@ -231,28 +205,30 @@ let rec aval_rename from_id to_id = function
| AV_record (avals, typ) -> AV_record (Bindings.map (aval_rename from_id to_id) avals, typ)
| AV_C_fragment (fragment, typ) -> AV_C_fragment (frag_rename from_id to_id fragment, typ)
-let rec aexp_rename from_id to_id aexp =
+let rec aexp_rename from_id to_id (AE_aux (aexp, env, l)) =
let recur = aexp_rename from_id to_id in
- match aexp with
- | AE_val aval -> AE_val (aval_rename from_id to_id aval)
- | AE_app (id, avals, typ) -> AE_app (id, List.map (aval_rename from_id to_id) avals, typ)
- | AE_cast (aexp, typ) -> AE_cast (recur aexp, typ)
- | AE_assign (id, typ, aexp) when Id.compare from_id id = 0 -> AE_assign (to_id, typ, aexp)
- | AE_assign (id, typ, aexp) -> AE_assign (id, typ, aexp)
- | AE_let (id, typ1, aexp1, aexp2, typ2) when Id.compare from_id id = 0 -> AE_let (id, typ1, aexp1, aexp2, typ2)
- | AE_let (id, typ1, aexp1, aexp2, typ2) -> AE_let (id, typ1, recur aexp1, recur aexp2, typ2)
- | AE_block (aexps, aexp, typ) -> AE_block (List.map recur aexps, recur aexp, typ)
- | AE_return (aval, typ) -> AE_return (aval_rename from_id to_id aval, typ)
- | AE_throw (aval, typ) -> AE_throw (aval_rename from_id to_id aval, typ)
- | AE_if (aval, then_aexp, else_aexp, typ) -> AE_if (aval_rename from_id to_id aval, recur then_aexp, recur else_aexp, typ)
- | AE_field (aval, id, typ) -> AE_field (aval_rename from_id to_id aval, id, typ)
- | AE_case (aval, apexps, typ) -> AE_case (aval_rename from_id to_id aval, List.map (apexp_rename from_id to_id) apexps, typ)
- | AE_try (aexp, apexps, typ) -> AE_try (aexp_rename from_id to_id aexp, List.map (apexp_rename from_id to_id) apexps, typ)
- | AE_record_update (aval, avals, typ) -> AE_record_update (aval_rename from_id to_id aval, Bindings.map (aval_rename from_id to_id) avals, typ)
- | AE_for (id, aexp1, aexp2, aexp3, order, aexp4) when Id.compare from_id to_id = 0 -> AE_for (id, aexp1, aexp2, aexp3, order, aexp4)
- | AE_for (id, aexp1, aexp2, aexp3, order, aexp4) -> AE_for (id, recur aexp1, recur aexp2, recur aexp3, order, recur aexp4)
- | AE_loop (loop, aexp1, aexp2) -> AE_loop (loop, recur aexp1, recur aexp2)
- | AE_short_circuit (op, aval, aexp) -> AE_short_circuit (op, aval_rename from_id to_id aval, recur aexp)
+ let aexp = match aexp with
+ | AE_val aval -> AE_val (aval_rename from_id to_id aval)
+ | AE_app (id, avals, typ) -> AE_app (id, List.map (aval_rename from_id to_id) avals, typ)
+ | AE_cast (aexp, typ) -> AE_cast (recur aexp, typ)
+ | AE_assign (id, typ, aexp) when Id.compare from_id id = 0 -> AE_assign (to_id, typ, aexp)
+ | AE_assign (id, typ, aexp) -> AE_assign (id, typ, aexp)
+ | AE_let (id, typ1, aexp1, aexp2, typ2) when Id.compare from_id id = 0 -> AE_let (id, typ1, aexp1, aexp2, typ2)
+ | AE_let (id, typ1, aexp1, aexp2, typ2) -> AE_let (id, typ1, recur aexp1, recur aexp2, typ2)
+ | AE_block (aexps, aexp, typ) -> AE_block (List.map recur aexps, recur aexp, typ)
+ | AE_return (aval, typ) -> AE_return (aval_rename from_id to_id aval, typ)
+ | AE_throw (aval, typ) -> AE_throw (aval_rename from_id to_id aval, typ)
+ | AE_if (aval, then_aexp, else_aexp, typ) -> AE_if (aval_rename from_id to_id aval, recur then_aexp, recur else_aexp, typ)
+ | AE_field (aval, id, typ) -> AE_field (aval_rename from_id to_id aval, id, typ)
+ | AE_case (aval, apexps, typ) -> AE_case (aval_rename from_id to_id aval, List.map (apexp_rename from_id to_id) apexps, typ)
+ | AE_try (aexp, apexps, typ) -> AE_try (aexp_rename from_id to_id aexp, List.map (apexp_rename from_id to_id) apexps, typ)
+ | AE_record_update (aval, avals, typ) -> AE_record_update (aval_rename from_id to_id aval, Bindings.map (aval_rename from_id to_id) avals, typ)
+ | AE_for (id, aexp1, aexp2, aexp3, order, aexp4) when Id.compare from_id to_id = 0 -> AE_for (id, aexp1, aexp2, aexp3, order, aexp4)
+ | AE_for (id, aexp1, aexp2, aexp3, order, aexp4) -> AE_for (id, recur aexp1, recur aexp2, recur aexp3, order, recur aexp4)
+ | AE_loop (loop, aexp1, aexp2) -> AE_loop (loop, recur aexp1, recur aexp2)
+ | AE_short_circuit (op, aval, aexp) -> AE_short_circuit (op, aval_rename from_id to_id aval, recur aexp)
+ in
+ AE_aux (aexp, env, l)
and apexp_rename from_id to_id (apat, aexp1, aexp2) =
if IdSet.mem from_id (apat_bindings apat) then
@@ -267,32 +243,41 @@ let new_shadow id =
incr shadow_counter;
shadow_id
-let rec no_shadow ids aexp =
- match aexp with
- | AE_val aval -> AE_val aval
- | AE_app (id, avals, typ) -> AE_app (id, avals, typ)
- | AE_cast (aexp, typ) -> AE_cast (no_shadow ids aexp, typ)
- | AE_assign (id, typ, aexp) -> AE_assign (id, typ, no_shadow ids aexp)
- | AE_let (id, typ1, aexp1, aexp2, typ2) when IdSet.mem id ids ->
- let shadow_id = new_shadow id in
- let aexp1 = no_shadow ids aexp1 in
- let ids = IdSet.add shadow_id ids in
- AE_let (shadow_id, typ1, aexp1, no_shadow ids (aexp_rename id shadow_id aexp2), typ2)
- | AE_let (id, typ1, aexp1, aexp2, typ2) ->
- AE_let (id, typ1, no_shadow ids aexp1, no_shadow (IdSet.add id ids) aexp2, typ2)
- | AE_block (aexps, aexp, typ) -> AE_block (List.map (no_shadow ids) aexps, no_shadow ids aexp, typ)
- | AE_return (aval, typ) -> AE_return (aval, typ)
- | AE_throw (aval, typ) -> AE_throw (aval, typ)
- | AE_if (aval, then_aexp, else_aexp, typ) -> AE_if (aval, no_shadow ids then_aexp, no_shadow ids else_aexp, typ)
- | AE_field (aval, id, typ) -> AE_field (aval, id, typ)
- | AE_case (aval, apexps, typ) -> AE_case (aval, List.map (no_shadow_apexp ids) apexps, typ)
- | AE_try (aexp, apexps, typ) -> AE_try (no_shadow ids aexp, List.map (no_shadow_apexp ids) apexps, typ)
- | AE_record_update (aval, avals, typ) -> AE_record_update (aval, avals, typ)
- | AE_for (id, aexp1, aexp2, aexp3, order, aexp4) ->
- let ids = IdSet.add id ids in
- AE_for (id, no_shadow ids aexp1, no_shadow ids aexp2, no_shadow ids aexp3, order, no_shadow ids aexp4)
- | AE_loop (loop, aexp1, aexp2) -> AE_loop (loop, no_shadow ids aexp1, no_shadow ids aexp2)
- | AE_short_circuit (op, aval, aexp) -> AE_short_circuit (op, aval, no_shadow ids aexp)
+let rec no_shadow ids (AE_aux (aexp, env, l)) =
+ let aexp = match aexp with
+ | AE_val aval -> AE_val aval
+ | AE_app (id, avals, typ) -> AE_app (id, avals, typ)
+ | AE_cast (aexp, typ) -> AE_cast (no_shadow ids aexp, typ)
+ | AE_assign (id, typ, aexp) -> AE_assign (id, typ, no_shadow ids aexp)
+ | AE_let (id, typ1, aexp1, aexp2, typ2) when IdSet.mem id ids ->
+ let shadow_id = new_shadow id in
+ let aexp1 = no_shadow ids aexp1 in
+ let ids = IdSet.add shadow_id ids in
+ AE_let (shadow_id, typ1, aexp1, no_shadow ids (aexp_rename id shadow_id aexp2), typ2)
+ | AE_let (id, typ1, aexp1, aexp2, typ2) ->
+ AE_let (id, typ1, no_shadow ids aexp1, no_shadow (IdSet.add id ids) aexp2, typ2)
+ | AE_block (aexps, aexp, typ) -> AE_block (List.map (no_shadow ids) aexps, no_shadow ids aexp, typ)
+ | AE_return (aval, typ) -> AE_return (aval, typ)
+ | AE_throw (aval, typ) -> AE_throw (aval, typ)
+ | AE_if (aval, then_aexp, else_aexp, typ) -> AE_if (aval, no_shadow ids then_aexp, no_shadow ids else_aexp, typ)
+ | AE_field (aval, id, typ) -> AE_field (aval, id, typ)
+ | AE_case (aval, apexps, typ) -> AE_case (aval, List.map (no_shadow_apexp ids) apexps, typ)
+ | AE_try (aexp, apexps, typ) -> AE_try (no_shadow ids aexp, List.map (no_shadow_apexp ids) apexps, typ)
+ | AE_record_update (aval, avals, typ) -> AE_record_update (aval, avals, typ)
+ | AE_for (id, aexp1, aexp2, aexp3, order, aexp4) when IdSet.mem id ids ->
+ let shadow_id = new_shadow id in
+ let aexp1 = no_shadow ids aexp1 in
+ let aexp2 = no_shadow ids aexp2 in
+ let aexp3 = no_shadow ids aexp3 in
+ let ids = IdSet.add shadow_id ids in
+ AE_for (shadow_id, aexp1, aexp2, aexp3, order, no_shadow ids (aexp_rename id shadow_id aexp4))
+ | AE_for (id, aexp1, aexp2, aexp3, order, aexp4) ->
+ let ids = IdSet.add id ids in
+ AE_for (id, no_shadow ids aexp1, no_shadow ids aexp2, no_shadow ids aexp3, order, no_shadow ids aexp4)
+ | AE_loop (loop, aexp1, aexp2) -> AE_loop (loop, no_shadow ids aexp1, no_shadow ids aexp2)
+ | AE_short_circuit (op, aval, aexp) -> AE_short_circuit (op, aval, no_shadow ids aexp)
+ in
+ AE_aux (aexp, env, l)
and no_shadow_apexp ids (apat, aexp1, aexp2) =
let shadows = IdSet.inter (apat_bindings apat) ids in
@@ -303,55 +288,58 @@ and no_shadow_apexp ids (apat, aexp1, aexp2) =
(rename_apat apat, no_shadow ids (rename aexp1), no_shadow ids (rename aexp2))
(* Map over all the avals in an aexp. *)
-let rec map_aval f = function
- | AE_val v -> AE_val (f v)
- | AE_cast (aexp, typ) -> AE_cast (map_aval f aexp, typ)
- | AE_assign (id, typ, aexp) -> AE_assign (id, typ, map_aval f aexp)
- | AE_app (id, vs, typ) -> AE_app (id, List.map f vs, typ)
- | AE_let (id, typ1, aexp1, aexp2, typ2) ->
- AE_let (id, typ1, map_aval f aexp1, map_aval f aexp2, typ2)
- | AE_block (aexps, aexp, typ) -> AE_block (List.map (map_aval f) aexps, map_aval f aexp, typ)
- | AE_return (aval, typ) -> AE_return (f aval, typ)
- | AE_throw (aval, typ) -> AE_throw (f aval, typ)
- | AE_if (aval, aexp1, aexp2, typ2) ->
- AE_if (f aval, map_aval f aexp1, map_aval f aexp2, typ2)
- | AE_loop (loop_typ, aexp1, aexp2) -> AE_loop (loop_typ, map_aval f aexp1, map_aval f aexp2)
- | AE_for (id, aexp1, aexp2, aexp3, order, aexp4) ->
- AE_for (id, map_aval f aexp1, map_aval f aexp2, map_aval f aexp3, order, map_aval f aexp4)
- | AE_record_update (aval, updates, typ) ->
- AE_record_update (f aval, Bindings.map f updates, typ)
- | AE_field (aval, field, typ) ->
- AE_field (f aval, field, typ)
- | AE_case (aval, cases, typ) ->
- AE_case (f aval, List.map (fun (pat, aexp1, aexp2) -> pat, map_aval f aexp1, map_aval f aexp2) cases, typ)
- | AE_try (aexp, cases, typ) ->
- AE_try (map_aval f aexp, List.map (fun (pat, aexp1, aexp2) -> pat, map_aval f aexp1, map_aval f aexp2) cases, typ)
- | AE_short_circuit (op, aval, aexp) -> AE_short_circuit (op, f aval, map_aval f aexp)
+let rec map_aval f (AE_aux (aexp, env, l)) =
+ let aexp = match aexp with
+ | AE_val v -> AE_val (f env l v)
+ | AE_cast (aexp, typ) -> AE_cast (map_aval f aexp, typ)
+ | AE_assign (id, typ, aexp) -> AE_assign (id, typ, map_aval f aexp)
+ | AE_app (id, vs, typ) -> AE_app (id, List.map (f env l) vs, typ)
+ | AE_let (id, typ1, aexp1, aexp2, typ2) ->
+ AE_let (id, typ1, map_aval f aexp1, map_aval f aexp2, typ2)
+ | AE_block (aexps, aexp, typ) -> AE_block (List.map (map_aval f) aexps, map_aval f aexp, typ)
+ | AE_return (aval, typ) -> AE_return (f env l aval, typ)
+ | AE_throw (aval, typ) -> AE_throw (f env l aval, typ)
+ | AE_if (aval, aexp1, aexp2, typ2) ->
+ AE_if (f env l aval, map_aval f aexp1, map_aval f aexp2, typ2)
+ | AE_loop (loop_typ, aexp1, aexp2) -> AE_loop (loop_typ, map_aval f aexp1, map_aval f aexp2)
+ | AE_for (id, aexp1, aexp2, aexp3, order, aexp4) ->
+ AE_for (id, map_aval f aexp1, map_aval f aexp2, map_aval f aexp3, order, map_aval f aexp4)
+ | AE_record_update (aval, updates, typ) ->
+ AE_record_update (f env l aval, Bindings.map (f env l) updates, typ)
+ | AE_field (aval, field, typ) ->
+ AE_field (f env l aval, field, typ)
+ | AE_case (aval, cases, typ) ->
+ AE_case (f env l aval, List.map (fun (pat, aexp1, aexp2) -> pat, map_aval f aexp1, map_aval f aexp2) cases, typ)
+ | AE_try (aexp, cases, typ) ->
+ AE_try (map_aval f aexp, List.map (fun (pat, aexp1, aexp2) -> pat, map_aval f aexp1, map_aval f aexp2) cases, typ)
+ | AE_short_circuit (op, aval, aexp) -> AE_short_circuit (op, f env l aval, map_aval f aexp)
+ in
+ AE_aux (aexp, env, l)
(* Map over all the functions in an aexp. *)
-let rec map_functions f = function
- | AE_app (id, vs, typ) -> f id vs typ
- | AE_cast (aexp, typ) -> AE_cast (map_functions f aexp, typ)
- | AE_assign (id, typ, aexp) -> AE_assign (id, typ, map_functions f aexp)
- | AE_short_circuit (op, aval, aexp) -> AE_short_circuit (op, aval, map_functions f aexp)
- | AE_let (id, typ1, aexp1, aexp2, typ2) -> AE_let (id, typ1, map_functions f aexp1, map_functions f aexp2, typ2)
- | AE_block (aexps, aexp, typ) -> AE_block (List.map (map_functions f) aexps, map_functions f aexp, typ)
- | AE_if (aval, aexp1, aexp2, typ) ->
- AE_if (aval, map_functions f aexp1, map_functions f aexp2, typ)
- | AE_loop (loop_typ, aexp1, aexp2) -> AE_loop (loop_typ, map_functions f aexp1, map_functions f aexp2)
- | AE_for (id, aexp1, aexp2, aexp3, order, aexp4) ->
- AE_for (id, map_functions f aexp1, map_functions f aexp2, map_functions f aexp3, order, map_functions f aexp4)
- | AE_case (aval, cases, typ) ->
- AE_case (aval, List.map (fun (pat, aexp1, aexp2) -> pat, map_functions f aexp1, map_functions f aexp2) cases, typ)
- | AE_try (aexp, cases, typ) ->
- AE_try (map_functions f aexp, List.map (fun (pat, aexp1, aexp2) -> pat, map_functions f aexp1, map_functions f aexp2) cases, typ)
- | AE_field _ | AE_record_update _ | AE_val _ | AE_return _ | AE_throw _ as v -> v
+let rec map_functions f (AE_aux (aexp, env, l)) =
+ let aexp = match aexp with
+ | AE_app (id, vs, typ) -> f env l id vs typ
+ | AE_cast (aexp, typ) -> AE_cast (map_functions f aexp, typ)
+ | AE_assign (id, typ, aexp) -> AE_assign (id, typ, map_functions f aexp)
+ | AE_short_circuit (op, aval, aexp) -> AE_short_circuit (op, aval, map_functions f aexp)
+ | AE_let (id, typ1, aexp1, aexp2, typ2) -> AE_let (id, typ1, map_functions f aexp1, map_functions f aexp2, typ2)
+ | AE_block (aexps, aexp, typ) -> AE_block (List.map (map_functions f) aexps, map_functions f aexp, typ)
+ | AE_if (aval, aexp1, aexp2, typ) ->
+ AE_if (aval, map_functions f aexp1, map_functions f aexp2, typ)
+ | AE_loop (loop_typ, aexp1, aexp2) -> AE_loop (loop_typ, map_functions f aexp1, map_functions f aexp2)
+ | AE_for (id, aexp1, aexp2, aexp3, order, aexp4) ->
+ AE_for (id, map_functions f aexp1, map_functions f aexp2, map_functions f aexp3, order, map_functions f aexp4)
+ | AE_case (aval, cases, typ) ->
+ AE_case (aval, List.map (fun (pat, aexp1, aexp2) -> pat, map_functions f aexp1, map_functions f aexp2) cases, typ)
+ | AE_try (aexp, cases, typ) ->
+ AE_try (map_functions f aexp, List.map (fun (pat, aexp1, aexp2) -> pat, map_functions f aexp1, map_functions f aexp2) cases, typ)
+ | AE_field _ | AE_record_update _ | AE_val _ | AE_return _ | AE_throw _ as v -> v
+ in
+ AE_aux (aexp, env, l)
(* For debugging we provide a pretty printer for ANF expressions. *)
-let pp_id id =
- string (string_of_id id)
-
let pp_lvar lvar doc =
match lvar with
| Register typ ->
@@ -372,7 +360,8 @@ let pp_order = function
| Ord_aux (Ord_dec, _) -> string "dec"
| _ -> assert false (* Order types have been specialised, so no polymorphism in C backend. *)
-let rec pp_aexp = function
+let rec pp_aexp (AE_aux (aexp, _, _)) =
+ match aexp with
| AE_val v -> pp_aval v
| AE_cast (aexp, typ) ->
pp_annot typ (string "$" ^^ pp_aexp aexp)
@@ -387,7 +376,7 @@ let rec pp_aexp = function
| AE_let (id, id_typ, binding, body, typ) -> group
begin
match binding with
- | AE_let _ ->
+ | AE_aux (AE_let _, _, _) ->
(pp_annot typ (separate space [string "let"; pp_annot id_typ (pp_id id); string "="])
^^ hardline ^^ nest 2 (pp_aexp binding))
^^ hardline ^^ string "in" ^^ space ^^ pp_aexp body
@@ -428,7 +417,8 @@ let rec pp_aexp = function
^^ separate (string ", ") (List.map (fun (id, aval) -> pp_id id ^^ string " = " ^^ pp_aval aval)
(Bindings.bindings updates)))
-and pp_apat = function
+and pp_apat (AP_aux (apat_aux, _, _)) =
+ match apat_aux with
| AP_wild -> string "_"
| AP_id (id, typ) -> pp_annot typ (pp_id id)
| AP_global (id, _) -> pp_id id
@@ -481,33 +471,39 @@ let rec split_block = function
exp :: exps, last
| [] -> c_error "empty block"
-let rec anf_pat ?global:(global=false) (P_aux (p_aux, (l, _)) as pat) =
+let rec anf_pat ?global:(global=false) (P_aux (p_aux, annot) as pat) =
+ let mk_apat aux = AP_aux (aux, env_of_annot annot, fst annot) in
match p_aux with
- | P_id id when global -> AP_global (id, pat_typ_of pat)
- | P_id id -> AP_id (id, pat_typ_of pat)
- | P_wild -> AP_wild
- | P_tup pats -> AP_tup (List.map (fun pat -> anf_pat ~global:global pat) pats)
- | P_app (id, [pat]) -> AP_app (id, anf_pat ~global:global pat)
- | P_app (id, pats) -> AP_app (id, AP_tup (List.map (fun pat -> anf_pat ~global:global pat) pats))
+ | P_id id when global -> mk_apat (AP_global (id, pat_typ_of pat))
+ | P_id id -> mk_apat (AP_id (id, pat_typ_of pat))
+ | P_wild -> mk_apat AP_wild
+ | P_tup pats -> mk_apat (AP_tup (List.map (fun pat -> anf_pat ~global:global pat) pats))
+ | P_app (id, [pat]) -> mk_apat (AP_app (id, anf_pat ~global:global pat))
+ | P_app (id, pats) -> mk_apat (AP_app (id, mk_apat (AP_tup (List.map (fun pat -> anf_pat ~global:global pat) pats))))
| P_typ (_, pat) -> anf_pat ~global:global pat
| P_var (pat, _) -> anf_pat ~global:global pat
- | P_cons (hd_pat, tl_pat) -> AP_cons (anf_pat ~global:global hd_pat, anf_pat ~global:global tl_pat)
- | P_list pats -> List.fold_right (fun pat apat -> AP_cons (anf_pat ~global:global pat, apat)) pats AP_nil
- | _ -> c_error ~loc:l ("Could not convert pattern to ANF: " ^ string_of_pat pat)
+ | P_cons (hd_pat, tl_pat) -> mk_apat (AP_cons (anf_pat ~global:global hd_pat, anf_pat ~global:global tl_pat))
+ | P_list pats -> List.fold_right (fun pat apat -> mk_apat (AP_cons (anf_pat ~global:global pat, apat))) pats (mk_apat AP_nil)
+ | _ -> c_error ~loc:(fst annot) ("Could not convert pattern to ANF: " ^ string_of_pat pat)
-let rec apat_globals = function
+let rec apat_globals (AP_aux (aux, _, _)) =
+ match aux with
| AP_nil | AP_wild | AP_id _ -> []
| AP_global (id, typ) -> [(id, typ)]
| AP_tup apats -> List.concat (List.map apat_globals apats)
| AP_app (_, apat) -> apat_globals apat
| AP_cons (hd_apat, tl_apat) -> apat_globals hd_apat @ apat_globals tl_apat
-let rec anf (E_aux (e_aux, exp_annot) as exp) =
- let to_aval = function
+let rec anf (E_aux (e_aux, ((l, _) as exp_annot)) as exp) =
+ let mk_aexp aexp = AE_aux (aexp, env_of_annot exp_annot, l) in
+
+ let to_aval (AE_aux (aexp_aux, env, l) as aexp) =
+ let mk_aexp aexp = AE_aux (aexp, env, l) in
+ match aexp_aux with
| AE_val v -> (v, fun x -> x)
- | AE_short_circuit (_, _, _) as aexp ->
+ | AE_short_circuit (_, _, _) ->
let id = gensym () in
- (AV_id (id, Local (Immutable, bool_typ)), fun x -> AE_let (id, bool_typ, aexp, x, typ_of exp))
+ (AV_id (id, Local (Immutable, bool_typ)), fun x -> mk_aexp (AE_let (id, bool_typ, aexp, x, typ_of exp)))
| AE_app (_, _, typ)
| AE_let (_, _, _, _, typ)
| AE_return (_, typ)
@@ -517,31 +513,30 @@ let rec anf (E_aux (e_aux, exp_annot) as exp) =
| AE_field (_, _, typ)
| AE_case (_, _, typ)
| AE_try (_, _, typ)
- | AE_record_update (_, _, typ)
- as aexp ->
+ | AE_record_update (_, _, typ) ->
let id = gensym () in
- (AV_id (id, Local (Immutable, typ)), fun x -> AE_let (id, typ, aexp, x, typ_of exp))
- | AE_assign _ | AE_block _ | AE_for _ | AE_loop _ as aexp ->
+ (AV_id (id, Local (Immutable, typ)), fun x -> mk_aexp (AE_let (id, typ, aexp, x, typ_of exp)))
+ | AE_assign _ | AE_block _ | AE_for _ | AE_loop _ ->
let id = gensym () in
- (AV_id (id, Local (Immutable, unit_typ)), fun x -> AE_let (id, unit_typ, aexp, x, typ_of exp))
+ (AV_id (id, Local (Immutable, unit_typ)), fun x -> mk_aexp (AE_let (id, unit_typ, aexp, x, typ_of exp)))
in
match e_aux with
- | E_lit lit -> ae_lit lit (typ_of exp)
+ | E_lit lit -> mk_aexp (ae_lit lit (typ_of exp))
| E_block exps ->
let exps, last = split_block exps in
let aexps = List.map anf exps in
let alast = anf last in
- AE_block (aexps, alast, typ_of exp)
+ mk_aexp (AE_block (aexps, alast, typ_of exp))
| E_assign (LEXP_aux (LEXP_deref dexp, _), exp) ->
let gs = gensym () in
- AE_let (gs, typ_of dexp, anf dexp, AE_assign (gs, typ_of dexp, anf exp), unit_typ)
+ mk_aexp (AE_let (gs, typ_of dexp, anf dexp, mk_aexp (AE_assign (gs, typ_of dexp, anf exp)), unit_typ))
| E_assign (LEXP_aux (LEXP_id id, _), exp)
- | E_assign (LEXP_aux (LEXP_cast (_, id), _), exp) ->
+ | E_assign (LEXP_aux (LEXP_cast (_, id), _), exp) ->
let aexp = anf exp in
- AE_assign (id, lvar_typ (Env.lookup_id id (env_of exp)), aexp)
+ mk_aexp (AE_assign (id, lvar_typ (Env.lookup_id id (env_of exp)), aexp))
| E_assign (lexp, _) ->
failwith ("Encountered complex l-expression " ^ string_of_lexp lexp ^ " when converting to ANF")
@@ -549,17 +544,17 @@ let rec anf (E_aux (e_aux, exp_annot) as exp) =
| E_loop (loop_typ, cond, exp) ->
let acond = anf cond in
let aexp = anf exp in
- AE_loop (loop_typ, acond, aexp)
+ mk_aexp (AE_loop (loop_typ, acond, aexp))
| E_for (id, exp1, exp2, exp3, order, body) ->
let aexp1, aexp2, aexp3, abody = anf exp1, anf exp2, anf exp3, anf body in
- AE_for (id, aexp1, aexp2, aexp3, order, abody)
+ mk_aexp (AE_for (id, aexp1, aexp2, aexp3, order, abody))
| E_if (cond, then_exp, else_exp) ->
let cond_val, wrap = to_aval (anf cond) in
let then_aexp = anf then_exp in
let else_aexp = anf else_exp in
- wrap (AE_if (cond_val, then_aexp, else_aexp, typ_of then_exp))
+ wrap (mk_aexp (AE_if (cond_val, then_aexp, else_aexp, typ_of then_exp)))
| E_app_infix (x, Id_aux (Id op, l), y) ->
anf (E_aux (E_app (Id_aux (DeIid op, l), [x; y]), exp_annot))
@@ -570,85 +565,85 @@ let rec anf (E_aux (e_aux, exp_annot) as exp) =
let aexps = List.map anf exps in
let avals = List.map to_aval aexps in
let wrap = List.fold_left (fun f g x -> f (g x)) (fun x -> x) (List.map snd avals) in
- wrap (AE_val (AV_vector (List.map fst avals, typ_of exp)))
+ wrap (mk_aexp (AE_val (AV_vector (List.map fst avals, typ_of exp))))
| E_list exps ->
let aexps = List.map anf exps in
let avals = List.map to_aval aexps in
let wrap = List.fold_left (fun f g x -> f (g x)) (fun x -> x) (List.map snd avals) in
- wrap (AE_val (AV_list (List.map fst avals, typ_of exp)))
+ wrap (mk_aexp (AE_val (AV_list (List.map fst avals, typ_of exp))))
| E_field (field_exp, id) ->
let aval, wrap = to_aval (anf field_exp) in
- wrap (AE_field (aval, id, typ_of exp))
+ wrap (mk_aexp (AE_field (aval, id, typ_of exp)))
| E_record_update (exp, FES_aux (FES_Fexps (fexps, _), _)) ->
- let anf_fexp (FE_aux (FE_Fexp (id, exp), _)) =
- let aval, wrap = to_aval (anf exp) in
- (id, aval), wrap
- in
- let aval, exp_wrap = to_aval (anf exp) in
- let fexps = List.map anf_fexp fexps in
- let wrap = List.fold_left (fun f g x -> f (g x)) (fun x -> x) (List.map snd fexps) in
- let record = List.fold_left (fun r (id, aval) -> Bindings.add id aval r) Bindings.empty (List.map fst fexps) in
- exp_wrap (wrap (AE_record_update (aval, record, typ_of exp)))
+ let anf_fexp (FE_aux (FE_Fexp (id, exp), _)) =
+ let aval, wrap = to_aval (anf exp) in
+ (id, aval), wrap
+ in
+ let aval, exp_wrap = to_aval (anf exp) in
+ let fexps = List.map anf_fexp fexps in
+ let wrap = List.fold_left (fun f g x -> f (g x)) (fun x -> x) (List.map snd fexps) in
+ let record = List.fold_left (fun r (id, aval) -> Bindings.add id aval r) Bindings.empty (List.map fst fexps) in
+ exp_wrap (wrap (mk_aexp (AE_record_update (aval, record, typ_of exp))))
| E_app (id, [exp1; exp2]) when string_of_id id = "and_bool" ->
let aexp1 = anf exp1 in
let aexp2 = anf exp2 in
let aval1, wrap = to_aval aexp1 in
- wrap (AE_short_circuit (SC_and, aval1, aexp2))
+ wrap (mk_aexp (AE_short_circuit (SC_and, aval1, aexp2)))
| E_app (id, [exp1; exp2]) when string_of_id id = "or_bool" ->
let aexp1 = anf exp1 in
let aexp2 = anf exp2 in
let aval1, wrap = to_aval aexp1 in
- wrap (AE_short_circuit (SC_or, aval1, aexp2))
+ wrap (mk_aexp (AE_short_circuit (SC_or, aval1, aexp2)))
| E_app (id, exps) ->
let aexps = List.map anf exps in
let avals = List.map to_aval aexps in
let wrap = List.fold_left (fun f g x -> f (g x)) (fun x -> x) (List.map snd avals) in
- wrap (AE_app (id, List.map fst avals, typ_of exp))
+ wrap (mk_aexp (AE_app (id, List.map fst avals, typ_of exp)))
| E_throw exn_exp ->
let aexp = anf exn_exp in
let aval, wrap = to_aval aexp in
- wrap (AE_throw (aval, typ_of exp))
+ wrap (mk_aexp (AE_throw (aval, typ_of exp)))
| E_exit exp ->
let aexp = anf exp in
let aval, wrap = to_aval aexp in
- wrap (AE_app (mk_id "sail_exit", [aval], unit_typ))
+ wrap (mk_aexp (AE_app (mk_id "sail_exit", [aval], unit_typ)))
| E_return ret_exp ->
let aexp = anf ret_exp in
let aval, wrap = to_aval aexp in
- wrap (AE_return (aval, typ_of exp))
+ wrap (mk_aexp (AE_return (aval, typ_of exp)))
| E_assert (exp1, exp2) ->
let aexp1 = anf exp1 in
let aexp2 = anf exp2 in
let aval1, wrap1 = to_aval aexp1 in
let aval2, wrap2 = to_aval aexp2 in
- wrap1 (wrap2 (AE_app (mk_id "sail_assert", [aval1; aval2], unit_typ)))
+ wrap1 (wrap2 (mk_aexp (AE_app (mk_id "sail_assert", [aval1; aval2], unit_typ))))
| E_cons (exp1, exp2) ->
let aexp1 = anf exp1 in
let aexp2 = anf exp2 in
let aval1, wrap1 = to_aval aexp1 in
let aval2, wrap2 = to_aval aexp2 in
- wrap1 (wrap2 (AE_app (mk_id "cons", [aval1; aval2], unit_typ)))
+ wrap1 (wrap2 (mk_aexp (AE_app (mk_id "cons", [aval1; aval2], unit_typ))))
| E_id id ->
let lvar = Env.lookup_id id (env_of exp) in
begin match lvar with
- | _ -> AE_val (AV_id (id, lvar))
+ | _ -> mk_aexp (AE_val (AV_id (id, lvar)))
end
| E_ref id ->
let lvar = Env.lookup_id id (env_of exp) in
- AE_val (AV_ref (id, lvar))
+ mk_aexp (AE_val (AV_ref (id, lvar)))
| E_case (match_exp, pexps) ->
let match_aval, match_wrap = to_aval (anf match_exp) in
@@ -657,9 +652,9 @@ let rec anf (E_aux (e_aux, exp_annot) as exp) =
| Pat_when (pat, guard, body) ->
(anf_pat pat, anf guard, anf body)
| Pat_exp (pat, body) ->
- (anf_pat pat, AE_val (AV_lit (mk_lit (L_true), bool_typ)), anf body)
+ (anf_pat pat, mk_aexp (AE_val (AV_lit (mk_lit (L_true), bool_typ))), anf body)
in
- match_wrap (AE_case (match_aval, List.map anf_pexp pexps, typ_of exp))
+ match_wrap (mk_aexp (AE_case (match_aval, List.map anf_pexp pexps, typ_of exp)))
| E_try (match_exp, pexps) ->
let match_aexp = anf match_exp in
@@ -668,16 +663,16 @@ let rec anf (E_aux (e_aux, exp_annot) as exp) =
| Pat_when (pat, guard, body) ->
(anf_pat pat, anf guard, anf body)
| Pat_exp (pat, body) ->
- (anf_pat pat, AE_val (AV_lit (mk_lit (L_true), bool_typ)), anf body)
+ (anf_pat pat, mk_aexp (AE_val (AV_lit (mk_lit (L_true), bool_typ))), anf body)
in
- AE_try (match_aexp, List.map anf_pexp pexps, typ_of exp)
+ mk_aexp (AE_try (match_aexp, List.map anf_pexp pexps, typ_of exp))
| E_var (LEXP_aux (LEXP_id id, _), binding, body)
- | E_var (LEXP_aux (LEXP_cast (_, id), _), binding, body)
- | E_let (LB_aux (LB_val (P_aux (P_id id, _), binding), _), body) ->
+ | E_var (LEXP_aux (LEXP_cast (_, id), _), binding, body)
+ | E_let (LB_aux (LB_val (P_aux (P_id id, _), binding), _), body) ->
let env = env_of body in
let lvar = Env.lookup_id id env in
- AE_let (id, lvar_typ lvar, anf binding, anf body, typ_of exp)
+ mk_aexp (AE_let (id, lvar_typ lvar, anf binding, anf body, typ_of exp))
| E_var (lexp, _, _) ->
failwith ("Encountered complex l-expression " ^ string_of_lexp lexp ^ " when converting to ANF")
@@ -689,7 +684,7 @@ let rec anf (E_aux (e_aux, exp_annot) as exp) =
let aexps = List.map anf exps in
let avals = List.map to_aval aexps in
let wrap = List.fold_left (fun f g x -> f (g x)) (fun x -> x) (List.map snd avals) in
- wrap (AE_val (AV_tuple (List.map fst avals)))
+ wrap (mk_aexp (AE_val (AV_tuple (List.map fst avals))))
| E_record (FES_aux (FES_Fexps (fexps, _), _)) ->
let anf_fexp (FE_aux (FE_Fexp (id, exp), _)) =
@@ -699,9 +694,9 @@ let rec anf (E_aux (e_aux, exp_annot) as exp) =
let fexps = List.map anf_fexp fexps in
let wrap = List.fold_left (fun f g x -> f (g x)) (fun x -> x) (List.map snd fexps) in
let record = List.fold_left (fun r (id, aval) -> Bindings.add id aval r) Bindings.empty (List.map fst fexps) in
- wrap (AE_val (AV_record (record, typ_of exp)))
+ wrap (mk_aexp (AE_val (AV_record (record, typ_of exp))))
- | E_cast (typ, exp) -> AE_cast (anf exp, typ)
+ | E_cast (typ, exp) -> mk_aexp (AE_cast (anf exp, typ))
| E_vector_access _ | E_vector_subrange _ | E_vector_update _ | E_vector_update_subrange _ | E_vector_append _ ->
(* Should be re-written by type checker *)
@@ -738,7 +733,9 @@ type ctx =
enums : IdSet.t Bindings.t;
variants : (ctyp Bindings.t) Bindings.t;
tc_env : Env.t;
- letbinds : int list
+ local_env : Env.t;
+ letbinds : int list;
+ recursive_functions : IdSet.t
}
let initial_ctx env =
@@ -746,7 +743,9 @@ let initial_ctx env =
enums = Bindings.empty;
variants = Bindings.empty;
tc_env = env;
- letbinds = []
+ local_env = env;
+ letbinds = [];
+ recursive_functions = IdSet.empty
}
let rec ctyp_equal ctyp1 ctyp2 =
@@ -770,27 +769,6 @@ let rec ctyp_equal ctyp1 ctyp2 =
| CT_ref ctyp1, CT_ref ctyp2 -> ctyp_equal ctyp1 ctyp2
| _, _ -> false
-(* String representation of ctyps here is only for debugging and
- intermediate language pretty-printer. *)
-let rec string_of_ctyp = function
- | CT_mpz -> "mpz_t"
- | CT_bv true -> "bv_t(dec)"
- | CT_bv false -> "bv_t(inc)"
- | CT_uint64 (n, true) -> "uint64_t(" ^ string_of_int n ^ ", dec)"
- | CT_uint64 (n, false) -> "uint64_t(" ^ string_of_int n ^ ", int)"
- | CT_int64 -> "int64_t"
- | CT_bit -> "bit"
- | CT_unit -> "unit"
- | CT_bool -> "bool"
- | CT_real -> "real"
- | CT_tup ctyps -> "(" ^ Util.string_of_list ", " string_of_ctyp ctyps ^ ")"
- | CT_struct (id, _) | CT_enum (id, _) | CT_variant (id, _) -> string_of_id id
- | CT_string -> "string"
- | CT_vector (true, ctyp) -> "vector(dec, " ^ string_of_ctyp ctyp ^ ")"
- | CT_vector (false, ctyp) -> "vector(inc, " ^ string_of_ctyp ctyp ^ ")"
- | CT_list ctyp -> "list(" ^ string_of_ctyp ctyp ^ ")"
- | CT_ref ctyp -> "ref(" ^ string_of_ctyp ctyp ^ ")"
-
(** Convert a sail type into a C-type **)
let rec ctyp_of_typ ctx typ =
let Typ_aux (typ_aux, l) as typ = Env.expand_synonyms ctx.tc_env typ in
@@ -808,6 +786,12 @@ let rec ctyp_of_typ ctx typ =
| Nexp_aux (Nexp_constant n, _), Nexp_aux (Nexp_constant m, _)
when Big_int.less_equal min_int64 n && Big_int.less_equal m max_int64 ->
CT_int64
+ | n, m when !optimize_z3 ->
+ prerr_endline ("optimize atom " ^ string_of_nexp n ^ ", " ^ string_of_nexp m ^ " in context " ^ (Util.string_of_list ", " string_of_n_constraint (Env.get_constraints ctx.local_env)));
+ if prove ctx.local_env (nc_lteq (nconstant min_int64) n) && prove ctx.local_env (nc_lteq m (nconstant max_int64)) then
+ (prerr_endline "yes"; CT_int64)
+ else
+ (prerr_endline "no"; CT_mpz)
| _ -> CT_mpz
end
@@ -844,6 +828,18 @@ let rec ctyp_of_typ ctx typ =
| Typ_tup typs -> CT_tup (List.map (ctyp_of_typ ctx) typs)
+ | Typ_exist _ when !optimize_z3 ->
+ (* Use Type_check.destruct_exist when optimising with z3, to ensure that we
+ don't cause any type variable clashes in local_env. *)
+ begin match destruct_exist ctx.local_env typ with
+ | Some (kids, nc, typ) ->
+ c_debug (lazy ("optimize existential: " ^ string_of_n_constraint nc ^ ". " ^ string_of_typ typ
+ ^ " in context " ^ (Util.string_of_list ", " string_of_n_constraint (Env.get_constraints ctx.local_env))));
+ let env = add_existential l kids nc ctx.local_env in
+ ctyp_of_typ { ctx with local_env = env } typ
+ | None -> c_error "Existential cannot be destructured. This should be impossible!"
+ end
+
| Typ_exist (_, _, typ) -> ctyp_of_typ ctx typ
| _ -> c_error ~loc:l ("No C type for type " ^ string_of_typ typ)
@@ -900,14 +896,14 @@ let literal_to_fragment (L_aux (l_aux, _) as lit) =
| _ -> None
let c_literals ctx =
- let rec c_literal = function
- | AV_lit (lit, typ) as v when is_stack_ctyp (ctyp_of_typ ctx typ) ->
+ let rec c_literal env l = function
+ | AV_lit (lit, typ) as v when is_stack_ctyp (ctyp_of_typ { ctx with local_env = env } typ) ->
begin
match literal_to_fragment lit with
| Some frag -> AV_C_fragment (frag, typ)
| None -> v
end
- | AV_tuple avals -> AV_tuple (List.map c_literal avals)
+ | AV_tuple avals -> AV_tuple (List.map (c_literal env l) avals)
| v -> v
in
map_aval c_literal
@@ -964,21 +960,39 @@ let c_fragment = function
| AV_C_fragment (frag, _) -> frag
| _ -> assert false
-let analyze_primop' ctx id args typ =
+let analyze_primop' ctx env l id args typ =
+ let ctx = { ctx with local_env = env } in
let no_change = AE_app (id, args, typ) in
let args = List.map (c_aval ctx) args in
let extern = if Env.is_extern id ctx.tc_env "c" then Env.get_extern id ctx.tc_env "c" else failwith "Not extern" in
(* prerr_endline ("Analysing: " ^ string_of_typ typ ^ " " ^ extern ^ Pretty_print_sail.to_string (separate_map (string ", ") pp_aval args)); *)
let v_one = F_lit (V_int (Big_int.of_int 1)) in
+ let v_int n = F_lit (V_int (Big_int.of_int n)) in
match extern, args with
| "eq_bits", [AV_C_fragment (v1, typ1); AV_C_fragment (v2, typ2)] ->
AE_val (AV_C_fragment (F_op (v1, "==", v2), typ))
+ | "eq_int", [AV_C_fragment (v1, typ1); AV_C_fragment (v2, typ2)] ->
+ AE_val (AV_C_fragment (F_op (v1, "==", v2), typ))
+
+ (*
+ | "add_bits", [AV_C_fragment (v1, typ1); AV_C_fragment (v2, typ2)] ->
+ AE_val (AV_C_fragment (F_op (v1, "+", v2), typ)) *)
+
+ | "xor_bits", [AV_C_fragment (v1, typ1); AV_C_fragment (v2, typ2)] ->
+ AE_val (AV_C_fragment (F_op (v1, "^", v2), typ))
+
+ | "or_bits", [AV_C_fragment (v1, typ1); AV_C_fragment (v2, typ2)] ->
+ AE_val (AV_C_fragment (F_op (v1, "|", v2), typ))
+
+ | "and_bits", [AV_C_fragment (v1, typ1); AV_C_fragment (v2, typ2)] ->
+ AE_val (AV_C_fragment (F_op (v1, "&", v2), typ))
+
| "vector_subrange", [AV_C_fragment (vec, _); AV_C_fragment (f, _); AV_C_fragment (t, _)] ->
let len = F_op (f, "-", F_op (t, "-", v_one)) in
- AE_val (AV_C_fragment (F_op (F_op (F_op (v_one, "<<", len), "-", v_one), "&", F_op (vec, ">>", t)), typ))
+ AE_val (AV_C_fragment (F_op (F_call ("safe_rshift", [F_raw "UINT64_MAX"; F_op (v_int 64, "-", len)]), "&", F_op (vec, ">>", t)), typ))
| "vector_access", [AV_C_fragment (vec, _); AV_C_fragment (n, _)] ->
AE_val (AV_C_fragment (F_op (v_one, "&", F_op (vec, ">>", n)), typ))
@@ -987,7 +1001,7 @@ let analyze_primop' ctx id args typ =
AE_val (AV_C_fragment (F_op (a, "==", b), typ))
| "slice", [AV_C_fragment (vec, _); AV_C_fragment (start, _); AV_C_fragment (len, _)] ->
- AE_val (AV_C_fragment (F_op (F_op (F_op (v_one, "<<", len), "-", v_one), "&", F_op (vec, ">>", start)), typ))
+ AE_val (AV_C_fragment (F_op (F_call ("safe_rshift", [F_raw "UINT64_MAX"; F_op (v_int 64, "-", len)]), "&", F_op (vec, ">>", start)), typ))
| "undefined_bit", _ ->
AE_val (AV_C_fragment (F_lit (V_bit Sail_values.B0), typ))
@@ -1022,10 +1036,10 @@ let analyze_primop' ctx id args typ =
| _, _ -> no_change
-let analyze_primop ctx id args typ =
+let analyze_primop ctx env l id args typ =
let no_change = AE_app (id, args, typ) in
- if !optimize_primops then
- try analyze_primop' ctx id args typ with
+ if !optimize_primops then
+ try analyze_primop' ctx env l id args typ with
| Failure _ -> no_change
else
no_change
@@ -1056,52 +1070,6 @@ let analyze_primop ctx id args typ =
expression), cleanup instructions (to deallocate that memory) and
possibly typing information about what has been translated. **)
-let instr_counter = ref 0
-
-let instr_number () =
- let n = !instr_counter in
- incr instr_counter;
- n
-
-let idecl ?loc:(l=Parse_ast.Unknown) ctyp id =
- I_aux (I_decl (ctyp, id), (instr_number (), l))
-let ialloc ?loc:(l=Parse_ast.Unknown) ctyp id =
- I_aux (I_alloc (ctyp, id), (instr_number (), l))
-let iinit ?loc:(l=Parse_ast.Unknown) ctyp id cval =
- I_aux (I_init (ctyp, id, cval), (instr_number (), l))
-let iif ?loc:(l=Parse_ast.Unknown) cval then_instrs else_instrs ctyp =
- I_aux (I_if (cval, then_instrs, else_instrs, ctyp), (instr_number (), l))
-let ifuncall ?loc:(l=Parse_ast.Unknown) clexp id cvals ctyp =
- I_aux (I_funcall (clexp, false, id, cvals, ctyp), (instr_number (), l))
-let iextern ?loc:(l=Parse_ast.Unknown) clexp id cvals ctyp =
- I_aux (I_funcall (clexp, true, id, cvals, ctyp), (instr_number (), l))
-let icopy ?loc:(l=Parse_ast.Unknown) clexp cval =
- I_aux (I_copy (clexp, cval), (instr_number (), l))
-let iconvert ?loc:(l=Parse_ast.Unknown) clexp ctyp1 id ctyp2 =
- I_aux (I_convert (clexp, ctyp1, id, ctyp2), (instr_number (), l))
-let iclear ?loc:(l=Parse_ast.Unknown) ctyp id =
- I_aux (I_clear (ctyp, id), (instr_number (), l))
-let ireturn ?loc:(l=Parse_ast.Unknown) cval =
- I_aux (I_return cval, (instr_number (), l))
-let iblock ?loc:(l=Parse_ast.Unknown) instrs =
- I_aux (I_block instrs, (instr_number (), l))
-let itry_block ?loc:(l=Parse_ast.Unknown) instrs =
- I_aux (I_try_block instrs, (instr_number (), l))
-let ithrow ?loc:(l=Parse_ast.Unknown) cval =
- I_aux (I_throw cval, (instr_number (), l))
-let icomment ?loc:(l=Parse_ast.Unknown) str =
- I_aux (I_comment str, (instr_number (), l))
-let ilabel ?loc:(l=Parse_ast.Unknown) label =
- I_aux (I_label label, (instr_number (), l))
-let igoto ?loc:(l=Parse_ast.Unknown) label =
- I_aux (I_goto label, (instr_number (), l))
-let imatch_failure ?loc:(l=Parse_ast.Unknown) () =
- I_aux (I_match_failure, (instr_number (), l))
-let iraw ?loc:(l=Parse_ast.Unknown) str =
- I_aux (I_raw str, (instr_number (), l))
-let ijump ?loc:(l=Parse_ast.Unknown) cval label =
- I_aux (I_jump (cval, label), (instr_number (), l))
-
let ctype_def_ctyps = function
| CTD_enum _ -> []
| CTD_struct (_, fields) -> List.map snd fields
@@ -1162,121 +1130,6 @@ let cdef_ctyps ctx = function
@ List.concat (List.map instr_ctyps instrs)
@ List.concat (List.map instr_ctyps cleanup)
-(* For debugging we define a pretty printer for Sail IR instructions *)
-
-let pp_ctyp ctyp =
- string (string_of_ctyp ctyp |> Util.yellow |> Util.clear)
-
-let pp_keyword str =
- string ((str |> Util.red |> Util.clear) ^ " ")
-
-let pp_cval (frag, ctyp) = string (string_of_fragment ~zencode:false frag) ^^ string " : " ^^ pp_ctyp ctyp
-
-let rec pp_clexp = function
- | CL_id id -> pp_id id
- | CL_field (id, field) -> pp_id id ^^ string "." ^^ string field
- | CL_addr id -> string "*" ^^ pp_id id
- | CL_current_exception -> string "current_exception"
- | CL_have_exception -> string "have_exception"
-
-let rec pp_instr ?short:(short=false) (I_aux (instr, aux)) =
- match instr with
- | I_decl (ctyp, id) ->
- pp_keyword "var" ^^ pp_id id ^^ string " : " ^^ pp_ctyp ctyp
- | I_if (cval, then_instrs, else_instrs, ctyp) ->
- let pp_if_block = function
- | [] -> string "{}"
- | instrs -> surround 2 0 lbrace (separate_map (semi ^^ hardline) pp_instr instrs) rbrace
- in
- parens (pp_ctyp ctyp) ^^ space
- ^^ pp_keyword "if" ^^ pp_cval cval
- ^^ if short then
- empty
- else
- pp_keyword " then" ^^ pp_if_block then_instrs
- ^^ pp_keyword " else" ^^ pp_if_block else_instrs
- | I_jump (cval, label) ->
- pp_keyword "jump" ^^ pp_cval cval ^^ space ^^ string (label |> Util.blue |> Util.clear)
- | I_block instrs ->
- surround 2 0 lbrace (separate_map (semi ^^ hardline) pp_instr instrs) rbrace
- | I_try_block instrs ->
- pp_keyword "try" ^^ surround 2 0 lbrace (separate_map (semi ^^ hardline) pp_instr instrs) rbrace
- | I_alloc (ctyp, id) ->
- pp_keyword "create" ^^ pp_id id ^^ string " : " ^^ pp_ctyp ctyp
- | I_reset (ctyp, id) ->
- pp_keyword "recreate" ^^ pp_id id ^^ string " : " ^^ pp_ctyp ctyp
- | I_init (ctyp, id, cval) ->
- pp_keyword "create" ^^ pp_id id ^^ string " : " ^^ pp_ctyp ctyp ^^ string " = " ^^ pp_cval cval
- | I_reinit (ctyp, id, cval) ->
- pp_keyword "recreate" ^^ pp_id id ^^ string " : " ^^ pp_ctyp ctyp ^^ string " = " ^^ pp_cval cval
- | I_funcall (x, _, f, args, ctyp2) ->
- separate space [ pp_clexp x; string "=";
- string (string_of_id f |> Util.green |> Util.clear) ^^ parens (separate_map (string ", ") pp_cval args);
- string ":"; pp_ctyp ctyp2 ]
- | I_convert (x, ctyp1, y, ctyp2) ->
- separate space [ pp_clexp x; colon; pp_ctyp ctyp1; string "=";
- pp_keyword "convert" ^^ pp_id y; colon; pp_ctyp ctyp2 ]
- | I_copy (clexp, cval) ->
- separate space [pp_clexp clexp; string "="; pp_cval cval]
- | I_clear (ctyp, id) ->
- pp_keyword "kill" ^^ pp_id id ^^ string " : " ^^ pp_ctyp ctyp
- | I_return cval ->
- pp_keyword "return" ^^ pp_cval cval
- | I_throw cval ->
- pp_keyword "throw" ^^ pp_cval cval
- | I_comment str ->
- string ("// " ^ str |> Util.magenta |> Util.clear)
- | I_label str ->
- string (str |> Util.blue |> Util.clear) ^^ string ":"
- | I_goto str ->
- pp_keyword "goto" ^^ string (str |> Util.blue |> Util.clear)
- | I_match_failure ->
- pp_keyword "match_failure"
- | I_raw str ->
- pp_keyword "C" ^^ string (str |> Util.cyan |> Util.clear)
-
-let pp_ctype_def = function
- | CTD_enum (id, ids) ->
- pp_keyword "enum" ^^ pp_id id ^^ string " = "
- ^^ separate_map (string " | ") pp_id ids
- | CTD_struct (id, fields) ->
- pp_keyword "struct" ^^ pp_id id ^^ string " = "
- ^^ surround 2 0 lbrace (separate_map (semi ^^ hardline) (fun (id, ctyp) -> pp_id id ^^ string " : " ^^ pp_ctyp ctyp) fields) rbrace
- | CTD_variant (id, ctors) ->
- pp_keyword "union" ^^ pp_id id ^^ string " = "
- ^^ surround 2 0 lbrace (separate_map (semi ^^ hardline) (fun (id, ctyp) -> pp_id id ^^ string " : " ^^ pp_ctyp ctyp) ctors) rbrace
-
-let pp_cdef = function
- | CDEF_spec (id, ctyps, ctyp) ->
- pp_keyword "val" ^^ pp_id id ^^ string " : " ^^ parens (separate_map (comma ^^ space) pp_ctyp ctyps) ^^ string " -> " ^^ pp_ctyp ctyp
- ^^ hardline
- | CDEF_fundef (id, ret, args, instrs) ->
- let ret = match ret with
- | None -> empty
- | Some id -> space ^^ pp_id id
- in
- pp_keyword "function" ^^ pp_id id ^^ ret ^^ parens (separate_map (comma ^^ space) pp_id args) ^^ space
- ^^ surround 2 0 lbrace (separate_map (semi ^^ hardline) pp_instr instrs) rbrace
- ^^ hardline
- | CDEF_reg_dec (id, ctyp) ->
- pp_keyword "register" ^^ pp_id id ^^ string " : " ^^ pp_ctyp ctyp
- ^^ hardline
- | CDEF_type tdef -> pp_ctype_def tdef ^^ hardline
- | CDEF_let (n, bindings, instrs, cleanup) ->
- let pp_binding (id, ctyp) = pp_id id ^^ string " : " ^^ pp_ctyp ctyp in
- pp_keyword "let" ^^ string (string_of_int n) ^^ parens (separate_map (comma ^^ space) pp_binding bindings) ^^ space
- ^^ surround 2 0 lbrace (separate_map (semi ^^ hardline) pp_instr instrs) rbrace ^^ space
- ^^ surround 2 0 lbrace (separate_map (semi ^^ hardline) pp_instr cleanup) rbrace ^^ space
- ^^ hardline
- | CDEF_startup (id, instrs)->
- pp_keyword "startup" ^^ pp_id id ^^ space
- ^^ surround 2 0 lbrace (separate_map (semi ^^ hardline) pp_instr instrs) rbrace
- ^^ hardline
- | CDEF_finish (id, instrs)->
- pp_keyword "finish" ^^ pp_id id ^^ space
- ^^ surround 2 0 lbrace (separate_map (semi ^^ hardline) pp_instr instrs) rbrace
- ^^ hardline
-
let is_ct_enum = function
| CT_enum _ -> true
| _ -> false
@@ -1493,17 +1346,22 @@ let rec compile_aval ctx = function
(F_id gs, CT_list ctyp),
[iclear (CT_list ctyp) gs]
-let compile_funcall ctx id args typ =
+let compile_funcall l ctx id args typ =
let setup = ref [] in
let cleanup = ref [] in
- let _, Typ_aux (fn_typ, _) = Env.get_val_spec id ctx.tc_env in
+ let quant, Typ_aux (fn_typ, _) =
+ try Env.get_val_spec id ctx.local_env
+ with Type_error _ ->
+ c_debug (lazy ("Falling back to global env for " ^ string_of_id id)); Env.get_val_spec id ctx.tc_env
+ in
let arg_typs, ret_typ = match fn_typ with
| Typ_fn (Typ_aux (Typ_tup arg_typs, _), ret_typ, _) -> arg_typs, ret_typ
| Typ_fn (arg_typ, ret_typ, _) -> [arg_typ], ret_typ
| _ -> assert false
in
- let arg_ctyps, ret_ctyp = List.map (ctyp_of_typ ctx) arg_typs, ctyp_of_typ ctx ret_typ in
+ let ctx' = { ctx with local_env = add_typquant (id_loc id) quant ctx.local_env } in
+ let arg_ctyps, ret_ctyp = List.map (ctyp_of_typ ctx') arg_typs, ctyp_of_typ ctx' ret_typ in
let final_ctyp = ctyp_of_typ ctx typ in
let setup_arg ctyp aval =
@@ -1520,7 +1378,7 @@ let compile_funcall ctx id args typ =
cleanup := iclear ctyp gs :: !cleanup;
(F_id gs, ctyp)
else
- c_error ~loc:(id_loc id)
+ c_error ~loc:l
(Printf.sprintf "Failure when setting up function %s arguments: %s and %s." (string_of_id id) (string_of_ctyp have_ctyp) (string_of_ctyp ctyp))
in
@@ -1537,15 +1395,20 @@ let compile_funcall ctx id args typ =
setup := ifuncall (CL_id gs) id sargs ret_ctyp :: !setup;
cleanup := iclear ret_ctyp gs :: !cleanup;
fun ret -> iconvert ret final_ctyp gs ret_ctyp
+ else if is_stack_ctyp ret_ctyp && not (is_stack_ctyp final_ctyp) then
+ let gs = gensym () in
+ setup := idecl ret_ctyp gs :: !setup;
+ setup := ifuncall (CL_id gs) id sargs ret_ctyp :: !setup;
+ fun ret -> iconvert ret final_ctyp gs ret_ctyp
else
- assert false
+ c_error (Printf.sprintf "Funcall call type mismatch between %s and %s" (string_of_ctyp ret_ctyp) (string_of_ctyp final_ctyp))
in
(List.rev !setup, final_ctyp, call, !cleanup)
-let rec compile_match ctx apat cval case_label =
- prerr_endline ("Compiling match " ^ Pretty_print_sail.to_string (pp_apat apat) ^ " cval " ^ Pretty_print_sail.to_string (pp_cval cval));
- match apat, cval with
+let rec compile_match ctx (AP_aux (apat_aux, env, l)) cval case_label =
+ let ctx = { ctx with local_env = env } in
+ match apat_aux, cval with
| AP_id (pid, _), (frag, ctyp) when Env.is_union_constructor pid ctx.tc_env ->
[ijump (F_op (F_field (frag, "kind"), "!=", F_lit (V_ctor_kind (string_of_id pid))), CT_bool) case_label],
[]
@@ -1620,7 +1483,9 @@ let label str =
incr label_counter;
str
-let rec compile_aexp ctx = function
+let rec compile_aexp ctx (AE_aux (aexp_aux, env, l)) =
+ let ctx = { ctx with local_env = env } in
+ match aexp_aux with
| AE_let (id, _, binding, body, typ) ->
let setup, ctyp, call, cleanup = compile_aexp ctx binding in
let letb_setup, letb_cleanup =
@@ -1644,7 +1509,7 @@ let rec compile_aexp ctx = function
end
| AE_app (id, vs, typ) ->
- compile_funcall ctx id vs typ
+ compile_funcall l ctx id vs typ
| AE_val aval ->
let setup, cval, cleanup = compile_aval ctx aval in
@@ -1658,12 +1523,14 @@ let rec compile_aexp ctx = function
let finish_match_label = label "finish_match_" in
let compile_case (apat, guard, body) =
let trivial_guard = match guard with
- | AE_val (AV_lit (L_aux (L_true, _), _))
- | AE_val (AV_C_fragment (F_lit (V_bool true), _)) -> true
+ | AE_aux (AE_val (AV_lit (L_aux (L_true, _), _)), _, _)
+ | AE_aux (AE_val (AV_C_fragment (F_lit (V_bool true), _)), _, _) -> true
| _ -> false
in
let case_label = label "case_" in
+ c_debug (lazy ("Compiling match"));
let destructure, destructure_cleanup = compile_match ctx apat cval case_label in
+ c_debug (lazy ("Compiled match"));
let guard_setup, _, guard_call, guard_cleanup = compile_aexp ctx guard in
let body_setup, _, body_call, body_cleanup = compile_aexp ctx body in
let gs = gensym () in
@@ -1697,8 +1564,8 @@ let rec compile_aexp ctx = function
let handled_exception_label = label "handled_exception_" in
let compile_case (apat, guard, body) =
let trivial_guard = match guard with
- | AE_val (AV_lit (L_aux (L_true, _), _))
- | AE_val (AV_C_fragment (F_lit (V_bool true), _)) -> true
+ | AE_aux (AE_val (AV_lit (L_aux (L_true, _), _)), _, _)
+ | AE_aux (AE_val (AV_C_fragment (F_lit (V_bool true), _)), _, _) -> true
| _ -> false
in
let try_label = label "try_" in
@@ -1719,27 +1586,48 @@ let rec compile_aexp ctx = function
in
[iblock case_instrs; ilabel try_label]
in
+ assert (ctyp_equal ctyp (ctyp_of_typ ctx typ));
[icomment "begin try catch";
- idecl ctyp try_return_id],
- ctyp,
- (fun clexp -> itry_block (aexp_setup @ [aexp_call clexp] @ aexp_cleanup)),
- [ijump (F_unary ("!", F_have_exception), CT_bool) handled_exception_label]
+ idecl ctyp try_return_id;
+ itry_block (aexp_setup @ [aexp_call (CL_id try_return_id)] @ aexp_cleanup);
+ ijump (F_unary ("!", F_have_exception), CT_bool) handled_exception_label]
@ List.concat (List.map compile_case cases)
- @ [imatch_failure ()]
- @ [ilabel handled_exception_label]
- @ [icopy CL_have_exception (F_lit (V_bool false), CT_bool)]
+ @ [imatch_failure ();
+ ilabel handled_exception_label;
+ icopy CL_have_exception (F_lit (V_bool false), CT_bool)],
+ ctyp,
+ (fun clexp -> icopy clexp (F_id try_return_id, ctyp)),
+ []
| AE_if (aval, then_aexp, else_aexp, if_typ) ->
let if_ctyp = ctyp_of_typ ctx if_typ in
let compile_branch aexp =
let setup, ctyp, call, cleanup = compile_aexp ctx aexp in
- fun clexp -> setup @ [call clexp] @ cleanup
+ if ctyp_equal if_ctyp ctyp then
+ fun clexp -> setup @ [call clexp] @ cleanup
+ else if is_stack_ctyp ctyp then
+ fun clexp ->
+ let gs = gensym() in
+ setup
+ @ [idecl ctyp gs;
+ call (CL_id gs);
+ iconvert clexp if_ctyp gs ctyp]
+ @ cleanup
+ else
+ fun clexp ->
+ let gs = gensym () in
+ setup
+ @ [idecl ctyp gs;
+ ialloc ctyp gs;
+ call (CL_id gs);
+ iconvert clexp if_ctyp gs ctyp;
+ iclear ctyp gs]
+ @ cleanup
in
- let setup, ctyp, call, cleanup = compile_aexp ctx (AE_val aval) in
- let gs = gensym () in
- setup @ [idecl ctyp gs; call (CL_id gs)],
+ let setup, cval, cleanup = compile_aval ctx aval in
+ setup,
if_ctyp,
- (fun clexp -> iif (F_id gs, ctyp)
+ (fun clexp -> iif cval
(compile_branch then_aexp clexp)
(compile_branch else_aexp clexp)
if_ctyp),
@@ -1792,8 +1680,9 @@ let rec compile_aexp ctx = function
(* This is a faster assignment rule for updating fields of a
struct. Turned on by !optimize_struct_updates. *)
- | AE_assign (id, assign_typ, AE_record_update (AV_id (rid, _), fields, typ))
+ | AE_assign (id, assign_typ, AE_aux (AE_record_update (AV_id (rid, _), fields, typ), _, _))
when Id.compare id rid = 0 && !optimize_struct_updates ->
+ c_debug (lazy ("Optimizing struct update"));
let compile_fields (field_id, aval) =
let field_setup, cval, field_cleanup = compile_aval ctx aval in
field_setup
@@ -1869,7 +1758,7 @@ let rec compile_aexp ctx = function
let body_setup, _, body_call, body_cleanup = compile_aexp ctx body in
let gs = gensym () in
let unit_gs = gensym () in
- let loop_test = (F_unary ("!", F_id gs), CT_bool) in
+ let loop_test = (F_id gs, CT_bool) in
[idecl CT_bool gs; idecl CT_unit unit_gs]
@ [ilabel loop_start_label]
@ [iblock (body_setup
@@ -1888,9 +1777,28 @@ let rec compile_aexp ctx = function
| AE_cast (aexp, typ) -> compile_aexp ctx aexp
| AE_return (aval, typ) ->
+ let fn_return_ctyp = match Env.get_ret_typ env with
+ | Some typ -> ctyp_of_typ ctx typ
+ | None -> c_error ~loc:l "No function return type found when compiling return statement"
+ in
(* Cleanup info will be re-added by fix_early_return *)
let return_setup, cval, _ = compile_aval ctx aval in
- return_setup @ [ireturn cval],
+ let creturn =
+ if ctyp_equal fn_return_ctyp (cval_ctyp cval) then
+ [ireturn cval]
+ else if is_stack_ctyp (cval_ctyp cval) && not (is_stack_ctyp fn_return_ctyp) then
+ let gs1 = gensym () in
+ let gs2 = gensym () in
+ [idecl (cval_ctyp cval) gs1;
+ icopy (CL_id gs1) cval;
+ idecl fn_return_ctyp gs2;
+ ialloc fn_return_ctyp gs2;
+ iconvert (CL_id gs2) fn_return_ctyp gs1 (cval_ctyp cval);
+ ireturn (F_id gs2, fn_return_ctyp)]
+ else
+ c_error ~loc:l "Can only do return type conversion from stack to heap"
+ in
+ return_setup @ creturn,
ctyp_of_typ ctx typ,
(fun clexp -> icomment "unreachable after return"),
[]
@@ -1911,10 +1819,62 @@ let rec compile_aexp ctx = function
(fun clexp -> icopy clexp (F_field (fst cval, Util.zencode_string (string_of_id id)), ctyp)),
cleanup
- | AE_for _ ->
- [],
+ | AE_for (loop_var, loop_from, loop_to, loop_step, Ord_aux (ord, _), body) ->
+ (* This is a bit of a hack, we force loop_var to be CT_int64 by
+ forcing it's type to be a known nexp that will map to
+ CT_int64. *)
+ let make_small _ _ = function
+ | AV_id (id, Local (Immutable, typ)) when Id.compare id loop_var = 0 -> AV_id (id, Local (Immutable, atom_typ (nint 0)))
+ | aval -> aval
+ in
+ let body = map_aval make_small body in
+
+ let is_inc = match ord with
+ | Ord_inc -> true
+ | Ord_dec -> false
+ | Ord_var _ -> c_error "Polymorphic loop direction in C backend"
+ in
+
+ (* Loop variables *)
+ let from_setup, from_ctyp, from_call, from_cleanup = compile_aexp ctx loop_from in
+ let from_gs = gensym () in
+ let to_setup, to_ctyp, to_call, to_cleanup = compile_aexp ctx loop_to in
+ let to_gs = gensym () in
+ let step_setup, step_ctyp, step_call, step_cleanup = compile_aexp ctx loop_step in
+ let step_gs = gensym () in
+ let variable_init gs setup ctyp call cleanup =
+ [idecl CT_int64 gs;
+ if is_stack_ctyp ctyp then
+ iblock (setup @ [call (CL_id gs)] @ cleanup)
+ else
+ let gs' = gensym () in
+ iblock (setup
+ @ [idecl ctyp gs'; ialloc ctyp gs'; call (CL_id gs'); iconvert (CL_id gs) CT_int64 gs' ctyp; iclear ctyp gs']
+ @ cleanup)]
+ in
+
+ let loop_start_label = label "for_start_" in
+ let body_setup, _, body_call, body_cleanup = compile_aexp ctx body in
+ let body_gs = gensym () in
+
+ variable_init from_gs from_setup from_ctyp from_call from_cleanup
+ @ variable_init to_gs to_setup to_ctyp to_call to_cleanup
+ @ variable_init step_gs step_setup step_ctyp step_call step_cleanup
+ @ [iblock ([idecl CT_int64 loop_var;
+ icopy (CL_id loop_var) (F_id from_gs, CT_int64);
+ ilabel loop_start_label;
+ idecl CT_unit body_gs;
+ iblock (body_setup
+ @ [body_call (CL_id body_gs)]
+ @ body_cleanup
+ @ if is_inc then
+ [icopy (CL_id loop_var) (F_op (F_id loop_var, "+", F_id step_gs), CT_int64);
+ ijump (F_op (F_id loop_var, "<=", F_id to_gs), CT_bool) loop_start_label]
+ else
+ [icopy (CL_id loop_var) (F_op (F_id loop_var, "-", F_id step_gs), CT_int64);
+ ijump (F_op (F_id loop_var, ">=", F_id to_gs), CT_bool) loop_start_label])])],
CT_unit,
- (fun clexp -> icomment "for loop"),
+ (fun clexp -> icopy clexp unit_fragment),
[]
(*
@@ -2008,7 +1968,7 @@ let fix_early_return ret ctx instrs =
| instrs, [] -> instrs
| before, I_aux (I_block instrs, _) :: after ->
before
- @ [iblock (rewrite_return (generate_cleanup (historic @ before)) instrs)]
+ @ [iblock (rewrite_return (historic @ before) instrs)]
@ rewrite_return (historic @ before) after
| before, I_aux (I_if (cval, then_instrs, else_instrs, ctyp), _) :: after ->
let historic = historic @ before in
@@ -2045,7 +2005,7 @@ let fix_early_stack_return ctx instrs =
| instrs, [] -> instrs
| before, I_aux (I_block instrs, _) :: after ->
before
- @ [iblock (rewrite_return (generate_cleanup (historic @ before)) instrs)]
+ @ [iblock (rewrite_return (historic @ before) instrs)]
@ rewrite_return (historic @ before) after
| before, I_aux (I_if (cval, then_instrs, else_instrs, ctyp), _) :: after ->
let historic = historic @ before in
@@ -2053,9 +2013,8 @@ let fix_early_stack_return ctx instrs =
@ [iif cval (rewrite_return historic then_instrs) (rewrite_return historic else_instrs) ctyp]
@ rewrite_return historic after
| before, (I_aux (I_return cval, _) as ret) :: after ->
- let cleanup_label = label "cleanup_" in
- let end_cleanup_label = label "end_cleanup_" in
before
+ @ [icomment "early return cleanup"]
@ generate_cleanup (historic @ before)
@ [ret]
(* There could be jumps into here *)
@@ -2080,7 +2039,7 @@ let fix_exception_block ctx instrs =
| instrs, [] -> instrs
| before, I_aux (I_block instrs, _) :: after ->
before
- @ [iblock (rewrite_exception (generate_cleanup (historic @ before)) instrs)]
+ @ [iblock (rewrite_exception (historic @ before) instrs)]
@ rewrite_exception (historic @ before) after
| before, I_aux (I_if (cval, then_instrs, else_instrs, ctyp), _) :: after ->
let historic = historic @ before in
@@ -2166,19 +2125,23 @@ let rec compile_def ctx = function
| DEF_reg_dec _ -> failwith "Unsupported register declaration" (* FIXME *)
| DEF_spec (VS_aux (VS_val_spec (_, id, _, _), _)) ->
- let _, Typ_aux (fn_typ, _) = Env.get_val_spec id ctx.tc_env in
+ c_debug (lazy "Compiling VS");
+ let quant, Typ_aux (fn_typ, _) = Env.get_val_spec id ctx.tc_env in
let arg_typs, ret_typ = match fn_typ with
| Typ_fn (Typ_aux (Typ_tup arg_typs, _), ret_typ, _) -> arg_typs, ret_typ
| Typ_fn (arg_typ, ret_typ, _) -> [arg_typ], ret_typ
| _ -> assert false
in
- let arg_ctyps, ret_ctyp = List.map (ctyp_of_typ ctx) arg_typs, ctyp_of_typ ctx ret_typ in
+ let ctx' = { ctx with local_env = add_typquant (id_loc id) quant ctx.local_env } in
+ let arg_ctyps, ret_ctyp = List.map (ctyp_of_typ ctx') arg_typs, ctyp_of_typ ctx' ret_typ in
[CDEF_spec (id, arg_ctyps, ret_ctyp)], ctx
| DEF_fundef (FD_aux (FD_function (_, _, _, [FCL_aux (FCL_Funcl (id, Pat_aux (Pat_exp (pat, exp), _)), _)]), _)) ->
+ c_debug (lazy ("Compiling function " ^ string_of_id id));
let aexp = map_functions (analyze_primop ctx) (c_literals ctx (no_shadow (pat_ids pat) (anf exp))) in
prerr_endline (Pretty_print_sail.to_string (pp_aexp aexp));
let setup, ctyp, call, cleanup = compile_aexp ctx aexp in
+ c_debug (lazy "Compiled aexp");
let fundef_label = label "fundef_fail_" in
let _, Typ_aux (fn_typ, _) = Env.get_val_spec id ctx.tc_env in
let arg_typ, ret_typ = match fn_typ with
@@ -2215,6 +2178,7 @@ let rec compile_def ctx = function
[CDEF_type tdef], ctx
| DEF_val (LB_aux (LB_val (pat, exp), _)) ->
+ c_debug (lazy ("Compiling letbind " ^ string_of_pat pat));
let aexp = map_functions (analyze_primop ctx) (c_literals ctx (no_shadow IdSet.empty (anf exp))) in
let setup, ctyp, call, cleanup = compile_aexp ctx aexp in
let apat = anf_pat ~global:true pat in
@@ -2291,178 +2255,7 @@ let add_local_labels instrs =
| _ -> assert false
(**************************************************************************)
-(* 5. Dependency Graphs *)
-(**************************************************************************)
-
-type graph_node =
- | G_id of id
- | G_label of string
- | G_instr of int * instr
- | G_start
-
-let string_of_node = function
- | G_id id -> string_of_id id
- | G_label label -> label
- | G_instr (n, instr) -> string_of_int n ^ ": " ^ Pretty_print_sail.to_string (pp_instr ~short:true instr)
- | G_start -> "START"
-
-module Node = struct
- type t = graph_node
- let compare gn1 gn2 =
- match gn1, gn2 with
- | G_id id1, G_id id2 -> Id.compare id1 id2
- | G_label str1, G_label str2 -> String.compare str1 str2
- | G_instr (n1, _), G_instr (n2, _) -> compare n1 n2
- | G_start , _ -> 1
- | _ , G_start -> -1
- | G_instr _, _ -> 1
- | _ , G_instr _ -> -1
- | G_id _ , _ -> 1
- | _ , G_id _ -> -1
-end
-
-module NM = Map.Make(Node)
-module NS = Set.Make(Node)
-
-type dep_graph = NS.t NM.t
-
-let rec fragment_deps = function
- | F_id id | F_ref id -> NS.singleton (G_id id)
- | F_lit _ -> NS.empty
- | F_field (frag, _) | F_unary (_, frag) -> fragment_deps frag
- | F_call (_, frags) -> List.fold_left NS.union NS.empty (List.map fragment_deps frags)
- | F_op (frag1, _, frag2) -> NS.union (fragment_deps frag1) (fragment_deps frag2)
- | F_current_exception -> NS.empty
- | F_have_exception -> NS.empty
-
-let cval_deps = function (frag, _) -> fragment_deps frag
-
-let rec clexp_deps = function
- | CL_id id -> NS.singleton (G_id id)
- | CL_field (id, _) -> NS.singleton (G_id id)
- | CL_addr id -> NS.singleton (G_id id)
- | CL_have_exception -> NS.empty
- | CL_current_exception -> NS.empty
-
-(** Return the direct, non program-order dependencies of a single
- instruction **)
-let instr_deps = function
- | I_decl (ctyp, id) -> NS.empty, NS.singleton (G_id id)
- | I_alloc (ctyp, id) | I_reset (ctyp, id) -> NS.empty, NS.singleton (G_id id)
- | I_init (ctyp, id, cval) | I_reinit (ctyp, id, cval) -> cval_deps cval, NS.singleton (G_id id)
- | I_if (cval, _, _, _) -> cval_deps cval, NS.empty
- | I_jump (cval, label) -> cval_deps cval, NS.singleton (G_label label)
- | I_funcall (clexp, _, _, cvals, _) -> List.fold_left NS.union NS.empty (List.map cval_deps cvals), clexp_deps clexp
- | I_convert (clexp, _, id, _) -> NS.singleton (G_id id), clexp_deps clexp
- | I_copy (clexp, cval) -> cval_deps cval, clexp_deps clexp
- | I_clear (_, id) -> NS.singleton (G_id id), NS.singleton (G_id id)
- | I_throw cval | I_return cval -> cval_deps cval, NS.empty
- | I_block _ | I_try_block _ -> NS.empty, NS.empty
- | I_comment _ | I_raw _ -> NS.empty, NS.empty
- | I_label label -> NS.singleton (G_label label), NS.empty
- | I_goto label -> NS.empty, NS.singleton (G_label label)
- | I_match_failure -> NS.empty, NS.empty
-
-let add_link from_node to_node graph =
- try
- NM.add from_node (NS.add to_node (NM.find from_node graph)) graph
- with
- | Not_found -> NM.add from_node (NS.singleton to_node) graph
-
-let leaves graph =
- List.fold_left (fun acc (from_node, to_nodes) -> NS.filter (fun to_node -> Node.compare to_node from_node != 0) (NS.union acc to_nodes))
- NS.empty
- (NM.bindings graph)
-
-(* Ensure that all leaves exist in the graph *)
-let fix_leaves graph =
- NS.fold (fun leaf graph -> if NM.mem leaf graph then graph else NM.add leaf NS.empty graph) (leaves graph) graph
-
-let instrs_graph instrs =
- let icounter = ref 0 in
- let graph = ref NM.empty in
-
- let rec add_instr last_instr (I_aux (instr, _) as iaux) =
- incr icounter;
- let node = G_instr (!icounter, iaux) in
- match instr with
- | I_block instrs | I_try_block instrs ->
- List.fold_left add_instr last_instr instrs
- | I_if (_, then_instrs, else_instrs, _) ->
- begin
- let inputs, _ = instr_deps instr in (* if has no outputs *)
- graph := add_link last_instr node !graph;
- NS.iter (fun input -> graph := add_link input node !graph) inputs;
- let n1 = List.fold_left add_instr node then_instrs in
- let n2 = List.fold_left add_instr node else_instrs in
- incr icounter;
- let join = G_instr (!icounter, icomment "join") in
- graph := add_link n1 join !graph;
- graph := add_link n2 join !graph;
- join
- end
- | I_goto label ->
- begin
- let _, outputs = instr_deps instr in
- graph := add_link last_instr node !graph;
- NS.iter (fun output -> graph := add_link node output !graph) outputs;
- incr icounter;
- G_instr (!icounter, icomment "after goto")
- end
- | _ ->
- begin
- let inputs, outputs = instr_deps instr in
- graph := add_link last_instr node !graph;
- NS.iter (fun input -> graph := add_link input node !graph) inputs;
- NS.iter (fun output -> graph := add_link node output !graph) outputs;
- node
- end
- in
- ignore (List.fold_left add_instr G_start instrs);
- fix_leaves !graph
-
-let make_dot id graph =
- Util.opt_colors := false;
- let to_string node = String.escaped (string_of_node node) in
- let node_color = function
- | G_start -> "lightpink"
- | G_id _ -> "yellow"
- | G_instr (_, I_aux (I_decl _, _)) -> "olivedrab1"
- | G_instr (_, I_aux (I_init _, _)) -> "springgreen"
- | G_instr (_, I_aux (I_alloc _, _)) -> "palegreen"
- | G_instr (_, I_aux (I_clear _, _)) -> "peachpuff"
- | G_instr (_, I_aux (I_goto _, _)) -> "orange1"
- | G_instr (_, I_aux (I_label _, _)) -> "white"
- | G_instr (_, I_aux (I_raw _, _)) -> "khaki"
- | G_instr _ -> "azure"
- | G_label _ -> "lightpink"
- in
- let edge_color from_node to_node =
- match from_node, to_node with
- | G_start , _ -> "goldenrod4"
- | G_label _, _ -> "darkgreen"
- | _ , G_label _ -> "goldenrod4"
- | G_instr _, G_instr _ -> "black"
- | G_id _ , G_instr _ -> "blue3"
- | G_instr _, G_id _ -> "red3"
- | _ , _ -> "coral3"
- in
- let out_chan = open_out (Util.zencode_string (string_of_id id) ^ ".gv") in
- output_string out_chan "digraph DEPS {\n";
- let make_node from_node =
- output_string out_chan (Printf.sprintf " \"%s\" [fillcolor=%s;style=filled];\n" (to_string from_node) (node_color from_node))
- in
- let make_line from_node to_node =
- output_string out_chan (Printf.sprintf " \"%s\" -> \"%s\" [color=%s];\n" (to_string from_node) (to_string to_node) (edge_color from_node to_node))
- in
- NM.bindings graph |> List.iter (fun (from_node, _) -> make_node from_node);
- NM.bindings graph |> List.iter (fun (from_node, to_nodes) -> NS.iter (make_line from_node) to_nodes);
- output_string out_chan "}\n";
- Util.opt_colors := true;
- close_out out_chan
-
-(**************************************************************************)
-(* 6. Optimizations *)
+(* 5. Optimizations *)
(**************************************************************************)
let clexp_rename from_id to_id =
@@ -2471,6 +2264,7 @@ let clexp_rename from_id to_id =
| CL_id id -> CL_id (rename id)
| CL_field (id, field) -> CL_field (rename id, field)
| CL_addr id -> CL_addr (rename id)
+ | CL_addr_field (id, field) -> CL_addr_field (rename id, field)
| CL_current_exception -> CL_current_exception
| CL_have_exception -> CL_have_exception
@@ -2513,6 +2307,10 @@ let hoist_id () =
id
let hoist_allocations ctx = function
+ | CDEF_fundef (function_id, _, _, _) as cdef when IdSet.mem function_id ctx.recursive_functions ->
+ c_debug (lazy (Printf.sprintf "skipping recursive function %s" (string_of_id function_id)));
+ [cdef]
+
| CDEF_fundef (function_id, heap_return, args, body) ->
let decls = ref [] in
let cleanups = ref [] in
@@ -2610,15 +2408,78 @@ let flatten_instrs ctx =
| cdef -> [cdef]
+(* When this optimization fires we know we have bytecode of the form
+
+ recreate x : S; x = y; ...
+
+ when this continues with x.A = a, x.B = b etc until y = x. Then
+ provided there are no further references to x we can eliminate
+ the variable x.
+
+ Must be called after hoist_allocations, otherwise does nothing. *)
+let fix_struct_updates ctx =
+ (* FIXME need to check no remaining references *)
+ let rec fix_updates struct_id id = function
+ | I_aux (I_copy (CL_field (struct_id', field), cval), aux) :: instrs
+ when Id.compare struct_id struct_id' = 0 ->
+ Util.option_map (fun instrs -> I_aux (I_copy (CL_field (id, field), cval), aux) :: instrs) (fix_updates struct_id id instrs)
+ | I_aux (I_copy (CL_id id', (F_id struct_id', ctyp)), aux) :: instrs
+ when Id.compare struct_id struct_id' = 0 && Id.compare id id' = 0->
+ Some instrs
+ | _ -> None
+ in
+ let rec fix_updates_ret struct_id id = function
+ | I_aux (I_copy (CL_field (struct_id', field), cval), aux) :: instrs
+ when Id.compare struct_id struct_id' = 0 ->
+ Util.option_map (fun instrs -> I_aux (I_copy (CL_addr_field (id, field), cval), aux) :: instrs) (fix_updates_ret struct_id id instrs)
+ | I_aux (I_copy (CL_addr id', (F_id struct_id', ctyp)), aux) :: instrs
+ when Id.compare struct_id struct_id' = 0 && Id.compare id id' = 0->
+ Some instrs
+ | _ -> None
+ in
+ let rec opt hr = function
+ | (I_aux (I_reset (ctyp, struct_id), _) as instr1)
+ :: (I_aux (I_copy (CL_id struct_id', (F_id id, ctyp')), _) as instr2)
+ :: instrs
+ when is_ct_struct ctyp && ctyp_equal ctyp ctyp' && Id.compare struct_id struct_id' = 0 ->
+ prerr_endline ("Potential struct update " ^ string_of_id struct_id);
+ begin match fix_updates struct_id id instrs with
+ | None -> instr1 :: instr2 :: opt hr instrs
+ | Some updated -> opt hr updated
+ end
+
+ | (I_aux (I_reset (ctyp, struct_id), _) as instr) :: instrs
+ when is_ct_struct ctyp && Util.is_some hr ->
+ let id = match hr with Some id -> id | None -> assert false in
+ prerr_endline ("Potential struct return " ^ string_of_id struct_id ^ " to " ^ string_of_id id);
+ begin match fix_updates_ret struct_id id instrs with
+ | None -> instr :: opt hr instrs
+ | Some updated -> opt hr updated
+ end
+
+ | I_aux (I_block block, aux) :: instrs -> I_aux (I_block (opt hr block), aux) :: opt hr instrs
+ | I_aux (I_try_block block, aux) :: instrs -> I_aux (I_try_block (opt hr block), aux) :: opt hr instrs
+ | I_aux (I_if (cval, then_instrs, else_instrs, ctyp), aux) :: instrs ->
+ I_aux (I_if (cval, opt hr then_instrs, opt hr else_instrs, ctyp), aux) :: opt hr instrs
+
+ | instr :: instrs -> instr :: opt hr instrs
+ | [] -> []
+ in
+ function
+ | CDEF_fundef (function_id, heap_return, args, body) ->
+ [CDEF_fundef (function_id, heap_return, args, opt heap_return body)]
+ | cdef -> [cdef]
+
let concatMap f xs = List.concat (List.map f xs)
let optimize ctx cdefs =
let nothing cdefs = cdefs in
cdefs
- |> if !optimize_hoist_allocations then concatMap (hoist_allocations ctx) else nothing
+ |> (if !optimize_hoist_allocations then concatMap (hoist_allocations ctx) else nothing)
+ |> (if !optimize_struct_updates then concatMap (fix_struct_updates ctx) else nothing)
(**************************************************************************)
-(* 7. Code generation *)
+(* 6. Code generation *)
(**************************************************************************)
let sgen_id id = Util.zencode_string (string_of_id id)
@@ -2678,6 +2539,7 @@ let sgen_clexp = function
| CL_id id -> "&" ^ sgen_id id
| CL_field (id, field) -> "&(" ^ sgen_id id ^ "." ^ Util.zencode_string field ^ ")"
| CL_addr id -> sgen_id id
+ | CL_addr_field (id, field) -> "&(" ^ sgen_id id ^ "->" ^ Util.zencode_string field ^ ")"
| CL_have_exception -> "have_exception"
| CL_current_exception -> "current_exception"
@@ -2685,6 +2547,7 @@ let sgen_clexp_pure = function
| CL_id id -> sgen_id id
| CL_field (id, field) -> sgen_id id ^ "." ^ Util.zencode_string field
| CL_addr id -> sgen_id id
+ | CL_addr_field (id, field) -> sgen_id id ^ "->" ^ Util.zencode_string field
| CL_have_exception -> "have_exception"
| CL_current_exception -> "current_exception"
@@ -2760,7 +2623,12 @@ let rec codegen_instr fid ctx (I_aux (instr, _)) =
| "undefined_vector", _ -> Printf.sprintf "undefined_vector_%s" (sgen_ctyp_name ctyp)
| fname, _ -> fname
in
- if is_stack_ctyp ctyp then
+ if fname = "reg_deref" then
+ if is_stack_ctyp ctyp then
+ string (Printf.sprintf " %s = *(%s);" (sgen_clexp_pure x) c_args)
+ else
+ string (Printf.sprintf " set_%s(&%s, *(%s));" (sgen_ctyp_name ctyp) (sgen_clexp_pure x) c_args)
+ else if is_stack_ctyp ctyp then
string (Printf.sprintf " %s = %s(%s);" (sgen_clexp_pure x) fname c_args)
else
string (Printf.sprintf " %s(%s, %s);" fname (sgen_clexp x) c_args)
@@ -2786,7 +2654,10 @@ let rec codegen_instr fid ctx (I_aux (instr, _)) =
special conversion code-generator for full generality *)
| I_convert (x, CT_tup ctyps1, y, CT_tup ctyps2) when List.length ctyps1 = List.length ctyps2 ->
let convert i (ctyp1, ctyp2) =
- if ctyp_equal ctyp1 ctyp2 then string " /* no change */"
+ if ctyp_equal ctyp1 ctyp2 then
+ string (Printf.sprintf " %s.ztup%i = %s.ztup%i;" (sgen_clexp_pure x) i (sgen_id y) i)
+ else if ctyp_equal ctyp1 ctyp2 then
+ c_error "heap tuple type conversion"
else if is_stack_ctyp ctyp1 then
string (Printf.sprintf " %s.ztup%i = convert_%s_of_%s(%s.ztup%i);"
(sgen_clexp_pure x)
@@ -3172,7 +3043,7 @@ let codegen_vector ctx (direction, ctyp) =
^^ string "}"
in
let internal_vector_update =
- string (Printf.sprintf "void internal_vector_update_%s(%s *rop, %s op, const int64_t n, const %s elem) {\n" (sgen_id id) (sgen_id id) (sgen_id id) (sgen_ctyp ctyp))
+ string (Printf.sprintf "void internal_vector_update_%s(%s *rop, %s op, const int64_t n, %s elem) {\n" (sgen_id id) (sgen_id id) (sgen_id id) (sgen_ctyp ctyp))
^^ string (if is_stack_ctyp ctyp then
" rop->data[n] = elem;\n"
else
@@ -3247,13 +3118,14 @@ let codegen_def' ctx = function
| CDEF_fundef (id, ret_arg, args, instrs) as def ->
if !opt_ddump_flow_graphs then make_dot id (instrs_graph instrs) else ();
let instrs = add_local_labels instrs in
- let _, Typ_aux (fn_typ, _) = Env.get_val_spec id ctx.tc_env in
+ let quant, Typ_aux (fn_typ, _) = Env.get_val_spec id ctx.tc_env in
let arg_typs, ret_typ = match fn_typ with
| Typ_fn (Typ_aux (Typ_tup arg_typs, _), ret_typ, _) -> arg_typs, ret_typ
| Typ_fn (arg_typ, ret_typ, _) -> [arg_typ], ret_typ
| _ -> assert false
in
- let arg_ctyps, ret_ctyp = List.map (ctyp_of_typ ctx) arg_typs, ctyp_of_typ ctx ret_typ in
+ let ctx' = { ctx with local_env = add_typquant (id_loc id) quant ctx.local_env } in
+ let arg_ctyps, ret_ctyp = List.map (ctyp_of_typ ctx') arg_typs, ctyp_of_typ ctx' ret_typ in
if (List.length arg_ctyps <> List.length args) then
c_error ~loc:(id_loc id) ("function arguments "
^ Util.string_of_list ", " string_of_id args
@@ -3272,22 +3144,12 @@ let codegen_def' ctx = function
^^ parens (string (sgen_ctyp ret_ctyp ^ " *" ^ sgen_id gs ^ ", ") ^^ string args)
^^ hardline
in
- let instrs =
- if !optimize_struct_undefined && is_ct_struct ret_ctyp && Str.string_match (Str.regexp_string "undefined_") (string_of_id id) 0 then
- []
- else
- instrs
- in
- let instrs =
- if !optimize_enum_undefined && is_ct_enum ret_ctyp && Str.string_match (Str.regexp_string "undefined_") (string_of_id id) 0 then
- []
- else
- instrs
- in
function_header
+ (* ^^ string (Printf.sprintf "{ fprintf(stderr, \"%s \"); " (string_of_id id)) *)
^^ string "{"
^^ jump 0 2 (separate_map hardline (codegen_instr id ctx) instrs) ^^ hardline
^^ string "}"
+ (* ^^ string "}" *)
| CDEF_type ctype_def ->
codegen_type_def ctx ctype_def
@@ -3341,7 +3203,7 @@ let codegen_def ctx def =
let lists = List.map (fun ctyp -> codegen_list ctx (unlist ctyp)) lists in
let vectors = List.filter is_ct_vector (cdef_ctyps ctx def) in
let vectors = List.map (fun ctyp -> codegen_vector ctx (unvector ctyp)) vectors in
- prerr_endline (Pretty_print_sail.to_string (pp_cdef def));
+ (* prerr_endline (Pretty_print_sail.to_string (pp_cdef def)); *)
concat tups
^^ concat lists
^^ concat vectors
@@ -3368,16 +3230,28 @@ let sgen_finish = function
let bytecode_ast ctx rewrites (Defs defs) =
let assert_vs = Initial_check.extern_of_string dec_ord (mk_id "sail_assert") "(bool, string) -> unit effect {escape}" in
let exit_vs = Initial_check.extern_of_string dec_ord (mk_id "sail_exit") "unit -> unit effect {escape}" in
- let ctx = { ctx with tc_env = snd (check ctx.tc_env (Defs [assert_vs; exit_vs])) } in
+ let ctx = { ctx with tc_env = snd (Type_error.check ctx.tc_env (Defs [assert_vs; exit_vs])) } in
let chunks, ctx = List.fold_left (fun (chunks, ctx) def -> let defs, ctx = compile_def ctx def in defs :: chunks, ctx) ([], ctx) defs in
let cdefs = List.concat (List.rev chunks) in
rewrites cdefs
+let rec get_recursive_functions (Defs defs) =
+ match defs with
+ | DEF_internal_mutrec fundefs :: defs ->
+ IdSet.union (List.map id_of_fundef fundefs |> IdSet.of_list) (get_recursive_functions (Defs defs))
+ | _ :: defs -> get_recursive_functions (Defs defs)
+ | [] -> IdSet.empty
+
let compile_ast ctx (Defs defs) =
try
+ c_debug (lazy (Util.log_line __MODULE__ __LINE__ "Identifying recursive functions"));
+ let recursive_functions = Spec_analysis.top_sort_defs (Defs defs) |> get_recursive_functions in
+ let ctx = { ctx with recursive_functions = recursive_functions } in
+ c_debug (lazy (Util.string_of_list ", " string_of_id (IdSet.elements recursive_functions)));
+
let assert_vs = Initial_check.extern_of_string dec_ord (mk_id "sail_assert") "(bool, string) -> unit effect {escape}" in
let exit_vs = Initial_check.extern_of_string dec_ord (mk_id "sail_exit") "unit -> unit effect {escape}" in
- let ctx = { ctx with tc_env = snd (check ctx.tc_env (Defs [assert_vs; exit_vs])) } in
+ let ctx = { ctx with tc_env = snd (Type_error.check ctx.tc_env (Defs [assert_vs; exit_vs])) } in
let chunks, ctx = List.fold_left (fun (chunks, ctx) def -> let defs, ctx = compile_def ctx def in defs :: chunks, ctx) ([], ctx) defs in
let cdefs = List.concat (List.rev chunks) in
let cdefs = optimize ctx cdefs in
@@ -3444,4 +3318,4 @@ let compile_ast ctx (Defs defs) =
Pretty_print_sail.to_string (preamble ^^ hlhl ^^ separate hlhl docs ^^ hlhl ^^ postamble)
|> print_endline
with
- Type_error (l, err) -> prerr_endline ("Unexpected type error when compiling to C:\n" ^ string_of_type_error err)
+ Type_error (l, err) -> c_error ("Unexpected type error when compiling to C:\n" ^ Type_error.string_of_type_error err)