autocorres-crefine: update CRefine demo to work after AutoCorres refactor
Also fixes an AutoCorres bug that surfaced in the demo.
This commit is contained in:
parent
0afb748b1b
commit
c31ee7a6a9
|
@ -311,8 +311,10 @@ fun modifies_simp_term ctxt =
|
|||
* Returns tuple of (state var, function arg vars, measure var, prop).
|
||||
* The returned vars are Free in the prop; the measure var is NONE for non-recursive functions.
|
||||
*)
|
||||
fun gen_modifies_prop ctxt fn_info (prog_info: ProgramInfo.prog_info) f_name c_prop = let
|
||||
val f_info = FunctionInfo.get_phase_info fn_info FunctionInfo.TS f_name;
|
||||
fun gen_modifies_prop ctxt
|
||||
(fn_info: FunctionInfo.function_info Symtab.table)
|
||||
(prog_info: ProgramInfo.prog_info) f_name c_prop = let
|
||||
val f_info = the (Symtab.lookup fn_info f_name);
|
||||
val globals_type = #globals_type prog_info;
|
||||
val globals_term = #globals_getter prog_info;
|
||||
val ac_ret_type = #return_type f_info;
|
||||
|
@ -325,7 +327,7 @@ fun gen_modifies_prop ctxt fn_info (prog_info: ProgramInfo.prog_info) f_name c_p
|
|||
val modifies_postcond = Abs (Name.uu_, ac_ret_type, Abs ("s", globals_type, modifies_eqn))
|
||||
|> modifies_simp_term ctxt;
|
||||
val arg_vars = map Free (#args f_info);
|
||||
val measure_var = if FunctionInfo.is_function_recursive fn_info f_name
|
||||
val measure_var = if FunctionInfo.is_function_recursive f_info
|
||||
(* will not clash with arg_vars as C identifiers do not contain primes *)
|
||||
then SOME (Free ("measure'", @{typ nat})) else NONE;
|
||||
val f_const = #const f_info
|
||||
|
@ -442,7 +444,7 @@ fun do_modifies_one ctxt fn_info (prog_info: ProgramInfo.prog_info) callee_modif
|
|||
val (state0_var, arg_vars, measure_var, ac_modifies_prop) =
|
||||
gen_modifies_prop ctxt fn_info prog_info f_name c_modifies_prop;
|
||||
val _ = if isSome measure_var then error ("do_modifies_one bug: got recursive function " ^ f_name) else ();
|
||||
val f_def = FunctionInfo.get_phase_info fn_info FunctionInfo.TS f_name |> #definition;
|
||||
val f_def = the (Symtab.lookup fn_info f_name) |> #definition;
|
||||
fun leaf_tac ctxt n = FIRST [modifies_call_tac callee_modifies ctxt n, modifies_invariant_tac true ctxt n,
|
||||
print_tac ctxt ("do_modifies_one failed (goal " ^ string_of_int n ^ ")")];
|
||||
val thm = Goal.prove ctxt (map (fn (Free (v, _)) => v) (state0_var :: arg_vars)) [] ac_modifies_prop
|
||||
|
@ -463,7 +465,7 @@ fun do_modifies_recursive ctxt fn_info (prog_info: ProgramInfo.prog_info) (calle
|
|||
val c_modifies_props = map (fn f_name => Thm.prop_of (Proof_Context.get_thm ctxt (f_name ^ "_modifies"))) f_names;
|
||||
val modifies_props =
|
||||
map2 (gen_modifies_prop ctxt fn_info prog_info) f_names c_modifies_props;
|
||||
val f_defs = map (fn f_name => FunctionInfo.get_phase_info fn_info FunctionInfo.TS f_name |> #definition) f_names;
|
||||
val f_defs = map (fn f_name => the (Symtab.lookup fn_info f_name) |> #definition) f_names;
|
||||
|
||||
fun free_name (Free (v, _)) = v;
|
||||
|
||||
|
@ -593,7 +595,7 @@ fun do_modifies_recursive ctxt fn_info (prog_info: ProgramInfo.prog_info) (calle
|
|||
|
||||
(* Prove and store modifies rules for one function or recursive function group. *)
|
||||
fun prove_modifies
|
||||
(fn_info: FunctionInfo.fn_info)
|
||||
(fn_info: FunctionInfo.function_info Symtab.table)
|
||||
(prog_info: ProgramInfo.prog_info)
|
||||
(callee_modifies: incr_net)
|
||||
(results: thm Symtab.table)
|
||||
|
@ -601,19 +603,19 @@ fun prove_modifies
|
|||
(thm_names: string list)
|
||||
ctxt
|
||||
: (thm list * Proof.context) option = let
|
||||
val f_infos = map (FunctionInfo.get_function_info fn_info) f_names;
|
||||
val f_infos = map (the o Symtab.lookup fn_info) f_names;
|
||||
val maybe_thms =
|
||||
if length f_names = 1 andalso #is_simpl_wrapper (hd f_infos)
|
||||
then let
|
||||
val f_name = hd f_names;
|
||||
val _ = tracing (f_name ^ " is un-translated; transferring C-parser's modifies rule directly")
|
||||
val f_def = FunctionInfo.get_phase_info fn_info FunctionInfo.TS f_name |> #definition;
|
||||
val _ = tracing (f_name ^ " is un-translated; transferring C-parser's modifies rule directly");
|
||||
val f_def = the (Symtab.lookup fn_info f_name) |> #definition;
|
||||
val orig_modifies = Proof_Context.get_thm ctxt (f_name ^ "_modifies");
|
||||
val transfer_thm = @{thm autocorres_modifies_transfer};
|
||||
val thm = transfer_thm OF [f_def, orig_modifies];
|
||||
in SOME [modifies_simp ctxt thm] end
|
||||
else let
|
||||
val callees = map (Symset.make o FunctionInfo.get_function_callees fn_info) f_names
|
||||
val callees = map (FunctionInfo.all_callees o the o Symtab.lookup fn_info) f_names
|
||||
|> Symset.union_sets |> Symset.dest;
|
||||
val missing_callees = callees |> filter_out (fn callee =>
|
||||
Symtab.defined results callee orelse member op= f_names callee);
|
||||
|
@ -652,23 +654,28 @@ fun define_modifies_group fn_info prog_info f_names (acc as (callee_modifies, re
|
|||
* recently translated set of functions from a given C file.
|
||||
*)
|
||||
fun new_modifies_rules filename ctxt = let
|
||||
val fn_info = Symtab.lookup (AutoCorresFunctionInfo.get (Proof_Context.theory_of ctxt)) filename |> the;
|
||||
val all_fn_info = Symtab.lookup (AutoCorresFunctionInfo.get (Proof_Context.theory_of ctxt)) filename |> the;
|
||||
val ts_info = FunctionInfo.Phasetab.lookup all_fn_info FunctionInfo.TS |> the;
|
||||
val prog_info = ProgramInfo.get_prog_info ctxt filename;
|
||||
(* Assume that the user has already generated and named modifies rules
|
||||
* for previously-translated callees. *)
|
||||
val existing_modifies =
|
||||
Symtab.dest (FunctionInfo.get_all_functions fn_info)
|
||||
Symtab.dest ts_info
|
||||
|> List.mapPartial (fn (fn_name, fn_def) =>
|
||||
try (fn _ => (fn_name, Proof_Context.get_thm ctxt (fn_name ^ "'_modifies"))) ())
|
||||
|> Symtab.make;
|
||||
val all_function_groups =
|
||||
FunctionInfo.map_fn_info (fn info =>
|
||||
if Symtab.defined existing_modifies (#name info) then NONE else SOME info) fn_info
|
||||
|> FunctionInfo.get_topo_sorted_functions;
|
||||
(* We will do modifies proofs for these functions *)
|
||||
val pending_fn_info =
|
||||
Symtab.dest ts_info
|
||||
|> List.mapPartial (fn (f, info) =>
|
||||
if Symtab.defined existing_modifies f then NONE else SOME (f, info))
|
||||
|> Symtab.make;
|
||||
val (call_graph, _) = FunctionInfo.calc_call_graph pending_fn_info;
|
||||
val (callee_modifies, results, ctxt') =
|
||||
fold (define_modifies_group fn_info prog_info)
|
||||
all_function_groups (build_incr_net (Symtab.dest existing_modifies |> map snd),
|
||||
existing_modifies, ctxt)
|
||||
fold (define_modifies_group ts_info prog_info)
|
||||
(#topo_sorted_functions call_graph |> map Symset.dest)
|
||||
(build_incr_net (Symtab.dest existing_modifies |> map snd),
|
||||
existing_modifies, ctxt)
|
||||
in ctxt' end
|
||||
|
||||
end;
|
||||
|
|
|
@ -377,79 +377,58 @@ lemma clzl'_ac_corres: "ac_corres globals ct \<Gamma> ret__long_' (\<lambda>s. x
|
|||
end
|
||||
|
||||
text \<open>Add our manual translation of clzl into the AutoCorres function info.\<close>
|
||||
ML \<open>
|
||||
fun phasetab_merge_with merge (tab1, tab2) =
|
||||
sort_distinct FunctionInfo.phase_ord
|
||||
(FunctionInfo.Phasetab.keys tab1 @ FunctionInfo.Phasetab.keys tab2)
|
||||
|> map (fn k => (k, case (FunctionInfo.Phasetab.lookup tab1 k, FunctionInfo.Phasetab.lookup tab2 k) of
|
||||
(SOME x1, SOME x2) => merge (x1, x2)
|
||||
| (SOME x1, NONE) => x1
|
||||
| (NONE, SOME x2) => x2
|
||||
(* (NONE, NONE) impossible *)))
|
||||
|> FunctionInfo.Phasetab.make;
|
||||
\<close>
|
||||
setup {*
|
||||
fn thy =>
|
||||
let val clzl_cp = {
|
||||
name = "clzl",
|
||||
invented_body = false,
|
||||
is_simpl_wrapper = false,
|
||||
callees = Symset.empty,
|
||||
rec_callees = Symset.empty,
|
||||
phase = FunctionInfo.CP,
|
||||
args = [("x", @{typ "32 word"})],
|
||||
return_type = @{typ "32 signed word"},
|
||||
const = @{term "clzl_'proc"},
|
||||
raw_const = @{term "clzl_'proc"},
|
||||
definition = @{thm kernel_all_substitute.clzl_body_def},
|
||||
mono_thm = NONE
|
||||
}: FunctionInfo.phase_info;
|
||||
val clzl_l1 = {
|
||||
phase = FunctionInfo.L1,
|
||||
args = [("x", @{typ "32 word"})],
|
||||
return_type = @{typ "32 signed word"},
|
||||
const = @{term "kernel_all_substitute.l1_clzl'"},
|
||||
raw_const = @{term "kernel_all_substitute.l1_clzl'"},
|
||||
definition = @{thm kernel_all_substitute.l1_clzl'_def},
|
||||
mono_thm = NONE
|
||||
}: FunctionInfo.phase_info;
|
||||
val clzl_l2 = {
|
||||
phase = FunctionInfo.L2,
|
||||
args = [("x", @{typ "32 word"})],
|
||||
return_type = @{typ "32 signed word"},
|
||||
const = @{term "kernel_all_substitute.l2_clzl'"},
|
||||
raw_const = @{term "kernel_all_substitute.l2_clzl'"},
|
||||
definition = @{thm kernel_all_substitute.l2_clzl'_def},
|
||||
mono_thm = NONE
|
||||
}: FunctionInfo.phase_info;
|
||||
val clzl_ts = {
|
||||
phase = FunctionInfo.TS,
|
||||
args = [("x", @{typ "32 word"})],
|
||||
return_type = @{typ "32 signed word"},
|
||||
const = @{term "kernel_all_substitute.clzl'"},
|
||||
raw_const = @{term "kernel_all_substitute.clzl'"},
|
||||
definition = @{thm kernel_all_substitute.clzl'_def},
|
||||
mono_thm = NONE
|
||||
}: FunctionInfo.phase_info;
|
||||
val clzl_info = {
|
||||
name = "clzl",
|
||||
invented_body = false,
|
||||
is_simpl_wrapper = false,
|
||||
phases = FunctionInfo.Phasetab.make
|
||||
[(FunctionInfo.CP, clzl_cp),
|
||||
(FunctionInfo.L1, clzl_l1),
|
||||
(FunctionInfo.L2, clzl_l2),
|
||||
(FunctionInfo.HL, FunctionInfo.phase_info_upd_phase FunctionInfo.HL clzl_l2),
|
||||
(FunctionInfo.WA, FunctionInfo.phase_info_upd_phase FunctionInfo.WA clzl_l2),
|
||||
(FunctionInfo.TS, clzl_ts)]
|
||||
mono_thm = NONE,
|
||||
corres_thm = @{thm TrueI}
|
||||
}: FunctionInfo.function_info;
|
||||
val clzl_l1 = clzl_cp
|
||||
|> FunctionInfo.function_info_upd_phase FunctionInfo.L1
|
||||
|> FunctionInfo.function_info_upd_const @{term "kernel_all_substitute.l1_clzl'"}
|
||||
|> FunctionInfo.function_info_upd_definition @{thm kernel_all_substitute.l1_clzl'_def}
|
||||
|> FunctionInfo.function_info_upd_corres_thm @{thm "kernel_all_substitute.l1_clzl'_corres"};
|
||||
val clzl_l2 = clzl_l1
|
||||
|> FunctionInfo.function_info_upd_phase FunctionInfo.L2
|
||||
|> FunctionInfo.function_info_upd_const @{term "kernel_all_substitute.l2_clzl'"}
|
||||
|> FunctionInfo.function_info_upd_definition @{thm kernel_all_substitute.l2_clzl'_def}
|
||||
|> FunctionInfo.function_info_upd_corres_thm @{thm "kernel_all_substitute.l2_clzl'_corres"};
|
||||
val clzl_ts = clzl_l2
|
||||
|> FunctionInfo.function_info_upd_phase FunctionInfo.TS
|
||||
|> FunctionInfo.function_info_upd_const @{term "kernel_all_substitute.clzl'"}
|
||||
|> FunctionInfo.function_info_upd_definition @{thm kernel_all_substitute.clzl'_def}
|
||||
|> FunctionInfo.function_info_upd_corres_thm @{thm "kernel_all_substitute.clzl'_TScorres"};
|
||||
val clzl_info = FunctionInfo.Phasetab.make
|
||||
(map (fn info => (#phase info, Symtab.make [("clzl", info)]))
|
||||
[clzl_cp, clzl_l1, clzl_l2, clzl_ts]);
|
||||
val file = "c/kernel_all.c_pp";
|
||||
val fn_info = the (Symtab.lookup (AutoCorresFunctionInfo.get @{theory}) file);
|
||||
(* hack to work around opacity of fn_info *)
|
||||
fun add_fn_info fn_info new_infos = let
|
||||
val fn_infos = FunctionInfo.get_all_functions fn_info;
|
||||
val {base = locale_name,...} = OS.Path.splitBaseExt (OS.Path.file file);
|
||||
val SOME ctxt = try (Named_Target.begin (locale_name, Position.none)) thy;
|
||||
in FunctionInfo.init_fn_info ctxt file
|
||||
|> FunctionInfo.map_fn_info (fn info =>
|
||||
case Symtab.lookup new_infos (#name info) of
|
||||
NONE => Symtab.lookup fn_infos (#name info)
|
||||
| SOME ni => SOME ni) end;
|
||||
|
||||
val fn_info' = add_fn_info fn_info (Symtab.make [("clzl", clzl_info)]);
|
||||
val fn_info = the (Symtab.lookup (AutoCorresFunctionInfo.get thy) file);
|
||||
val fn_info' = phasetab_merge_with (Symtab.merge (K false)) (fn_info, clzl_info);
|
||||
in
|
||||
thy
|
||||
|> AutoCorresFunctionInfo.map (Symtab.update (file, fn_info'))
|
||||
|> AutoCorresData.add_def file "L1def" "clzl" @{thm kernel_all_substitute.l1_clzl'_def}
|
||||
|> AutoCorresData.add_def file "L2def" "clzl" @{thm kernel_all_substitute.l2_clzl'_def}
|
||||
|> AutoCorresData.add_def file "TSdef" "clzl" @{thm kernel_all_substitute.clzl'_def}
|
||||
|> AutoCorresData.add_thm file "L1corres" "clzl" @{thm kernel_all_substitute.l1_clzl'_corres}
|
||||
|> AutoCorresData.add_thm file "L2corres" "clzl" @{thm kernel_all_substitute.l2_clzl'_corres}
|
||||
|> AutoCorresData.add_thm file "TScorres" "clzl" @{thm kernel_all_substitute.clzl'_TScorres}
|
||||
end
|
||||
*}
|
||||
|
||||
|
|
|
@ -372,17 +372,13 @@ let
|
|||
val _ = if not (isSome existing_phases) then () else
|
||||
tracing ("Attempting to restart from previous translation of " ^ filename)
|
||||
|
||||
(* Fetch any existing translations, when being run in incremental mode. *)
|
||||
fun get_existing_optional_phase phase =
|
||||
case existing_phases of
|
||||
NONE => SOME Symtab.empty
|
||||
| SOME phases => FunctionInfo.Phasetab.lookup phases phase
|
||||
fun get_existing_phase phase =
|
||||
Option.getOpt (get_existing_optional_phase phase, Symtab.empty)
|
||||
(* FIXME: if skip_heap_abs or skip_word_abs are used for some parts of
|
||||
* an incremental translation, some functions will be missing.
|
||||
* We ought to either handle this nicely (by carrying the
|
||||
* L2/HL versions forward), or detect it early and
|
||||
* produce an error report. *)
|
||||
val [existing_simpl_info,
|
||||
existing_l1_info,
|
||||
existing_l2_info,
|
||||
|
@ -396,6 +392,12 @@ let
|
|||
FunctionInfo.HL,
|
||||
FunctionInfo.WA,
|
||||
FunctionInfo.TS]
|
||||
(* HL and WA functions may be missing if skip_heap_abs and skip_word_abs
|
||||
* are set. In that case, we carry forward the L2 or HL functions and
|
||||
* cross our fingers. (Should work fine if skip_foo is used consistently
|
||||
* for all functions, might not work if they are mixed.) *)
|
||||
val existing_hl_info = Utils.symtab_merge_with snd (existing_l2_info, existing_hl_info);
|
||||
val existing_wa_info = Utils.symtab_merge_with snd (existing_hl_info, existing_wa_info);
|
||||
|
||||
(* Skip functions that have already been translated. *)
|
||||
val already_translated = Symset.make (Symtab.keys existing_ts_info)
|
||||
|
|
|
@ -308,8 +308,7 @@ let
|
|||
let
|
||||
(* Fix function parameters. *)
|
||||
val fn_info = the (Symtab.lookup l2_infos fn_name)
|
||||
(* Only produce measure parameters for recursive functions.
|
||||
* FIXME: recalculate call graph prior to this *)
|
||||
(* Only produce measure parameters for recursive functions. *)
|
||||
val all_arg_names = (if is_recursive then ["rec_measure'"] else []) @
|
||||
map fst (#args fn_info)
|
||||
val all_arg_types = (if is_recursive then [AutoCorresUtil.measureT] else []) @
|
||||
|
@ -362,6 +361,9 @@ let
|
|||
(* NB: discard lthy because we don't want the placeholders to be fixed during define_functions *)
|
||||
val (input_defs, _) = fold_map gen_fun_def_term (Utils.zip3 fn_names dicts thms) lthy
|
||||
val (ts_defs, lthy) = Utils.define_functions input_defs false is_recursive lthy
|
||||
(* TODO: we may want to cleanup callees and rec_callees here, like we do
|
||||
* in other phases. It's not crucial, however, since this is the
|
||||
* final phase. *)
|
||||
|
||||
(* Instantiate variables in our equivalence theorem to their newly-defined values. *)
|
||||
fun do_inst_thm thm =
|
||||
|
|
Loading…
Reference in New Issue