Support extra specs, ctzl, clzl in SimplExport.

This patch permits the user to supply additional specs for functions
whose bodies were not imported (DONT_TRANSLATE or not present in parsed
C source). Those specs are exported by SimplExport.

The existing apparatus can import builtin functions like ctzl/clzl in C
sources by admitting them without bodies (DONT_TRANSLATE) and giving
them axiomatic Hoare triples (FNSPEC).

Translation validation then requires export of useful semantics. The user
can supply a made-up body, and show that it is a refinement of the body
that the parser created (derived from the FNSPEC and MODIFIES clauses).
The body must export out the graph language correctly. For ctzl/clzl etc
this is easy.
This commit is contained in:
Thomas Sewell 2017-03-10 00:22:20 +11:00
parent 6cda8f50d0
commit 971c6782e5
8 changed files with 185 additions and 61 deletions

View File

@ -66,31 +66,8 @@ lemma snd_snd_gs_new_frames_new_cnodes[simp]:
"snd (snd ((if P then f else g) gs)) = (if P then snd (snd (f gs)) else snd (snd (g gs)))"
by (simp_all add: gs_new_frames_def gs_new_cnodes_def gs_clear_region_def)
ML {* val nm = "Kernel_C.invert_l1index" *}
(*
(* If test_all_graph_refine_proofs_parallel fails, debug it by uncommenting this comment block
and setting "nm" to the failed C function. *)
local_setup {* define_graph_fun_short funs nm *}
ML {*
val ctxt = @{context}
val hints = SimplToGraphProof.mk_hints funs ctxt nm
val init_thm = SimplToGraphProof.simpl_to_graph_upto_subgoals funs hints nm
ctxt
*}
ML {*
val v = ProveSimplToGraphGoals.test_graph_refine_proof funs (csenv ()) ctxt nm
*}
schematic_goal "PROP ?P"
apply (tactic {* resolve_tac @{context} [init_thm] 1 *})
apply (tactic {* ALLGOALS (TRY o ProveSimplToGraphGoals.graph_refine_proof_full_goal_tac
(csenv ()) @{context}) *})
*)
(* If this fails, it can be debugged with the assistance of the
script in TestGraphRefine.thy *)
ML {* ProveSimplToGraphGoals.test_all_graph_refine_proofs_parallel
funs (csenv ()) @{context} *}

View File

@ -26,7 +26,23 @@ val csenv = let
context kernel_all_substitute begin
ML {*
lemma ctzl_body_refines:
"simple_simpl_refines \<Gamma> (Guard ImpossibleSpec \<lbrace>\<acute>x \<noteq> 0\<rbrace>
(\<acute>ret__long :== ucast (bv_ctz (\<acute>x)))) ctzl_body"
apply (simp add: ctzl_body_def)
apply (rule simple_simpl_refines_guarded_Basic_guarded_spec_body)
apply (clarsimp simp: bv_ctz_def meq_def)
done
lemma clzl_body_refines:
"simple_simpl_refines \<Gamma> (Guard ImpossibleSpec \<lbrace>\<acute>x \<noteq> 0\<rbrace>
(\<acute>ret__long :== ucast (bv_clz (\<acute>x)))) clzl_body"
apply (simp add: clzl_body_def)
apply (rule simple_simpl_refines_guarded_Basic_guarded_spec_body)
apply (clarsimp simp: bv_clz_def meq_def)
done
ML {*
emit_C_everything_relative @{context} (csenv ()) "CFunDump.txt";
*}

View File

