summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--language/bytecode.ott133
-rw-r--r--src/Makefile13
-rw-r--r--src/ast.sed1
-rw-r--r--src/c_backend.ml667
4 files changed, 450 insertions, 364 deletions
diff --git a/language/bytecode.ott b/language/bytecode.ott
new file mode 100644
index 00000000..7342a1e9
--- /dev/null
+++ b/language/bytecode.ott
@@ -0,0 +1,133 @@
+indexvar n , m , i , j ::=
+ {{ phantom }}
+ {{ com Index variables for meta-lists }}
+
+metavar nat ::=
+ {{ phantom }}
+ {{ ocaml int }}
+ {{ lem nat }}
+
+metavar id ::=
+ {{ phantom }}
+ {{ ocaml id }}
+ {{ lem id }}
+
+metavar mid ::=
+ {{ phantom }}
+ {{ ocaml id option }}
+ {{ lem maybe id }}
+
+metavar string ::=
+ {{ phantom }}
+ {{ ocaml string }}
+ {{ lem string }}
+
+metavar op ::=
+ {{ phantom }}
+ {{ ocaml string }}
+ {{ lem string }}
+
+metavar bool ::=
+ {{ phantom }}
+ {{ ocaml bool }}
+ {{ lem bool }}
+
+embed
+{{ lem
+
+open import Ast
+
+}}
+
+grammar
+
+
+% Fragments are small pure snippets of (abstract) C code, mostly
+% expressions, used by the aval and cval types.
+fragment :: 'F_' ::=
+ | id :: :: id
+ | string :: :: lit
+ | have_exception :: :: have_exception
+ | current_exception :: :: current_exception
+ | fragment op fragment' :: :: op
+ | op fragment :: :: unary
+ | fragment . string :: :: field
+
+ctyp :: 'CT_' ::=
+ {{ com C type }}
+ | mpz_t :: :: mpz
+% Arbitrary precision GMP integer, mpz_t in C. }}
+ | bv_t ( bool ) :: :: bv
+% Variable length bitvector - flag represents direction, inc or dec }}
+ | uint64_t ( nat , bool ) :: :: uint64
+% Fixed length bitvector that fits within a 64-bit word. - int
+% represents length, and flag is the same as CT_bv. }}
+ | int64_t :: :: int64
+% Used for (signed) integers that fit within 64-bits. }}
+ | unit_t :: :: unit
+% unit is a value in sail, so we represent it as a one element type
+% here too for clarity but we actually compile it to an int which is
+% always 0.
+ | bool_t :: :: bool
+ | real_t :: :: real
+ | bit_t :: :: bit
+% The real type in sail. Abstract here, but implemented using either
+% GMP rationals or high-precision floating point.
+ | ( ctyp0 , ... , ctypn ) :: :: tup
+ | string_t :: :: string
+ | enum id ( id0 , ... , idn ) :: :: enum
+ | struct id ( id0 * ctyp0 , ... , idn * ctypn ) :: :: struct
+ | variant id ( id0 * ctyp0 , ... , idn * ctypn ) :: :: variant
+% Abstractly represent how all the Sail user defined types get mapped
+% into C. We don't fully worry about precise implementation details at
+% this point, as C doesn't have variants or tuples natively, but these
+% need to be encoded.
+
+cval :: 'CV_' ::=
+ {{ ocaml fragment * ctyp }}
+ {{ lem fragment * ctyp }}
+
+clexp :: 'CL_' ::=
+ | id :: :: id
+ | id . string :: :: field
+ | * id :: :: addr
+ | current_exception :: :: current_exception
+ | have_exception :: :: have_exception
+
+ctype_def :: 'CTD_' ::=
+ {{ com C type definition }}
+ | enum id = id0 '|' ... '|' idn :: :: enum
+ | struct id = { id0 : ctyp0 , ... , idn : ctypn } :: :: struct
+ | variant id = { id0 : ctyp0 , ... , idn : ctypn } :: :: variant
+
+iannot :: 'IA_' ::=
+ {{ lem nat * nat * nat }}
+ {{ ocaml int * int * int }}
+
+instr :: 'I_' ::=
+ {{ aux _ iannot }}
+ | ctyp id :: :: decl
+ | alloc ctyp id :: :: alloc
+ | ctyp id = cval :: :: init
+ | if ( cval ) { instr0 ; ... ; instrn }
+ else { instr0 ; ... ; instrm } : ctyp :: :: if
+ | clexp = id ( cval0 , ... , cvaln ) : ctyp :: :: funcall
+ | clexp = cval :: :: copy
+ | clexp = ( ctyp ) id : ctyp' :: :: convert
+ | clear ctyp id :: :: clear
+ | return cval :: :: return
+ | { instr0 ; ... ; instrn } :: :: block
+ | try { instr0 ; ... ; instrn } :: :: try_block
+ | throw cval :: :: throw
+ | '//' string :: :: comment
+ | C string :: :: raw % only used for GCC attributes
+ | string : :: :: label
+ | goto string :: :: goto
+ | match_failure :: :: match_failure
+
+cdef :: 'CDEF_' ::=
+ | register id : ctyp :: :: reg_dec
+ | ctype_def :: :: type
+ | function id mid ( id0 , ... , idn ) {
+ instr0 ; ... ; instrm
+ } :: :: fundef \ No newline at end of file
diff --git a/src/Makefile b/src/Makefile
index 2a9fcc32..924cfb1c 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -60,17 +60,24 @@ full: sail lib power doc test
ast.lem: ../language/l2.ott
ott -sort false -generate_aux_rules true -o ast.lem -picky_multiple_parses true ../language/l2.ott
+bytecode.lem: ../language/bytecode.ott ast.lem
+ ott -sort false -generate_aux_rules true -o bytecode.lem -picky_multiple_parses true ../language/bytecode.ott
+
ast.ml: ast.lem
lem -ocaml ast.lem
sed -i -f ast.sed ast.ml
+bytecode.ml: bytecode.lem
+ lem -ocaml bytecode.lem
+ sed -i -f ast.sed bytecode.ml
+
lem_interp/interp_ast.lem: ../language/l2.ott
ott -sort false -generate_aux_rules true -o lem_interp/interp_ast.lem -picky_multiple_parses true ../language/l2.ott
-sail: ast.ml
+sail: ast.ml bytecode.ml
ocamlbuild -use-ocamlfind sail.native
-isail: ast.ml
+isail: ast.ml bytecode.ml
ocamlbuild -use-ocamlfind isail.native
sail.native: sail
@@ -265,6 +272,8 @@ clean:
-rm -rf sail.docdir
-rm -f ast.ml
-rm -f ast.lem
+ -rm -f bytecode.ml
+ -rm -f bytecode.lem
doc:
ocamlbuild -use-ocamlfind sail.docdir/index.html
diff --git a/src/ast.sed b/src/ast.sed
index 39c58a50..3f53dc78 100644
--- a/src/ast.sed
+++ b/src/ast.sed
@@ -1,2 +1,3 @@
s/type l = | Unknown/type l = Parse_ast.l/
s/type value = | Val/open Value/
+s/type iannot = int \* int \* int/type iannot = int \* Parse_ast.l/ \ No newline at end of file
diff --git a/src/c_backend.ml b/src/c_backend.ml
index d39680b9..753922f2 100644
--- a/src/c_backend.ml
+++ b/src/c_backend.ml
@@ -50,6 +50,7 @@
open Ast
open Ast_util
+open Bytecode
open Type_check
open PPrint
module Big_int = Nat_big_num
@@ -74,15 +75,6 @@ let lvar_typ = function
(* | Union (_, typ) -> typ *)
| _ -> assert false
-(** Fragments are small pure snippets of C code, mostly expressions,
- used by the AV_C_fragment and CV_C_fragment constructors. *)
-type fragment =
- | F_id of id
- | F_lit of string
- | F_field of fragment * string
- | F_op of fragment * string * fragment
- | F_unary of string * fragment
-
let rec string_of_fragment = function
| F_id id -> Util.zencode_string (string_of_id id)
| F_lit str -> str
@@ -92,6 +84,8 @@ let rec string_of_fragment = function
Printf.sprintf "%s %s %s" (string_of_fragment' f1) op (string_of_fragment f2)
| F_unary (op, f) ->
op ^ string_of_fragment' f
+ | F_have_exception -> "have_exception"
+ | F_current_exception -> "(*current_exception)"
and string_of_fragment' f =
match f with
| F_op _ -> "(" ^ string_of_fragment f ^ ")"
@@ -537,35 +531,6 @@ let rec anf (E_aux (e_aux, exp_annot) as exp) =
let max_int64 = Big_int.of_int64 Int64.max_int
let min_int64 = Big_int.of_int64 Int64.min_int
-type ctyp =
- (* Arbitrary precision GMP integer, mpz_t in C. *)
- | CT_mpz
- (* The real type in sail. Abstract here, but implemented using
- either GMP rationals or high-precision floating point. *)
- | CT_real
- (* Variable length bitvector - flag represents direction, inc or dec *)
- | CT_bv of bool
- (* Fixed length bitvector that fits within a 64-bit word. - int
- represents length, and flag is the same as CT_bv. *)
- | CT_uint64 of int * bool
- | CT_int
- (* Used for (signed) integers that fit within 64-bits. *)
- | CT_int64
- (* unit is a value in sail, so we represent it as a one element type
- here too for clarity but we actually compile it to an int which
- is always 0. *)
- | CT_unit
- | CT_bool
- (* Abstractly represent how all the Sail user defined types get
- mapped into C. We don't fully worry about precise implementation
- details at this point, as C doesn't have variants or tuples
- natively, but these need to be encoded. *)
- | CT_tup of ctyp list
- | CT_struct of id * ctyp Bindings.t
- | CT_enum of id * IdSet.t
- | CT_variant of id * ctyp Bindings.t
- | CT_string
-
type ctx =
{ records : (ctyp Bindings.t) Bindings.t;
enums : IdSet.t Bindings.t;
@@ -585,7 +550,7 @@ let rec ctyp_equal ctyp1 ctyp2 =
| CT_mpz, CT_mpz -> true
| CT_bv d1, CT_bv d2 -> d1 = d2
| CT_uint64 (m1, d1), CT_uint64 (m2, d2) -> m1 = m2 && d1 = d2
- | CT_int, CT_int -> true
+ | CT_bit, CT_bit -> true
| CT_int64, CT_int64 -> true
| CT_unit, CT_unit -> true
| CT_bool, CT_bool -> true
@@ -606,7 +571,7 @@ let rec string_of_ctyp = function
| 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_int -> "int"
+ | CT_bit -> "bit"
| CT_unit -> "unit"
| CT_bool -> "bool"
| CT_real -> "real"
@@ -618,7 +583,7 @@ let rec string_of_ctyp = function
let rec ctyp_of_typ ctx typ =
let Typ_aux (typ_aux, l) as typ = Env.expand_synonyms ctx.tc_env typ in
match typ_aux with
- | Typ_id id when string_of_id id = "bit" -> CT_int
+ | Typ_id id when string_of_id id = "bit" -> CT_bit
| Typ_id id when string_of_id id = "bool" -> CT_bool
| Typ_id id when string_of_id id = "int" -> CT_mpz
| Typ_app (id, _) when string_of_id id = "range" || string_of_id id = "atom" ->
@@ -646,9 +611,9 @@ let rec ctyp_of_typ ctx typ =
| Typ_id id when string_of_id id = "string" -> CT_string
| Typ_id id when string_of_id id = "real" -> CT_real
- | Typ_id id | Typ_app (id, _) when Bindings.mem id ctx.records -> CT_struct (id, Bindings.find id ctx.records)
- | Typ_id id | Typ_app (id, _) when Bindings.mem id ctx.variants -> CT_variant (id, Bindings.find id ctx.variants)
- | Typ_id id when Bindings.mem id ctx.enums -> CT_enum (id, Bindings.find id ctx.enums)
+ | Typ_id id | Typ_app (id, _) when Bindings.mem id ctx.records -> CT_struct (id, Bindings.find id ctx.records |> Bindings.bindings)
+ | Typ_id id | Typ_app (id, _) when Bindings.mem id ctx.variants -> CT_variant (id, Bindings.find id ctx.variants |> Bindings.bindings)
+ | Typ_id id when Bindings.mem id ctx.enums -> CT_enum (id, Bindings.find id ctx.enums |> IdSet.elements)
| Typ_tup typs -> CT_tup (List.map (ctyp_of_typ ctx) typs)
@@ -657,14 +622,16 @@ let rec ctyp_of_typ ctx typ =
| _ -> c_error ~loc:l ("No C-type for type " ^ string_of_typ typ)
let rec is_stack_ctyp ctyp = match ctyp with
- | CT_uint64 _ | CT_int64 | CT_int | CT_unit | CT_bool | CT_enum _ -> true
+ | CT_uint64 _ | CT_int64 | CT_bit | CT_unit | CT_bool | CT_enum _ -> true
| CT_bv _ | CT_mpz | CT_real | CT_string -> false
- | CT_struct (_, fields) -> Bindings.for_all (fun _ ctyp -> is_stack_ctyp ctyp) fields
- | CT_variant (_, ctors) -> Bindings.for_all (fun _ ctyp -> is_stack_ctyp ctyp) ctors
+ | CT_struct (_, fields) -> List.for_all (fun (_, ctyp) -> is_stack_ctyp ctyp) fields
+ | CT_variant (_, ctors) -> List.for_all (fun (_, ctyp) -> is_stack_ctyp ctyp) ctors
| CT_tup ctyps -> List.for_all is_stack_ctyp ctyps
let is_stack_typ ctx typ = is_stack_ctyp (ctyp_of_typ ctx typ)
+let ctor_bindings = List.fold_left (fun map (id, ctyp) -> Bindings.add id ctyp map) Bindings.empty
+
(**************************************************************************)
(* 3. Optimization of primitives and literals *)
(**************************************************************************)
@@ -807,9 +774,10 @@ let analyze_primop ctx id args typ =
(* 4. Conversion to low-level AST *)
(**************************************************************************)
-(** We now define a low-level AST that is only slightly abstracted
- away from C. To be succint in comments we usually refer to this as
- Sail IR or IR rather than low-level AST repeatedly.
+(** We now use a low-level AST (see language/bytecode.ott) that is
+ only slightly abstracted away from C. To be succint in comments we
+ usually refer to this as Sail IR or IR rather than low-level AST
+ repeatedly.
The general idea is ANF expressions are converted into lists of
instructions (type instr) where allocations and deallocations are
@@ -828,65 +796,69 @@ let analyze_primop ctx id args typ =
expression), cleanup instructions (to deallocate that memory) and
possibly typing information about what has been translated. **)
-type ctype_def =
- | CTD_enum of id * IdSet.t
- | CTD_record of id * ctyp Bindings.t
- | CTD_variant of id * ctyp Bindings.t
+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, 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 ctype_def_ctyps = function
| CTD_enum _ -> []
- | CTD_record (_, fields) -> List.map snd (Bindings.bindings fields)
- | CTD_variant (_, ctors) -> List.map snd (Bindings.bindings ctors)
-
-type cval =
- | CV_id of id * ctyp
- | CV_C_fragment of fragment * ctyp
-
-let cval_ctyp = function
- | CV_id (_, ctyp) -> ctyp
- | CV_C_fragment (_, ctyp) -> ctyp
-
-type clexp =
- | CL_id of id
- | CL_field of id * id
- | CL_addr of clexp
- | CL_raw of string
-
-type instr =
- | I_decl of ctyp * id
- | I_alloc of ctyp * id
- | I_init of ctyp * id * cval
- | I_if of cval * instr list * instr list * ctyp
- | I_funcall of clexp * id * cval list * ctyp
- | I_convert of clexp * ctyp * id * ctyp
- | I_assign of id * cval
- | I_copy of clexp * cval
- | I_clear of ctyp * id
- | I_throw of cval
- | I_return of cval
- | I_block of instr list
- | I_try_block of instr list
- | I_comment of string
- | I_label of string
- | I_goto of string
- | I_raw of string
-
-let rec map_instrs f instr =
+ | CTD_struct (_, fields) -> List.map snd fields
+ | CTD_variant (_, ctors) -> List.map snd ctors
+
+let cval_ctyp = function (_, ctyp) -> ctyp
+
+let rec map_instrs f (I_aux (instr, aux)) =
+ let instr = match instr with
+ | I_decl _ | I_alloc _ | I_init _ -> instr
+ | I_if (cval, instrs1, instrs2, ctyp) ->
+ I_if (cval, f (List.map (map_instrs f) instrs1), f (List.map (map_instrs f) instrs2), ctyp)
+ | I_funcall _ | I_convert _ | I_copy _ | I_clear _ | I_throw _ | I_return _ -> instr
+ | I_block instrs -> I_block (f (List.map (map_instrs f) instrs))
+ | I_try_block instrs -> I_try_block (f (List.map (map_instrs f) instrs))
+ | I_comment _ | I_label _ | I_goto _ | I_raw _ | I_match_failure -> instr
+ in
+ I_aux (instr, aux)
+
+let rec instr_ctyps (I_aux (instr, aux)) =
match instr with
- | I_decl _ | I_alloc _ | I_init _ -> instr
- | I_if (cval, instrs1, instrs2, ctyp) ->
- I_if (cval, f (List.map (map_instrs f) instrs1), f (List.map (map_instrs f) instrs2), ctyp)
- | I_funcall _ | I_convert _ | I_assign _ | I_copy _ | I_clear _ | I_throw _ | I_return _ -> instr
- | I_block instrs -> I_block (f (List.map (map_instrs f) instrs))
- | I_try_block instrs -> I_try_block (f (List.map (map_instrs f) instrs))
- | I_comment _ | I_label _ | I_goto _ | I_raw _ -> instr
-
-type cdef =
- | CDEF_reg_dec of ctyp * id
- | CDEF_fundef of id * id option * id list * instr list
- | CDEF_type of ctype_def
-
-let rec instr_ctyps = function
| I_decl (ctyp, _) | I_alloc (ctyp, _) | I_clear (ctyp, _) -> [ctyp]
| I_init (ctyp, _, cval) -> [ctyp; cval_ctyp cval]
| I_if (cval, instrs1, instrs2, ctyp) ->
@@ -894,13 +866,13 @@ let rec instr_ctyps = function
| I_funcall (_, _, cvals, ctyp) ->
ctyp :: List.map cval_ctyp cvals
| I_convert (_, ctyp1, _, ctyp2) -> [ctyp1; ctyp2]
- | I_assign (_, cval) | I_copy (_, cval) -> [cval_ctyp cval]
+ | I_copy (_, cval) -> [cval_ctyp cval]
| I_block instrs | I_try_block instrs -> List.concat (List.map instr_ctyps instrs)
| I_throw cval | I_return cval -> [cval_ctyp cval]
- | I_comment _ | I_label _ | I_goto _ | I_raw _ -> []
+ | I_comment _ | I_label _ | I_goto _ | I_raw _ | I_match_failure -> []
let cdef_ctyps = function
- | CDEF_reg_dec (ctyp, _) -> [ctyp]
+ | CDEF_reg_dec (_, ctyp) -> [ctyp]
| CDEF_fundef (_, _, _, instrs) -> List.concat (List.map instr_ctyps instrs)
| CDEF_type tdef -> ctype_def_ctyps tdef
@@ -912,17 +884,17 @@ let pp_ctyp ctyp =
let pp_keyword str =
string ((str |> Util.red |> Util.clear) ^ "$")
-let pp_cval = function
- | CV_id (id, ctyp) -> parens (pp_ctyp ctyp) ^^ (pp_id id)
- | CV_C_fragment (frag, ctyp) -> parens (pp_ctyp ctyp) ^^ (string (string_of_fragment frag |> Util.cyan |> Util.clear))
+let pp_cval (frag, ctyp) = parens (pp_ctyp ctyp) ^^ (string (string_of_fragment frag |> Util.cyan |> Util.clear))
let rec pp_clexp = function
| CL_id id -> pp_id id
- | CL_field (id, field) -> pp_id id ^^ string "." ^^ pp_id field
- | CL_addr clexp -> string "*" ^^ pp_clexp clexp
- | CL_raw str -> string str
+ | 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) = function
+let rec pp_instr ?short:(short=false) (I_aux (instr, aux)) =
+ match instr with
| I_decl (ctyp, id) ->
parens (pp_ctyp ctyp) ^^ space ^^ pp_id id
| I_if (cval, then_instrs, else_instrs, ctyp) ->
@@ -950,8 +922,6 @@ let rec pp_instr ?short:(short=false) = function
separate space [ pp_clexp x; string ":=";
pp_keyword "CONVERT" ^^ pp_ctyp ctyp2 ^^ parens (pp_id y);
string "->"; pp_ctyp ctyp1 ]
- | I_assign (id, cval) ->
- separate space [pp_id id; string ":="; pp_cval cval]
| I_copy (clexp, cval) ->
separate space [string "let"; pp_clexp clexp; string "="; pp_cval cval]
| I_clear (ctyp, id) ->
@@ -966,6 +936,8 @@ let rec pp_instr ?short:(short=false) = function
string (str ^ ":")
| I_goto str ->
pp_keyword "GOTO" ^^ string str
+ | I_match_failure ->
+ pp_keyword "MATCH_FAILURE"
| I_raw str ->
pp_keyword "C" ^^ string str
@@ -983,33 +955,27 @@ let is_ct_tup = function
let rec compile_aval ctx = function
| AV_C_fragment (frag, typ) ->
- [], CV_C_fragment (frag, ctyp_of_typ ctx typ), []
+ [], (frag, ctyp_of_typ ctx typ), []
| AV_id (id, typ) ->
- begin
- match ctyp_of_typ ctx (lvar_typ typ) with
- | CT_enum (_, elems) when IdSet.mem id elems ->
- [], CV_C_fragment (F_id id, ctyp_of_typ ctx (lvar_typ typ)), []
- | _ ->
- [], CV_id (id, ctyp_of_typ ctx (lvar_typ typ)), []
- end
+ [], (F_id id, ctyp_of_typ ctx (lvar_typ typ)), []
| AV_lit (L_aux (L_string str, _), typ) ->
- [], CV_C_fragment (F_lit ("\"" ^ str ^ "\""), ctyp_of_typ ctx typ), []
+ [], (F_lit ("\"" ^ str ^ "\""), ctyp_of_typ ctx typ), []
| AV_lit (L_aux (L_num n, _), typ) when Big_int.less_equal min_int64 n && Big_int.less_equal n max_int64 ->
let gs = gensym () in
- [I_decl (CT_mpz, gs);
- I_init (CT_mpz, gs, CV_C_fragment (F_lit (Big_int.to_string n ^ "L"), CT_int64))],
- CV_id (gs, CT_mpz),
- [I_clear (CT_mpz, gs)]
+ [idecl CT_mpz gs;
+ iinit CT_mpz gs (F_lit (Big_int.to_string n ^ "L"), CT_int64)],
+ (F_id gs, CT_mpz),
+ [iclear CT_mpz gs]
| AV_lit (L_aux (L_num n, _), typ) ->
let gs = gensym () in
- [ I_decl (CT_mpz, gs);
- I_init (CT_mpz, gs, CV_C_fragment (F_lit ("\"" ^ Big_int.to_string n ^ "\""), CT_string)) ],
- CV_id (gs, CT_mpz),
- [I_clear (CT_mpz, gs)]
+ [idecl CT_mpz gs;
+ iinit CT_mpz gs (F_lit ("\"" ^ Big_int.to_string n ^ "\""), CT_string)],
+ (F_id gs, CT_mpz),
+ [iclear CT_mpz gs]
| AV_tuple avals ->
let elements = List.map (compile_aval ctx) avals in
@@ -1019,9 +985,9 @@ let rec compile_aval ctx = function
let tup_ctyp = CT_tup (List.map cval_ctyp cvals) in
let gs = gensym () in
setup
- @ [I_decl (tup_ctyp, gs)]
- @ List.mapi (fun n cval -> I_copy (CL_field (gs, mk_id ("tup" ^ string_of_int n)), cval)) cvals,
- CV_id (gs, CT_tup (List.map cval_ctyp cvals)),
+ @ [idecl tup_ctyp gs]
+ @ List.mapi (fun n cval -> icopy (CL_field (gs, "tup" ^ string_of_int n)) cval) cvals,
+ (F_id gs, CT_tup (List.map cval_ctyp cvals)),
cleanup
let compile_funcall ctx id args typ =
@@ -1054,10 +1020,10 @@ let compile_funcall ctx id args typ =
cval
else if is_stack_ctyp have_ctyp && not (is_stack_ctyp ctyp) then
let gs = gensym () in
- setup := I_decl (ctyp, gs) :: !setup;
- setup := I_init (ctyp, gs, cval) :: !setup;
- cleanup := I_clear (ctyp, gs) :: !cleanup;
- CV_id (gs, ctyp)
+ setup := idecl ctyp gs :: !setup;
+ setup := iinit ctyp gs cval :: !setup;
+ cleanup := iclear ctyp gs :: !cleanup;
+ (F_id gs, ctyp)
else
c_error ~loc:(id_loc id)
(Printf.sprintf "Failure when setting up function arguments: %s and %s." (string_of_ctyp have_ctyp) (string_of_ctyp ctyp))
@@ -1067,13 +1033,13 @@ let compile_funcall ctx id args typ =
let call =
if ctyp_equal final_ctyp ret_ctyp then
- fun ret -> I_funcall (ret, id, sargs, ret_ctyp)
+ fun ret -> ifuncall ret id sargs ret_ctyp
else if not (is_stack_ctyp ret_ctyp) && is_stack_ctyp final_ctyp then
let gs = gensym () in
- setup := I_alloc (ret_ctyp, gs) :: !setup;
- setup := I_funcall (CL_id gs, id, sargs, ret_ctyp) :: !setup;
- cleanup := I_clear (ret_ctyp, gs) :: !cleanup;
- fun ret -> I_convert (ret, final_ctyp, gs, ret_ctyp)
+ setup := ialloc ret_ctyp gs :: !setup;
+ 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
assert false
in
@@ -1082,40 +1048,21 @@ let compile_funcall ctx id args typ =
let rec compile_match ctx apat cval case_label =
match apat, cval with
- | AP_id pid, _ when is_ct_variant (cval_ctyp cval) ->
- let frag = match cval with
- | CV_id (id, _) -> F_id id
- | CV_C_fragment (frag, _) -> frag
- in
- [I_if (CV_C_fragment (F_op (F_field (frag, "kind"), "!=", F_lit ("Kind_" ^ Util.zencode_string (string_of_id pid))), CT_bool),
- [I_goto case_label],
- [],
- CT_unit)],
+ | AP_id pid, (frag, ctyp) when is_ct_variant ctyp ->
+ [iif (F_op (F_field (frag, "kind"), "!=", F_lit ("Kind_" ^ Util.zencode_string (string_of_id pid))), CT_bool)
+ [igoto case_label]
+ []
+ CT_unit],
[]
- | AP_id pid, CV_C_fragment (code, ctyp) when is_ct_enum ctyp ->
- [I_if (CV_C_fragment (F_op (F_id pid, "!=", code), CT_bool), [I_goto case_label], [], CT_unit)], []
- | AP_id pid, CV_id (id, ctyp) when is_ct_enum ctyp ->
- [I_if (CV_C_fragment (F_op (F_id pid, "!=", F_id id), CT_bool), [I_goto case_label], [], CT_unit)], []
+ | AP_id pid, (frag, ctyp) when is_ct_enum ctyp ->
+ [iif (F_op (F_id pid, "!=", frag), CT_bool) [igoto case_label] [] CT_unit], []
| AP_id pid, _ ->
let ctyp = cval_ctyp cval in
- let init, cleanup = if is_stack_ctyp ctyp then I_decl (ctyp, pid), [] else I_alloc (ctyp, pid), [I_clear (ctyp, pid)] in
- [init; I_copy (CL_id pid, cval)], cleanup
- | AP_tup apats, CV_id (id, ctyp) ->
- begin
- let get_tup n ctyp = CV_C_fragment (F_field (F_id id, "ztup" ^ string_of_int n), ctyp) in
- let fold (instrs, cleanup, n) apat ctyp =
- let instrs', cleanup' = compile_match ctx apat (get_tup n ctyp) case_label in
- instrs @ instrs', cleanup' @ cleanup, n + 1
- in
- match ctyp with
- | CT_tup ctyps ->
- let instrs, cleanup, _ = List.fold_left2 fold ([], [], 0) apats ctyps in
- instrs, cleanup
- | _ -> assert false
- end
- | AP_tup apats, CV_C_fragment (frag, ctyp) ->
+ let init, cleanup = if is_stack_ctyp ctyp then idecl ctyp pid, [] else ialloc ctyp pid, [iclear ctyp pid] in
+ [init; icopy (CL_id pid) cval], cleanup
+ | AP_tup apats, (frag, ctyp) ->
begin
- let get_tup n ctyp = CV_C_fragment (F_field (frag, "ztup" ^ string_of_int n), ctyp) in
+ let get_tup n ctyp = (F_field (frag, "ztup" ^ string_of_int n), ctyp) in
let fold (instrs, cleanup, n) apat ctyp =
let instrs', cleanup' = compile_match ctx apat (get_tup n ctyp) case_label in
instrs @ instrs', cleanup' @ cleanup, n + 1
@@ -1126,37 +1073,23 @@ let rec compile_match ctx apat cval case_label =
instrs, cleanup
| _ -> assert false
end
- | AP_app (ctor, apat), CV_id (id, ctyp) ->
- begin match ctyp with
- | CT_variant (_, ctors) ->
- let ctor_c_id = Util.zencode_string (string_of_id ctor) in
- let ctor_ctyp = Bindings.find ctor ctors in
- let instrs, cleanup = compile_match ctx apat (CV_C_fragment (F_field (F_id id, ctor_c_id), ctor_ctyp)) case_label in
- [ I_if (CV_C_fragment (F_op (F_field (F_id id, "kind"), "!=", F_lit ("Kind_" ^ ctor_c_id)), CT_bool),
- [I_goto case_label],
- [],
- CT_unit) ]
- @ instrs,
- cleanup
- | _ -> failwith "AP_app constructor with non-variant type"
- end
- | AP_app (ctor, apat), CV_C_fragment (frag, ctyp) ->
+ | AP_app (ctor, apat), (frag, ctyp) ->
begin match ctyp with
| CT_variant (_, ctors) ->
let ctor_c_id = Util.zencode_string (string_of_id ctor) in
- let ctor_ctyp = Bindings.find ctor ctors in
- let instrs, cleanup = compile_match ctx apat (CV_C_fragment (F_field (frag, ctor_c_id), ctor_ctyp)) case_label in
- [ I_if (CV_C_fragment (F_op (F_field (frag, "kind"), "!=", F_lit ("Kind_" ^ ctor_c_id)), CT_bool),
- [I_goto case_label],
- [],
- CT_unit) ]
+ let ctor_ctyp = Bindings.find ctor (ctor_bindings ctors) in
+ let instrs, cleanup = compile_match ctx apat ((F_field (frag, ctor_c_id), ctor_ctyp)) case_label in
+ [iif (F_op (F_field (frag, "kind"), "!=", F_lit ("Kind_" ^ ctor_c_id)), CT_bool)
+ [igoto case_label]
+ []
+ CT_unit]
@ instrs,
cleanup
| _ -> failwith "AP_app constructor with non-variant type"
end
| AP_wild, _ -> [], []
-let unit_fragment = CV_C_fragment (F_lit "UNIT", CT_unit)
+let unit_fragment = (F_lit "UNIT", CT_unit)
(** GLOBAL: label_counter is used to make sure all labels have unique
names. Like gensym_counter it should be safe to reset between
@@ -1173,9 +1106,9 @@ let rec compile_aexp ctx = function
let setup, ctyp, call, cleanup = compile_aexp ctx binding in
let letb1, letb1c =
if is_stack_ctyp ctyp then
- [I_decl (ctyp, id); call (CL_id id)], []
+ [idecl ctyp id; call (CL_id id)], []
else
- [I_alloc (ctyp, id); call (CL_id id)], [I_clear (ctyp, id)]
+ [ialloc ctyp id; call (CL_id id)], [iclear ctyp id]
in
let letb2 = setup @ letb1 @ cleanup in
let setup, ctyp, call, cleanup = compile_aexp ctx body in
@@ -1186,7 +1119,7 @@ let rec compile_aexp ctx = function
| AE_val aval ->
let setup, cval, cleanup = compile_aval ctx aval in
- setup, cval_ctyp cval, (fun clexp -> I_copy (clexp, cval)), cleanup
+ setup, cval_ctyp cval, (fun clexp -> icopy clexp cval), cleanup
(* Compile case statements *)
| AE_case (aval, cases, typ) ->
@@ -1206,26 +1139,26 @@ let rec compile_aexp ctx = function
let body_setup, _, body_call, body_cleanup = compile_aexp ctx body in
let gs = gensym () in
let case_instrs =
- destructure @ [I_comment "end destructuring"]
+ destructure @ [icomment "end destructuring"]
@ (if not trivial_guard then
- guard_setup @ [I_decl (CT_bool, gs); guard_call (CL_id gs)] @ guard_cleanup
- @ [I_if (CV_C_fragment (F_unary ("!", F_id gs), CT_bool), destructure_cleanup @ [I_goto case_label], [], CT_unit)]
- @ [I_comment "end guard"]
+ guard_setup @ [idecl CT_bool gs; guard_call (CL_id gs)] @ guard_cleanup
+ @ [iif (F_unary ("!", F_id gs), CT_bool) (destructure_cleanup @ [igoto case_label]) [] CT_unit]
+ @ [icomment "end guard"]
else [])
@ body_setup @ [body_call (CL_id case_return_id)] @ body_cleanup @ destructure_cleanup
- @ [I_goto finish_match_label]
+ @ [igoto finish_match_label]
in
- [I_block case_instrs; I_label case_label]
+ [iblock case_instrs; ilabel case_label]
in
- [I_comment "begin match"]
- @ aval_setup @ [I_decl (ctyp, case_return_id)]
+ [icomment "begin match"]
+ @ aval_setup @ [idecl ctyp case_return_id]
@ List.concat (List.map compile_case cases)
- @ [I_raw "sail_match_failure();"]
- @ [I_label finish_match_label],
+ @ [imatch_failure ()]
+ @ [ilabel finish_match_label],
ctyp,
- (fun clexp -> I_copy (clexp, CV_id (case_return_id, ctyp))),
+ (fun clexp -> icopy clexp (F_id case_return_id, ctyp)),
aval_cleanup
- @ [I_comment "end match"]
+ @ [icomment "end match"]
(* Compile try statement *)
| AE_try (aexp, cases, typ) ->
@@ -1239,32 +1172,32 @@ let rec compile_aexp ctx = function
| _ -> false
in
let try_label = label "try_" in
- let exn_cval = CV_C_fragment (F_lit "(*current_exception)", ctyp_of_typ ctx (mk_typ (Typ_id (mk_id "exception")))) in
+ let exn_cval = (F_current_exception, ctyp_of_typ ctx (mk_typ (Typ_id (mk_id "exception")))) in
let destructure, destructure_cleanup = compile_match ctx apat exn_cval try_label in
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
let case_instrs =
- destructure @ [I_comment "end destructuring"]
+ destructure @ [icomment "end destructuring"]
@ (if not trivial_guard then
- guard_setup @ [I_decl (CT_bool, gs); guard_call (CL_id gs)] @ guard_cleanup
- @ [I_if (CV_C_fragment (F_unary ("!", F_id gs), CT_bool), [I_goto try_label], [], CT_unit)]
- @ [I_comment "end guard"]
+ guard_setup @ [idecl CT_bool gs; guard_call (CL_id gs)] @ guard_cleanup
+ @ [iif (F_unary ("!", F_id gs), CT_bool) [igoto try_label] [] CT_unit]
+ @ [icomment "end guard"]
else [])
@ body_setup @ [body_call (CL_id try_return_id)] @ body_cleanup @ destructure_cleanup
- @ [I_goto handled_exception_label]
+ @ [igoto handled_exception_label]
in
- [I_block case_instrs; I_label try_label]
+ [iblock case_instrs; ilabel try_label]
in
- [I_comment "begin try catch";
- I_decl (ctyp, try_return_id)],
+ [icomment "begin try catch";
+ idecl ctyp try_return_id],
ctyp,
- (fun clexp -> I_try_block (aexp_setup @ [aexp_call clexp] @ aexp_cleanup)),
- [I_if (CV_C_fragment (F_lit "!have_exception", CT_bool), [I_goto handled_exception_label], [], CT_unit)]
+ (fun clexp -> itry_block (aexp_setup @ [aexp_call clexp] @ aexp_cleanup)),
+ [iif (F_unary ("!", F_have_exception), CT_bool) [igoto handled_exception_label] [] CT_unit]
@ List.concat (List.map compile_case cases)
- @ [I_raw "sail_match_failure();"]
- @ [I_label handled_exception_label]
- @ [I_raw "have_exception = false;"]
+ @ [imatch_failure ()]
+ @ [ilabel handled_exception_label]
+ @ [icopy CL_have_exception (F_lit "false", CT_bool)]
| AE_if (aval, then_aexp, else_aexp, if_typ) ->
let if_ctyp = ctyp_of_typ ctx if_typ in
@@ -1274,12 +1207,12 @@ let rec compile_aexp ctx = function
in
let setup, ctyp, call, cleanup = compile_aexp ctx (AE_val aval) in
let gs = gensym () in
- setup @ [I_decl (ctyp, gs); call (CL_id gs)],
+ setup @ [idecl ctyp gs; call (CL_id gs)],
if_ctyp,
- (fun clexp -> I_if (CV_id (gs, ctyp),
- compile_branch then_aexp clexp,
- compile_branch else_aexp clexp,
- if_ctyp)),
+ (fun clexp -> iif (F_id gs, ctyp)
+ (compile_branch then_aexp clexp)
+ (compile_branch else_aexp clexp)
+ if_ctyp),
cleanup
| AE_record_update (aval, fields, typ) ->
@@ -1290,10 +1223,10 @@ let rec compile_aexp ctx = function
let setup, calls, cleanup = List.fold_left update_field ([], [], []) (Bindings.bindings fields) in
let ctyp = ctyp_of_typ ctx typ in
let gs = gensym () in
- [I_alloc (ctyp, gs)] @ setup @ List.map (fun call -> call (CL_id gs)) calls,
+ [ialloc ctyp gs] @ setup @ List.map (fun call -> call (CL_id gs)) calls,
ctyp,
- (fun clexp -> I_copy (clexp, CV_id (gs, ctyp))),
- cleanup @ [I_clear (ctyp, gs)]
+ (fun clexp -> icopy clexp (F_id gs, ctyp)),
+ cleanup @ [iclear ctyp gs]
| AE_assign (id, assign_typ, aexp) ->
(* assign_ctyp is the type of the C variable we are assigning to,
@@ -1303,16 +1236,16 @@ let rec compile_aexp ctx = function
let setup, ctyp, call, cleanup = compile_aexp ctx aexp in
let comment = "assign " ^ string_of_ctyp assign_ctyp ^ " := " ^ string_of_ctyp ctyp in
if ctyp_equal assign_ctyp ctyp then
- setup @ [call (CL_id id)], CT_unit, (fun clexp -> I_copy (clexp, unit_fragment)), cleanup
+ setup @ [call (CL_id id)], CT_unit, (fun clexp -> icopy clexp unit_fragment), cleanup
else if not (is_stack_ctyp assign_ctyp) && is_stack_ctyp ctyp then
let gs = gensym () in
- setup @ [ I_comment comment;
- I_decl (ctyp, gs);
+ setup @ [ icomment comment;
+ idecl ctyp gs;
call (CL_id gs);
- I_convert (CL_id id, assign_ctyp, gs, ctyp)
+ iconvert (CL_id id) assign_ctyp gs ctyp
],
CT_unit,
- (fun clexp -> I_copy (clexp, unit_fragment)),
+ (fun clexp -> icopy clexp unit_fragment),
cleanup
else
failwith comment
@@ -1329,17 +1262,17 @@ 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 = CV_C_fragment (F_unary ("!", F_id gs), CT_bool) in
- cond_setup @ [I_decl (CT_bool, gs); I_decl (CT_unit, unit_gs)]
- @ [I_label loop_start_label]
- @ [I_block ([cond_call (CL_id gs); I_if (loop_test, [I_goto loop_end_label], [], CT_unit)]
- @ body_setup
- @ [body_call (CL_id unit_gs)]
- @ body_cleanup
- @ [I_goto loop_start_label])]
- @ [I_label loop_end_label],
+ let loop_test = (F_unary ("!", F_id gs), CT_bool) in
+ cond_setup @ [idecl CT_bool gs; idecl CT_unit unit_gs]
+ @ [ilabel loop_start_label]
+ @ [iblock ([cond_call (CL_id gs); iif loop_test [igoto loop_end_label] [] CT_unit]
+ @ body_setup
+ @ [body_call (CL_id unit_gs)]
+ @ body_cleanup
+ @ [igoto loop_start_label])]
+ @ [ilabel loop_end_label],
CT_unit,
- (fun clexp -> I_copy (clexp, unit_fragment)),
+ (fun clexp -> icopy clexp unit_fragment),
cond_cleanup
| AE_cast (aexp, typ) -> compile_aexp ctx aexp
@@ -1347,17 +1280,17 @@ let rec compile_aexp ctx = function
| AE_return (aval, typ) ->
(* Cleanup info will be re-added by fix_early_return *)
let return_setup, cval, _ = compile_aval ctx aval in
- return_setup @ [I_return cval],
+ return_setup @ [ireturn cval],
CT_unit,
- (fun clexp -> I_copy (clexp, unit_fragment)),
+ (fun clexp -> icopy clexp unit_fragment),
[]
| AE_throw (aval, typ) ->
(* Cleanup info will be handled by fix_exceptions *)
let throw_setup, cval, _ = compile_aval ctx aval in
- throw_setup @ [I_throw cval],
+ throw_setup @ [ithrow cval],
ctyp_of_typ ctx typ,
- (fun clexp -> I_copy (clexp, unit_fragment)),
+ (fun clexp -> icopy clexp unit_fragment),
[]
| aexp -> failwith ("Cannot compile ANF expression: " ^ Pretty_print_sail.to_string (pp_aexp aexp))
@@ -1368,7 +1301,7 @@ and compile_block ctx = function
let setup, _, call, cleanup = compile_aexp ctx exp in
let rest = compile_block ctx exps in
let gs = gensym () in
- setup @ [I_decl (CT_unit, gs); call (CL_id gs)] @ cleanup @ rest
+ setup @ [idecl CT_unit gs; call (CL_id gs)] @ cleanup @ rest
let rec pat_ids (P_aux (p_aux, (l, _)) as pat) =
match p_aux with
@@ -1389,12 +1322,12 @@ let rec pat_ids (P_aux (p_aux, (l, _)) as pat) =
let compile_type_def ctx (TD_aux (type_def, _)) =
match type_def with
| TD_enum (id, _, ids, _) ->
- CTD_enum (id, IdSet.of_list ids),
+ CTD_enum (id, ids),
{ ctx with enums = Bindings.add id (IdSet.of_list ids) ctx.enums }
| TD_record (id, _, _, ctors, _) ->
let ctors = List.fold_left (fun ctors (typ, id) -> Bindings.add id (ctyp_of_typ ctx typ) ctors) Bindings.empty ctors in
- CTD_record (id, ctors),
+ CTD_struct (id, Bindings.bindings ctors),
{ ctx with records = Bindings.add id ctors ctx.records }
| TD_variant (id, _, _, tus, _) ->
@@ -1404,7 +1337,7 @@ let compile_type_def ctx (TD_aux (type_def, _)) =
| Tu_ty_id (typ, id) -> ctyp_of_typ ctx typ, id
in
let ctus = List.fold_left (fun ctus (ctyp, id) -> Bindings.add id ctyp ctus) Bindings.empty (List.map compile_tu tus) in
- CTD_variant (id, ctus),
+ CTD_variant (id, Bindings.bindings ctus),
{ ctx with variants = Bindings.add id ctus ctx.variants }
(* Will be re-written before here, see bitfield.ml *)
@@ -1421,13 +1354,14 @@ let instr_split_at f =
instr_split_at' f []
let generate_cleanup instrs =
- let generate_cleanup' = function
- | I_decl (ctyp, id) when not (is_stack_ctyp ctyp) -> [(id, I_clear (ctyp, id))]
- | I_alloc (ctyp, id) when not (is_stack_ctyp ctyp) -> [(id, I_clear (ctyp, id))]
+ let generate_cleanup' (I_aux (instr, _)) =
+ match instr with
+ | I_decl (ctyp, id) when not (is_stack_ctyp ctyp) -> [(id, iclear ctyp id)]
+ | I_alloc (ctyp, id) when not (is_stack_ctyp ctyp) -> [(id, iclear ctyp id)]
| instr -> []
in
let is_clear ids = function
- | I_clear (_, id) -> IdSet.add id ids
+ | I_aux (I_clear (_, id), _) -> IdSet.add id ids
| _ -> ids
in
let cleaned = List.fold_left is_clear IdSet.empty instrs in
@@ -1450,67 +1384,73 @@ let generate_cleanup instrs =
same block? *)
let fix_early_return ret ctx instrs =
let end_function_label = label "end_function_" in
- let is_return_recur = function
+ let is_return_recur (I_aux (instr, _)) =
+ match instr with
| I_return _ | I_if _ | I_block _ -> true
| _ -> false
in
let rec rewrite_return pre_cleanup instrs =
match instr_split_at is_return_recur instrs with
| instrs, [] -> instrs
- | before, I_block instrs :: after ->
+ | before, I_aux (I_block instrs, _) :: after ->
before
- @ [I_block (rewrite_return (pre_cleanup @ generate_cleanup before) instrs)]
+ @ [iblock (rewrite_return (pre_cleanup @ generate_cleanup before) instrs)]
@ rewrite_return pre_cleanup after
- | before, I_if (cval, then_instrs, else_instrs, ctyp) :: after ->
+ | before, I_aux (I_if (cval, then_instrs, else_instrs, ctyp), _) :: after ->
let cleanup = pre_cleanup @ generate_cleanup before in
before
- @ [I_if (cval, rewrite_return cleanup then_instrs, rewrite_return cleanup else_instrs, ctyp)]
+ @ [iif cval (rewrite_return cleanup then_instrs) (rewrite_return cleanup else_instrs) ctyp]
@ rewrite_return pre_cleanup after
- | before, I_return cval :: after ->
+ | before, I_aux (I_return cval, _) :: after ->
let cleanup_label = label "cleanup_" in
let end_cleanup_label = label "end_cleanup_" in
before
- @ [I_copy (ret, cval);
- I_goto cleanup_label]
+ @ [icopy ret cval;
+ igoto cleanup_label]
(* This is probably dead code until cleanup_label, but how can we be sure there are no jumps into it? *)
@ rewrite_return pre_cleanup after
- @ [I_goto end_cleanup_label]
- @ [I_label cleanup_label]
+ @ [igoto end_cleanup_label]
+ @ [ilabel cleanup_label]
@ pre_cleanup
@ generate_cleanup before
- @ [I_goto end_function_label]
- @ [I_label end_cleanup_label]
+ @ [igoto end_function_label]
+ @ [ilabel end_cleanup_label]
| _, _ -> assert false
in
rewrite_return [] instrs
- @ [I_label end_function_label]
+ @ [ilabel end_function_label]
let fix_exception_block ctx instrs =
let end_block_label = label "end_block_exception_" in
- let is_exception_stop = function
+ let is_exception_stop (I_aux (instr, _)) =
+ match instr with
| I_throw _ | I_if _ | I_block _ | I_funcall _ -> true
| _ -> false
in
+ (* In this function 'after' is instructions after the one we've
+ matched on, 'before is instructions before the instruction we've
+ matched with, but after the previous match, and 'historic' are
+ all the befores from previous matches. *)
let rec rewrite_exception historic instrs =
match instr_split_at is_exception_stop instrs with
| instrs, [] -> instrs
- | before, I_block instrs :: after ->
+ | before, I_aux (I_block instrs, _) :: after ->
before
- @ [I_block (rewrite_exception (generate_cleanup (historic @ before)) instrs)]
+ @ [iblock (rewrite_exception (generate_cleanup (historic @ before)) instrs)]
@ rewrite_exception (historic @ before) after
- | before, I_if (cval, then_instrs, else_instrs, ctyp) :: after ->
+ | before, I_aux (I_if (cval, then_instrs, else_instrs, ctyp), _) :: after ->
let historic = historic @ before in
before
- @ [I_if (cval, rewrite_exception historic then_instrs, rewrite_exception historic else_instrs, ctyp)]
+ @ [iif cval (rewrite_exception historic then_instrs) (rewrite_exception historic else_instrs) ctyp]
@ rewrite_exception historic after
- | before, I_throw cval :: after ->
+ | before, I_aux (I_throw cval, _) :: after ->
before
- @ [I_copy (CL_raw "current_exception", cval);
- I_raw "have_exception = true;"]
+ @ [icopy CL_current_exception cval;
+ icopy CL_have_exception (F_lit "true", CT_bool)]
@ generate_cleanup (historic @ before)
- @ [I_goto end_block_label]
+ @ [igoto end_block_label]
@ rewrite_exception (historic @ before) after
- | before, (I_funcall (x, f, args, ctyp) as funcall) :: after ->
+ | before, (I_aux (I_funcall (x, f, args, ctyp), _) as funcall) :: after ->
let effects = match Env.get_val_spec f ctx.tc_env with
| _, Typ_aux (Typ_fn (_, _, effects), _) -> effects
| exception (Type_error _) -> no_effect (* nullary union constructor, so no val spec *)
@@ -1519,24 +1459,26 @@ let fix_exception_block ctx instrs =
if has_effect effects BE_escape then
before
@ [funcall;
- I_if (CV_C_fragment (F_lit "have_exception", CT_bool), generate_cleanup (historic @ before) @ [I_goto end_block_label], [], CT_unit)]
+ iif (F_have_exception, CT_bool) (generate_cleanup (historic @ before) @ [igoto end_block_label]) [] CT_unit]
@ rewrite_exception (historic @ before) after
else
before @ funcall :: rewrite_exception (historic @ before) after
| _, _ -> assert false (* unreachable *)
in
rewrite_exception [] instrs
- @ [I_label end_block_label]
-
-let rec map_try_block f instr =
- match instr with
- | I_decl _ | I_alloc _ | I_init _ -> instr
- | I_if (cval, instrs1, instrs2, ctyp) ->
- I_if (cval, List.map (map_try_block f) instrs1, List.map (map_try_block f) instrs2, ctyp)
- | I_funcall _ | I_convert _ | I_assign _ | I_copy _ | I_clear _ | I_throw _ | I_return _ -> instr
- | I_block instrs -> I_block (List.map (map_try_block f) instrs)
- | I_try_block instrs -> I_try_block (f (List.map (map_try_block f) instrs))
- | I_comment _ | I_label _ | I_goto _ | I_raw _ -> instr
+ @ [ilabel end_block_label]
+
+let rec map_try_block f (I_aux (instr, aux)) =
+ let instr = match instr with
+ | I_decl _ | I_alloc _ | I_init _ -> instr
+ | I_if (cval, instrs1, instrs2, ctyp) ->
+ I_if (cval, List.map (map_try_block f) instrs1, List.map (map_try_block f) instrs2, ctyp)
+ | I_funcall _ | I_convert _ | I_copy _ | I_clear _ | I_throw _ | I_return _ -> instr
+ | I_block instrs -> I_block (List.map (map_try_block f) instrs)
+ | I_try_block instrs -> I_try_block (f (List.map (map_try_block f) instrs))
+ | I_comment _ | I_label _ | I_goto _ | I_raw _ | I_match_failure -> instr
+ in
+ I_aux (instr, aux)
let fix_exception ctx instrs =
let instrs = List.map (map_try_block (fix_exception_block ctx)) instrs in
@@ -1545,7 +1487,7 @@ let fix_exception ctx instrs =
(** Compile a Sail toplevel definition into an IR definition **)
let compile_def ctx = function
| DEF_reg_dec (DEC_aux (DEC_reg (typ, id), _)) ->
- [CDEF_reg_dec (ctyp_of_typ ctx typ, id)], ctx
+ [CDEF_reg_dec (id, ctyp_of_typ ctx typ)], ctx
| DEF_reg_dec _ -> failwith "Unsupported register declaration" (* FIXME *)
| DEF_spec _ -> [], ctx
@@ -1559,12 +1501,12 @@ let compile_def ctx = function
let setup, ctyp, call, cleanup = compile_aexp ctx aexp in
let gs = gensym () in
if is_stack_ctyp ctyp then
- let instrs = [I_decl (ctyp, gs)] @ setup @ [call (CL_id gs)] @ cleanup @ [I_return (CV_id (gs, ctyp))] in
+ let instrs = [idecl ctyp gs] @ setup @ [call (CL_id gs)] @ cleanup @ [ireturn (F_id gs, ctyp)] in
let instrs = fix_exception ctx instrs in
[CDEF_fundef (id, None, pat_ids pat, instrs)], ctx
else
- let instrs = setup @ [call (CL_addr (CL_id gs))] @ cleanup in
- let instrs = fix_early_return (CL_addr (CL_id gs)) ctx instrs in
+ let instrs = setup @ [call (CL_addr gs)] @ cleanup in
+ let instrs = fix_early_return (CL_addr gs) ctx instrs in
let instrs = fix_exception ctx instrs in
[CDEF_fundef (id, Some gs, pat_ids pat, instrs)], ctx
| _ -> assert false
@@ -1599,20 +1541,21 @@ let compile_def ctx = function
See https://gcc.gnu.org/onlinedocs/gcc/Local-Labels.html **)
let add_local_labels' instrs =
- let is_label = function
+ let is_label (I_aux (instr, _)) =
+ match instr with
| I_label str -> [str]
| _ -> []
in
let labels = List.concat (List.map is_label instrs) in
- let local_label_decl = I_raw ("__label__ " ^ String.concat ", " labels ^ ";\n") in
+ let local_label_decl = iraw ("__label__ " ^ String.concat ", " labels ^ ";\n") in
if labels = [] then
instrs
else
local_label_decl :: instrs
let add_local_labels instrs =
- match map_instrs add_local_labels' (I_block instrs) with
- | I_block instrs -> instrs
+ match map_instrs add_local_labels' (iblock instrs) with
+ | I_aux (I_block instrs, _) -> instrs
| _ -> assert false
(**************************************************************************)
@@ -1642,8 +1585,8 @@ module Node = struct
| _ , G_start -> -1
| G_instr _, _ -> 1
| _ , G_instr _ -> -1
- | _ , G_id _ -> 1
- | G_id _ , _ -> -1
+ | G_id _ , _ -> 1
+ | _ , G_id _ -> -1
end
module NM = Map.Make(Node)
@@ -1656,16 +1599,17 @@ let rec fragment_deps = function
| F_lit _ -> NS.empty
| F_field (frag, _) | F_unary (_, frag) -> fragment_deps frag
| 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
- | CV_id (id, _) -> NS.singleton (G_id id)
- | CV_C_fragment (frag, _) -> fragment_deps frag
+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 clexp -> clexp_deps clexp
- | CL_raw _ -> NS.empty
+ | 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 **)
@@ -1676,7 +1620,6 @@ let instr_deps = function
| I_if (cval, _, _, _) -> cval_deps cval, NS.empty
| 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_assign (id, cval) -> cval_deps cval, NS.singleton (G_id id)
| 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
@@ -1684,6 +1627,7 @@ let instr_deps = function
| 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
@@ -1704,9 +1648,9 @@ let instrs_graph instrs =
let icounter = ref 0 in
let graph = ref NM.empty in
- let rec add_instr last_instr instr =
+ let rec add_instr last_instr (I_aux (instr, _) as iaux) =
incr icounter;
- let node = G_instr (!icounter, instr) in
+ 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
@@ -1718,7 +1662,7 @@ let instrs_graph instrs =
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, I_comment "join") in
+ let join = G_instr (!icounter, icomment "join") in
graph := add_link n1 join !graph;
graph := add_link n2 join !graph;
join
@@ -1729,7 +1673,7 @@ let instrs_graph instrs =
graph := add_link last_instr node !graph;
NS.iter (fun output -> graph := add_link node output !graph) outputs;
incr icounter;
- G_instr (!icounter, I_comment "after goto")
+ G_instr (!icounter, icomment "after goto")
end
| _ ->
begin
@@ -1740,28 +1684,28 @@ let instrs_graph instrs =
node
end
in
- List.fold_left add_instr G_start instrs;
+ 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_decl _) -> "olivedrab1"
- | G_instr (_, I_init _) -> "springgreen"
- | G_instr (_, I_alloc _) -> "palegreen"
- | G_instr (_, I_clear _) -> "peachpuff"
- | G_instr (_, I_goto _) -> "orange1"
- | G_instr (_, I_label _) -> "white"
- | G_instr (_, I_raw _) -> "khaki"
- | G_instr _ -> "azure"
- | G_label _ -> "lightpink"
+ | 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_start , _ -> "goldenrod4"
| G_label _, _ -> "darkgreen"
| _ , G_label _ -> "goldenrod4"
| G_instr _, G_instr _ -> "black"
@@ -1795,7 +1739,7 @@ let upper_codegen_id id = string (upper_sgen_id id)
let sgen_ctyp = function
| CT_unit -> "unit"
- | CT_int -> "int"
+ | CT_bit -> "bit"
| CT_bool -> "bool"
| CT_uint64 _ -> "uint64_t"
| CT_int64 -> "int64_t"
@@ -1809,7 +1753,7 @@ let sgen_ctyp = function
let sgen_ctyp_name = function
| CT_unit -> "unit"
- | CT_int -> "int"
+ | CT_bit -> "bit"
| CT_bool -> "bool"
| CT_uint64 _ -> "uint64_t"
| CT_int64 -> "int64_t"
@@ -1821,26 +1765,24 @@ let sgen_ctyp_name = function
| CT_variant (id, _) -> sgen_id id
| CT_string -> "sail_string"
-let sgen_cval = function
- | CV_C_fragment (frag, _) -> string_of_fragment frag
- | CV_id (id, _) -> sgen_id id
- | _ -> "CVAL??"
+let sgen_cval = function (frag, _) -> string_of_fragment frag
let sgen_clexp = function
| CL_id id -> "&" ^ sgen_id id
- | CL_field (id, field) -> "&(" ^ sgen_id id ^ "." ^ sgen_id field ^ ")"
- | CL_addr (CL_id id) -> sgen_id id
- | CL_raw str -> str
- | _ -> assert false
+ | CL_field (id, field) -> "&(" ^ sgen_id id ^ "." ^ field ^ ")"
+ | CL_addr id -> sgen_id id
+ | CL_have_exception -> "have_exception"
+ | CL_current_exception -> "current_exception"
let sgen_clexp_pure = function
| CL_id id -> sgen_id id
- | CL_field (id, field) -> sgen_id id ^ "." ^ sgen_id field
- | CL_raw str -> str
- | CL_addr (CL_id id) -> sgen_id id
- | _ -> assert false
+ | CL_field (id, field) -> sgen_id id ^ "." ^ field
+ | CL_addr id -> sgen_id id
+ | CL_have_exception -> "have_exception"
+ | CL_current_exception -> "current_exception"
-let rec codegen_instr ctx = function
+let rec codegen_instr ctx (I_aux (instr, _)) =
+ match instr with
| I_decl (ctyp, id) ->
string (Printf.sprintf " %s %s;" (sgen_ctyp ctyp) (sgen_id id))
| I_copy (clexp, cval) ->
@@ -1849,7 +1791,6 @@ let rec codegen_instr ctx = function
string (Printf.sprintf " %s = %s;" (sgen_clexp_pure clexp) (sgen_cval cval))
else
string (Printf.sprintf " set_%s(%s, %s);" (sgen_ctyp_name ctyp) (sgen_clexp clexp) (sgen_cval cval))
- | I_assign _ -> failwith "I_assign is currently unused"
| I_if (cval, [then_instr], [], ctyp) ->
string (Printf.sprintf " if (%s)" (sgen_cval cval)) ^^ hardline
^^ twice space ^^ codegen_instr ctx then_instr
@@ -1913,13 +1854,15 @@ let rec codegen_instr ctx = function
string (Printf.sprintf " goto %s;" str)
| I_raw str ->
string (" " ^ str)
+ | I_match_failure ->
+ string (" sail_match_failure();")
let codegen_type_def ctx = function
| CTD_enum (id, ids) ->
string (Printf.sprintf "// enum %s" (string_of_id id)) ^^ hardline
- ^^ separate space [string "enum"; codegen_id id; lbrace; separate_map (comma ^^ space) upper_codegen_id (IdSet.elements ids); rbrace ^^ semi]
+ ^^ separate space [string "enum"; codegen_id id; lbrace; separate_map (comma ^^ space) upper_codegen_id ids; rbrace ^^ semi]
- | CTD_record (id, ctors) ->
+ | CTD_struct (id, ctors) ->
(* Generate a set_T function for every struct T *)
let codegen_set (id, ctyp) =
if is_stack_ctyp ctyp then
@@ -1952,14 +1895,14 @@ let codegen_type_def ctx = function
string (Printf.sprintf "// struct %s" (string_of_id id)) ^^ hardline
^^ string "struct" ^^ space ^^ codegen_id id ^^ space
^^ surround 2 0 lbrace
- (separate_map (semi ^^ hardline) codegen_ctor (Bindings.bindings ctors) ^^ semi)
+ (separate_map (semi ^^ hardline) codegen_ctor ctors ^^ semi)
rbrace
^^ semi ^^ twice hardline
- ^^ codegen_setter id ctors
+ ^^ codegen_setter id (ctor_bindings ctors)
^^ twice hardline
- ^^ codegen_init "init" id ctors
+ ^^ codegen_init "init" id (ctor_bindings ctors)
^^ twice hardline
- ^^ codegen_init "clear" id ctors
+ ^^ codegen_init "clear" id (ctor_bindings ctors)
| CTD_variant (id, tus) ->
let codegen_tu (ctor_id, ctyp) =
@@ -1979,7 +1922,7 @@ let codegen_type_def ctx = function
in
let codegen_init =
let n = sgen_id id in
- let ctor_id, ctyp = List.hd (Bindings.bindings tus) in
+ let ctor_id, ctyp = List.hd tus in
string (Printf.sprintf "void init_%s(struct %s *op)" n n)
^^ hardline
^^ surround 2 0 lbrace
@@ -1999,7 +1942,7 @@ let codegen_type_def ctx = function
let n = sgen_id id in
string (Printf.sprintf "void clear_%s(struct %s *op)" n n) ^^ hardline
^^ surround 2 0 lbrace
- (each_ctor "op->" (clear_field "op") (Bindings.bindings tus) ^^ semi)
+ (each_ctor "op->" (clear_field "op") tus ^^ semi)
rbrace
in
let codegen_ctor (ctor_id, ctyp) =
@@ -2021,7 +1964,7 @@ let codegen_type_def ctx = function
string (Printf.sprintf "void %s(struct %s *rop, %s)" (sgen_id ctor_id) (sgen_id id) ctor_args) ^^ hardline
^^ surround 2 0 lbrace
(tuple
- ^^ each_ctor "rop->" (clear_field "rop") (Bindings.bindings tus) ^^ hardline
+ ^^ each_ctor "rop->" (clear_field "rop") tus ^^ hardline
^^ string ("rop->kind = Kind_" ^ sgen_id ctor_id) ^^ semi ^^ hardline
^^ if is_stack_ctyp ctyp then
string (Printf.sprintf "rop->%s = op;" (sgen_id ctor_id))
@@ -2041,18 +1984,18 @@ let codegen_type_def ctx = function
in
string (Printf.sprintf "void set_%s(struct %s *rop, struct %s op)" n n n) ^^ hardline
^^ surround 2 0 lbrace
- (each_ctor "rop->" (clear_field "rop") (Bindings.bindings tus)
+ (each_ctor "rop->" (clear_field "rop") tus
^^ semi ^^ hardline
^^ string "rop->kind = op.kind"
^^ semi ^^ hardline
- ^^ each_ctor "op." set_field (Bindings.bindings tus))
+ ^^ each_ctor "op." set_field tus)
rbrace
in
string (Printf.sprintf "// union %s" (string_of_id id)) ^^ hardline
^^ string "enum" ^^ space
^^ string ("kind_" ^ sgen_id id) ^^ space
^^ separate space [ lbrace;
- separate_map (comma ^^ space) (fun id -> string ("Kind_" ^ sgen_id id)) (List.map fst (Bindings.bindings tus));
+ separate_map (comma ^^ space) (fun id -> string ("Kind_" ^ sgen_id id)) (List.map fst tus);
rbrace ^^ semi ]
^^ twice hardline
^^ string "struct" ^^ space ^^ codegen_id id ^^ space
@@ -2061,7 +2004,7 @@ let codegen_type_def ctx = function
^^ hardline
^^ string "union" ^^ space
^^ surround 2 0 lbrace
- (separate_map (semi ^^ hardline) codegen_tu (Bindings.bindings tus) ^^ semi)
+ (separate_map (semi ^^ hardline) codegen_tu tus ^^ semi)
rbrace
^^ semi)
rbrace
@@ -2073,7 +2016,7 @@ let codegen_type_def ctx = function
^^ twice hardline
^^ codegen_setter
^^ twice hardline
- ^^ separate_map (twice hardline) codegen_ctor (Bindings.bindings tus)
+ ^^ separate_map (twice hardline) codegen_ctor tus
(* If this is the exception type, then we setup up some global variables to deal with exceptions. *)
^^ if string_of_id id = "exception" then
twice hardline
@@ -2110,10 +2053,10 @@ let codegen_tup ctx ctyps =
ctyps
in
generated_tuples := IdSet.add id !generated_tuples;
- codegen_type_def ctx (CTD_record (id, fields)) ^^ twice hardline
+ codegen_type_def ctx (CTD_struct (id, Bindings.bindings fields)) ^^ twice hardline
let codegen_def' ctx = function
- | CDEF_reg_dec (ctyp, id) ->
+ | CDEF_reg_dec (id, ctyp) ->
string (Printf.sprintf "// register %s" (string_of_id id)) ^^ hardline
^^ string (Printf.sprintf "%s %s;" (sgen_ctyp ctyp) (sgen_id id))