diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/c_backend.ml | 257 | ||||
| -rw-r--r-- | src/initial_check.mli | 2 |
2 files changed, 198 insertions, 61 deletions
diff --git a/src/c_backend.ml b/src/c_backend.ml index f189f526..8c33fd5c 100644 --- a/src/c_backend.ml +++ b/src/c_backend.ml @@ -62,7 +62,7 @@ let c_debug str = if !c_verbosity > 0 then prerr_endline str else () let c_error ?loc:(l=Parse_ast.Unknown) message = - raise (Reporting_basic.err_general l ("C backend: " ^ message)) + raise (Reporting_basic.err_general l ("\nC backend: " ^ message)) let zencode_id = function | Id_aux (Id str, l) -> Id_aux (Id (Util.zencode_string str), l) @@ -75,21 +75,22 @@ let lvar_typ = function (* | Union (_, typ) -> typ *) | _ -> assert false -let rec string_of_fragment = function - | F_id id -> Util.zencode_string (string_of_id id) +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_lit str -> str | F_field (f, field) -> - Printf.sprintf "%s.%s" (string_of_fragment' 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' f1) op (string_of_fragment 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' f + op ^ string_of_fragment' ~zencode:zencode f | F_have_exception -> "have_exception" | F_current_exception -> "(*current_exception)" -and string_of_fragment' f = +and string_of_fragment' ?zencode:(zencode=true) f = match f with - | F_op _ -> "(" ^ string_of_fragment f ^ ")" - | _ -> string_of_fragment f + | F_op _ -> "(" ^ string_of_fragment ~zencode:zencode f ^ ")" + | _ -> string_of_fragment ~zencode:zencode f (**************************************************************************) (* 1. Conversion to A-normal form (ANF) *) @@ -141,6 +142,7 @@ type aexp = and apat = | AP_tup of apat list | AP_id of id + | AP_global of id * typ | AP_app of id * apat | AP_wild @@ -275,6 +277,7 @@ let rec pp_aexp = function and pp_apat = function | AP_wild -> string "_" | AP_id id -> pp_id id + | AP_global (id, _) -> pp_id id | AP_tup apats -> parens (separate_map (comma ^^ space) pp_apat apats) | AP_app (id, apat) -> pp_id id ^^ parens (pp_apat apat) @@ -318,14 +321,23 @@ let rec split_block = function exp :: exps, last | [] -> c_error "empty block" -let rec anf_pat (P_aux (p_aux, (l, _)) as pat) = +let rec anf_pat ?global:(global=false) (P_aux (p_aux, (l, _)) as pat) = match p_aux with + | P_id id when global -> AP_global (id, pat_typ_of pat) | P_id id -> AP_id id | P_wild -> AP_wild - | P_tup pats -> AP_tup (List.map anf_pat pats) - | P_app (id, [pat]) -> AP_app (id, anf_pat pat) - | P_app (id, pats) -> AP_app (id, AP_tup (List.map anf_pat pats)) - | _ -> c_error ~loc:l ("anf_pat: " ^ string_of_pat pat) + | 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_typ (_, pat) -> anf_pat ~global:global pat + | P_var (pat, _) -> anf_pat ~global:global pat + | _ -> c_error ~loc:l ("Could not convert pattern to ANF: " ^ string_of_pat pat) + +let rec apat_globals = function + | 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 let rec anf (E_aux (e_aux, exp_annot) as exp) = let to_aval = function @@ -522,7 +534,7 @@ let rec anf (E_aux (e_aux, exp_annot) as exp) = | E_internal_cast _ | E_internal_exp _ | E_sizeof_internal _ | E_internal_plet _ | E_internal_return _ | E_internal_exp_user _ -> failwith "encountered unexpected internal node when converting to ANF" - | E_record _ -> failwith ("Cannot convert to ANF: " ^ string_of_exp exp) + | E_record _ -> c_error ("Cannot convert to ANF: " ^ string_of_exp exp) (**************************************************************************) (* 2. Converting sail types to C types *) @@ -535,14 +547,16 @@ type ctx = { records : (ctyp Bindings.t) Bindings.t; enums : IdSet.t Bindings.t; variants : (ctyp Bindings.t) Bindings.t; - tc_env : Env.t + tc_env : Env.t; + letbinds : int list } let initial_ctx env = { records = Bindings.empty; enums = Bindings.empty; variants = Bindings.empty; - tc_env = env + tc_env = env; + letbinds = [] } let rec ctyp_equal ctyp1 ctyp2 = @@ -597,6 +611,7 @@ let rec ctyp_of_typ ctx typ = CT_int64 | _ -> CT_mpz end + | Typ_app (id, [Typ_arg_aux (Typ_arg_nexp n, _); Typ_arg_aux (Typ_arg_order ord, _); Typ_arg_aux (Typ_arg_typ (Typ_aux (Typ_id vtyp_id, _)), _)]) @@ -607,6 +622,13 @@ let rec ctyp_of_typ ctx typ = | Nexp_aux (Nexp_constant n, _) when Big_int.less_equal n (Big_int.of_int 64) -> CT_uint64 (Big_int.to_int n, direction) | _ -> CT_bv direction end + | Typ_app (id, [Typ_arg_aux (Typ_arg_nexp n, _); + Typ_arg_aux (Typ_arg_order ord, _); + Typ_arg_aux (Typ_arg_typ typ, _)]) + when string_of_id id = "vector" -> + let direction = match ord with Ord_aux (Ord_dec, _) -> true | Ord_aux (Ord_inc, _) -> false | _ -> assert false in + CT_vector (direction, ctyp_of_typ ctx typ) + | Typ_id id when string_of_id id = "unit" -> CT_unit | Typ_id id when string_of_id id = "string" -> CT_string | Typ_id id when string_of_id id = "real" -> CT_real @@ -619,7 +641,7 @@ let rec ctyp_of_typ ctx typ = | Typ_exist (_, _, typ) -> ctyp_of_typ ctx typ - | _ -> c_error ~loc:l ("No C-type for type " ^ string_of_typ 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_bit | CT_unit | CT_bool | CT_enum _ -> true @@ -709,7 +731,6 @@ let analyze_primop' ctx id args typ = match nexp_simp n, nexp_simp m with | Nexp_aux (Nexp_constant n, _), Nexp_aux (Nexp_constant m, _) -> if Big_int.less_equal min_int64 n && Big_int.less_equal m max_int64 then - let x, y = c_aval ctx x, c_aval ctx y in if is_c_fragment x && is_c_fragment y then AE_val (AV_C_fragment (F_op (c_fragment x, "+", c_fragment y), typ)) else @@ -877,6 +898,10 @@ let cdef_ctyps = function | CDEF_reg_dec (_, ctyp) -> [ctyp] | CDEF_fundef (_, _, _, instrs) -> List.concat (List.map instr_ctyps instrs) | CDEF_type tdef -> ctype_def_ctyps tdef + | CDEF_let (_, bindings, instrs, cleanup) -> + List.map snd bindings + @ 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 *) @@ -886,7 +911,7 @@ let pp_ctyp ctyp = let pp_keyword str = string ((str |> Util.red |> Util.clear) ^ " ") -let pp_cval (frag, ctyp) = string (string_of_fragment frag) ^^ string " : " ^^ pp_ctyp ctyp +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 @@ -972,6 +997,12 @@ let pp_cdef = function 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 let is_ct_enum = function | CT_enum _ -> true @@ -985,6 +1016,16 @@ let is_ct_tup = function | CT_tup _ -> true | _ -> false +let rec is_bitvector = function + | [] -> true + | AV_lit (L_aux (L_zero, _), _) :: avals -> is_bitvector avals + | AV_lit (L_aux (L_one, _), _) :: avals -> is_bitvector avals + | _ :: _ -> false + +let rec string_of_aval_bit = function + | AV_lit (L_aux (L_zero, _), _) -> "0" + | AV_lit (L_aux (L_one, _), _) -> "1" + let rec compile_aval ctx = function | AV_C_fragment (frag, typ) -> [], (frag, ctyp_of_typ ctx typ), [] @@ -1009,6 +1050,13 @@ let rec compile_aval ctx = function (F_id gs, CT_mpz), [iclear CT_mpz gs] + | AV_lit (L_aux (L_zero, _), _) -> [], (F_lit "0", CT_bit), [] + | AV_lit (L_aux (L_one, _), _) -> [], (F_lit "1", CT_bit), [] + + + | AV_lit (L_aux (_, l) as lit, _) -> + c_error ~loc:l ("Encountered unexpected literal " ^ string_of_lit lit) + | AV_tuple avals -> let elements = List.map (compile_aval ctx) avals in let cvals = List.map (fun (_, cval, _) -> cval) elements in @@ -1016,11 +1064,35 @@ let rec compile_aval ctx = function let cleanup = List.concat (List.rev (List.map (fun (_, _, cleanup) -> cleanup) elements)) in let tup_ctyp = CT_tup (List.map cval_ctyp cvals) in let gs = gensym () in + let tup_setup, tup_cleanup = + if is_stack_ctyp tup_ctyp then [], [] else [ialloc tup_ctyp gs], [iclear tup_ctyp gs] + in setup - @ [idecl tup_ctyp gs] - @ List.mapi (fun n cval -> icopy (CL_field (gs, "tup" ^ string_of_int n)) cval) cvals, + @ [idecl tup_ctyp gs] @ tup_setup + @ List.mapi (fun n cval -> icopy (CL_field (gs, "ztup" ^ string_of_int n)) cval) cvals, (F_id gs, CT_tup (List.map cval_ctyp cvals)), - cleanup + tup_cleanup @ cleanup + + | AV_vector ([], _) -> + c_error "Encountered empty vector literal" + + | AV_vector (avals, typ) when is_bitvector avals && List.length avals <= 64 -> + begin + let bitstring = F_lit ("0b" ^ String.concat "" (List.map string_of_aval_bit avals)) in + let len = List.length avals in + match destruct_vector ctx.tc_env typ with + | Some (_, Ord_aux (Ord_inc, _), _) -> + [], (bitstring, CT_uint64 (len, false)), [] + | Some (_, Ord_aux (Ord_dec, _), _) -> + [], (bitstring, CT_uint64 (len, true)), [] + | Some _ -> + c_error "Encountered order polymorphic bitvector literal" + | None -> + c_error "Encountered vector literal without vector type" + end + + | AV_vector _ -> + c_error "Have AV_vector" let compile_funcall ctx id args typ = let setup = ref [] in @@ -1068,7 +1140,7 @@ let compile_funcall ctx id args typ = 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 := ialloc ret_ctyp gs :: !setup; + setup := idecl ret_ctyp gs :: 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 @@ -1083,12 +1155,13 @@ let rec compile_match ctx apat cval case_label = | AP_id pid, (frag, ctyp) when is_ct_variant ctyp -> [ijump (F_op (F_field (frag, "kind"), "!=", F_lit ("Kind_" ^ Util.zencode_string (string_of_id pid))), CT_bool) case_label], [] + | AP_global (pid, _), _ -> [icopy (CL_id pid) cval], [] | AP_id pid, (frag, ctyp) when is_ct_enum ctyp -> [ijump (F_op (F_id pid, "!=", frag), CT_bool) case_label], [] | AP_id pid, _ -> let ctyp = cval_ctyp cval in - 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 + let init, cleanup = if is_stack_ctyp ctyp then [], [] else [ialloc ctyp pid], [iclear ctyp pid] in + [idecl ctyp pid] @ init @ [icopy (CL_id pid) cval], cleanup | AP_tup apats, (frag, ctyp) -> begin let get_tup n ctyp = (F_field (frag, "ztup" ^ string_of_int n), ctyp) in @@ -1134,7 +1207,7 @@ let rec compile_aexp ctx = function if is_stack_ctyp ctyp then [idecl ctyp id; call (CL_id id)], [] else - [ialloc ctyp id; call (CL_id id)], [iclear ctyp id] + [idecl 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 @@ -1249,7 +1322,7 @@ 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 - [ialloc ctyp gs] @ setup @ List.map (fun call -> call (CL_id gs)) calls, + [idecl ctyp gs; ialloc ctyp gs] @ setup @ List.map (fun call -> call (CL_id gs)) calls, ctyp, (fun clexp -> icopy clexp (F_id gs, ctyp)), cleanup @ [iclear ctyp gs] @@ -1336,6 +1409,7 @@ let rec pat_ids (P_aux (p_aux, (l, _)) as pat) = | P_lit (L_aux (L_unit, _)) -> let gs = gensym () in [gs] | P_wild -> let gs = gensym () in [gs] | P_var (pat, _) -> pat_ids pat + | P_typ (_, pat) -> pat_ids pat | _ -> c_error ~loc:l ("Cannot compile pattern " ^ string_of_pat pat ^ " to C") (** Compile a sail type definition into a IR one. Most of the @@ -1382,7 +1456,7 @@ let instr_split_at f = let generate_cleanup instrs = let generate_cleanup' (I_aux (instr, _)) = match instr with - | I_decl (ctyp, id) when not (is_stack_ctyp ctyp) -> [(id, iclear ctyp id)] + | I_init (ctyp, id, cval) 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 @@ -1510,6 +1584,8 @@ let fix_exception ctx instrs = let instrs = List.map (map_try_block (fix_exception_block ctx)) instrs in fix_exception_block ctx instrs +let letdef_count = ref 0 + (** Compile a Sail toplevel definition into an IR definition **) let compile_def ctx = function | DEF_reg_dec (DEC_aux (DEC_reg (typ, id), _)) -> @@ -1518,24 +1594,24 @@ let compile_def ctx = function | DEF_spec _ -> [], ctx - | DEF_fundef (FD_aux (FD_function (_, _, _, [FCL_aux (FCL_Funcl (id, pexp), _)]), _)) -> - begin - match pexp with - | Pat_aux (Pat_exp (pat, exp), _) -> - let aexp = map_functions (analyze_primop ctx) (c_literals ctx (anf exp)) in - let setup, ctyp, call, cleanup = compile_aexp ctx aexp in - let gs = gensym () in - if is_stack_ctyp ctyp then - 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 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 - end + | DEF_fundef (FD_aux (FD_function (_, _, _, [FCL_aux (FCL_Funcl (id, Pat_aux (Pat_exp (pat, exp), _)), _)]), _)) -> + let aexp = map_functions (analyze_primop ctx) (c_literals ctx (anf exp)) in + let setup, ctyp, call, cleanup = compile_aexp ctx aexp in + let gs = gensym () in + if is_stack_ctyp ctyp then + 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 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 + + | DEF_fundef (FD_aux (FD_function (_, _, _, []), (l, _))) -> + c_error ~loc:l "Encountered function with no clauses" + | DEF_fundef (FD_aux (FD_function (_, _, _, funcls), (l, _))) -> + c_error ~loc:l "Encountered function with multiple clauses" (* All abbreviations should expanded by the typechecker, so we don't need to translate type abbreviations into C typedefs. *) @@ -1545,6 +1621,40 @@ let compile_def ctx = function let tdef, ctx = compile_type_def ctx type_def in [CDEF_type tdef], ctx + | DEF_val (LB_aux (LB_val (pat, exp), _)) -> + let aexp = map_functions (analyze_primop ctx) (c_literals ctx (anf exp)) in + let setup, ctyp, call, cleanup = compile_aexp ctx aexp in + let apat = anf_pat ~global:true pat in + let gs = gensym () in + let end_label = label "let_end_" in + let destructure, destructure_cleanup = compile_match ctx apat (F_id gs, ctyp) end_label in + let gs_setup, gs_cleanup = + if is_stack_ctyp ctyp then [idecl ctyp gs], [] else + [idecl ctyp gs; ialloc ctyp gs], [iclear ctyp gs] + in + let bindings = List.map (fun (id, typ) -> id, ctyp_of_typ ctx typ) (apat_globals apat) in + let global_setup = + List.concat (List.map (fun (id, ctyp) -> if is_stack_ctyp ctyp then [] else [ialloc ctyp id]) bindings) + in + let global_cleanup = + List.concat (List.map (fun (id, ctyp) -> if is_stack_ctyp ctyp then [] else [iclear ctyp id]) bindings) + in + let n = !letdef_count in + incr letdef_count; + let instrs = + global_setup @ [icomment "gs_setup"] @ gs_setup @ [icomment "setup"] @ setup + @ [icomment "call"] + @ [call (CL_id gs)] + @ [icomment "cleanup"] + @ cleanup + @ [icomment "destructure"] + @ destructure + @ destructure_cleanup @ gs_cleanup + @ [ilabel end_label] + in + [CDEF_let (n, bindings, instrs, global_cleanup)], + { ctx with letbinds = n :: ctx.letbinds } + (* Only DEF_default that matters is default Order, but all order polymorphism is specialised by this point. *) | DEF_default _ -> [], ctx @@ -1854,9 +1964,7 @@ let rec codegen_instr ctx (I_aux (instr, _)) = (sgen_id id) (sgen_cval cval)) | I_alloc (ctyp, id) -> - string (Printf.sprintf " %s %s;" (sgen_ctyp ctyp) (sgen_id id)) - ^^ hardline - ^^ string (Printf.sprintf " init_%s(&%s);" (sgen_ctyp_name ctyp) (sgen_id id)) + string (Printf.sprintf " init_%s(&%s);" (sgen_ctyp_name ctyp) (sgen_id id)) | I_convert (x, ctyp1, y, ctyp2) -> if is_stack_ctyp ctyp1 then string (Printf.sprintf " %s = convert_%s_of_%s(%s);" @@ -2118,6 +2226,18 @@ let codegen_def' ctx = function | CDEF_type ctype_def -> codegen_type_def ctx ctype_def + | CDEF_let (number, bindings, instrs, cleanup) -> + let instrs = add_local_labels instrs in + separate_map hardline (fun (id, ctyp) -> string (Printf.sprintf "%s %s;" (sgen_ctyp ctyp) (sgen_id id))) bindings + ^^ hardline ^^ string (Printf.sprintf "void create_letbind_%d(void) " number) + ^^ string "{" + ^^ jump 0 2 (separate_map hardline (codegen_instr ctx) instrs) ^^ hardline + ^^ string "}" + ^^ hardline ^^ string (Printf.sprintf "void kill_letbind_%d(void) " number) + ^^ string "{" + ^^ jump 0 2 (separate_map hardline (codegen_instr ctx) cleanup) ^^ hardline + ^^ string "}" + let codegen_def ctx def = let untup = function | CT_tup ctyps -> ctyps @@ -2131,6 +2251,8 @@ let codegen_def ctx def = let compile_ast ctx (Defs defs) = try + let assert_vs = Initial_check.extern_of_string dec_ord (mk_id "assert") "(bool, string) -> unit effect {escape}" in + let ctx = { ctx with tc_env = snd (check ctx.tc_env (Defs [assert_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 docs = List.map (codegen_def ctx) cdefs in @@ -2139,16 +2261,31 @@ let compile_ast ctx (Defs defs) = [ string "#include \"sail.h\"" ] in - let postamble = separate hardline - [ string "int main(void)"; - string "{"; - string " current_exception = malloc(sizeof(struct zexception));"; - string " init_zexception(current_exception);"; - string " zmain(UNIT);"; - string " clear_zexception(current_exception);"; - string " free(current_exception);"; - string " if (have_exception) fprintf(stderr, \"Exiting due to uncaught exception\\n\");"; - string "}" ] + let exn_boilerplate = + if not (Bindings.mem (mk_id "exception") ctx.variants) then ([], []) else + ([ " current_exception = malloc(sizeof(struct zexception));"; + " init_zexception(current_exception);" ], + [ " clear_zexception(current_exception);"; + " free(current_exception);"; + " if (have_exception) fprintf(stderr, \"Exiting due to uncaught exception\\n\");" ]) + in + + let letbind_initializers = + List.map (fun n -> Printf.sprintf " create_letbind_%d();" n) (List.rev ctx.letbinds) + in + let letbind_finalizers = + List.map (fun n -> Printf.sprintf " kill_letbind_%d();" n) ctx.letbinds + in + + let postamble = separate hardline (List.map string + ( [ "int main(void)"; + "{" ] + @ fst exn_boilerplate + @ letbind_initializers + @ [ " zmain(UNIT);" ] + @ letbind_finalizers + @ snd exn_boilerplate + @ [ "}" ] )) in let hlhl = hardline ^^ hardline in diff --git a/src/initial_check.mli b/src/initial_check.mli index 197139f4..757959f7 100644 --- a/src/initial_check.mli +++ b/src/initial_check.mli @@ -61,7 +61,7 @@ val opt_magic_hash : bool ref back. Otherwise generated T_of_num and num_of_T functions must be manually used for each enum T *) val opt_enum_casts : bool ref - + (* This is a bit of a hack right now - it ensures that the undefiend builtins (undefined_vector etc), only get added to the ast once. The original assumption in sail is that the whole AST gets |