@ -15,7 +15,7 @@ imports "../../lib/CTranslationNICTA"
begin
text {* Additional constants needed to make conversion to graph lang easy *}
text {* Additional constants needed to make conversion to and from the graph lang easy *}
definition
bvshl :: "'a :: len0 word \<Rightarrow> 'a word \<Rightarrow> 'a word"
@ -37,16 +37,20 @@ definition
where
"bv_shift_amount n = of_nat (min n ((2 ^ len_of TYPE('a)) - 1))"
definition
"count_leading_zeroes z = length (takeWhile Not (to_bl z))"
definition
"count_trailing_zeroes z = length (takeWhile Not (rev (to_bl z)))"
definition
bv_clz :: "('a :: len) word \<Rightarrow> 'a word"
where
"bv_clz x = of_nat (count_leading_zeroes x)"
"bv_clz x = of_nat (word_clz x)"
definition
bv_ctz :: "('a :: len) word \<Rightarrow> 'a word"
where
"bv_ctz x = of_nat (word_ctz x)"
definition
bv_popcount :: "('a :: len) word \<Rightarrow> 'a word"
where
"bv_popcount x = of_nat (pop_count x)"
definition
"mem_acc mem addr = h_val mem (Ptr addr)"

View File

@ -0,0 +1,97 @@
(*
* Copyright 2016, Data61
*
* This software may be distributed and modified according to the terms of
* the BSD 2-Clause license. Note that NO WARRANTY is provided.
* See "LICENSE_BSD2.txt" for details.
*
* @TAG(NICTA_BSD)
*)
theory ExtraSpecs
imports
"../../lib/TypHeapLib"
begin
definition
"simple_simpl_refines \<Gamma> com com'
= (\<forall>s. (\<exists>ft. \<Gamma> \<turnstile> \<langle>com', Normal s\<rangle> \<Rightarrow> Fault ft)
\<or> ((\<forall>xs. \<Gamma> \<turnstile> \<langle>com, Normal s\<rangle> \<Rightarrow> xs \<longrightarrow> \<Gamma> \<turnstile> \<langle>com', Normal s\<rangle> \<Rightarrow> xs)
\<and> (\<not> terminates \<Gamma> com (Normal s) \<longrightarrow> \<not> terminates \<Gamma> com' (Normal s))))"
lemma simple_simpl_refines_no_fault_execD:
"\<Gamma> \<turnstile> \<langle>com,Normal s\<rangle> \<Rightarrow> xs
\<Longrightarrow> simple_simpl_refines \<Gamma> com com'
\<Longrightarrow> (\<forall>ft. \<not> \<Gamma> \<turnstile> \<langle>com',Normal s\<rangle> \<Rightarrow> Fault ft)
\<Longrightarrow> \<Gamma> \<turnstile> \<langle>com', Normal s\<rangle> \<Rightarrow> xs"
by (auto simp add: simple_simpl_refines_def)
lemma simple_simpl_refines_no_fault_terminatesD:
"simple_simpl_refines \<Gamma> com com'
\<Longrightarrow> (\<forall>ft. \<not> \<Gamma> \<turnstile> \<langle>com',Normal s\<rangle> \<Rightarrow> Fault ft)
\<Longrightarrow> \<not> terminates \<Gamma> com (Normal s) \<longrightarrow> \<not> terminates \<Gamma> com' (Normal s)"
by (auto simp add: simple_simpl_refines_def)
lemma simple_simpl_refines_refl:
"simple_simpl_refines \<Gamma> com com"
by (auto simp add: simple_simpl_refines_def)
lemma simple_simpl_refines_from_def_eq:
"body \<equiv> body' \<Longrightarrow> simple_simpl_refines \<Gamma> body' body"
(* these are flipped, because the "implementation" is on the rhs of
definitional equalities, but the lhs of refinement thms. *)
by (simp add: simple_simpl_refines_def)
lemma simple_simpl_refines_trans:
"simple_simpl_refines \<Gamma> com com' \<Longrightarrow> simple_simpl_refines \<Gamma> com' com''
\<Longrightarrow> simple_simpl_refines \<Gamma> com com''"
by (simp add: simple_simpl_refines_def, metis)
lemma simple_simpl_refines_drop_Guard:
"simple_simpl_refines \<Gamma> com (Guard F G com)"
apply (clarsimp simp add: simple_simpl_refines_def)
apply (case_tac "s \<in> G")
apply (auto intro: exec.Guard exec.GuardFault
elim!: terminates_Normal_elim_cases)
done
lemma simple_simpl_refines_guarded_Basic_guarded_spec_body:
"(\<forall>s s'. (s, s') \<in> R \<longrightarrow> (s \<in> G \<and> (s, f s) \<in> R))
\<Longrightarrow> simple_simpl_refines \<Gamma> (Guard F' G (Basic f)) (guarded_spec_body F R)"
apply (simp add: guarded_spec_body_def simple_simpl_refines_def)
apply (intro allI, drule_tac x=s in spec)
apply (erule impCE)
apply (rule disjI1)
apply (fastforce intro: exec.GuardFault)
apply (rule disjI2)
apply (auto intro!: exec.Guard terminates.Guard
intro: exec.GuardFault exec.Spec terminates.Basic image_eqI[rotated]
elim!: exec_Normal_elim_cases terminates_Normal_elim_cases)
done
lemmas simple_simpl_refines_Basic_guarded_spec_body
= simple_simpl_refines_trans[OF
simple_simpl_refines_drop_Guard[where G=UNIV]
simple_simpl_refines_guarded_Basic_guarded_spec_body
]
ML {*
structure Get_Body_Refines = struct
fun get ctxt name = let
fun pget sfx = try (Proof_Context.get_thm ctxt o suffix sfx) name
val eqv = pget "_body_refines"
val def = pget "_body_def"
in case (eqv, def) of
(SOME eqvt, _) => eqvt
| (_, SOME deft) => (deft RS @{thm simple_simpl_refines_from_def_eq})
| _ => raise THM ("Get_Body_Refines.get: "
^ "no body_def or body_refines: " ^ name, 1, [])
end
end
*}
end

View File

@ -570,6 +570,7 @@ val opers = Symtab.make [
("WordArrayAccess", @{const_name "fun_app"}),
("WordArrayUpdate", @{const_name "fun_upd"}),
("CountLeadingZeroes", @{const_name "bv_clz"}),
("CountTrailingZeroes", @{const_name "bv_ctz"}),
("True", @{const_name "True"}),
("False", @{const_name "False"}),
("IfThenElse", @{const_name "If"}),

View File

@ -10,8 +10,11 @@
theory GraphRefine
imports TailrecPre GraphLangLemmas "../../lib/LemmaBucket_C"
imports
TailrecPre
GraphLangLemmas
"../../lib/LemmaBucket_C"
ExtraSpecs
begin
type_synonym ('s, 'x, 'e) c_trace = "nat \<Rightarrow> (('s, 'x, 'e) com \<times> ('s, 'e) xstate) option"
@ -935,9 +938,10 @@ lemma trace_end_Ret_Err:
auto simp: exec_graph_invariant_def)
done
lemma graph_fun_refines_from_simpl_to_graph:
lemma graph_fun_refines_from_simpl_to_graph_with_refine:
"\<lbrakk> SGamma proc = Some com; GGamma fname = Some gf;
\<And>Q. simpl_to_graph SGamma GGamma fname (NextNode (entry_point gf)) (add_cont com []) 0
simple_simpl_refines SGamma com' com;
\<And>Q. simpl_to_graph SGamma GGamma fname (NextNode (entry_point gf)) (add_cont com' []) 0
[Q] UNIV I eqs
(\<lambda>s s'. map (\<lambda>i. var_acc i s) (function_outputs gf) = map (\<lambda>i. i s') outs);
eq_impl (NextNode (entry_point gf))
@ -949,8 +953,8 @@ lemma graph_fun_refines_from_simpl_to_graph:
apply (clarsimp simp: graph_fun_refines_def)
apply (frule exec_trace_def[THEN eqset_imp_iff, THEN iffD1])
apply clarsimp
apply (erule_tac x="UNIV \<times> {[0 \<mapsto> (com, Normal s)]}" in meta_allE)
apply (drule_tac tr=tr and tr'="[0 \<mapsto> (com, Normal s)]"
apply (erule_tac x="UNIV \<times> {[0 \<mapsto> (com', Normal s)]}" in meta_allE)
apply (drule_tac tr=tr and tr'="[0 \<mapsto> (com', Normal s)]"
and n'=0 and n''=0 and sst=s in simpl_to_graphD)
apply (rule conjI, assumption)
apply (simp add: suffix_tuple_closure_inter_def exec_trace_def)
@ -967,16 +971,23 @@ lemma graph_fun_refines_from_simpl_to_graph:
apply clarsimp
apply (drule step_preserves_termination[rotated])
apply (erule step.Call)
apply (simp add: c_trace_nontermination)
apply (drule simple_simpl_refines_no_fault_terminatesD)
apply (blast intro: exec.Call)
apply (simp add: c_trace_nontermination simple_simpl_refines_def)
apply (frule(1) trace_end_Ret_Err)
apply (clarsimp simp: exec_final_step_def acc_vars_def)
apply metis
apply clarsimp
apply (erule exec.Call)
apply (rule exec.Call, assumption)
apply (erule simple_simpl_refines_no_fault_execD[rotated])
apply (blast intro: exec.Call)
apply (simp add: exec_via_trace)
apply metis
done
lemmas graph_fun_refines_from_simpl_to_graph
= graph_fun_refines_from_simpl_to_graph_with_refine[OF _ _ simple_simpl_refines_refl]
lemma simpl_to_graph_name_simpl_state:
"(\<And>sst. sst \<in> P \<Longrightarrow> simpl_to_graph SGamma GGamma gf nn com n traces {sst} I inp_eqs out_eqs)
\<Longrightarrow> simpl_to_graph SGamma GGamma gf nn com n traces P I inp_eqs out_eqs"
@ -2259,17 +2270,17 @@ fun mk_hints (funs : ParseGraph.funs) ctxt nm = case Symtab.lookup funs nm of
err_conds = ec} end
fun init_graph_refines_proof funs nm ctxt = let
val body_thm = Proof_Context.get_thm ctxt
(Long_Name.base_name nm ^ "_body_def")
val body_ref_thm = Get_Body_Refines.get ctxt (Long_Name.base_name nm)
val ct = mk_graph_refines funs ctxt nm |> Thm.cterm_of ctxt
in Thm.trivial ct
|> (resolve0_tac [@{thm graph_fun_refines_from_simpl_to_graph}] 1
|> (resolve_tac ctxt [@{thm graph_fun_refines_from_simpl_to_graph_with_refine}] 1
THEN apply_impl_thm ctxt 1
THEN graph_gamma_tac ctxt 1
THEN ALLGOALS (simp_tac (put_simpset HOL_basic_ss ctxt addsimps [body_thm]
THEN resolve_tac ctxt [body_ref_thm] 1
THEN ALLGOALS (simp_tac (put_simpset HOL_basic_ss ctxt
addsimps @{thms entry_point.simps function_inputs.simps
function_outputs.simps list.simps}))
THEN TRY ((resolve0_tac [@{thm simpl_to_graph_noop_same_eqs}]
THEN TRY ((resolve_tac ctxt [@{thm simpl_to_graph_noop_same_eqs}]
THEN' inst_graph_tac ctxt) 1)
)
|> Seq.hd

View File

@ -136,6 +136,22 @@ lemma drop_sign_isomorphism_bitwise:
| safe
| simp add: test_bit_bin)+
lemma drop_sign_of_nat:
"drop_sign (of_nat n) = of_nat n"
by (simp add: drop_sign_def ucast_of_nat is_down_def
target_size_def source_size_def word_size)
lemma drop_sign_to_bl:
"to_bl (drop_sign w) = to_bl w"
by (simp add: drop_sign_def to_bl_ucast)
lemma drop_sign_extra_bl_ops:
"drop_sign (bv_clz w) = bv_clz (drop_sign w)"
"drop_sign (bv_ctz w) = bv_ctz (drop_sign w)"
"drop_sign (bv_popcount w) = bv_popcount (drop_sign w)"
by (simp_all add: bv_clz_def bv_ctz_def bv_popcount_def drop_sign_of_nat
word_ctz_def word_clz_def pop_count_def drop_sign_to_bl)
lemma drop_sign_number[simp]:
"drop_sign (numeral n) = numeral n"
"drop_sign (- numeral n) = - numeral n"
@ -153,8 +169,8 @@ lemma drop_sign_projections:
lemmas drop_sign_isomorphism
= drop_sign_isomorphism_ariths drop_sign_projections
drop_sign_isomorphism_bitwise
ucast_id
drop_sign_isomorphism_bitwise drop_sign_of_nat
drop_sign_extra_bl_ops ucast_id
lemma drop_sign_h_val[simp]:
"drop_sign (h_val hp p :: ('a :: len8) signed word) = h_val hp (ptr_coerce p)"

View File

@ -10,7 +10,7 @@
theory SimplExport
imports GraphLang CommonOpsLemmas GlobalsSwap
imports GraphLang CommonOpsLemmas GlobalsSwap ExtraSpecs
begin
@ -75,6 +75,8 @@ val ops = Symtab.make [
(@{const_name "shiftl"}, ("ShiftLeft", false)),
(@{const_name "shiftr"}, ("ShiftRight", false)),
(@{const_name "sshiftr"}, ("SignedShiftRight", false)),
(@{const_name "bv_clz"}, ("CountLeadingZeroes", true)),
(@{const_name "bv_ctz"}, ("CountTrailingZeroes", true)),
(@{const_name "all_htd_updates"}, ("HTDUpdate", false))
] |> Symtab.lookup
@ -736,11 +738,6 @@ and convert_ph3 ctxt params (Const (@{const_name Collect}, _) $ S $ x)
in if t1 = t2 then convert_ph3 ctxt params x
else convert_ph3 ctxt params (Const (@{const_name ucast}, t1 --> t2) $ x)
end
| convert_ph3 ctxt params (t as (Const (@{const_name of_nat}, _) $
(Const (@{const_name count_leading_zeroes}, _) $ x)))
= convert_op ctxt params "CountLeadingZeroes" (convert_type false ctxt (fastype_of t)) [x]
(* | convert_ph3 ctxt params (t as (Const (@{const_name unat}, _) $ _))
= convert_ph3 ctxt params (@{term "of_nat :: nat \<Rightarrow> word32"} $ t) *)
| convert_ph3 ctxt params (t as (Const (@{const_name of_nat}, _) $ _))
= convert_ph3 ctxt params (ptr_simp_term ctxt "of_nat" t t)
| convert_ph3 ctxt params (t as (Const (@{const_name power}, _) $ x $ y))
@ -868,7 +865,7 @@ fun reduce_set_mem ctxt x S = let
fun is_spec_body_const @{const_name Spec} = true
| is_spec_body_const @{const_name guarded_spec_body} = true
| is_spec_body_const c = false
| is_spec_body_const _ = false
fun has_reads body = exists_Const (fn (s, T) =>
snd (strip_type T) = @{typ heap_raw_state}
@ -1083,13 +1080,18 @@ fun emit_func_body ctxt outfile eparams name = let
val outputs = (filter (fn p => fst p = HoarePackage.Out) params
|> maps snd) @ (if no_write then [] else all_c_params)
val body = Proof_Context.get_thm ctxt (name ^ "_body_def")
|> simplify (put_simpset HOL_basic_ss ctxt
val body = Get_Body_Refines.get ctxt name
|> simplify (put_simpset HOL_basic_ss ctxt
addsimps @{thms switch.simps fst_conv snd_conv
insert_iff empty_iff
ptr_add_assertion_def if_True if_False})
|> Thm.concl_of |> Logic.dest_equals |> snd
handle ERROR _ => @{term "Spec S"}
ptr_add_assertion_def if_True if_False
bv_clz_def[symmetric] bv_ctz_def[symmetric]
})
|> Thm.concl_of |> HOLogic.dest_Trueprop
|> (fn t => (case t of Const (@{const_name simple_simpl_refines}, _) $ _ $ lhs $ _ => lhs
| _ => raise Option))
handle Option => @{term "Spec S"}
| THM _ => @{term "Spec S"}
val full_nm = read_const ctxt (name ^ "_'proc")
|> dest_Const |> fst |> unsuffix "_'proc"