summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBrian Campbell2018-03-30 15:15:47 +0100
committerBrian Campbell2018-04-04 14:45:00 +0100
commitc36900a7b95e14f9bcfa8b2c5687fbfd0f7fa6a5 (patch)
tree530da8b5efda4f52004b1c0e2b706654d9fb05da /src
parent20e5023944f97ba4aafb04ff32a3a937353225b4 (diff)
Initial rewrite to move complex nexps in fn sigs into constraints
(for monomorphisation, off for now because the analysis needs extended). Also tighten up orig_nexp, make Lem backend replace # in type variables.
Diffstat (limited to 'src')
-rw-r--r--src/monomorphise.ml171
-rw-r--r--src/monomorphise.mli1
-rw-r--r--src/pretty_print_lem.ml8
-rw-r--r--src/process_file.ml2
-rw-r--r--src/process_file.mli1
-rw-r--r--src/sail.ml3
-rw-r--r--src/type_check.ml22
7 files changed, 199 insertions, 9 deletions
diff --git a/src/monomorphise.ml b/src/monomorphise.ml
index be8ff5d4..8ff5dc20 100644
--- a/src/monomorphise.ml
+++ b/src/monomorphise.ml
@@ -3817,10 +3817,172 @@ let add_bitvector_casts (Defs defs) =
in Defs (List.map rewrite_def defs)
end
+let replace_nexp_in_typ env typ orig new_nexp =
+ let rec aux (Typ_aux (t,l) as typ) =
+ match t with
+ | Typ_id _
+ | Typ_var _
+ -> false, typ
+ | Typ_fn (arg,res,eff) ->
+ let f1, arg = aux arg in
+ let f2, res = aux res in
+ f1 || f2, Typ_aux (Typ_fn (arg, res, eff),l)
+ | Typ_tup typs ->
+ let fs, typs = List.split (List.map aux typs) in
+ List.exists (fun x -> x) fs, Typ_aux (Typ_tup typs,l)
+ | Typ_exist (kids,nc,typ') -> (* TODO avoid capture *)
+ let f, typ' = aux typ' in
+ f, Typ_aux (Typ_exist (kids,nc,typ'),l)
+ | Typ_app (id, targs) ->
+ let fs, targs = List.split (List.map aux_targ targs) in
+ List.exists (fun x -> x) fs, Typ_aux (Typ_app (id, targs),l)
+ and aux_targ (Typ_arg_aux (ta,l) as typ_arg) =
+ match ta with
+ | Typ_arg_nexp nexp ->
+ if prove env (nc_eq nexp orig)
+ then true, Typ_arg_aux (Typ_arg_nexp new_nexp,l)
+ else false, typ_arg
+ | Typ_arg_typ typ ->
+ let f, typ = aux typ in
+ f, Typ_arg_aux (Typ_arg_typ typ,l)
+ | Typ_arg_order _ -> false, typ_arg
+ in aux typ
+
+(* TODO: replace with more informative mangled name *)
+let fresh_top_kid =
+ let counter = ref 0 in
+ fun () ->
+ let n = !counter in
+ let () = counter := n+1 in
+ mk_kid ("mono#nexp#" ^ string_of_int n)
+
+let rewrite_toplevel_nexps (Defs defs) =
+ let find_nexp env nexp_map nexp =
+ let is_equal (kid,nexp') = prove env (nc_eq nexp nexp') in
+ List.find is_equal nexp_map
+ in
+ let rec rewrite_typ_in_spec env nexp_map (Typ_aux (t,ann) as typ_full) =
+ match t with
+ | Typ_fn (args,res,eff) ->
+ let nexp_map, args = rewrite_typ_in_spec env nexp_map args in
+ let nexp_map, res = rewrite_typ_in_spec env nexp_map res in
+ nexp_map, Typ_aux (Typ_fn (args,res,eff),ann)
+ | Typ_tup typs ->
+ let nexp_map, typs =
+ List.fold_right (fun typ (nexp_map,t) ->
+ let nexp_map, typ = rewrite_typ_in_spec env nexp_map typ in
+ (nexp_map, typ::t)) typs (nexp_map,[])
+ in nexp_map, Typ_aux (Typ_tup typs,ann)
+ | _ ->
+ let typ' = Env.base_typ_of env typ_full in
+ let nexp_opt =
+ match destruct_atom_nexp env typ' with
+ | Some nexp -> Some nexp
+ | None ->
+ if is_bitvector_typ typ' then
+ let (_,size,_,_) = vector_typ_args_of typ' in
+ Some size
+ else None
+ in match nexp_opt with
+ | None -> nexp_map, typ_full
+ | Some (Nexp_aux (Nexp_constant _,_))
+ | Some (Nexp_aux (Nexp_var _,_)) -> nexp_map, typ_full
+ | Some nexp ->
+ let nexp_map, kid =
+ match find_nexp env nexp_map nexp with
+ | (kid,_) -> nexp_map, kid
+ | exception Not_found ->
+ let kid = fresh_top_kid () in
+ (kid, nexp)::nexp_map, kid
+ in
+ let new_nexp = nvar kid in
+ (* Try to avoid expanding the original type *)
+ let changed, typ = replace_nexp_in_typ env typ_full nexp new_nexp in
+ if changed then nexp_map, typ
+ else nexp_map, snd (replace_nexp_in_typ env typ' nexp new_nexp)
+ in
+ let rewrite_valspec (VS_aux (VS_val_spec (TypSchm_aux (TypSchm_ts (tqs,typ),ts_l),id,ext_opt,is_cast),ann)) =
+ match tqs, ext_opt "lem" with (* does it really matter if this is wrong? *)
+ | _, Some _
+ | TypQ_aux (TypQ_no_forall,_), _ -> None
+ | TypQ_aux (TypQ_tq qs, tq_l), None ->
+ let env = env_of_annot ann in
+ let env = add_typquant tqs env in
+ let nexp_map, typ = rewrite_typ_in_spec env [] typ in
+ match nexp_map with
+ | [] -> None
+ | _ ->
+ let new_vars = List.map (fun (kid,nexp) -> QI_aux (QI_id (KOpt_aux (KOpt_none kid,Generated Unknown)), Generated tq_l)) nexp_map in
+ let new_constraints = List.map (fun (kid,nexp) -> QI_aux (QI_const (nc_eq (nvar kid) nexp), Generated tq_l)) nexp_map in
+ let tqs = TypQ_aux (TypQ_tq (qs @ new_vars @ new_constraints),tq_l) in
+ let vs =
+ VS_aux (VS_val_spec (TypSchm_aux (TypSchm_ts (tqs,typ),ts_l),id,ext_opt,is_cast),ann) in
+ Some (id, nexp_map, vs)
+ in
+ let rewrite_typ_in_body env nexp_map typ =
+ let rec aux (Typ_aux (t,l) as typ_full) =
+ match t with
+ | Typ_tup typs -> Typ_aux (Typ_tup (List.map aux typs),l)
+ | Typ_exist (kids,nc,typ') -> (* TODO: avoid shadowing *)
+ Typ_aux (Typ_exist (kids,(* TODO? *) nc, aux typ'),l)
+ | Typ_app (id,targs) -> Typ_aux (Typ_app (id,List.map aux_targ targs),l)
+ | _ -> typ_full
+ and aux_targ (Typ_arg_aux (ta,l) as ta_full) =
+ match ta with
+ | Typ_arg_typ typ -> Typ_arg_aux (Typ_arg_typ (aux typ),l)
+ | Typ_arg_order _ -> ta_full
+ | Typ_arg_nexp nexp ->
+ match find_nexp env nexp_map nexp with
+ | (kid,_) -> Typ_arg_aux (Typ_arg_nexp (nvar kid),l)
+ | exception Not_found -> ta_full
+ in aux typ
+ in
+ let rewrite_one_exp nexp_map (e,ann) =
+ match e with
+ | E_cast (typ,e') -> E_aux (E_cast (rewrite_typ_in_body (env_of_annot ann) nexp_map typ,e'),ann)
+ | E_sizeof nexp ->
+ (match find_nexp (env_of_annot ann) nexp_map nexp with
+ | (kid,_) -> E_aux (E_sizeof (nvar kid),ann)
+ | exception Not_found -> E_aux (e,ann))
+ | _ -> E_aux (e,ann)
+ in
+ let rewrite_one_pat nexp_map (p,ann) =
+ match p with
+ | P_typ (typ,p') -> P_aux (P_typ (rewrite_typ_in_body (env_of_annot ann) nexp_map typ,p'),ann)
+ | _ -> P_aux (p,ann)
+ in
+ let rewrite_body nexp_map pexp =
+ let open Rewriter in
+ fold_pexp { id_exp_alg with
+ e_aux = rewrite_one_exp nexp_map;
+ pat_alg = { id_pat_alg with p_aux = rewrite_one_pat nexp_map }
+ } pexp
+ in
+ let rewrite_funcl spec_map (FCL_aux (FCL_Funcl (id,pexp),ann) as funcl) =
+ match Bindings.find id spec_map with
+ | nexp_map -> FCL_aux (FCL_Funcl (id,rewrite_body nexp_map pexp),ann)
+ | exception Not_found -> funcl
+ in
+ let rewrite_def spec_map def =
+ match def with
+ | DEF_spec vs -> (match rewrite_valspec vs with
+ | None -> spec_map, def
+ | Some (id, nexp_map, vs) -> Bindings.add id nexp_map spec_map, DEF_spec vs)
+ | DEF_fundef (FD_aux (FD_function (recopt,tann,eff,funcls),ann)) ->
+ spec_map,
+ DEF_fundef (FD_aux (FD_function (recopt,tann,eff,List.map (rewrite_funcl spec_map) funcls),ann))
+ | _ -> spec_map, def
+ in
+ let _, defs = List.fold_left (fun (spec_map,t) def ->
+ let spec_map, def = rewrite_def spec_map def in
+ (spec_map, def::t)) (Bindings.empty, []) defs
+ in Defs (List.rev defs)
+
type options = {
auto : bool;
debug_analysis : int;
rewrites : bool;
+ rewrite_toplevel_nexps : bool;
rewrite_size_parameters : bool;
all_split_errors : bool;
continue_anyway : bool;
@@ -3835,14 +3997,17 @@ let recheck defs =
r
let monomorphise opts splits env defs =
+ let defs =
+ if opts.rewrite_toplevel_nexps
+ then rewrite_toplevel_nexps defs
+ else defs
+ in
let (defs,env) =
if opts.rewrites then
let defs = MonoRewrites.mono_rewrite defs in
- (* TODO: is this necessary? *)
recheck defs
- else (defs,env)
+ else recheck defs
in
-(*let _ = Pretty_print.pp_defs stdout defs in*)
let ok_analysis, new_splits, extra_splits =
if opts.auto
then
diff --git a/src/monomorphise.mli b/src/monomorphise.mli
index 3e561e32..3baa7d12 100644
--- a/src/monomorphise.mli
+++ b/src/monomorphise.mli
@@ -52,6 +52,7 @@ type options = {
auto : bool; (* Analyse ast to find splits for monomorphisation *)
debug_analysis : int; (* Debug output level for the automatic analysis *)
rewrites : bool; (* Experimental rewrites for variable-sized operations *)
+ rewrite_toplevel_nexps : bool; (* Move complex nexps in function signatures into constraints *)
rewrite_size_parameters : bool; (* Make implicit type parameters explicit for (e.g.) lem *)
all_split_errors : bool;
continue_anyway : bool;
diff --git a/src/pretty_print_lem.ml b/src/pretty_print_lem.ml
index 79eada3b..97b618e8 100644
--- a/src/pretty_print_lem.ml
+++ b/src/pretty_print_lem.ml
@@ -170,15 +170,19 @@ let is_regtyp (Typ_aux (typ, _)) env = match typ with
| _ -> false
let doc_nexp_lem nexp =
+ let nice_kid kid =
+ let (Kid_aux (Var kid,l)) = orig_kid kid in
+ Kid_aux (Var (String.map (function '#' -> '_' | c -> c) kid),l)
+ in
let (Nexp_aux (nexp, l) as full_nexp) = nexp_simp nexp in
match nexp with
| Nexp_constant i -> string ("ty" ^ Big_int.to_string i)
- | Nexp_var v -> string (string_of_kid (orig_kid v))
+ | Nexp_var v -> string (string_of_kid (nice_kid v))
| _ ->
let rec mangle_nexp (Nexp_aux (nexp, _)) = begin
match nexp with
| Nexp_id id -> string_of_id id
- | Nexp_var kid -> string_of_id (id_of_kid (orig_kid kid))
+ | Nexp_var kid -> string_of_id (id_of_kid (nice_kid kid))
| Nexp_constant i -> Pretty_print_lem_ast.lemnum Big_int.to_string i
| Nexp_times (n1, n2) -> mangle_nexp n1 ^ "_times_" ^ mangle_nexp n2
| Nexp_sum (n1, n2) -> mangle_nexp n1 ^ "_plus_" ^ mangle_nexp n2
diff --git a/src/process_file.ml b/src/process_file.ml
index ffd61fae..e9d04c5b 100644
--- a/src/process_file.ml
+++ b/src/process_file.ml
@@ -190,6 +190,7 @@ let opt_ddump_raw_mono_ast = ref false
let opt_dmono_analysis = ref 0
let opt_auto_mono = ref false
let opt_mono_rewrites = ref false
+let opt_mono_complex_nexps = ref false
let opt_dall_split_errors = ref false
let opt_dmono_continue = ref false
@@ -199,6 +200,7 @@ let monomorphise_ast locs type_env ast =
auto = !opt_auto_mono;
debug_analysis = !opt_dmono_analysis;
rewrites = !opt_mono_rewrites;
+ rewrite_toplevel_nexps = !opt_mono_complex_nexps;
rewrite_size_parameters = !Pretty_print_lem.opt_mwords;
all_split_errors = !opt_dall_split_errors;
continue_anyway = !opt_dmono_continue;
diff --git a/src/process_file.mli b/src/process_file.mli
index 54415621..2f418ff9 100644
--- a/src/process_file.mli
+++ b/src/process_file.mli
@@ -75,6 +75,7 @@ val opt_dmono_analysis : int ref
val opt_dmono_continue : bool ref
val opt_auto_mono : bool ref
val opt_mono_rewrites : bool ref
+val opt_mono_complex_nexps : bool ref
val opt_dall_split_errors : bool ref
type out_type =
diff --git a/src/sail.ml b/src/sail.ml
index 61e38f8a..2632f9a4 100644
--- a/src/sail.ml
+++ b/src/sail.ml
@@ -164,6 +164,9 @@ let options = Arg.align ([
( "-mono_rewrites",
Arg.Set Process_file.opt_mono_rewrites,
" turn on rewrites for combining bitvector operations");
+ ( "-mono_complex_nexps",
+ Arg.Set Process_file.opt_mono_complex_nexps,
+ " move complex size expressions in function signatures into constraints");
( "-dall_split_errors",
Arg.Set Process_file.opt_dall_split_errors,
" display all case split errors from monomorphisation, rather than one");
diff --git a/src/type_check.ml b/src/type_check.ml
index 06fbed0a..760345a6 100644
--- a/src/type_check.ml
+++ b/src/type_check.ml
@@ -140,7 +140,9 @@ let string_of_bind (typquant, typ) = string_of_typquant typquant ^ ". " ^ string
let orig_kid (Kid_aux (Var v, l) as kid) =
try
let i = String.rindex v '#' in
- Kid_aux (Var ("'" ^ String.sub v (i + 1) (String.length v - i - 1)), l)
+ if i >= 3 && String.sub v 0 3 = "'fv" then
+ Kid_aux (Var ("'" ^ String.sub v (i + 1) (String.length v - i - 1)), l)
+ else kid
with
| Not_found -> kid
@@ -3553,7 +3555,13 @@ let infer_funtyp l env tannotopt funcls =
end
| Typ_annot_opt_aux (Typ_annot_opt_none, _) -> typ_error l "Cannot infer function type for unannotated function"
-let mk_val_spec typq typ id = DEF_spec (VS_aux (VS_val_spec (TypSchm_aux (TypSchm_ts (typq, typ), Parse_ast.Unknown), id, (fun _ -> None), false), (Parse_ast.Unknown, None)))
+let mk_val_spec env typq typ id =
+ let eff =
+ match typ with
+ | Typ_aux (Typ_fn (_,_,eff),_) -> eff
+ | _ -> no_effect
+ in
+ DEF_spec (VS_aux (VS_val_spec (TypSchm_aux (TypSchm_ts (typq, typ), Parse_ast.Unknown), id, (fun _ -> None), false), (Parse_ast.Unknown, Some (env,typ,eff))))
let check_tannotopt env typq ret_typ = function
| Typ_annot_opt_aux (Typ_annot_opt_none, _) -> ()
@@ -3595,7 +3603,7 @@ let check_fundef env (FD_aux (FD_function (recopt, tannotopt, effectopt, funcls)
if not have_val_spec
then
let typ = Typ_aux (Typ_fn (vtyp_arg, vtyp_ret, eff), vl) in
- [mk_val_spec quant typ id], Env.add_val_spec id (quant, typ) env, eff
+ [mk_val_spec env quant typ id], Env.add_val_spec id (quant, typ) env, eff
else [], env, declared_eff
in
let env = Env.define_val_spec id env in
@@ -3608,6 +3616,7 @@ let check_fundef env (FD_aux (FD_function (recopt, tannotopt, effectopt, funcls)
context. We have to destructure the various kinds of val specs, but
the difference is irrelevant for the typechecker. *)
let check_val_spec env (VS_aux (vs, (l, _))) =
+ let annotate vs typ eff = DEF_spec (VS_aux (vs, (l, Some (env,typ,eff)))) in
let (id, quants, typ, env) = match vs with
| VS_val_spec (TypSchm_aux (TypSchm_ts (quants, typ), _) as typschm, id, ext_opt, is_cast) ->
typ_debug ("VS typschm: " ^ string_of_id id ^ ", " ^ string_of_typschm typschm);
@@ -3623,7 +3632,12 @@ let check_val_spec env (VS_aux (vs, (l, _))) =
let env = if is_cast then Env.add_cast id env else env in
(id, quants, typ, env)
in
- [DEF_spec (VS_aux (vs, (l, None)))], Env.add_val_spec id (quants, Env.expand_synonyms (add_typquant quants env) typ) env
+ let eff =
+ match typ with
+ | Typ_aux (Typ_fn (_,_,eff),_) -> eff
+ | _ -> no_effect
+ in
+ [annotate vs typ eff], Env.add_val_spec id (quants, Env.expand_synonyms (add_typquant quants env) typ) env
let check_default env (DT_aux (ds, l)) =
match ds with