diff options
Diffstat (limited to 'src/spec_analysis.ml')
| -rw-r--r-- | src/spec_analysis.ml | 186 |
1 files changed, 92 insertions, 94 deletions
diff --git a/src/spec_analysis.ml b/src/spec_analysis.ml index 8cb5a796..bdbc031a 100644 --- a/src/spec_analysis.ml +++ b/src/spec_analysis.ml @@ -42,10 +42,9 @@ open Ast open Util -open Big_int -open Type_internal +open Ast_util -type typ = Type_internal.t +module Nameset = Set.Make(String) let mt = Nameset.empty @@ -58,7 +57,7 @@ let set_to_string n = (*Query a spec for its default order if one is provided. Assumes Inc if not *) -let get_default_order_sp (DT_aux(spec,_)) = +(* let get_default_order_sp (DT_aux(spec,_)) = match spec with | DT_order (Ord_aux(o,_)) -> (match o with @@ -77,11 +76,11 @@ let rec default_order (Defs defs) = | def::defs -> match get_default_order_def def with | None -> default_order (Defs defs) - | Some o -> o + | Some o -> o *) (*Is within range*) -let check_in_range (candidate : big_int) (range : typ) : bool = +(* let check_in_range (candidate : big_int) (range : typ) : bool = match range.t with | Tapp("range", [TA_nexp min; TA_nexp max]) | Tabbrev(_,{t=Tapp("range", [TA_nexp min; TA_nexp max])}) -> let min,max = @@ -182,21 +181,18 @@ let is_within_range candidate range constraints = | _ -> Maybe) | _ -> Maybe -let is_within_machine64 candidate constraints = is_within_range candidate int64_t constraints +let is_within_machine64 candidate constraints = is_within_range candidate int64_t constraints *) (************************************************************************************************) (*FV finding analysis: identifies the free variables of a function, expression, etc *) -let id_to_string (Ast.Id_aux (i,_)) = match i with - | Ast.Id s | Ast.DeIid s -> s - let conditional_add typ_or_exp bound used id = let known_list = if typ_or_exp (*true for typ*) - then ["bit";"vector";"unit";"string";"int";"bool";"boolean"] + then ["bit";"vector";"unit";"string";"int";"bool"] else ["=="; "!="; "|";"~";"&";"add_int"] in - let i = (id_to_string id) in - if Nameset.mem i bound || List.mem i known_list + let i = (string_of_id id) in + if Nameset.mem i bound || List.mem i known_list then used else Nameset.add i used @@ -207,39 +203,32 @@ let conditional_add_exp = conditional_add false let nameset_bigunion = List.fold_left Nameset.union mt -let rec free_type_names_t consider_var {t = t} = match t with - | Tvar name -> if consider_var then Nameset.add name mt else mt - | Tid name -> Nameset.add name mt - | Tfn (t1,t2,_,_) -> Nameset.union (free_type_names_t consider_var t1) - (free_type_names_t consider_var t2) - | Ttup ts -> free_type_names_ts consider_var ts - | Tapp (name,targs) -> Nameset.add name (free_type_names_t_args consider_var targs) - | Tabbrev (t1,t2) -> Nameset.union (free_type_names_t consider_var t1) +let rec free_type_names_t consider_var (Typ_aux (t, _)) = match t with + | Typ_var name -> if consider_var then Nameset.add (string_of_kid name) mt else mt + | Typ_id name -> Nameset.add (string_of_id name) mt + | Typ_fn (t1,t2,_) -> Nameset.union (free_type_names_t consider_var t1) (free_type_names_t consider_var t2) - | Toptions (t,m_t) -> Nameset.union (free_type_names_t consider_var t) - (free_type_names_maybe_t consider_var m_t) - | Tuvar _ -> mt + | Typ_tup ts -> free_type_names_ts consider_var ts + | Typ_app (name,targs) -> Nameset.add (string_of_id name) (free_type_names_t_args consider_var targs) + | Typ_exist (kids,_,t') -> List.fold_left (fun s kid -> Nameset.remove (string_of_kid kid) s) (free_type_names_t consider_var t') kids and free_type_names_ts consider_var ts = nameset_bigunion (List.map (free_type_names_t consider_var) ts) and free_type_names_maybe_t consider_var = function | Some t -> free_type_names_t consider_var t | None -> mt and free_type_names_t_arg consider_var = function - | TA_typ t -> free_type_names_t consider_var t + | Typ_arg_aux (Typ_arg_typ t, _) -> free_type_names_t consider_var t | _ -> mt and free_type_names_t_args consider_var targs = nameset_bigunion (List.map (free_type_names_t_arg consider_var) targs) let rec free_type_names_tannot consider_var = function - | NoTyp -> mt - | Base ((_,t),_ ,_,_,_,_) -> free_type_names_t consider_var t - | Overload (tannot,_,tannots) -> - nameset_bigunion (List.map (free_type_names_tannot consider_var) (tannot :: tannots)) + | None -> mt + | Some (_, t, _) -> free_type_names_t consider_var t let rec fv_of_typ consider_var bound used (Typ_aux (t,_)) : Nameset.t = match t with - | Typ_wild -> used | Typ_var (Kid_aux (Var v,l)) -> if consider_var then conditional_add_typ bound used (Ast.Id_aux (Ast.Id v,l)) @@ -248,7 +237,8 @@ let rec fv_of_typ consider_var bound used (Typ_aux (t,_)) : Nameset.t = | Typ_fn(arg,ret,_) -> fv_of_typ consider_var bound (fv_of_typ consider_var bound used arg) ret | Typ_tup ts -> List.fold_right (fun t n -> fv_of_typ consider_var bound n t) ts used | Typ_app(id,targs) -> - List.fold_right (fun ta n -> fv_of_targ consider_var bound n ta) targs (conditional_add_typ bound used id) + List.fold_right (fun ta n -> fv_of_targ consider_var bound n ta) targs (conditional_add_typ bound used id) + | Typ_exist (kids,_,t') -> fv_of_typ consider_var (List.fold_left (fun b (Kid_aux (Var v,_)) -> Nameset.add v b) bound kids) used t' and fv_of_targ consider_var bound used (Ast.Typ_arg_aux(targ,_)) : Nameset.t = match targ with | Typ_arg_typ t -> fv_of_typ consider_var bound used t @@ -285,22 +275,20 @@ let rec pat_bindings consider_var bound used (P_aux(p,(_,tannot))) = let list_fv bound used ps = List.fold_right (fun p (b,n) -> pat_bindings consider_var b n p) ps (bound, used) in match p with | P_as(p,id) -> let b,ns = pat_bindings consider_var bound used p in - Nameset.add (id_to_string id) b,ns + Nameset.add (string_of_id id) b,ns | P_typ(t,p) -> let used = Nameset.union (free_type_names_tannot consider_var tannot) used in let ns = fv_of_typ consider_var bound used t in pat_bindings consider_var bound ns p | P_id id -> let used = Nameset.union (free_type_names_tannot consider_var tannot) used in - Nameset.add (id_to_string id) bound,used + Nameset.add (string_of_id id) bound,used | P_app(id,pats) -> let used = Nameset.union (free_type_names_tannot consider_var tannot) used in - list_fv bound (Nameset.add (id_to_string id) used) pats + list_fv bound (Nameset.add (string_of_id id) used) pats | P_record(fpats,_) -> List.fold_right (fun (Ast.FP_aux(Ast.FP_Fpat(_,p),_)) (b,n) -> pat_bindings consider_var bound used p) fpats (bound,used) | P_vector pats | Ast.P_vector_concat pats | Ast.P_tup pats | Ast.P_list pats -> list_fv bound used pats - | P_vector_indexed ipats -> - List.fold_right (fun (_,p) (b,n) -> pat_bindings consider_var b n p) ipats (bound,used) | _ -> bound,used let rec fv_of_exp consider_var bound used set (E_aux (e,(_,tannot))) : (Nameset.t * Nameset.t * Nameset.t) = @@ -324,14 +312,8 @@ let rec fv_of_exp consider_var bound used set (E_aux (e,(_,tannot))) : (Nameset. | E_if(c,t,e) -> list_fv bound used set [c;t;e] | E_for(id,from,to_,by,_,body) -> let _,used,set = list_fv bound used set [from;to_;by] in - fv_of_exp consider_var (Nameset.add (id_to_string id) bound) used set body - | E_vector_indexed (es_i,(Ast.Def_val_aux(default,_))) -> - let bound,used,set = - List.fold_right - (fun (_,e) (b,u,s) -> fv_of_exp consider_var b u s e) es_i (bound,used,set) in - (match default with - | Def_val_empty -> bound,used,set - | Def_val_dec e -> fv_of_exp consider_var bound used set e) + fv_of_exp consider_var (Nameset.add (string_of_id id) bound) used set body + | E_loop(_, cond, body) -> list_fv bound used set [cond; body] | E_vector_access(v,i) -> list_fv bound used set [v;i] | E_vector_subrange(v,i1,i2) -> list_fv bound used set [v;i1;i2] | E_vector_update(v,i,e) -> list_fv bound used set [v;i;e] @@ -358,6 +340,7 @@ let rec fv_of_exp consider_var bound used set (E_aux (e,(_,tannot))) : (Nameset. b,used,set | E_exit e -> fv_of_exp consider_var bound used set e | E_assert(c,m) -> list_fv bound used set [c;m] + | E_return e -> fv_of_exp consider_var bound used set e | _ -> bound,used,set and fv_of_pes consider_var bound used set pes = @@ -367,14 +350,14 @@ and fv_of_pes consider_var bound used set pes = let bound_p,us_p = pat_bindings consider_var bound used p in let bound_e,us_e,set_e = fv_of_exp consider_var bound_p us_p set e in fv_of_pes consider_var bound us_e set_e pes + | Pat_aux(Pat_when (p,g,e),_)::pes -> + let bound_p,us_p = pat_bindings consider_var bound used p in + let bound_g,us_g,set_g = fv_of_exp consider_var bound_p us_p set g in + let bound_e,us_e,set_e = fv_of_exp consider_var bound_g us_g set_g e in + fv_of_pes consider_var bound us_e set_e pes and fv_of_let consider_var bound used set (LB_aux(lebind,_)) = match lebind with - | LB_val_explicit(typsch,pat,exp) -> - let bound_t,us_t = fv_of_typschm consider_var bound used typsch in - let bound_p, us_p = pat_bindings consider_var (Nameset.union bound bound_t) used pat in - let _,us_e,set_e = fv_of_exp consider_var (Nameset.union bound bound_t) used set exp in - (Nameset.union bound_t bound_p),Nameset.union us_t (Nameset.union us_p us_e),set_e - | LB_val_implicit(pat,exp) -> + | LB_val(pat,exp) -> let bound_p, us_p = pat_bindings consider_var bound used pat in let _,us_e,set_e = fv_of_exp consider_var bound used set exp in bound_p,Nameset.union us_p us_e,set_e @@ -383,13 +366,13 @@ and fv_of_lexp consider_var bound used set (LEXP_aux(lexp,(_,tannot))) = match lexp with | LEXP_id id -> let used = Nameset.union (free_type_names_tannot consider_var tannot) used in - let i = id_to_string id in + let i = string_of_id id in if Nameset.mem i bound then bound, used, Nameset.add i set else Nameset.add i bound, Nameset.add i used, set | LEXP_cast(typ,id) -> let used = Nameset.union (free_type_names_tannot consider_var tannot) used in - let i = id_to_string id in + let i = string_of_id id in let used_t = fv_of_typ consider_var bound used typ in if Nameset.mem i bound then bound, used_t, Nameset.add i set @@ -401,7 +384,7 @@ and fv_of_lexp consider_var bound used set (LEXP_aux(lexp,(_,tannot))) = List.fold_right (fun e (b,u,s) -> fv_of_exp consider_var b u s e) args (bound,used,set) in - bound,Nameset.add (id_to_string id) used,set + bound,Nameset.add (string_of_id id) used,set | LEXP_field(lexp,_) -> fv_of_lexp consider_var bound used set lexp | LEXP_vector(lexp,exp) -> let bound_l,used,set = fv_of_lexp consider_var bound used set lexp in @@ -418,47 +401,36 @@ let init_env s = Nameset.singleton s let typ_variants consider_var bound tunions = List.fold_right (fun (Tu_aux(t,_)) (b,n) -> match t with - | Tu_id id -> Nameset.add (id_to_string id) b,n - | Tu_ty_id(t,id) -> Nameset.add (id_to_string id) b, fv_of_typ consider_var b n t) + | Tu_id id -> Nameset.add (string_of_id id) b,n + | Tu_ty_id(t,id) -> Nameset.add (string_of_id id) b, fv_of_typ consider_var b n t) tunions (bound,mt) let fv_of_kind_def consider_var (KD_aux(k,_)) = match k with - | KD_nabbrev(_,id,_,nexp) -> init_env (id_to_string id), fv_of_nexp consider_var mt mt nexp - | KD_abbrev(_,id,_,typschm) -> - init_env (id_to_string id), snd (fv_of_typschm consider_var mt mt typschm) - | KD_record(_,id,_,typq,tids,_) -> - let binds = init_env (id_to_string id) in - let bounds = if consider_var then typq_bindings typq else mt in - binds, List.fold_right (fun (t,_) n -> fv_of_typ consider_var bounds n t) tids mt - | KD_variant(_,id,_,typq,tunions,_) -> - let bindings = Nameset.add (id_to_string id) (if consider_var then typq_bindings typq else mt) in - typ_variants consider_var bindings tunions - | KD_enum(_,id,_,ids,_) -> - Nameset.of_list (List.map id_to_string (id::ids)),mt - | KD_register(_,id,n1,n2,_) -> - init_env (id_to_string id), fv_of_nexp consider_var mt (fv_of_nexp consider_var mt mt n1) n2 + | KD_nabbrev(_,id,_,nexp) -> init_env (string_of_id id), fv_of_nexp consider_var mt mt nexp let fv_of_type_def consider_var (TD_aux(t,_)) = match t with - | TD_abbrev(id,_,typschm) -> init_env (id_to_string id), snd (fv_of_typschm consider_var mt mt typschm) + | TD_abbrev(id,_,typschm) -> init_env (string_of_id id), snd (fv_of_typschm consider_var mt mt typschm) | TD_record(id,_,typq,tids,_) -> - let binds = init_env (id_to_string id) in + let binds = init_env (string_of_id id) in let bounds = if consider_var then typq_bindings typq else mt in binds, List.fold_right (fun (t,_) n -> fv_of_typ consider_var bounds n t) tids mt | TD_variant(id,_,typq,tunions,_) -> - let bindings = Nameset.add (id_to_string id) (if consider_var then typq_bindings typq else mt) in + let bindings = Nameset.add (string_of_id id) (if consider_var then typq_bindings typq else mt) in typ_variants consider_var bindings tunions | TD_enum(id,_,ids,_) -> - Nameset.of_list (List.map id_to_string (id::ids)),mt + Nameset.of_list (List.map string_of_id (id::ids)),mt | TD_register(id,n1,n2,_) -> - init_env (id_to_string id), fv_of_nexp consider_var mt (fv_of_nexp consider_var mt mt n1) n2 + init_env (string_of_id id), fv_of_nexp consider_var mt (fv_of_nexp consider_var mt mt n1) n2 let fv_of_tannot_opt consider_var (Typ_annot_opt_aux (t,_)) = match t with | Typ_annot_opt_some (typq,typ) -> let bindings = if consider_var then typq_bindings typq else mt in let free = fv_of_typ consider_var bindings mt typ in - (bindings,free) + (bindings,free) + | Typ_annot_opt_none -> + (mt, mt) (*Unlike the other fv, the bound returns are the names bound by the pattern for use in the exp*) let fv_of_funcl consider_var base_bounds (FCL_aux(FCL_Funcl(id,pat,exp),l)) = @@ -466,10 +438,10 @@ let fv_of_funcl consider_var base_bounds (FCL_aux(FCL_Funcl(id,pat,exp),l)) = let _, exp_ns, exp_sets = fv_of_exp consider_var pat_bs pat_ns mt exp in (pat_bs,exp_ns,exp_sets) -let fv_of_fun consider_var (FD_aux (FD_function(rec_opt,tannot_opt,_,funcls),_)) = +let fv_of_fun consider_var (FD_aux (FD_function(rec_opt,tannot_opt,_,funcls),_) as fd) = let fun_name = match funcls with | [] -> failwith "fv_of_fun fell off the end looking for the function name" - | FCL_aux(FCL_Funcl(id,_,_),_)::_ -> id_to_string id in + | FCL_aux(FCL_Funcl(id,_,_),_)::_ -> string_of_id id in let base_bounds = match rec_opt with | Rec_aux(Ast.Rec_rec,_) -> init_env fun_name | _ -> mt in @@ -477,16 +449,20 @@ let fv_of_fun consider_var (FD_aux (FD_function(rec_opt,tannot_opt,_,funcls),_)) | Typ_annot_opt_aux(Typ_annot_opt_some (typq, typ),_) -> let bindings = if consider_var then typq_bindings typq else mt in let bound = Nameset.union bindings base_bounds in - bound, fv_of_typ consider_var bound mt typ in + bound, fv_of_typ consider_var bound mt typ + | Typ_annot_opt_aux(Typ_annot_opt_none, _) -> + base_bounds, mt in let ns = List.fold_right (fun (FCL_aux(FCL_Funcl(_,pat,exp),_)) ns -> let pat_bs,pat_ns = pat_bindings consider_var base_bounds ns pat in let _, exp_ns,_ = fv_of_exp consider_var pat_bs pat_ns Nameset.empty exp in exp_ns) funcls mt in - init_env fun_name,Nameset.union ns ns_r + let ns_vs = init_env ("val:" ^ (string_of_id (id_of_fundef fd))) in + (* let _ = Printf.eprintf "Function %s uses %s\n" fun_name (set_to_string (Nameset.union ns ns_r)) in *) + init_env fun_name, Nameset.union ns_vs (Nameset.union ns ns_r) let fv_of_vspec consider_var (VS_aux(vspec,_)) = match vspec with - | VS_val_spec(ts,id) | VS_extern_no_rename (ts,id) | VS_extern_spec(ts,id,_)-> - init_env ("val:" ^ (id_to_string id)), snd (fv_of_typschm consider_var mt mt ts) + | VS_val_spec(ts,id,_,_) -> + init_env ("val:" ^ (string_of_id id)), snd (fv_of_typschm consider_var mt mt ts) let rec find_scattered_of name = function | [] -> [] @@ -495,7 +471,7 @@ let rec find_scattered_of name = function | SD_scattered_function(_,_,_,id) | SD_scattered_funcl(FCL_aux(FCL_Funcl(id,_,_),_)) | SD_scattered_unioncl(id,_) -> - if name = id_to_string id + if name = string_of_id id then [sd] else [] | _ -> [])@ (find_scattered_of name defs) @@ -506,17 +482,19 @@ let rec fv_of_scattered consider_var consider_scatter_as_one all_defs (SD_aux(sd let b,ns = (match tannot_opt with | Typ_annot_opt_aux(Typ_annot_opt_some (typq, typ),_) -> let bindings = if consider_var then typq_bindings typq else mt in - bindings, fv_of_typ consider_var bindings mt typ) in - init_env (id_to_string id),ns + bindings, fv_of_typ consider_var bindings mt typ + | Typ_annot_opt_aux(Typ_annot_opt_none, _) -> + mt, mt) in + init_env (string_of_id id),ns | SD_scattered_funcl (FCL_aux(FCL_Funcl(id,pat,exp),_)) -> let pat_bs,pat_ns = pat_bindings consider_var mt mt pat in let _,exp_ns,_ = fv_of_exp consider_var pat_bs pat_ns Nameset.empty exp in let scattered_binds = match pat with - | P_aux(P_app(pid,_),_) -> init_env ((id_to_string id) ^ "/" ^ (id_to_string pid)) + | P_aux(P_app(pid,_),_) -> init_env ((string_of_id id) ^ "/" ^ (string_of_id pid)) | _ -> mt in scattered_binds, exp_ns | SD_scattered_variant (id,_,_) -> - let name = id_to_string id in + let name = string_of_id id in let uses = if consider_scatter_as_one then @@ -528,12 +506,12 @@ let rec fv_of_scattered consider_var consider_scatter_as_one all_defs (SD_aux(sd else mt in init_env name, uses | SD_scattered_unioncl(id, type_union) -> - let typ_name = id_to_string id in + let typ_name = string_of_id id in let b = init_env typ_name in let (b,r) = typ_variants consider_var b [type_union] in (Nameset.remove typ_name b, Nameset.add typ_name r) | SD_scattered_end id -> - let name = id_to_string id in + let name = string_of_id id in let uses = if consider_scatter_as_one (*Note: if this is a function ending, the dec is included *) then @@ -545,11 +523,11 @@ let rec fv_of_scattered consider_var consider_scatter_as_one all_defs (SD_aux(sd let fv_of_rd consider_var (DEC_aux (d,_)) = match d with | DEC_reg(t,id) -> - init_env (id_to_string id), fv_of_typ consider_var mt mt t + init_env (string_of_id id), fv_of_typ consider_var mt mt t | DEC_alias(id,alias) -> - init_env (id_to_string id),mt + init_env (string_of_id id),mt | DEC_typ_alias(t,id,alias) -> - init_env (id_to_string id), mt + init_env (string_of_id id), mt let fv_of_def consider_var consider_scatter_as_one all_defs = function | DEF_kind kdef -> fv_of_kind_def consider_var kdef @@ -557,6 +535,8 @@ let fv_of_def consider_var consider_scatter_as_one all_defs = function | DEF_fundef fdef -> fv_of_fun consider_var fdef | DEF_val lebind -> ((fun (b,u,_) -> (b,u)) (fv_of_let consider_var mt mt mt lebind)) | DEF_spec vspec -> fv_of_vspec consider_var vspec + | DEF_fixity _ -> mt,mt + | DEF_overload (id,ids) -> init_env (string_of_id id), List.fold_left (fun ns id -> Nameset.add (string_of_id id) ns) mt ids | DEF_default def -> mt,mt | DEF_scattered sdef -> fv_of_scattered consider_var consider_scatter_as_one all_defs sdef | DEF_reg_dec rdec -> fv_of_rd consider_var rdec @@ -596,6 +576,20 @@ let rec print_dependencies orig_queue work_queue names = print_dependencies orig_queue orig_queue uses)); print_dependencies orig_queue wq names +let merge_mutrecs defs = + let merge_aux ((binds', uses'), def) ((binds, uses), fundefs) = + let fundefs = match def with + | DEF_fundef fundef -> fundef :: fundefs + | DEF_internal_mutrec fundefs' -> fundefs' @ fundefs + | _ -> + (* let _ = Pretty_print_sail2.pp_defs stderr (Defs [def]) in *) + raise (Reporting_basic.err_unreachable (def_loc def) + "Trying to merge non-function definition with mutually recursive functions") in + (* let _ = Printf.eprintf " - Merging %s (using %s)\n" (set_to_string binds') (set_to_string uses') in *) + ((Nameset.union binds' binds, Nameset.union uses' uses), fundefs) in + let ((binds, uses), fundefs) = List.fold_right merge_aux defs ((mt, mt), []) in + ((binds, uses), DEF_internal_mutrec fundefs) + let rec topological_sort work_queue defs = match work_queue with | [] -> List.rev defs @@ -609,11 +603,15 @@ let rec topological_sort work_queue defs = else match List.stable_sort compare_dbts work_queue with (*We wait to sort until there are no 0 dependency nodes on top*) | [] -> failwith "sort shrunk the list???" - | (((n,uses),_)::_) as wq -> + | (((n,uses),def)::rest) as wq -> if (Nameset.cardinal uses = 0) then topological_sort wq defs - else let _ = Printf.eprintf "Uses on failure are %s, binds are %s\n" (set_to_string uses) (set_to_string n) - in let _ = print_dependencies wq wq uses in failwith "A dependency was unmet" + else + let _ = Printf.eprintf "Merging (potentially) mutually recursive definitions %s and %s\n" (set_to_string n) (set_to_string uses) in + let is_used ((binds', uses'), def') = not(Nameset.is_empty(Nameset.inter binds' uses)) in + let (used, rest) = List.partition is_used rest in + let wq = merge_mutrecs (((n,uses),def)::used) :: rest in + topological_sort wq defs let rec add_to_partial_order ((binds,uses),def) = function | [] -> |
