From 9f6b294465270ac19497695d284ec485940fe5b2 Mon Sep 17 00:00:00 2001 From: Samuel Gruetter Date: Tue, 25 Jul 2023 21:47:05 -0400 Subject: [PATCH 01/15] define a WP.cmd' in terms of exec, might soon replace WP.cmd and rules for cmd' whose premises are copied from WP.cmd. This one is "fs everywhere" (ie list of functions everywhere). The wp_call rule requires a NoDup, which would be cumbersome to carry around. --- bedrock2/src/bedrock2/WeakestPrecondition.v | 364 +++++++++++++++++++- 1 file changed, 362 insertions(+), 2 deletions(-) diff --git a/bedrock2/src/bedrock2/WeakestPrecondition.v b/bedrock2/src/bedrock2/WeakestPrecondition.v index ce45aa805..de6409fd9 100644 --- a/bedrock2/src/bedrock2/WeakestPrecondition.v +++ b/bedrock2/src/bedrock2/WeakestPrecondition.v @@ -42,6 +42,28 @@ Section WeakestPrecondition. Fixpoint expr e := expr_body expr e. End WithMemAndLocals. + Ltac t := + repeat match goal with + | |- forall _, _ => progress intros + | H: exists _, _ |- _ => destruct H + | H: and _ _ |- _ => destruct H + | H: eq _ ?y |- _ => subst y + | _ => progress cbn in * + end; eauto. + + Lemma expr_sound: forall m l e mc post (H : WeakestPrecondition.expr m l e post), + exists v mc', Semantics.eval_expr m l e mc = Some (v, mc') /\ post v. + Proof. + induction e; t. + { destruct H. destruct H. eexists. eexists. rewrite H. eauto. } + { eapply IHe in H; t. cbv [WeakestPrecondition.load] in H0; t. rewrite H. rewrite H0. eauto. } + { eapply IHe in H; t. cbv [WeakestPrecondition.load] in H0; t. rewrite H. rewrite H0. eauto. } + { eapply IHe1 in H; t. eapply IHe2 in H0; t. rewrite H, H0; eauto. } + { eapply IHe1 in H; t. rewrite H. Tactics.destruct_one_match. + { eapply IHe3 in H0; t. } + { eapply IHe2 in H0; t. } } + Qed. + Section WithF. Context {A B} (f: A -> (B -> Prop) -> Prop). Definition list_map_body rec (xs : list A) (post : list B -> Prop) : Prop := @@ -55,10 +77,348 @@ Section WeakestPrecondition. Fixpoint list_map xs := list_map_body list_map xs. End WithF. + Lemma exprs_sound : forall m l args mc P, + list_map (expr m l) args P -> + exists x mc', Semantics.evaluate_call_args_log m l args mc = Some (x, mc') /\ P x. + Proof. + induction args; cbn; repeat (subst; t). + unfold Semantics.eval_expr in *. + eapply expr_sound in H; t; rewrite H. + eapply IHargs in H0; t; rewrite H0. + eauto. + Qed. + + Lemma getmany_sound: forall a l P, + list_map (get l) a P -> exists vs, map.getmany_of_list l a = Some vs /\ P vs. + Proof. + cbv [map.getmany_of_list]. + induction a; cbn; repeat (subst; t). + cbv [WeakestPrecondition.get] in H; t. + epose proof (IHa _ _ H0); clear IHa; t. + rewrite H. erewrite H1. eexists; split; eauto. + Qed. + + Definition dexpr m l e v := expr m l e (eq v). + Definition dexprs m l es vs := list_map (expr m l) es (eq vs). + + (* TODO move *) + Lemma map__invert_get_of_list{env_ok: map.ok env}: forall ksvs k v, + map.get (map.of_list (map := env) ksvs) k = Some v -> + List.In k (List.map fst ksvs). + Proof. + induction ksvs; cbn; intros. + - rewrite map.get_empty in H. discriminate H. + - destruct a as (k' & v'). rewrite Properties.map.get_put_dec in H. + destr.destr (String.eqb k' k). + + left. reflexivity. + + right. eapply IHksvs. eassumption. + Qed. + + Lemma exec_cons_env{env_ok: map.ok env}: forall fname fimpl fs c t m l mc post, + ~ List.In fname (List.map fst fs) -> + exec (map.of_list fs) c t m l mc post -> + exec (map.of_list ((fname, fimpl) :: fs)) c t m l mc post. + Proof. + induction 2; try solve [econstructor; eauto]. + econstructor; try eassumption. + cbn. rewrite map.get_put_diff. 1: eassumption. + intro C. subst fname0. + apply H. + eapply map__invert_get_of_list. + eassumption. + Qed. + + Section WithFunctionList1. + Context (fs: list (String.string * (list String.string * list String.string * cmd))). + + Inductive cmd' (c : Syntax.cmd) (t : trace) (m : mem) (l : locals) + (post : (trace -> mem -> locals -> Prop)) : Prop := + | mk_cmd' (_ : forall mc, exec (map.of_list fs) c t m l mc + (fun t' m' l' mc' => post t' m' l')). + + Lemma invert_cmd': forall c t m l post, + cmd' c t m l post -> + forall mc, exec (map.of_list fs) c t m l mc (fun t' m' l' mc' => post t' m' l'). + Proof. intros. inversion H. apply H0. Qed. + + Definition func' '(innames, outnames, c) (t : trace) (m : mem) (args : list word) + (post : trace -> mem -> list word -> Prop) := + exists l, map.of_list_zip innames args = Some l /\ + cmd' c t m l (fun t m l => + list_map (get l) outnames (fun rets => + post t m rets)). + End WithFunctionList1. + + Definition call_body' rec (functions : list (String.string * (list String.string * list String.string * cmd.cmd))) + (fname : String.string) (t : trace) (m : mem) (args : list word) + (post : trace -> mem -> list word -> Prop) : Prop := + match functions with + | nil => False + | cons (f, decl) functions => + if String.eqb f fname + then func' functions decl t m args post + else rec functions fname t m args post + end. + Fixpoint call' functions := call_body' call' functions. + + Section Dedup. + Context [A: Type] (aeq: A -> A -> bool). + + (* dedup on (x :: xs) with x having a duplicate in xs discards x, whereas + head_prio_dedup keeps x but removes its duplicate from xs *) + Fixpoint List__head_prio_dedup (xs : list A) : list A := + match xs with + | nil => nil + | cons h t => let t' := List__head_prio_dedup t in + cons h (List.removeb aeq h t') + end. + End Dedup. + + Lemma NoDup_head_prio_dedup[V: Type]: forall (l: list (String.string * V)), + List.NoDup (List.map fst (List__head_prio_dedup + (fun '(f1, _) '(f2, _) => String.eqb f1 f2) l)). + Proof. + induction l; cbn. 1: constructor. + destruct a as (k, v). cbn. + constructor. + - intro C. eapply List.in_map_iff in C. + destruct C as [[k' v'] [E C]]. cbn in E. subst k'. + unfold List.removeb in *. + eapply List.filter_In in C. apply proj2 in C. rewrite String.eqb_refl in C. + discriminate C. + - + Admitted. (* hopefully holds *) + + Lemma map__get_of_list_filter_diff{env_ok: map.ok env}: forall k k' kvs, + k <> k' -> + map.get (map.of_list (map := env) kvs) k' = + map.get (map.of_list (List.filter + (fun p => negb (let '(kj, _) := p in String.eqb k kj)) kvs)) k'. + Proof. + induction kvs; cbn; intros. 1: reflexivity. + destruct a as (kj & v). + rewrite Properties.map.get_put_dec. destr.destr (String.eqb kj k'). + - destr.destr (String.eqb k k'). 1: contradiction. + cbn. rewrite map.get_put_same. reflexivity. + - destr.destr (String.eqb k kj); cbn. + + eapply IHkvs. assumption. + + rewrite map.get_put_diff by congruence. eapply IHkvs. assumption. + Qed. + + Lemma map__of_list_ignores_head_prio_dedup{env_ok: map.ok env}: forall ksvs, + map.of_list (map := env) ksvs = + map.of_list (List__head_prio_dedup (fun '(f1, _) '(f2, _) => String.eqb f1 f2) ksvs). + Proof. + induction ksvs; cbn. 1: reflexivity. + destruct a as (k & v). + eapply map.map_ext. + intros k'. rewrite? Properties.map.get_put_dec. destr.destr (String.eqb k k'). + 1: reflexivity. + rewrite IHksvs. + unfold List.removeb. + remember (List__head_prio_dedup (fun '(f1, _) '(f2, _) => String.eqb f1 f2) ksvs) as L. + apply map__get_of_list_filter_diff. assumption. + Qed. + + Lemma call'_ignores_head_prio_dedup_otherdirection{env_ok: map.ok env}: + forall fs fname t m args post, + call' (List__head_prio_dedup (fun '(f1, _) '(f2, _) => String.eqb f1 f2) fs) + fname t m args post -> + call' fs fname t m args post. + Proof. + induction fs; cbn; intros. 1: assumption. + destruct a as (f, decl). destr.destr (String.eqb f fname). + - unfold func' in *. destruct decl as ((argnames, retnames), body). + destruct H as (l & Hl & Hbody). exists l. split. 1: exact Hl. + inversion Hbody. constructor. intro mc. specialize (H mc). + rewrite map__of_list_ignores_head_prio_dedup in H. + Abort. + + Lemma call'_ignores_head_prio_dedup{env_ok: map.ok env}: + forall fs fname t m args post, + call' fs fname t m args post -> + call' (List__head_prio_dedup (fun '(f1, _) '(f2, _) => String.eqb f1 f2) fs) + fname t m args post. + Proof. + induction fs; cbn; intros. 1: assumption. + destruct a as (f, decl). destr.destr (String.eqb f fname). + - unfold func' in *. destruct decl as ((argnames, retnames), body). + destruct H as (l & Hl & Hbody). exists l. split. 1: exact Hl. + constructor. intro mc. eapply invert_cmd' in Hbody. + rewrite map__of_list_ignores_head_prio_dedup in Hbody. + Admitted. (* TODO probably DOES NOT HOLD because recursive call of call' is made + on smaller env with current function removed *) + + Section WithFunctionList2. + Implicit Type post : trace -> mem -> locals -> Prop. + Context (fs: list (String.string * (list String.string * list String.string * cmd))). + + Notation cmd' := (cmd' fs). + + Ltac step := + match reverse goal with + | H: _ /\ _ |- _ => destruct H + | H: exists x, _ |- _ => let n := fresh x in destruct H as [n H] + | |- _ => progress unfold dlet, dexpr, store in * + | H: cmd' _ _ _ _ _ |- _ => pose proof (invert_cmd' _ _ _ _ _ _ H); clear H + | |- _ => constructor + | |- _ => assumption + | H: forall _: MetricLogging.MetricLog, _ |- _ => apply H + | |- _ => progress intros + | |- _ => progress subst + (* creates an evar for metrics, therefore needs to be applied from top to bottom, + so we need `match reverse` instead of `match` *) + | H: expr _ _ _ _ |- _ => eapply expr_sound in H + | |- _ => solve [econstructor; eauto] + end. + Ltac tac := repeat step. + + Lemma wp_skip: forall t m l post, post t m l -> cmd' cmd.skip t m l post. + Proof. tac. Qed. + + Lemma wp_set: forall x ev t m l post, + (exists v, dexpr m l ev v /\ + dlet! l := map.put l x v in + post t m l) -> + cmd' (cmd.set x ev) t m l post. + Proof. tac. Qed. + + Lemma wp_unset: forall x t m l post, + (dlet! l := map.remove l x in + post t m l) -> + cmd' (cmd.unset x) t m l post. + Proof. tac. Qed. + + Lemma wp_store: forall sz ea ev t m l post, + (exists a, dexpr m l ea a /\ + exists v, dexpr m l ev v /\ + store sz m a v (fun m => + post t m l)) -> + cmd' (cmd.store sz ea ev) t m l post. + Proof. tac. Qed. + + Lemma wp_stackalloc: forall x n c t m l post, + (Z.modulo n (bytes_per_word width) = 0 /\ + forall a mStack mCombined, + anybytes a n mStack -> map.split mCombined m mStack -> + dlet! l := map.put l x a in + cmd' c t mCombined l (fun t' mCombined' l' => + exists m' mStack', + anybytes a n mStack' /\ map.split mCombined' m' mStack' /\ + post t' m' l')) -> + cmd' (cmd.stackalloc x n c) t m l post. + Proof. tac. specialize H0 with (1 := H1) (2 := H2). tac. Qed. + + Lemma wp_cond: forall br ct cf t m l post, + (exists v, dexpr m l br v /\ + (word.unsigned v <> 0%Z -> cmd' ct t m l post) /\ + (word.unsigned v = 0%Z -> cmd' cf t m l post)) -> + cmd' (cmd.cond br ct cf) t m l post. + Proof. + tac. destr.destr (Z.eqb (word.unsigned v0) 0). + - specialize H1 with (1 := E). tac. + - specialize H0 with (1 := E). tac. + Qed. + + Lemma wp_seq: forall c1 c2 t m l post, + cmd' c1 t m l (fun t m l => cmd' c2 t m l post) -> + cmd' (cmd.seq c1 c2) t m l post. + Proof. + tac. eapply exec.weaken. + { econstructor. 1: eapply H0. tac. } + tac. + Qed. + + Lemma wp_while: forall e c t m l post, + (exists measure (lt:measure->measure->Prop) (inv:measure->trace->mem->locals->Prop), + Coq.Init.Wf.well_founded lt /\ + (exists v, inv v t m l) /\ + (forall v t m l, inv v t m l -> + exists b, dexpr m l e b /\ + (word.unsigned b <> 0%Z -> cmd' c t m l (fun t' m l => + exists v', inv v' t' m l /\ lt v' v)) /\ + (word.unsigned b = 0%Z -> post t m l))) -> + cmd' (cmd.while e c) t m l post. + Proof. + intros. destruct H as (measure & lt & inv & Hwf & HInit & Hbody). + destruct HInit as (v0 & HInit). + econstructor. intros. + revert t m l mc HInit. pattern v0. revert v0. + eapply (well_founded_ind Hwf). intros. + specialize Hbody with (1 := HInit). destruct Hbody as (b & Hb & Ht & Hf). + eapply expr_sound in Hb. destruct Hb as (b' & mc' & Hb & ?). subst b'. + destr.destr (Z.eqb (word.unsigned b) 0). + - specialize Hf with (1 := E). eapply exec.while_false; eassumption. + - specialize Ht with (1 := E). inversion Ht. clear Ht. + eapply exec.while_true; eauto. + cbv beta. intros * (v' & HInv & HLt). eauto. + Qed. + + Lemma wp_call0{env_ok: map.ok env} + (Hnd : List.NoDup (List.map fst fs)): (* <--------- *) + forall binds fname arges t m l post, + (exists args, dexprs m l arges args /\ + call' fs fname t m args (fun t m rets => + exists l', map.putmany_of_list_zip binds rets l = Some l' /\ + post t m l')) -> + cmd' (cmd.call binds fname arges) t m l post. + Proof. + tac. + unfold dexprs in *. + eapply exprs_sound in H. destruct H as (argvs & mc' & HEv & ?). subst argvs. + unfold call' in *. + revert fname H0. induction fs; intros. + - cbn in H0. contradiction. + - rename l0 into fs0. + destruct a as (fnameHere & ((argnames & retnames) & fbody)). + inversion Hnd. subst. + cbn in H0. + destr.destr (String.eqb fnameHere fname). + + destruct H0 as (l1 & Hl1 & Hbody). + inversion Hbody. clear Hbody. rename H into Hbody. + eapply exec.call. + * cbn. rewrite map.get_put_same. reflexivity. + * eassumption. + * eassumption. + * eapply exec_cons_env. 1: assumption. apply Hbody. + * cbv beta. intros. eapply getmany_sound. assumption. + + eapply exec_cons_env. 1: assumption. + eapply IHl0; assumption. + Qed. + + Lemma wp_interact: forall binds action arges t m l post, + (exists args, dexprs m l arges args /\ + exists mKeep mGive, map.split m mKeep mGive /\ + ext_spec t mGive action args (fun mReceive rets => + exists l', map.putmany_of_list_zip binds rets l = Some l' /\ + forall m', map.split m' mKeep mReceive -> + post (cons ((mGive, action, args), (mReceive, rets)) t) m' l')) -> + cmd' (cmd.interact binds action arges) t m l post. + Proof. + tac. + eapply exprs_sound in H. destruct H as (argvs & mc' & HEv & ?). subst argvs. + tac. + Qed. + End WithFunctionList2. + + (* without NoDup assumption, but probably doesn't hold *) + Lemma wp_call{env_ok: map.ok env}: forall fs binds fname arges t m l post, + (exists args, dexprs m l arges args /\ + call' fs fname t m args (fun t m rets => + exists l', map.putmany_of_list_zip binds rets l = Some l' /\ + post t m l')) -> + cmd' fs (cmd.call binds fname arges) t m l post. + Proof. + intros. destruct H as (args & Hargs & H). + constructor. rewrite map__of_list_ignores_head_prio_dedup. eapply invert_cmd'. + eapply (wp_call0 _ (env_ok := env_ok)). + 1: eapply NoDup_head_prio_dedup. + eexists. split. 1: eassumption. + eapply call'_ignores_head_prio_dedup. assumption. + Qed. + Section WithFunctions. Context (call : String.string -> trace -> mem -> list word -> (trace -> mem -> list word -> Prop) -> Prop). - Definition dexpr m l e v := expr m l e (eq v). - Definition dexprs m l es vs := list_map (expr m l) es (eq vs). Definition cmd_body (rec:_->_->_->_->_->Prop) (c : cmd) (t : trace) (m : mem) (l : locals) (post : trace -> mem -> locals -> Prop) : Prop := (* give value of each pure expression when stating its subproof *) From aa6b219eb53fa8f1be4d7fcfffc06ed4a8fe27f9 Mon Sep 17 00:00:00 2001 From: Samuel Gruetter Date: Tue, 25 Jul 2023 22:11:43 -0400 Subject: [PATCH 02/15] dead simple `call` based on `map.get` --- bedrock2/src/bedrock2/WeakestPrecondition.v | 137 ++------------------ 1 file changed, 14 insertions(+), 123 deletions(-) diff --git a/bedrock2/src/bedrock2/WeakestPrecondition.v b/bedrock2/src/bedrock2/WeakestPrecondition.v index de6409fd9..e45fe7926 100644 --- a/bedrock2/src/bedrock2/WeakestPrecondition.v +++ b/bedrock2/src/bedrock2/WeakestPrecondition.v @@ -147,19 +147,13 @@ Section WeakestPrecondition. cmd' c t m l (fun t m l => list_map (get l) outnames (fun rets => post t m rets)). - End WithFunctionList1. - Definition call_body' rec (functions : list (String.string * (list String.string * list String.string * cmd.cmd))) - (fname : String.string) (t : trace) (m : mem) (args : list word) - (post : trace -> mem -> list word -> Prop) : Prop := - match functions with - | nil => False - | cons (f, decl) functions => - if String.eqb f fname - then func' functions decl t m args post - else rec functions fname t m args post - end. - Fixpoint call' functions := call_body' call' functions. + Definition call' (fname: String.string) := + match map.get (map.of_list fs) fname with + | Some fimpl => func' fimpl + | None => fun _ _ _ _ => False + end. + End WithFunctionList1. Section Dedup. Context [A: Type] (aeq: A -> A -> bool). @@ -174,81 +168,6 @@ Section WeakestPrecondition. end. End Dedup. - Lemma NoDup_head_prio_dedup[V: Type]: forall (l: list (String.string * V)), - List.NoDup (List.map fst (List__head_prio_dedup - (fun '(f1, _) '(f2, _) => String.eqb f1 f2) l)). - Proof. - induction l; cbn. 1: constructor. - destruct a as (k, v). cbn. - constructor. - - intro C. eapply List.in_map_iff in C. - destruct C as [[k' v'] [E C]]. cbn in E. subst k'. - unfold List.removeb in *. - eapply List.filter_In in C. apply proj2 in C. rewrite String.eqb_refl in C. - discriminate C. - - - Admitted. (* hopefully holds *) - - Lemma map__get_of_list_filter_diff{env_ok: map.ok env}: forall k k' kvs, - k <> k' -> - map.get (map.of_list (map := env) kvs) k' = - map.get (map.of_list (List.filter - (fun p => negb (let '(kj, _) := p in String.eqb k kj)) kvs)) k'. - Proof. - induction kvs; cbn; intros. 1: reflexivity. - destruct a as (kj & v). - rewrite Properties.map.get_put_dec. destr.destr (String.eqb kj k'). - - destr.destr (String.eqb k k'). 1: contradiction. - cbn. rewrite map.get_put_same. reflexivity. - - destr.destr (String.eqb k kj); cbn. - + eapply IHkvs. assumption. - + rewrite map.get_put_diff by congruence. eapply IHkvs. assumption. - Qed. - - Lemma map__of_list_ignores_head_prio_dedup{env_ok: map.ok env}: forall ksvs, - map.of_list (map := env) ksvs = - map.of_list (List__head_prio_dedup (fun '(f1, _) '(f2, _) => String.eqb f1 f2) ksvs). - Proof. - induction ksvs; cbn. 1: reflexivity. - destruct a as (k & v). - eapply map.map_ext. - intros k'. rewrite? Properties.map.get_put_dec. destr.destr (String.eqb k k'). - 1: reflexivity. - rewrite IHksvs. - unfold List.removeb. - remember (List__head_prio_dedup (fun '(f1, _) '(f2, _) => String.eqb f1 f2) ksvs) as L. - apply map__get_of_list_filter_diff. assumption. - Qed. - - Lemma call'_ignores_head_prio_dedup_otherdirection{env_ok: map.ok env}: - forall fs fname t m args post, - call' (List__head_prio_dedup (fun '(f1, _) '(f2, _) => String.eqb f1 f2) fs) - fname t m args post -> - call' fs fname t m args post. - Proof. - induction fs; cbn; intros. 1: assumption. - destruct a as (f, decl). destr.destr (String.eqb f fname). - - unfold func' in *. destruct decl as ((argnames, retnames), body). - destruct H as (l & Hl & Hbody). exists l. split. 1: exact Hl. - inversion Hbody. constructor. intro mc. specialize (H mc). - rewrite map__of_list_ignores_head_prio_dedup in H. - Abort. - - Lemma call'_ignores_head_prio_dedup{env_ok: map.ok env}: - forall fs fname t m args post, - call' fs fname t m args post -> - call' (List__head_prio_dedup (fun '(f1, _) '(f2, _) => String.eqb f1 f2) fs) - fname t m args post. - Proof. - induction fs; cbn; intros. 1: assumption. - destruct a as (f, decl). destr.destr (String.eqb f fname). - - unfold func' in *. destruct decl as ((argnames, retnames), body). - destruct H as (l & Hl & Hbody). exists l. split. 1: exact Hl. - constructor. intro mc. eapply invert_cmd' in Hbody. - rewrite map__of_list_ignores_head_prio_dedup in Hbody. - Admitted. (* TODO probably DOES NOT HOLD because recursive call of call' is made - on smaller env with current function removed *) - Section WithFunctionList2. Implicit Type post : trace -> mem -> locals -> Prop. Context (fs: list (String.string * (list String.string * list String.string * cmd))). @@ -354,9 +273,7 @@ Section WeakestPrecondition. cbv beta. intros * (v' & HInv & HLt). eauto. Qed. - Lemma wp_call0{env_ok: map.ok env} - (Hnd : List.NoDup (List.map fst fs)): (* <--------- *) - forall binds fname arges t m l post, + Lemma wp_call{env_ok: map.ok env}: forall binds fname arges t m l post, (exists args, dexprs m l arges args /\ call' fs fname t m args (fun t m rets => exists l', map.putmany_of_list_zip binds rets l = Some l' /\ @@ -367,23 +284,13 @@ Section WeakestPrecondition. unfold dexprs in *. eapply exprs_sound in H. destruct H as (argvs & mc' & HEv & ?). subst argvs. unfold call' in *. - revert fname H0. induction fs; intros. - - cbn in H0. contradiction. - - rename l0 into fs0. - destruct a as (fnameHere & ((argnames & retnames) & fbody)). - inversion Hnd. subst. - cbn in H0. - destr.destr (String.eqb fnameHere fname). - + destruct H0 as (l1 & Hl1 & Hbody). - inversion Hbody. clear Hbody. rename H into Hbody. - eapply exec.call. - * cbn. rewrite map.get_put_same. reflexivity. - * eassumption. - * eassumption. - * eapply exec_cons_env. 1: assumption. apply Hbody. - * cbv beta. intros. eapply getmany_sound. assumption. - + eapply exec_cons_env. 1: assumption. - eapply IHl0; assumption. + Tactics.destruct_one_match_hyp. 2: contradiction. + unfold func' in *. + destruct p as ((argnames & retnames) & fbody). + destruct H0 as (l1 & Hl1 & Hbody). + inversion Hbody. clear Hbody. rename H into Hbody. + eapply exec.call; eauto. + cbv beta. intros. eapply getmany_sound. assumption. Qed. Lemma wp_interact: forall binds action arges t m l post, @@ -401,22 +308,6 @@ Section WeakestPrecondition. Qed. End WithFunctionList2. - (* without NoDup assumption, but probably doesn't hold *) - Lemma wp_call{env_ok: map.ok env}: forall fs binds fname arges t m l post, - (exists args, dexprs m l arges args /\ - call' fs fname t m args (fun t m rets => - exists l', map.putmany_of_list_zip binds rets l = Some l' /\ - post t m l')) -> - cmd' fs (cmd.call binds fname arges) t m l post. - Proof. - intros. destruct H as (args & Hargs & H). - constructor. rewrite map__of_list_ignores_head_prio_dedup. eapply invert_cmd'. - eapply (wp_call0 _ (env_ok := env_ok)). - 1: eapply NoDup_head_prio_dedup. - eexists. split. 1: eassumption. - eapply call'_ignores_head_prio_dedup. assumption. - Qed. - Section WithFunctions. Context (call : String.string -> trace -> mem -> list word -> (trace -> mem -> list word -> Prop) -> Prop). Definition cmd_body (rec:_->_->_->_->_->Prop) (c : cmd) (t : trace) (m : mem) (l : locals) From 18d9e85d93353656610f48479e3d15e1f035b249 Mon Sep 17 00:00:00 2001 From: Samuel Gruetter Date: Tue, 25 Jul 2023 22:17:22 -0400 Subject: [PATCH 03/15] convert from "fs everywhere" to "env everywhere" --- bedrock2/src/bedrock2/WeakestPrecondition.v | 62 +++------------------ 1 file changed, 8 insertions(+), 54 deletions(-) diff --git a/bedrock2/src/bedrock2/WeakestPrecondition.v b/bedrock2/src/bedrock2/WeakestPrecondition.v index e45fe7926..f4cd7ac80 100644 --- a/bedrock2/src/bedrock2/WeakestPrecondition.v +++ b/bedrock2/src/bedrock2/WeakestPrecondition.v @@ -101,44 +101,16 @@ Section WeakestPrecondition. Definition dexpr m l e v := expr m l e (eq v). Definition dexprs m l es vs := list_map (expr m l) es (eq vs). - (* TODO move *) - Lemma map__invert_get_of_list{env_ok: map.ok env}: forall ksvs k v, - map.get (map.of_list (map := env) ksvs) k = Some v -> - List.In k (List.map fst ksvs). - Proof. - induction ksvs; cbn; intros. - - rewrite map.get_empty in H. discriminate H. - - destruct a as (k' & v'). rewrite Properties.map.get_put_dec in H. - destr.destr (String.eqb k' k). - + left. reflexivity. - + right. eapply IHksvs. eassumption. - Qed. - - Lemma exec_cons_env{env_ok: map.ok env}: forall fname fimpl fs c t m l mc post, - ~ List.In fname (List.map fst fs) -> - exec (map.of_list fs) c t m l mc post -> - exec (map.of_list ((fname, fimpl) :: fs)) c t m l mc post. - Proof. - induction 2; try solve [econstructor; eauto]. - econstructor; try eassumption. - cbn. rewrite map.get_put_diff. 1: eassumption. - intro C. subst fname0. - apply H. - eapply map__invert_get_of_list. - eassumption. - Qed. - - Section WithFunctionList1. - Context (fs: list (String.string * (list String.string * list String.string * cmd))). + Section WithFunctionEnv. + Context (e: env). Inductive cmd' (c : Syntax.cmd) (t : trace) (m : mem) (l : locals) (post : (trace -> mem -> locals -> Prop)) : Prop := - | mk_cmd' (_ : forall mc, exec (map.of_list fs) c t m l mc - (fun t' m' l' mc' => post t' m' l')). + | mk_cmd' (_ : forall mc, exec e c t m l mc (fun t' m' l' mc' => post t' m' l')). Lemma invert_cmd': forall c t m l post, cmd' c t m l post -> - forall mc, exec (map.of_list fs) c t m l mc (fun t' m' l' mc' => post t' m' l'). + forall mc, exec e c t m l mc (fun t' m' l' mc' => post t' m' l'). Proof. intros. inversion H. apply H0. Qed. Definition func' '(innames, outnames, c) (t : trace) (m : mem) (args : list word) @@ -149,37 +121,19 @@ Section WeakestPrecondition. post t m rets)). Definition call' (fname: String.string) := - match map.get (map.of_list fs) fname with + match map.get e fname with | Some fimpl => func' fimpl | None => fun _ _ _ _ => False end. - End WithFunctionList1. - Section Dedup. - Context [A: Type] (aeq: A -> A -> bool). - - (* dedup on (x :: xs) with x having a duplicate in xs discards x, whereas - head_prio_dedup keeps x but removes its duplicate from xs *) - Fixpoint List__head_prio_dedup (xs : list A) : list A := - match xs with - | nil => nil - | cons h t => let t' := List__head_prio_dedup t in - cons h (List.removeb aeq h t') - end. - End Dedup. - - Section WithFunctionList2. Implicit Type post : trace -> mem -> locals -> Prop. - Context (fs: list (String.string * (list String.string * list String.string * cmd))). - - Notation cmd' := (cmd' fs). Ltac step := match reverse goal with | H: _ /\ _ |- _ => destruct H | H: exists x, _ |- _ => let n := fresh x in destruct H as [n H] | |- _ => progress unfold dlet, dexpr, store in * - | H: cmd' _ _ _ _ _ |- _ => pose proof (invert_cmd' _ _ _ _ _ _ H); clear H + | H: cmd' _ _ _ _ _ |- _ => pose proof (invert_cmd' _ _ _ _ _ H); clear H | |- _ => constructor | |- _ => assumption | H: forall _: MetricLogging.MetricLog, _ |- _ => apply H @@ -275,7 +229,7 @@ Section WeakestPrecondition. Lemma wp_call{env_ok: map.ok env}: forall binds fname arges t m l post, (exists args, dexprs m l arges args /\ - call' fs fname t m args (fun t m rets => + call' fname t m args (fun t m rets => exists l', map.putmany_of_list_zip binds rets l = Some l' /\ post t m l')) -> cmd' (cmd.call binds fname arges) t m l post. @@ -306,7 +260,7 @@ Section WeakestPrecondition. eapply exprs_sound in H. destruct H as (argvs & mc' & HEv & ?). subst argvs. tac. Qed. - End WithFunctionList2. + End WithFunctionEnv. Section WithFunctions. Context (call : String.string -> trace -> mem -> list word -> (trace -> mem -> list word -> Prop) -> Prop). From b83d340b77acffcaea25aad8f78f9810958b8b29 Mon Sep 17 00:00:00 2001 From: Samuel Gruetter Date: Thu, 27 Jul 2023 20:56:50 -0400 Subject: [PATCH 04/15] instead of unfold1_cmd_goal, eapply lemma_corresponding_to_command In an "env everywhere" setting, where program_logic_goal_for! adds a (map.get fs fname = Some fimpl) hypothesis. Surprise #1: There's no case in straightline that handles if-then-else Surprise #2: unfold1_... tactics are not the only place that depend on conversion: There also exists a letexists in SPI that turns a (WP (cmd.cond e _ _) ...) into an (exists v, eval e v /\ ...), and probably more elsewhere. --- bedrock2/src/bedrock2/Loops.v | 96 +++++----- bedrock2/src/bedrock2/ProgramLogic.v | 24 ++- bedrock2/src/bedrock2/WeakestPrecondition.v | 176 +++++------------- .../bedrock2/WeakestPreconditionProperties.v | 113 ++--------- bedrock2/src/bedrock2Examples/SPI.v | 11 ++ bedrock2/src/bedrock2Examples/swap_by_add.v | 2 +- 6 files changed, 134 insertions(+), 288 deletions(-) diff --git a/bedrock2/src/bedrock2/Loops.v b/bedrock2/src/bedrock2/Loops.v index 11950acc1..b36f2896f 100644 --- a/bedrock2/src/bedrock2/Loops.v +++ b/bedrock2/src/bedrock2/Loops.v @@ -11,15 +11,12 @@ From bedrock2 Require Import WeakestPrecondition WeakestPreconditionProperties. Section Loops. Context {width: Z} {BW: Bitwidth width} {word: word.word width} {mem: map.map word Byte.byte}. Context {locals: map.map String.string word}. - Context {env: map.map String.string (list String.string * list String.string * Syntax.cmd)}. Context {ext_spec: ExtSpec}. Context {word_ok : word.ok word} {mem_ok : map.ok mem}. Context {locals_ok : map.ok locals}. - Context {env_ok : map.ok env}. Context {ext_spec_ok : Semantics.ext_spec.ok ext_spec}. - Context {functions : list (String.string * (list String.string * list String.string * Syntax.cmd))}. - Let call := WeakestPrecondition.call functions. + Context {fs : env}. Lemma tailrec_localsmap_1ghost {e c t} {m: mem} {l} {post : trace -> mem -> locals -> Prop} @@ -32,15 +29,16 @@ Section Loops. (Hbody: forall v g t m l, P v g t m l -> exists br, expr m l e (eq br) /\ - (word.unsigned br <> 0%Z -> cmd call c t m l + (word.unsigned br <> 0%Z -> cmd fs c t m l (fun t' m' l' => exists v' g', P v' g' t' m' l' /\ lt v' v /\ (forall t'' m'' l'', Q v' g' t'' m'' l'' -> Q v g t'' m'' l''))) /\ (word.unsigned br = 0%Z -> Q v g t m l)) (Hpost: forall t m l, Q v0 g0 t m l -> post t m l) - : cmd call (cmd.while e c) t m l post. + : cmd fs (cmd.while e c) t m l post. Proof. + eapply wp_while. eexists measure, lt, (fun v t m l => exists g, P v g t m l /\ forall t'' m'' l'', Q v g t'' m'' l'' -> Q v0 g0 t'' m'' l''). split; [assumption|]. @@ -50,8 +48,7 @@ Section Loops. destruct Hbody as (br & ? & Hbody). exists br; split; [assumption|]. destruct Hbody as (Htrue & Hfalse). split; intros Hbr; [pose proof(Htrue Hbr)as Hpc|pose proof(Hfalse Hbr)as Hpc]; clear Hbr Htrue Hfalse. - { eapply Proper_cmd; [reflexivity..| | |eapply Hpc]. - { eapply Proper_call; firstorder idtac. } + { eapply Proper_cmd; [ |eapply Hpc]. intros tj mj lj (vj& gj & HPj & Hlt & Qji); eauto 9. } { eauto. } Qed. @@ -67,16 +64,17 @@ Section Loops. (Hbody: forall v g t m l, P v g t m l -> exists br, expr m l e (eq br) /\ - (word.unsigned br <> 0%Z -> cmd call c t m l + (word.unsigned br <> 0%Z -> cmd fs c t m l (fun t' m' l' => exists v' g', P v' g' t' m' l' /\ lt v' v /\ (forall t'' m'' l'', Q v' g' t'' m'' l'' -> Q v g t'' m'' l''))) /\ - (word.unsigned br = 0%Z -> cmd call rest t m l (Q v g))) - : cmd call (cmd.seq (cmd.while e c) rest) t m l (Q v0 g0). + (word.unsigned br = 0%Z -> cmd fs rest t m l (Q v g))) + : cmd fs (cmd.seq (cmd.while e c) rest) t m l (Q v0 g0). Proof. + eapply wp_seq. cbn. eapply tailrec_localsmap_1ghost with - (Q := fun v g t m l => cmd call rest t m l (Q v g)). + (Q := fun v g t m l => cmd fs rest t m l (Q v g)). 1: eassumption. 1: exact Hpre. 2: intros *; exact id. @@ -85,14 +83,12 @@ Section Loops. destruct Hbody as (br & ? & Hbody). exists br; split; [assumption|]. destruct Hbody as (Htrue & Hfalse). split; intros Hbr; [pose proof(Htrue Hbr)as Hpc|pose proof(Hfalse Hbr)as Hpc]; clear Hbr Htrue Hfalse. - { eapply Proper_cmd; [reflexivity..| | |eapply Hpc]. - { eapply Proper_call; firstorder idtac. } + { eapply Proper_cmd; [ |eapply Hpc]. intros tj mj lj (vj& gj & HPj & Hlt & Qji). do 2 eexists. split. 1: eassumption. split. 1: assumption. intros. - eapply Proper_cmd; [reflexivity..| | | ]. - 3: eassumption. - { eapply Proper_call; firstorder idtac. } + eapply Proper_cmd. + 2: eassumption. intros tk mk lk HH. eapply Qji. assumption. } eapply Hpc. Qed. @@ -166,10 +162,11 @@ Section Loops. invariant v t m l -> exists br, expr m l e (eq br) /\ (word.unsigned br <> 0 -> - cmd call c t m l (fun t m l => exists v', invariant v' t m l /\ lt v' v)) /\ + cmd fs c t m l (fun t m l => exists v', invariant v' t m l /\ lt v' v)) /\ (word.unsigned br = 0 -> post t m l)) - : cmd call (cmd.while e c) t m l post. + : cmd fs (cmd.while e c) t m l post. Proof. + eapply wp_while. eexists measure, lt, invariant. split. 1: exact Hwf. split. 1: eauto. @@ -190,13 +187,13 @@ Section Loops. let l := reconstruct variables localstuple in exists br, expr m l e (eq br) /\ (word.unsigned br <> 0 -> - cmd call c t m l (fun t m l => + cmd fs c t m l (fun t m l => Markers.unique (Markers.left (tuple.existss (fun localstuple => enforce variables localstuple l /\ Markers.right (Markers.unique (exists v', tuple.apply (invariant v' t m) localstuple /\ lt v' v))))))) /\ (word.unsigned br = 0 -> post t m l))) - : cmd call (cmd.while e c) t m l post. + : cmd fs (cmd.while e c) t m l post. Proof. eapply (while_localsmap (fun v t m l => exists localstuple, enforce variables localstuple l /\ @@ -210,7 +207,7 @@ Section Loops. destruct Hbody as (br & Cond & Again & Done). exists br. split; [exact Cond|]. split; [|exact Done]. intro NE. specialize (Again NE). - eapply Proper_cmd; [eapply Proper_call| |eapply Again]. + eapply Proper_cmd; [ |eapply Again]. cbv [Morphisms.pointwise_relation Basics.impl Markers.right Markers.unique Markers.left] in *. intros t' m' l' Ex. eapply hlist.existss_exists in Ex. cbv beta in Ex. destruct Ex as (ls & E & v' & Inv' & LT). @@ -234,7 +231,7 @@ Section Loops. match tuple.apply (hlist.apply (spec v) g t m) l with S_ => S_.(1) -> Markers.unique (Markers.left (exists br, expr m localsmap e (eq br) /\ Markers.right ( - (word.unsigned br <> 0%Z -> cmd call c t m localsmap + (word.unsigned br <> 0%Z -> cmd fs c t m localsmap (fun t' m' localsmap' => Markers.unique (Markers.left (hlist.existss (fun l' => enforce variables l' localsmap' /\ Markers.right ( Markers.unique (Markers.left (hlist.existss (fun g' => exists v', @@ -244,9 +241,10 @@ Section Loops. forall T M, hlist.foralls (fun L => tuple.apply (S'.(2) T M) L -> tuple.apply (S_.(2) T M) L)) end))))))))) /\ (word.unsigned br = 0%Z -> tuple.apply (S_.(2) t m) l))))end)))) (Hpost : match (tuple.apply (hlist.apply (spec v0) g0 t m) l0).(2) with Q0 => forall t m, hlist.foralls (fun l => tuple.apply (Q0 t m) l -> post t m (reconstruct variables l))end) - , cmd call (cmd.while e c) t m localsmap post ). + , cmd fs (cmd.while e c) t m localsmap post ). Proof. eapply hlist_forall_foralls; intros g0 **. + eapply wp_while. eexists measure, lt, (fun vi ti mi localsmapi => exists gi li, localsmapi = reconstruct variables li /\ match tuple.apply (hlist.apply (spec vi) gi ti mi) li with S_ => @@ -259,8 +257,7 @@ Section Loops. destruct (hlist.foralls_forall (hlist.foralls_forall (Hbody vi) gi ti mi) _ ltac:(eassumption)) as (br&?&X). exists br; split; [assumption|]. destruct X as (Htrue&Hfalse). split; intros Hbr; [pose proof(Htrue Hbr)as Hpc|pose proof(Hfalse Hbr)as Hpc]; clear Hbr Htrue Hfalse. - { eapply Proper_cmd; [reflexivity..| | |eapply Hpc]. - { eapply Proper_call; firstorder idtac. } + { eapply Proper_cmd; [ |eapply Hpc]. intros tj mj lmapj Hlj; eapply hlist.existss_exists in Hlj. destruct Hlj as (lj&Elj&HE); eapply reconstruct_enforce in Elj; subst lmapj. eapply hlist.existss_exists in HE. destruct HE as (l&?&?&?&HR). @@ -279,7 +276,7 @@ Section Loops. let S := spec v t m l in let (P, Q) := S in P -> exists br, expr m l e (eq br) /\ - (word.unsigned br <> 0%Z -> cmd call c t m l + (word.unsigned br <> 0%Z -> cmd fs c t m l (fun t' m' l' => exists v', let S' := spec v' t' m' l' in let '(P', Q') := S' in P' /\ @@ -287,8 +284,9 @@ Section Loops. forall T M L, Q' T M L -> Q T M L)) /\ (word.unsigned br = 0%Z -> Q t m l)) (Hpost : forall t m l, Q0 t m l -> post t m l) - : cmd call (cmd.while e c) t m l post. + : cmd fs (cmd.while e c) t m l post. Proof. + eapply wp_while. eexists measure, lt, (fun v t m l => let S := spec v t m l in let '(P, Q) := S in P /\ forall T M L, Q T M L -> Q0 T M L). @@ -299,8 +297,7 @@ Section Loops. destruct (Hbody _ _ _ _ ltac:(eassumption)) as (br&?&X); exists br; split; [assumption|]. destruct X as (Htrue&Hfalse). split; intros Hbr; [pose proof(Htrue Hbr)as Hpc|pose proof(Hfalse Hbr)as Hpc]; clear Hbr Htrue Hfalse. - { eapply Proper_cmd; [reflexivity..| | |eapply Hpc]. - { eapply Proper_call; firstorder idtac. } + { eapply Proper_cmd; [ |eapply Hpc]. intros tj mj lj (vj&dP&?&dQ); eauto 9. } { eauto. } Qed. @@ -328,12 +325,13 @@ Section Loops. (Henter : exists br, expr m l e (eq br) /\ (word.unsigned br = 0%Z -> post t m l)) (v0 : measure) (Hpre : invariant v0 t m l) (Hbody : forall v t m l, invariant v t m l -> - cmd call c t m l (fun t m l => + cmd fs c t m l (fun t m l => exists br, expr m l e (eq br) /\ (word.unsigned br <> 0 -> exists v', invariant v' t m l /\ lt v' v) /\ (word.unsigned br = 0 -> post t m l))) - : cmd call (cmd.while e c) t m l post. + : cmd fs (cmd.while e c) t m l post. Proof. + eapply wp_while. eexists (option measure), (with_bottom lt), (fun ov t m l => exists br, expr m l e (eq br) /\ ((word.unsigned br <> 0 -> exists v, ov = Some v /\ invariant v t m l) /\ @@ -349,7 +347,7 @@ Section Loops. intros vi ti mi li (br&Ebr&Hcontinue&Hexit). eexists; split; [eassumption|]; split. { intros Hc; destruct (Hcontinue Hc) as (v&?&Hinv); subst. - eapply Proper_cmd; [| |eapply Hbody; eassumption]; [eapply Proper_call|]. + eapply Proper_cmd; [ |eapply Hbody; eassumption]. intros t' m' l' (br'&Ebr'&Hinv'&Hpost'). destruct (BinInt.Z.eq_dec (word.unsigned br') 0). { exists None; split; try constructor. @@ -374,7 +372,7 @@ Section Loops. let S := spec v t m l in let (P, Q) := S in P -> exists br, expr m l e (eq br) /\ - (word.unsigned br <> 0%Z -> cmd call c t m l + (word.unsigned br <> 0%Z -> cmd fs c t m l (fun t' m' l' => (exists br, expr m' l' e (eq br) /\ word.unsigned br = 0 /\ Q t' m' l') \/ exists v', let S' := spec v' t' m' l' in let '(P', Q') := S' in @@ -383,8 +381,9 @@ Section Loops. forall T M L, Q' T M L -> Q T M L)) /\ (word.unsigned br = 0%Z -> Q t m l)) (Hpost : forall t m l, Q0 t m l -> post t m l) - : cmd call (cmd.while e c) t m l post. + : cmd fs (cmd.while e c) t m l post. Proof. + eapply wp_while. eexists (option measure), (with_bottom lt), (fun v t m l => match v with | None => exists br, expr m l e (eq br) /\ word.unsigned br = 0 /\ Q0 t m l @@ -399,8 +398,7 @@ Section Loops. { destruct (Hbody _ _ _ _ ltac:(eassumption)) as (br&?&X); exists br; split; [assumption|]. destruct X as (Htrue&Hfalse). split; intros Hbr; [pose proof(Htrue Hbr)as Hpc|pose proof(Hfalse Hbr)as Hpc]; eauto. - eapply Proper_cmd; [reflexivity..| | |eapply Hpc]. - { eapply Proper_call; firstorder idtac. } + eapply Proper_cmd; [ |eapply Hpc]. intros tj mj lj [(br'&Hbr'&Hz&HQ)|(vj&dP&?&dQ)]; [exists None | exists (Some vj)]; cbn [with_bottom]; eauto 9. } repeat esplit || eauto || intros; contradiction. @@ -423,7 +421,7 @@ Section Loops. match tuple.apply (hlist.apply (spec v) g t m) l with S_ => S_.(1) -> Markers.unique (Markers.left (exists br, expr m localsmap e (eq br) /\ Markers.right ( - (word.unsigned br <> 0%Z -> cmd call c t m localsmap + (word.unsigned br <> 0%Z -> cmd fs c t m localsmap (fun t' m' localsmap' => Markers.unique (Markers.left (hlist.existss (fun l' => enforce variables l' localsmap' /\ Markers.right ( Markers.unique (Markers.left (exists br, expr m' localsmap' e (eq br) /\ Markers.right ( word.unsigned br = 0 /\ tuple.apply (S_.(2) t' m') l') ) ) \/ @@ -434,9 +432,10 @@ Section Loops. forall T M, hlist.foralls (fun L => tuple.apply (S'.(2) T M) L -> tuple.apply (S_.(2) T M) L)) end))))))))) /\ (word.unsigned br = 0%Z -> tuple.apply (S_.(2) t m) l))))end)))) (Hpost : match (tuple.apply (hlist.apply (spec v0) g0 t m) l0).(2) with Q0 => forall t m, hlist.foralls (fun l => tuple.apply (Q0 t m) l -> post t m (reconstruct variables l))end) - , cmd call (cmd.while e c) t m localsmap post ). + , cmd fs (cmd.while e c) t m localsmap post ). Proof. eapply hlist_forall_foralls; intros g0 **. + eapply wp_while. eexists (option measure), (with_bottom lt), (fun vi ti mi localsmapi => exists li, localsmapi = reconstruct variables li /\ match vi with None => exists br, expr mi localsmapi e (eq br) /\ word.unsigned br = 0 /\ tuple.apply ((tuple.apply (hlist.apply (spec v0) g0 t m) l0).(2) ti mi) li | Some vi => @@ -455,8 +454,7 @@ Section Loops. destruct (hlist.foralls_forall (hlist.foralls_forall (Hbody vi) gi ti mi) _ ltac:(eassumption)) as (br&?&X). exists br; split; [assumption|]. destruct X as (Htrue&Hfalse). split; intros Hbr; [pose proof(Htrue Hbr)as Hpc|pose proof(Hfalse Hbr)as Hpc]; clear Hbr Htrue Hfalse. - { eapply Proper_cmd; [reflexivity..| | |eapply Hpc]. - { eapply Proper_call; firstorder idtac. } + { eapply Proper_cmd; [ |eapply Hpc]. intros tj mj lmapj Hlj; eapply hlist.existss_exists in Hlj. destruct Hlj as (lj&Elj&HE); eapply reconstruct_enforce in Elj; subst lmapj. destruct HE as [(br'&Hevalr'&Hz'&Hdone)|HE]. @@ -480,11 +478,11 @@ Section Loops. (v0 : measure) (Hpre : tuple.apply (invariant v0 t m) localstuple) (Hbody : forall v t m, tuple.foralls (fun localstuple => tuple.apply (invariant v t m) localstuple -> - cmd call c t m (reconstruct variables localstuple) (fun t m l => + cmd fs c t m (reconstruct variables localstuple) (fun t m l => exists br, expr m l e (eq br) /\ (word.unsigned br <> 0 -> Markers.unique (Markers.left (tuple.existss (fun localstuple => enforce variables localstuple l /\ Markers.right (Markers.unique (exists v', tuple.apply (invariant v' t m) localstuple /\ lt v' v)))))) /\ (word.unsigned br = 0 -> post t m l)))) - : cmd call (cmd.while e c) t m l post. + : cmd fs (cmd.while e c) t m l post. Proof. eapply (atleastonce_localsmap (fun v t m l => exists localstuple, Logic.and (enforce variables localstuple l) (tuple.apply (invariant v t m) localstuple))); eauto. intros vi ti mi li (?&X&Y). @@ -492,7 +490,7 @@ Section Loops. eapply hlist.foralls_forall in Hbody. specialize (Hbody Y). rewrite <-(reconstruct_enforce _ _ _ X) in Hbody. - eapply Proper_cmd; [eapply Proper_call| |eapply Hbody]. + eapply Proper_cmd; [ |eapply Hbody]. intros t' m' l' (?&?&HH&?). eexists; split; eauto. split; intros; eauto. @@ -504,7 +502,7 @@ Section Loops. Lemma while_zero_iterations {e c t l} {m : mem} {post : _->_->_-> Prop} (HCond: expr m l e (eq (word.of_Z 0))) (HPost: post t m l) - : cmd call (cmd.while e c) t m l post. + : cmd fs (cmd.while e c) t m l post. Proof. eapply (while_localsmap (fun n t' m' l' => t' = t /\ m' = m /\ l' = l) (PeanoNat.Nat.lt_wf 0) 0%nat). 1: unfold split; auto. intros *. intros (? & ? & ?). subst. @@ -525,14 +523,15 @@ Section Loops. (Hpre : (P v0 t l * R0) m) (Hbody : forall v t m l R, (P v t l * R) m -> exists br, expr m l e (eq br) /\ - (word.unsigned br <> 0%Z -> cmd call c t m l + (word.unsigned br <> 0%Z -> cmd fs c t m l (fun t' m' l' => exists v' dR, (P v' t' l' * (R * dR)) m' /\ lt v' v /\ forall T L, Q v' T L * dR ==> Q v T L)) /\ (word.unsigned br = 0%Z -> (Q v t l * R) m)) (Hpost : forall t m l, (Q v0 t l * R0) m -> post t m l) - : cmd call (cmd.while e c) t m l post. + : cmd fs (cmd.while e c) t m l post. Proof. + eapply wp_while. eexists measure, lt, (fun v t m l => exists R, (P v t l * R) m /\ forall T L, Q v T L * R ==> Q v0 T L * R0). split; [assumption|]. @@ -541,8 +540,7 @@ Section Loops. destruct (Hbody _ _ _ _ _ ltac:(eassumption)) as (br&?&X); exists br; split; [assumption|]. destruct X as (Htrue&Hfalse). split; intros Hbr; [pose proof(Htrue Hbr)as Hpc|pose proof(Hfalse Hbr)as Hpc]; clear Hbr Htrue Hfalse. - { eapply Proper_cmd; [reflexivity..| | |eapply Hpc]. - { eapply Proper_call; firstorder idtac. } + { eapply Proper_cmd; [ |eapply Hpc]. intros tj mj lj (vj&dR&dP&?&dQ). exists vj; split; [|assumption]. exists (Ri * dR); split; [assumption|]. diff --git a/bedrock2/src/bedrock2/ProgramLogic.v b/bedrock2/src/bedrock2/ProgramLogic.v index b0a5b6e63..a40d8f4bc 100644 --- a/bedrock2/src/bedrock2/ProgramLogic.v +++ b/bedrock2/src/bedrock2/ProgramLogic.v @@ -1,11 +1,12 @@ From coqutil.Tactics Require Import Tactics letexists eabstract rdelta reference_to_string ident_of_string. +Require Import coqutil.Map.Interface. Require Import bedrock2.Syntax. Require Import bedrock2.WeakestPrecondition. Require Import bedrock2.WeakestPreconditionProperties. Require Import bedrock2.Loops. Require Import bedrock2.Map.SeparationLogic bedrock2.Scalars. -Definition spec_of (procname:String.string) := list (String.string * (list String.string * list String.string * Syntax.cmd.cmd)) -> Prop. +Definition spec_of (procname:String.string) := env -> Prop. Existing Class spec_of. Module Import Coercions. @@ -55,9 +56,9 @@ Ltac program_logic_goal_for_function proc := let __ := constr:(proc : Syntax.func) in constr_string_basename_of_constr_reference_cps ltac:(Tactics.head proc) ltac:(fun fname => let spec := lazymatch constr:(_:spec_of fname) with ?s => s end in - exact (forall functions : list (string * Syntax.func), ltac:( + exact (forall functions : env, map.get functions fname = Some proc -> ltac:( let callees := eval cbv in (callees (snd proc)) in - let s := assuming_correctness_of_in callees functions (spec (cons (fname, proc) functions)) in + let s := assuming_correctness_of_in callees functions (spec functions) in exact s))). Definition program_logic_goal_for (_ : Syntax.func) (P : Prop) := P. @@ -84,7 +85,7 @@ Ltac bind_body_of_function f_ := (* note: f might have some implicit parameters (eg a record of constants) *) Ltac enter f := - cbv beta delta [program_logic_goal_for]; intros; + cbv beta delta [program_logic_goal_for]; bind_body_of_function f; lazymatch goal with |- ?s ?p => let s := rdelta s in change (s p); cbv beta end. @@ -228,13 +229,16 @@ Ltac straightline := match goal with | _ => straightline_cleanup | |- program_logic_goal_for ?f _ => - enter f; intros; - unfold1_call_goal; cbv match beta delta [call_body]; - lazymatch goal with |- if ?test then ?T else _ => - replace test with true by reflexivity; change T end; + enter f; + cbv beta delta [call]; + lazymatch goal with + | H: map.get ?functions ?fname = Some _ |- context[map.get ?functions ?fname] => + rewrite H; clear H + end; + intros; cbv match beta delta [WeakestPrecondition.func] | |- WeakestPrecondition.cmd _ (cmd.set ?s ?e) _ _ _ ?post => - unfold1_cmd_goal; cbv beta match delta [cmd_body]; + eapply wp_set; let __ := match s with String.String _ _ => idtac | String.EmptyString => idtac end in ident_of_constr_string_cps s ltac:(fun x => ensure_free x; @@ -246,7 +250,7 @@ Ltac straightline := | cmd.while _ _ => fail | cmd.cond _ _ _ => fail | cmd.interact _ _ _ => fail - | _ => unfold1_cmd_goal; cbv beta match delta [cmd_body] + | _ => apply_rule_for_command c end | |- @list_map _ _ (get _) _ _ => unfold1_list_map_goal; cbv beta match delta [list_map_body] | |- @list_map _ _ (expr _ _) _ _ => unfold1_list_map_goal; cbv beta match delta [list_map_body] diff --git a/bedrock2/src/bedrock2/WeakestPrecondition.v b/bedrock2/src/bedrock2/WeakestPrecondition.v index f4cd7ac80..6287c8a61 100644 --- a/bedrock2/src/bedrock2/WeakestPrecondition.v +++ b/bedrock2/src/bedrock2/WeakestPrecondition.v @@ -2,10 +2,15 @@ Require Import coqutil.Macros.subst coqutil.Macros.unique coqutil.Map.Interface Require Import Coq.ZArith.BinIntDef coqutil.Word.Interface coqutil.Word.Bitwidth. Require Import coqutil.dlet bedrock2.Syntax bedrock2.Semantics. +Require Import coqutil.Map.Interface. +Require coqutil.Map.SortedListString. + +#[export] Instance env: map.map String.string (list String.string * list String.string * Syntax.cmd.cmd) := SortedListString.map _. +#[export] Instance env_ok: map.ok env := SortedListString.ok _. + Section WeakestPrecondition. Context {width: Z} {BW: Bitwidth width} {word: word.word width} {mem: map.map word Byte.byte}. Context {locals: map.map String.string word}. - Context {env: map.map String.string (list String.string * list String.string * cmd)}. Context {ext_spec: ExtSpec}. Implicit Types (t : trace) (m : mem) (l : locals). @@ -104,25 +109,25 @@ Section WeakestPrecondition. Section WithFunctionEnv. Context (e: env). - Inductive cmd' (c : Syntax.cmd) (t : trace) (m : mem) (l : locals) + Inductive cmd (c : Syntax.cmd) (t : trace) (m : mem) (l : locals) (post : (trace -> mem -> locals -> Prop)) : Prop := - | mk_cmd' (_ : forall mc, exec e c t m l mc (fun t' m' l' mc' => post t' m' l')). + | mk_cmd (_ : forall mc, exec e c t m l mc (fun t' m' l' mc' => post t' m' l')). - Lemma invert_cmd': forall c t m l post, - cmd' c t m l post -> + Lemma invert_cmd: forall c t m l post, + cmd c t m l post -> forall mc, exec e c t m l mc (fun t' m' l' mc' => post t' m' l'). Proof. intros. inversion H. apply H0. Qed. - Definition func' '(innames, outnames, c) (t : trace) (m : mem) (args : list word) + Definition func '(innames, outnames, c) (t : trace) (m : mem) (args : list word) (post : trace -> mem -> list word -> Prop) := exists l, map.of_list_zip innames args = Some l /\ - cmd' c t m l (fun t m l => + cmd c t m l (fun t m l => list_map (get l) outnames (fun rets => post t m rets)). - Definition call' (fname: String.string) := + Definition call (fname: String.string) := match map.get e fname with - | Some fimpl => func' fimpl + | Some fimpl => func fimpl | None => fun _ _ _ _ => False end. @@ -133,7 +138,7 @@ Section WeakestPrecondition. | H: _ /\ _ |- _ => destruct H | H: exists x, _ |- _ => let n := fresh x in destruct H as [n H] | |- _ => progress unfold dlet, dexpr, store in * - | H: cmd' _ _ _ _ _ |- _ => pose proof (invert_cmd' _ _ _ _ _ H); clear H + | H: cmd _ _ _ _ _ |- _ => pose proof (invert_cmd _ _ _ _ _ H); clear H | |- _ => constructor | |- _ => assumption | H: forall _: MetricLogging.MetricLog, _ |- _ => apply H @@ -146,20 +151,20 @@ Section WeakestPrecondition. end. Ltac tac := repeat step. - Lemma wp_skip: forall t m l post, post t m l -> cmd' cmd.skip t m l post. + Lemma wp_skip: forall t m l post, post t m l -> cmd cmd.skip t m l post. Proof. tac. Qed. Lemma wp_set: forall x ev t m l post, (exists v, dexpr m l ev v /\ dlet! l := map.put l x v in post t m l) -> - cmd' (cmd.set x ev) t m l post. + cmd (cmd.set x ev) t m l post. Proof. tac. Qed. Lemma wp_unset: forall x t m l post, (dlet! l := map.remove l x in post t m l) -> - cmd' (cmd.unset x) t m l post. + cmd (cmd.unset x) t m l post. Proof. tac. Qed. Lemma wp_store: forall sz ea ev t m l post, @@ -167,7 +172,7 @@ Section WeakestPrecondition. exists v, dexpr m l ev v /\ store sz m a v (fun m => post t m l)) -> - cmd' (cmd.store sz ea ev) t m l post. + cmd (cmd.store sz ea ev) t m l post. Proof. tac. Qed. Lemma wp_stackalloc: forall x n c t m l post, @@ -175,18 +180,18 @@ Section WeakestPrecondition. forall a mStack mCombined, anybytes a n mStack -> map.split mCombined m mStack -> dlet! l := map.put l x a in - cmd' c t mCombined l (fun t' mCombined' l' => + cmd c t mCombined l (fun t' mCombined' l' => exists m' mStack', anybytes a n mStack' /\ map.split mCombined' m' mStack' /\ post t' m' l')) -> - cmd' (cmd.stackalloc x n c) t m l post. + cmd (cmd.stackalloc x n c) t m l post. Proof. tac. specialize H0 with (1 := H1) (2 := H2). tac. Qed. Lemma wp_cond: forall br ct cf t m l post, (exists v, dexpr m l br v /\ - (word.unsigned v <> 0%Z -> cmd' ct t m l post) /\ - (word.unsigned v = 0%Z -> cmd' cf t m l post)) -> - cmd' (cmd.cond br ct cf) t m l post. + (word.unsigned v <> 0%Z -> cmd ct t m l post) /\ + (word.unsigned v = 0%Z -> cmd cf t m l post)) -> + cmd (cmd.cond br ct cf) t m l post. Proof. tac. destr.destr (Z.eqb (word.unsigned v0) 0). - specialize H1 with (1 := E). tac. @@ -194,8 +199,8 @@ Section WeakestPrecondition. Qed. Lemma wp_seq: forall c1 c2 t m l post, - cmd' c1 t m l (fun t m l => cmd' c2 t m l post) -> - cmd' (cmd.seq c1 c2) t m l post. + cmd c1 t m l (fun t m l => cmd c2 t m l post) -> + cmd (cmd.seq c1 c2) t m l post. Proof. tac. eapply exec.weaken. { econstructor. 1: eapply H0. tac. } @@ -208,10 +213,10 @@ Section WeakestPrecondition. (exists v, inv v t m l) /\ (forall v t m l, inv v t m l -> exists b, dexpr m l e b /\ - (word.unsigned b <> 0%Z -> cmd' c t m l (fun t' m l => + (word.unsigned b <> 0%Z -> cmd c t m l (fun t' m l => exists v', inv v' t' m l /\ lt v' v)) /\ (word.unsigned b = 0%Z -> post t m l))) -> - cmd' (cmd.while e c) t m l post. + cmd (cmd.while e c) t m l post. Proof. intros. destruct H as (measure & lt & inv & Hwf & HInit & Hbody). destruct HInit as (v0 & HInit). @@ -227,19 +232,19 @@ Section WeakestPrecondition. cbv beta. intros * (v' & HInv & HLt). eauto. Qed. - Lemma wp_call{env_ok: map.ok env}: forall binds fname arges t m l post, + Lemma wp_call: forall binds fname arges t m l post, (exists args, dexprs m l arges args /\ - call' fname t m args (fun t m rets => + call fname t m args (fun t m rets => exists l', map.putmany_of_list_zip binds rets l = Some l' /\ post t m l')) -> - cmd' (cmd.call binds fname arges) t m l post. + cmd (cmd.call binds fname arges) t m l post. Proof. tac. unfold dexprs in *. eapply exprs_sound in H. destruct H as (argvs & mc' & HEv & ?). subst argvs. - unfold call' in *. + unfold call in *. Tactics.destruct_one_match_hyp. 2: contradiction. - unfold func' in *. + unfold func in *. destruct p as ((argnames & retnames) & fbody). destruct H0 as (l1 & Hl1 & Hbody). inversion Hbody. clear Hbody. rename H into Hbody. @@ -254,105 +259,28 @@ Section WeakestPrecondition. exists l', map.putmany_of_list_zip binds rets l = Some l' /\ forall m', map.split m' mKeep mReceive -> post (cons ((mGive, action, args), (mReceive, rets)) t) m' l')) -> - cmd' (cmd.interact binds action arges) t m l post. + cmd (cmd.interact binds action arges) t m l post. Proof. tac. eapply exprs_sound in H. destruct H as (argvs & mc' & HEv & ?). subst argvs. tac. Qed. End WithFunctionEnv. - - Section WithFunctions. - Context (call : String.string -> trace -> mem -> list word -> (trace -> mem -> list word -> Prop) -> Prop). - Definition cmd_body (rec:_->_->_->_->_->Prop) (c : cmd) (t : trace) (m : mem) (l : locals) - (post : trace -> mem -> locals -> Prop) : Prop := - (* give value of each pure expression when stating its subproof *) - match c with - | cmd.skip => post t m l - | cmd.set x ev => - exists v, dexpr m l ev v /\ - dlet! l := map.put l x v in - post t m l - | cmd.unset x => - dlet! l := map.remove l x in - post t m l - | cmd.store sz ea ev => - exists a, dexpr m l ea a /\ - exists v, dexpr m l ev v /\ - store sz m a v (fun m => - post t m l) - | cmd.stackalloc x n c => - Z.modulo n (bytes_per_word width) = 0 /\ - forall a mStack mCombined, - anybytes a n mStack -> map.split mCombined m mStack -> - dlet! l := map.put l x a in - rec c t mCombined l (fun t' mCombined' l' => - exists m' mStack', - anybytes a n mStack' /\ map.split mCombined' m' mStack' /\ - post t' m' l') - | cmd.cond br ct cf => - exists v, dexpr m l br v /\ - (word.unsigned v <> 0%Z -> rec ct t m l post) /\ - (word.unsigned v = 0%Z -> rec cf t m l post) - | cmd.seq c1 c2 => - rec c1 t m l (fun t m l => rec c2 t m l post) - | cmd.while e c => - exists measure (lt:measure->measure->Prop) (inv:measure->trace->mem->locals->Prop), - Coq.Init.Wf.well_founded lt /\ - (exists v, inv v t m l) /\ - (forall v t m l, inv v t m l -> - exists b, dexpr m l e b /\ - (word.unsigned b <> 0%Z -> rec c t m l (fun t' m l => - exists v', inv v' t' m l /\ lt v' v)) /\ - (word.unsigned b = 0%Z -> post t m l)) - | cmd.call binds fname arges => - exists args, dexprs m l arges args /\ - call fname t m args (fun t m rets => - exists l', map.putmany_of_list_zip binds rets l = Some l' /\ - post t m l') - | cmd.interact binds action arges => - exists args, dexprs m l arges args /\ - exists mKeep mGive, map.split m mKeep mGive /\ - ext_spec t mGive action args (fun mReceive rets => - exists l', map.putmany_of_list_zip binds rets l = Some l' /\ - forall m', map.split m' mKeep mReceive -> - post (cons ((mGive, action, args), (mReceive, rets)) t) m' l') - end. - Fixpoint cmd c := cmd_body cmd c. - End WithFunctions. - - Definition func call '(innames, outnames, c) (t : trace) (m : mem) (args : list word) (post : trace -> mem -> list word -> Prop) := - exists l, map.of_list_zip innames args = Some l /\ - cmd call c t m l (fun t m l => - list_map (get l) outnames (fun rets => - post t m rets)). - - Definition call_body rec (functions : list (String.string * (list String.string * list String.string * cmd.cmd))) - (fname : String.string) (t : trace) (m : mem) (args : list word) - (post : trace -> mem -> list word -> Prop) : Prop := - match functions with - | nil => False - | cons (f, decl) functions => - if String.eqb f fname - then func (rec functions) decl t m args post - else rec functions fname t m args post - end. - Fixpoint call functions := call_body call functions. - - Definition program funcs main t m l post : Prop := cmd (call funcs) main t m l post. End WeakestPrecondition. -Ltac unfold1_cmd e := - lazymatch e with - @cmd ?width ?BW ?word ?mem ?locals ?ext_spec ?CA ?c ?t ?m ?l ?post => - let c := eval hnf in c in - constr:(@cmd_body width BW word mem locals ext_spec CA - (@cmd width BW word mem locals ext_spec CA) c t m l post) +Ltac apply_rule_for_command c := + lazymatch c with + | cmd.skip => eapply wp_skip + | cmd.set ?x ?ev => eapply wp_set + | cmd.unset ?x => eapply wp_unset + | cmd.store ?sz ?ea ?ev => eapply wp_store + | cmd.stackalloc ?x ?n ?c => eapply wp_stackalloc + | cmd.cond ?br ?ct ?cf => eapply wp_cond + | cmd.seq ?c1 ?c2 => eapply wp_seq + | cmd.while ?e ?c => eapply wp_while + | cmd.call ?binds ?fname ?arges => eapply wp_call + | cmd.interact ?binds ?action ?arges => eapply wp_interact end. -Ltac unfold1_cmd_goal := - let G := lazymatch goal with |- ?G => G end in - let G := unfold1_cmd G in - change G. Ltac unfold1_expr e := lazymatch e with @@ -376,18 +304,6 @@ Ltac unfold1_list_map_goal := let G := unfold1_list_map G in change G. -Ltac unfold1_call e := - lazymatch e with - @call ?width ?BW ?word ?mem ?locals ?ext_spec ?fs ?fname ?t ?m ?l ?post => - let fs := eval hnf in fs in - constr:(@call_body width BW word mem locals ext_spec - (@call width BW word mem locals ext_spec) fs fname t m l post) - end. -Ltac unfold1_call_goal := - let G := lazymatch goal with |- ?G => G end in - let G := unfold1_call G in - change G. - Import Coq.ZArith.ZArith. Notation "'fnspec!' name a0 .. an '/' g0 .. gn '~>' r0 .. rn ',' '{' 'requires' tr mem := pre ';' 'ensures' tr' mem' ':=' post '}'" := diff --git a/bedrock2/src/bedrock2/WeakestPreconditionProperties.v b/bedrock2/src/bedrock2/WeakestPreconditionProperties.v index bb0a69516..e67b30da0 100644 --- a/bedrock2/src/bedrock2/WeakestPreconditionProperties.v +++ b/bedrock2/src/bedrock2/WeakestPreconditionProperties.v @@ -74,14 +74,15 @@ Section WeakestPrecondition. Global Instance Proper_cmd : Proper ( - (pointwise_relation _ (pointwise_relation _ (pointwise_relation _ (pointwise_relation _ (pointwise_relation _ ((pointwise_relation _ (pointwise_relation _ Basics.impl))) ==> Basics.impl)))) ==> + (pointwise_relation _ ( pointwise_relation _ ( pointwise_relation _ ( pointwise_relation _ ( pointwise_relation _ ( (pointwise_relation _ (pointwise_relation _ (pointwise_relation _ Basics.impl))) ==> - Basics.impl)))))) WeakestPrecondition.cmd. + Basics.impl))))))) WeakestPrecondition.cmd. Proof using env_ok ext_spec_ok locals_ok mem_ok word_ok. + Admitted. (* cbv [Proper respectful pointwise_relation Basics.flip Basics.impl]; ind_on Syntax.cmd.cmd; cbn in *; cbv [dlet.dlet] in *; intuition (try typeclasses eauto with core). { destruct H1 as (?&?&?). eexists. split. @@ -136,18 +137,19 @@ Section WeakestPrecondition. split; [assumption|]. eapply Semantics.ext_spec.weaken; [|solve[eassumption]]. intros ? ? (?&?&?); eauto 10. } } - Qed. + Qed. *) Global Instance Proper_func : Proper ( - (pointwise_relation _ (pointwise_relation _ (pointwise_relation _ (pointwise_relation _ (pointwise_relation _ ((pointwise_relation _ (pointwise_relation _ Basics.impl))) ==> Basics.impl)))) ==> + (pointwise_relation _ ( pointwise_relation _ ( pointwise_relation _ ( pointwise_relation _ ( pointwise_relation _ ( (pointwise_relation _ (pointwise_relation _ (pointwise_relation _ Basics.impl))) ==> - Basics.impl)))))) WeakestPrecondition.func. + Basics.impl))))))) WeakestPrecondition.func. Proof using word_ok mem_ok locals_ok ext_spec_ok env_ok. + Admitted. (* cbv [Proper respectful pointwise_relation Basics.flip Basics.impl WeakestPrecondition.func]; intros. destruct a. destruct p. destruct H1; intuition idtac. @@ -165,7 +167,7 @@ Section WeakestPrecondition. cbv [Proper respectful pointwise_relation Basics.flip Basics.impl WeakestPrecondition.func]; eauto. - eauto. - Qed. + Qed. *) Global Instance Proper_call : Proper ( @@ -177,6 +179,7 @@ Section WeakestPrecondition. (pointwise_relation _ (pointwise_relation _ (pointwise_relation _ Basics.impl))) ==> Basics.impl)))))))) WeakestPrecondition.call. Proof using word_ok mem_ok locals_ok ext_spec_ok env_ok. + Admitted. (* cbv [Proper respectful pointwise_relation Basics.impl]; ind_on (list (String.string * (list String.string * list String.string * Syntax.cmd.cmd))); cbn in *; intuition (try typeclasses eauto with core). destruct a. @@ -184,27 +187,7 @@ Section WeakestPrecondition. eapply Proper_func; cbv [Proper respectful pointwise_relation Basics.flip Basics.impl WeakestPrecondition.func]; eauto. - Qed. - - Global Instance Proper_program : - Proper ( - pointwise_relation _ ( - pointwise_relation _ ( - pointwise_relation _ ( - pointwise_relation _ ( - pointwise_relation _ ( - (pointwise_relation _ (pointwise_relation _ (pointwise_relation _ Basics.impl))) ==> - Basics.impl)))))) WeakestPrecondition.program. - Proof using word_ok mem_ok locals_ok ext_spec_ok env_ok. - cbv [Proper respectful pointwise_relation Basics.impl WeakestPrecondition.program]; intros. - eapply Proper_cmd; - cbv [Proper respectful pointwise_relation Basics.flip Basics.impl WeakestPrecondition.func]; - try solve [typeclasses eauto with core]. - intros. - eapply Proper_call; - cbv [Proper respectful pointwise_relation Basics.flip Basics.impl WeakestPrecondition.func]; - solve [typeclasses eauto with core]. - Qed. + Qed. *) Ltac t := repeat match goal with @@ -293,77 +276,10 @@ Section WeakestPrecondition. all : cbv [respectful pointwise_relation Basics.impl WeakestPrecondition.get]; intros; cbv beta; t. Qed. - Local Notation semantics_call := (fun e n t m args post => - exists params rets fbody, map.get e n = Some (params, rets, fbody) /\ - exists lf, map.putmany_of_list_zip params args map.empty = Some lf /\ - forall mc', Semantics.exec e fbody t m lf mc' (fun t' m' st1 mc'' => - exists retvs, map.getmany_of_list st1 rets = Some retvs /\ - post t' m' retvs)). - - Local Hint Constructors Semantics.exec : core. - Lemma sound_cmd' e c t m l mc post - (H:WeakestPrecondition.cmd (semantics_call e) c t m l post) - : Semantics.exec e c t m l mc (fun t' m' l' mc' => post t' m' l'). - Proof. - ind_on Syntax.cmd; repeat (t; try match reverse goal with H : WeakestPrecondition.expr _ _ _ _ |- _ => eapply expr_sound in H end). - { destruct (BinInt.Z.eq_dec (Interface.word.unsigned x) (BinNums.Z0)) as [Hb|Hb]; cycle 1. - { econstructor; t. } - { eapply Semantics.exec.if_false; t. } } - { revert dependent l; revert dependent m; revert dependent t; revert dependent mc; pattern x2. - eapply (well_founded_ind H); t. - pose proof (H1 _ _ _ _ ltac:(eassumption)); - repeat (t; try match goal with H : WeakestPrecondition.expr _ _ _ _ |- _ => eapply expr_sound in H end). - { destruct (BinInt.Z.eq_dec (Interface.word.unsigned x4) (BinNums.Z0)) as [Hb|Hb]. - { eapply Semantics.exec.while_false; t. } - { eapply Semantics.exec.while_true; t. t. } } } - { eapply sound_args in H; t. } - { eapply sound_args in H; t. } - Qed. - - - Section WithE. - Context fs (E: env) (HE: List.Forall (fun '(k, v) => map.get E k = Some v) fs). - Import coqutil.Tactics.Tactics. - Lemma sound_call' n t m args post - (H : WeakestPrecondition.call fs n t m args post) - : semantics_call E n t m args post. - Proof. - revert H; revert post args m t n; induction HE; intros. - { contradiction H. } - destruct x as [n' ((X&Y)&Z)]; t. - destr (String.eqb n' n); t. - eexists X, Y, Z; split; [assumption|]. - eexists; eauto. - eexists; eauto. - intros. - eapply sound_cmd'. - eapply Proper_cmd; try eapply H0. - all : cbv [respectful pointwise_relation Basics.impl]; intros; cbv beta. - 1: eapply IHf, Proper_call; eauto. - 2: eassumption. - eauto using sound_getmany. - Qed. - - Lemma sound_cmd'' c t m l mc post - (H : WeakestPrecondition.cmd (WeakestPrecondition.call fs) c t m l post) - : Semantics.exec E c t m l mc (fun t' m' l' mc' => post t' m' l'). - Proof. - eapply Proper_cmd in H; [ .. | reflexivity ]. - 1: apply sound_cmd'; exact H. - cbv [respectful pointwise_relation Basics.impl]; intros; cbv beta. - eapply sound_call', Proper_call, H1. - cbv [respectful pointwise_relation Basics.impl]; eauto. - Qed. - End WithE. - Lemma sound_cmd fs c t m l mc post - (Hnd : List.NoDup (List.map fst fs)) - (H : WeakestPrecondition.cmd (WeakestPrecondition.call fs) c t m l post) - : Semantics.exec (map.of_list fs) c t m l mc (fun t' m' l' mc' => post t' m' l'). - Proof. - eapply sound_cmd''; - try eapply Properties.map.all_gets_from_map_of_NoDup_list; eauto. - Qed. + (H : WeakestPrecondition.cmd fs c t m l post) + : Semantics.exec fs c t m l mc (fun t' m' l' mc' => post t' m' l'). + Proof. eapply WeakestPrecondition.invert_cmd. exact H. Qed. (** Ad-hoc lemmas here? *) @@ -376,6 +292,7 @@ Section WeakestPrecondition. post (cons (map.empty, binds, args, (map.empty, rets)) t) m l0)) : WeakestPrecondition.cmd call (cmd.interact action binds arges) t m l post. Proof using word_ok mem_ok ext_spec_ok. + Admitted. (* exists args; split; [exact Hargs|]. exists m. exists map.empty. @@ -383,7 +300,7 @@ Section WeakestPrecondition. eapply ext_spec.weaken; [|eapply Hext]; intros ? ? [? [? []]]. subst a; subst. eexists; split; [eassumption|]. intros. eapply Properties.map.split_empty_r in H. subst. assumption. - Qed. + Qed. *) Lemma intersect_expr: forall m l e (post1 post2: word -> Prop), WeakestPrecondition.expr m l e post1 -> diff --git a/bedrock2/src/bedrock2Examples/SPI.v b/bedrock2/src/bedrock2Examples/SPI.v index d484dc554..e15ea518f 100644 --- a/bedrock2/src/bedrock2Examples/SPI.v +++ b/bedrock2/src/bedrock2Examples/SPI.v @@ -130,6 +130,17 @@ Section WithParameters. cbv [isMMIOAddr addr]. ZnWords. } repeat straightline. + (* The hnf inside this letexists used to substitute + + c := cmd.cond (expr.op bopname.sru "busy" 31) cmd.skip + (cmd.set "i" (expr.op bopname.xor "i" "i")) : cmd.cmd + + and also unfolded WeakestPrecondition.cmd of c into + + WeakestPrecondition.dexpr m l0 cond letboundEvar /\ + ThenCorrectness /\ + ElseCorrectness + *) letexists. split. { repeat straightline. } split; intros. diff --git a/bedrock2/src/bedrock2Examples/swap_by_add.v b/bedrock2/src/bedrock2Examples/swap_by_add.v index 81e7898be..b7ac64911 100644 --- a/bedrock2/src/bedrock2Examples/swap_by_add.v +++ b/bedrock2/src/bedrock2Examples/swap_by_add.v @@ -56,7 +56,7 @@ Section WithParameters. repeat (straightline || straightline_call); eauto. Qed. - Lemma link_swap_swap_swap_swap : spec_of_swap_swap &[,swap_swap; swap]. + Lemma link_swap_swap_swap_swap : spec_of_swap_swap (map.of_list &[,swap_swap; swap]). Proof. eauto using swap_swap_ok, swap_ok. Qed. (* Print Assumptions link_swap_swap_swap_swap. *) From 069a89d6a052b109cd540f1a62c769748571990f Mon Sep 17 00:00:00 2001 From: Samuel Gruetter Date: Fri, 28 Jul 2023 20:30:52 -0400 Subject: [PATCH 05/15] wip "env everywhere" approach --- bedrock2/src/bedrock2/ProgramLogic.v | 4 ++-- bedrock2/src/bedrock2/WeakestPrecondition.v | 17 +++++++++++------ .../bedrock2/WeakestPreconditionProperties.v | 9 +++------ .../src/bedrock2Examples/FE310CompilerDemo.v | 4 ++-- .../bedrock2Examples/indirect_add_heapletwise.v | 6 ++++-- bedrock2/src/bedrock2Examples/memconst.v | 11 ++++++----- bedrock2/src/bedrock2Examples/swap.v | 2 +- 7 files changed, 29 insertions(+), 24 deletions(-) diff --git a/bedrock2/src/bedrock2/ProgramLogic.v b/bedrock2/src/bedrock2/ProgramLogic.v index a40d8f4bc..378a28054 100644 --- a/bedrock2/src/bedrock2/ProgramLogic.v +++ b/bedrock2/src/bedrock2/ProgramLogic.v @@ -56,7 +56,7 @@ Ltac program_logic_goal_for_function proc := let __ := constr:(proc : Syntax.func) in constr_string_basename_of_constr_reference_cps ltac:(Tactics.head proc) ltac:(fun fname => let spec := lazymatch constr:(_:spec_of fname) with ?s => s end in - exact (forall functions : env, map.get functions fname = Some proc -> ltac:( + exact (forall (functions : @map.rep _ _ env) (EnvContains : map.get functions fname = Some proc), ltac:( let callees := eval cbv in (callees (snd proc)) in let s := assuming_correctness_of_in callees functions (spec functions) in exact s))). @@ -238,7 +238,7 @@ Ltac straightline := intros; cbv match beta delta [WeakestPrecondition.func] | |- WeakestPrecondition.cmd _ (cmd.set ?s ?e) _ _ _ ?post => - eapply wp_set; + unfold1_cmd_goal; let __ := match s with String.String _ _ => idtac | String.EmptyString => idtac end in ident_of_constr_string_cps s ltac:(fun x => ensure_free x; diff --git a/bedrock2/src/bedrock2/WeakestPrecondition.v b/bedrock2/src/bedrock2/WeakestPrecondition.v index 6287c8a61..b8468911b 100644 --- a/bedrock2/src/bedrock2/WeakestPrecondition.v +++ b/bedrock2/src/bedrock2/WeakestPrecondition.v @@ -5,7 +5,7 @@ Require Import coqutil.dlet bedrock2.Syntax bedrock2.Semantics. Require Import coqutil.Map.Interface. Require coqutil.Map.SortedListString. -#[export] Instance env: map.map String.string (list String.string * list String.string * Syntax.cmd.cmd) := SortedListString.map _. +#[export] Instance env: map.map String.string Syntax.func := SortedListString.map _. #[export] Instance env_ok: map.ok env := SortedListString.ok _. Section WeakestPrecondition. @@ -56,13 +56,13 @@ Section WeakestPrecondition. | _ => progress cbn in * end; eauto. - Lemma expr_sound: forall m l e mc post (H : WeakestPrecondition.expr m l e post), + Lemma expr_sound: forall m l e mc post (H : expr m l e post), exists v mc', Semantics.eval_expr m l e mc = Some (v, mc') /\ post v. Proof. induction e; t. { destruct H. destruct H. eexists. eexists. rewrite H. eauto. } - { eapply IHe in H; t. cbv [WeakestPrecondition.load] in H0; t. rewrite H. rewrite H0. eauto. } - { eapply IHe in H; t. cbv [WeakestPrecondition.load] in H0; t. rewrite H. rewrite H0. eauto. } + { eapply IHe in H; t. cbv [load] in H0; t. rewrite H. rewrite H0. eauto. } + { eapply IHe in H; t. cbv [load] in H0; t. rewrite H. rewrite H0. eauto. } { eapply IHe1 in H; t. eapply IHe2 in H0; t. rewrite H, H0; eauto. } { eapply IHe1 in H; t. rewrite H. Tactics.destruct_one_match. { eapply IHe3 in H0; t. } @@ -98,7 +98,7 @@ Section WeakestPrecondition. Proof. cbv [map.getmany_of_list]. induction a; cbn; repeat (subst; t). - cbv [WeakestPrecondition.get] in H; t. + cbv [get] in H; t. epose proof (IHa _ _ H0); clear IHa; t. rewrite H. erewrite H1. eexists; split; eauto. Qed. @@ -245,7 +245,7 @@ Section WeakestPrecondition. unfold call in *. Tactics.destruct_one_match_hyp. 2: contradiction. unfold func in *. - destruct p as ((argnames & retnames) & fbody). + destruct f as ((argnames & retnames) & fbody). destruct H0 as (l1 & Hl1 & Hbody). inversion Hbody. clear Hbody. rename H into Hbody. eapply exec.call; eauto. @@ -282,6 +282,11 @@ Ltac apply_rule_for_command c := | cmd.interact ?binds ?action ?arges => eapply wp_interact end. +Ltac unfold1_cmd_goal := + lazymatch goal with + | |- cmd _ ?c _ _ _ ?post => let c := eval hnf in c in apply_rule_for_command c + end. + Ltac unfold1_expr e := lazymatch e with @expr ?width ?word ?mem ?locals ?m ?l ?arg ?post => diff --git a/bedrock2/src/bedrock2/WeakestPreconditionProperties.v b/bedrock2/src/bedrock2/WeakestPreconditionProperties.v index e67b30da0..29ffd9017 100644 --- a/bedrock2/src/bedrock2/WeakestPreconditionProperties.v +++ b/bedrock2/src/bedrock2/WeakestPreconditionProperties.v @@ -7,7 +7,6 @@ Require Import Coq.Classes.Morphisms. Section WeakestPrecondition. Context {width} {BW: Bitwidth width} {word: word.word width} {mem: map.map word Byte.byte}. Context {locals: map.map String.string word}. - Context {env: map.map String.string (list String.string * list String.string * Syntax.cmd)}. Context {ext_spec: Semantics.ExtSpec}. Ltac ind_on X := @@ -23,7 +22,6 @@ Section WeakestPrecondition. we'd get a typechecking failure at Qed time. *) repeat match goal with x : ?T |- _ => first [ constr_eq T X; move x before ext_spec - | constr_eq T X; move x before env | constr_eq T X; move x before locals | constr_eq T X; move x at top | revert x ] end; @@ -69,7 +67,6 @@ Section WeakestPrecondition. Context {word_ok : word.ok word} {mem_ok : map.ok mem}. Context {locals_ok : map.ok locals}. - Context {env_ok : map.ok env}. Context {ext_spec_ok : Semantics.ext_spec.ok ext_spec}. Global Instance Proper_cmd : @@ -81,7 +78,7 @@ Section WeakestPrecondition. pointwise_relation _ ( (pointwise_relation _ (pointwise_relation _ (pointwise_relation _ Basics.impl))) ==> Basics.impl))))))) WeakestPrecondition.cmd. - Proof using env_ok ext_spec_ok locals_ok mem_ok word_ok. + Proof using ext_spec_ok locals_ok mem_ok word_ok. Admitted. (* cbv [Proper respectful pointwise_relation Basics.flip Basics.impl]; ind_on Syntax.cmd.cmd; cbn in *; cbv [dlet.dlet] in *; intuition (try typeclasses eauto with core). @@ -148,7 +145,7 @@ Section WeakestPrecondition. pointwise_relation _ ( (pointwise_relation _ (pointwise_relation _ (pointwise_relation _ Basics.impl))) ==> Basics.impl))))))) WeakestPrecondition.func. - Proof using word_ok mem_ok locals_ok ext_spec_ok env_ok. + Proof using word_ok mem_ok locals_ok ext_spec_ok. Admitted. (* cbv [Proper respectful pointwise_relation Basics.flip Basics.impl WeakestPrecondition.func]; intros. destruct a. destruct p. @@ -178,7 +175,7 @@ Section WeakestPrecondition. pointwise_relation _ ( (pointwise_relation _ (pointwise_relation _ (pointwise_relation _ Basics.impl))) ==> Basics.impl)))))))) WeakestPrecondition.call. - Proof using word_ok mem_ok locals_ok ext_spec_ok env_ok. + Proof using word_ok mem_ok locals_ok ext_spec_ok. Admitted. (* cbv [Proper respectful pointwise_relation Basics.impl]; ind_on (list (String.string * (list String.string * list String.string * Syntax.cmd.cmd))); cbn in *; intuition (try typeclasses eauto with core). diff --git a/bedrock2/src/bedrock2Examples/FE310CompilerDemo.v b/bedrock2/src/bedrock2Examples/FE310CompilerDemo.v index d5ad2241c..ad4135054 100644 --- a/bedrock2/src/bedrock2Examples/FE310CompilerDemo.v +++ b/bedrock2/src/bedrock2Examples/FE310CompilerDemo.v @@ -158,7 +158,7 @@ Local Instance mapok: map.ok mem := SortedListWord.ok Naive.word32 _. Local Instance wordok: word.ok word := Naive.word32_ok. Lemma swap_chars_over_uart_correct m : - WeakestPrecondition.cmd (fun _ _ _ _ _ => False) swap_chars_over_uart nil m map.empty + WeakestPrecondition.cmd map.empty swap_chars_over_uart nil m map.empty (fun t m l => True). Proof. repeat t. @@ -242,7 +242,7 @@ Definition echo_server: cmd := ). Lemma echo_server_correct m : - WeakestPrecondition.cmd (fun _ _ _ _ _ => False) echo_server nil m map.empty + WeakestPrecondition.cmd map.empty echo_server nil m map.empty (fun t m l => echo_server_spec t None). Proof. repeat t. diff --git a/bedrock2/src/bedrock2Examples/indirect_add_heapletwise.v b/bedrock2/src/bedrock2Examples/indirect_add_heapletwise.v index d6f8e2334..788588e65 100644 --- a/bedrock2/src/bedrock2Examples/indirect_add_heapletwise.v +++ b/bedrock2/src/bedrock2Examples/indirect_add_heapletwise.v @@ -20,6 +20,7 @@ Require Import bedrock2.HeapletwiseHyps. Require Import bedrock2.enable_frame_trick. Require Import bedrock2.PurifySep. Require Import bedrock2.Semantics bedrock2.FE310CSemantics. +Require Import coqutil.Macros.WithBaseName. Require bedrock2.WeakestPreconditionProperties. From coqutil.Tactics Require Import letexists eabstract. @@ -75,11 +76,12 @@ Section WithParameters. { cbv [f]. ecancel_assumption. } Qed. - Example link_both : spec_of_indirect_add_twice (("indirect_add_twice",indirect_add_twice)::("indirect_add",indirect_add)::nil). + Example link_both : spec_of_indirect_add_twice + (map.of_list &[,indirect_add_twice; indirect_add]). Proof. auto using indirect_add_twice_ok, indirect_add_ok. Qed. (* - Require Import bedrock2.ToCString bedrock2.PrintString coqutil.Macros.WithBaseName. + Require Import bedrock2.ToCString bedrock2.PrintString. Goal True. print_string (c_module &[,indirect_add_twice; indirect_add]). Abort. *) diff --git a/bedrock2/src/bedrock2Examples/memconst.v b/bedrock2/src/bedrock2Examples/memconst.v index 81e246be4..4c2167540 100644 --- a/bedrock2/src/bedrock2Examples/memconst.v +++ b/bedrock2/src/bedrock2Examples/memconst.v @@ -33,20 +33,21 @@ Section WithParameters. ensures t' m := m =* bs$@p * R /\ t=t' }. Context {word_ok: word.ok word} {mem_ok: map.ok mem} {locals_ok : map.ok locals} - {env : map.map string (list string * list string * Syntax.cmd)} {env_ok : map.ok env} {ext_spec_ok : ext_spec.ok ext_spec}. Import coqutil.Tactics.letexists coqutil.Tactics.Tactics coqutil.Tactics.autoforward. Import coqutil.Word.Properties coqutil.Map.Properties. + Local Ltac normalize_body_of_function f ::= f. + Local Ltac ZnWords := destruct width_cases; bedrock2.ZnWords.ZnWords. Lemma memconst_ok ident bs functions : - spec_of_memconst ident bs ((ident, memconst bs) :: functions). + program_logic_goal_for + (memconst bs) + (map.get functions ident = Some (memconst bs) -> + spec_of_memconst ident bs functions). Proof. cbv [spec_of_memconst memconst]; repeat straightline. - unfold1_call_goal; cbv beta match delta [call_body]; rewrite String.eqb_refl. - cbv beta match delta [func]. - repeat straightline. refine ((Loops.tailrec (HList.polymorphic_list.cons _ (HList.polymorphic_list.cons _ diff --git a/bedrock2/src/bedrock2Examples/swap.v b/bedrock2/src/bedrock2Examples/swap.v index 9c3eaf5f6..36878febc 100644 --- a/bedrock2/src/bedrock2Examples/swap.v +++ b/bedrock2/src/bedrock2Examples/swap.v @@ -66,7 +66,7 @@ Section WithParameters. Lemma swap_swap_ok : program_logic_goal_for_function! swap_swap. Proof. repeat (straightline || straightline_call); eauto. Qed. - Lemma link_swap_swap_swap_swap : spec_of_swap_swap &[,swap_swap; swap]. + Lemma link_swap_swap_swap_swap : spec_of_swap_swap (map.of_list &[,swap_swap; swap]). Proof. eauto using swap_swap_ok, swap_ok. Qed. (* Print Assumptions link_swap_swap_swap_swap. *) From 88c5d5e1bbec0cc626bb859e0abea3399aacb47d Mon Sep 17 00:00:00 2001 From: Samuel Gruetter Date: Mon, 31 Jul 2023 18:49:59 -0400 Subject: [PATCH 06/15] make WeakestPrecondition.cmd complete wrt exec by leaving the structurally recursive cases of cmd_body unchanged, and defining the two non-structurally recursive cases (loop and call) directly in terms of exec. This seems to be the only approach that does not break proofs in bedrock2Examples too badly. --- bedrock2/src/bedrock2/Loops.v | 75 +++-- bedrock2/src/bedrock2/ProgramLogic.v | 15 +- bedrock2/src/bedrock2/WP.v | 122 ++++++++ bedrock2/src/bedrock2/WeakestPrecondition.v | 272 ++++-------------- .../bedrock2/WeakestPreconditionProperties.v | 222 +++++++++----- .../src/bedrock2Examples/ARPResponderProofs.v | 14 +- .../src/bedrock2Examples/FE310CompilerDemo.v | 33 +++ bedrock2/src/bedrock2Examples/indirect_add.v | 2 +- bedrock2/src/bedrock2Examples/lightbulb.v | 22 +- bedrock2/src/bedrock2Examples/memmove.v | 1 + 10 files changed, 448 insertions(+), 330 deletions(-) create mode 100644 bedrock2/src/bedrock2/WP.v diff --git a/bedrock2/src/bedrock2/Loops.v b/bedrock2/src/bedrock2/Loops.v index b36f2896f..5761c6313 100644 --- a/bedrock2/src/bedrock2/Loops.v +++ b/bedrock2/src/bedrock2/Loops.v @@ -6,7 +6,7 @@ Require Import coqutil.Map.Properties. Require Import coqutil.Tactics.destr. From bedrock2 Require Import Map.Separation Map.SeparationLogic. From bedrock2 Require Import Syntax Semantics Markers. -From bedrock2 Require Import WeakestPrecondition WeakestPreconditionProperties. +From bedrock2 Require Import WeakestPrecondition WeakestPreconditionProperties WP. Section Loops. Context {width: Z} {BW: Bitwidth width} {word: word.word width} {mem: map.map word Byte.byte}. @@ -17,6 +17,32 @@ Section Loops. Context {ext_spec_ok : Semantics.ext_spec.ok ext_spec}. Context {fs : env}. + Let call := fs. + + Lemma wp_while: forall e c t m l (post: _ -> _ -> _ -> Prop), + (exists measure (lt:measure->measure->Prop) (inv:measure->trace->mem->locals->Prop), + Coq.Init.Wf.well_founded lt /\ + (exists v, inv v t m l) /\ + (forall v t m l, inv v t m l -> + exists b, dexpr m l e b /\ + (word.unsigned b <> 0%Z -> cmd call c t m l (fun t' m l => + exists v', inv v' t' m l /\ lt v' v)) /\ + (word.unsigned b = 0%Z -> post t m l))) -> + wp_cmd call (cmd.while e c) t m l post. + Proof. + intros. destruct H as (measure & lt & inv & Hwf & HInit & Hbody). + destruct HInit as (v0 & HInit). + apply mk_wp_cmd. intros. + revert t m l mc HInit. pattern v0. revert v0. + eapply (well_founded_ind Hwf). intros. + specialize Hbody with (1 := HInit). destruct Hbody as (b & Hb & Ht & Hf). + eapply expr_sound in Hb. destruct Hb as (b' & mc' & Hb & ?). subst b'. + destr.destr (Z.eqb (word.unsigned b) 0). + - specialize Hf with (1 := E). eapply exec.while_false; eassumption. + - specialize Ht with (1 := E). eapply sound_cmd in Ht. + eapply exec.while_true; eauto. + cbv beta. intros * (v' & HInv & HLt). eauto. + Qed. Lemma tailrec_localsmap_1ghost {e c t} {m: mem} {l} {post : trace -> mem -> locals -> Prop} @@ -29,14 +55,14 @@ Section Loops. (Hbody: forall v g t m l, P v g t m l -> exists br, expr m l e (eq br) /\ - (word.unsigned br <> 0%Z -> cmd fs c t m l + (word.unsigned br <> 0%Z -> cmd call c t m l (fun t' m' l' => exists v' g', P v' g' t' m' l' /\ lt v' v /\ (forall t'' m'' l'', Q v' g' t'' m'' l'' -> Q v g t'' m'' l''))) /\ (word.unsigned br = 0%Z -> Q v g t m l)) (Hpost: forall t m l, Q v0 g0 t m l -> post t m l) - : cmd fs (cmd.while e c) t m l post. + : cmd call (cmd.while e c) t m l post. Proof. eapply wp_while. eexists measure, lt, (fun v t m l => @@ -64,17 +90,16 @@ Section Loops. (Hbody: forall v g t m l, P v g t m l -> exists br, expr m l e (eq br) /\ - (word.unsigned br <> 0%Z -> cmd fs c t m l + (word.unsigned br <> 0%Z -> cmd call c t m l (fun t' m' l' => exists v' g', P v' g' t' m' l' /\ lt v' v /\ (forall t'' m'' l'', Q v' g' t'' m'' l'' -> Q v g t'' m'' l''))) /\ - (word.unsigned br = 0%Z -> cmd fs rest t m l (Q v g))) - : cmd fs (cmd.seq (cmd.while e c) rest) t m l (Q v0 g0). + (word.unsigned br = 0%Z -> cmd call rest t m l (Q v g))) + : cmd call (cmd.seq (cmd.while e c) rest) t m l (Q v0 g0). Proof. - eapply wp_seq. cbn. eapply tailrec_localsmap_1ghost with - (Q := fun v g t m l => cmd fs rest t m l (Q v g)). + (Q := fun v g t m l => cmd call rest t m l (Q v g)). 1: eassumption. 1: exact Hpre. 2: intros *; exact id. @@ -187,13 +212,13 @@ Section Loops. let l := reconstruct variables localstuple in exists br, expr m l e (eq br) /\ (word.unsigned br <> 0 -> - cmd fs c t m l (fun t m l => + cmd call c t m l (fun t m l => Markers.unique (Markers.left (tuple.existss (fun localstuple => enforce variables localstuple l /\ Markers.right (Markers.unique (exists v', tuple.apply (invariant v' t m) localstuple /\ lt v' v))))))) /\ (word.unsigned br = 0 -> post t m l))) - : cmd fs (cmd.while e c) t m l post. + : cmd call (cmd.while e c) t m l post. Proof. eapply (while_localsmap (fun v t m l => exists localstuple, enforce variables localstuple l /\ @@ -231,7 +256,7 @@ Section Loops. match tuple.apply (hlist.apply (spec v) g t m) l with S_ => S_.(1) -> Markers.unique (Markers.left (exists br, expr m localsmap e (eq br) /\ Markers.right ( - (word.unsigned br <> 0%Z -> cmd fs c t m localsmap + (word.unsigned br <> 0%Z -> cmd call c t m localsmap (fun t' m' localsmap' => Markers.unique (Markers.left (hlist.existss (fun l' => enforce variables l' localsmap' /\ Markers.right ( Markers.unique (Markers.left (hlist.existss (fun g' => exists v', @@ -241,7 +266,7 @@ Section Loops. forall T M, hlist.foralls (fun L => tuple.apply (S'.(2) T M) L -> tuple.apply (S_.(2) T M) L)) end))))))))) /\ (word.unsigned br = 0%Z -> tuple.apply (S_.(2) t m) l))))end)))) (Hpost : match (tuple.apply (hlist.apply (spec v0) g0 t m) l0).(2) with Q0 => forall t m, hlist.foralls (fun l => tuple.apply (Q0 t m) l -> post t m (reconstruct variables l))end) - , cmd fs (cmd.while e c) t m localsmap post ). + , cmd call (cmd.while e c) t m localsmap post ). Proof. eapply hlist_forall_foralls; intros g0 **. eapply wp_while. @@ -276,7 +301,7 @@ Section Loops. let S := spec v t m l in let (P, Q) := S in P -> exists br, expr m l e (eq br) /\ - (word.unsigned br <> 0%Z -> cmd fs c t m l + (word.unsigned br <> 0%Z -> cmd call c t m l (fun t' m' l' => exists v', let S' := spec v' t' m' l' in let '(P', Q') := S' in P' /\ @@ -284,7 +309,7 @@ Section Loops. forall T M L, Q' T M L -> Q T M L)) /\ (word.unsigned br = 0%Z -> Q t m l)) (Hpost : forall t m l, Q0 t m l -> post t m l) - : cmd fs (cmd.while e c) t m l post. + : cmd call (cmd.while e c) t m l post. Proof. eapply wp_while. eexists measure, lt, (fun v t m l => @@ -325,11 +350,11 @@ Section Loops. (Henter : exists br, expr m l e (eq br) /\ (word.unsigned br = 0%Z -> post t m l)) (v0 : measure) (Hpre : invariant v0 t m l) (Hbody : forall v t m l, invariant v t m l -> - cmd fs c t m l (fun t m l => + cmd call c t m l (fun t m l => exists br, expr m l e (eq br) /\ (word.unsigned br <> 0 -> exists v', invariant v' t m l /\ lt v' v) /\ (word.unsigned br = 0 -> post t m l))) - : cmd fs (cmd.while e c) t m l post. + : cmd call (cmd.while e c) t m l post. Proof. eapply wp_while. eexists (option measure), (with_bottom lt), (fun ov t m l => @@ -372,7 +397,7 @@ Section Loops. let S := spec v t m l in let (P, Q) := S in P -> exists br, expr m l e (eq br) /\ - (word.unsigned br <> 0%Z -> cmd fs c t m l + (word.unsigned br <> 0%Z -> cmd call c t m l (fun t' m' l' => (exists br, expr m' l' e (eq br) /\ word.unsigned br = 0 /\ Q t' m' l') \/ exists v', let S' := spec v' t' m' l' in let '(P', Q') := S' in @@ -381,7 +406,7 @@ Section Loops. forall T M L, Q' T M L -> Q T M L)) /\ (word.unsigned br = 0%Z -> Q t m l)) (Hpost : forall t m l, Q0 t m l -> post t m l) - : cmd fs (cmd.while e c) t m l post. + : cmd call (cmd.while e c) t m l post. Proof. eapply wp_while. eexists (option measure), (with_bottom lt), (fun v t m l => @@ -421,7 +446,7 @@ Section Loops. match tuple.apply (hlist.apply (spec v) g t m) l with S_ => S_.(1) -> Markers.unique (Markers.left (exists br, expr m localsmap e (eq br) /\ Markers.right ( - (word.unsigned br <> 0%Z -> cmd fs c t m localsmap + (word.unsigned br <> 0%Z -> cmd call c t m localsmap (fun t' m' localsmap' => Markers.unique (Markers.left (hlist.existss (fun l' => enforce variables l' localsmap' /\ Markers.right ( Markers.unique (Markers.left (exists br, expr m' localsmap' e (eq br) /\ Markers.right ( word.unsigned br = 0 /\ tuple.apply (S_.(2) t' m') l') ) ) \/ @@ -432,7 +457,7 @@ Section Loops. forall T M, hlist.foralls (fun L => tuple.apply (S'.(2) T M) L -> tuple.apply (S_.(2) T M) L)) end))))))))) /\ (word.unsigned br = 0%Z -> tuple.apply (S_.(2) t m) l))))end)))) (Hpost : match (tuple.apply (hlist.apply (spec v0) g0 t m) l0).(2) with Q0 => forall t m, hlist.foralls (fun l => tuple.apply (Q0 t m) l -> post t m (reconstruct variables l))end) - , cmd fs (cmd.while e c) t m localsmap post ). + , cmd call (cmd.while e c) t m localsmap post ). Proof. eapply hlist_forall_foralls; intros g0 **. eapply wp_while. @@ -478,11 +503,11 @@ Section Loops. (v0 : measure) (Hpre : tuple.apply (invariant v0 t m) localstuple) (Hbody : forall v t m, tuple.foralls (fun localstuple => tuple.apply (invariant v t m) localstuple -> - cmd fs c t m (reconstruct variables localstuple) (fun t m l => + cmd call c t m (reconstruct variables localstuple) (fun t m l => exists br, expr m l e (eq br) /\ (word.unsigned br <> 0 -> Markers.unique (Markers.left (tuple.existss (fun localstuple => enforce variables localstuple l /\ Markers.right (Markers.unique (exists v', tuple.apply (invariant v' t m) localstuple /\ lt v' v)))))) /\ (word.unsigned br = 0 -> post t m l)))) - : cmd fs (cmd.while e c) t m l post. + : cmd call (cmd.while e c) t m l post. Proof. eapply (atleastonce_localsmap (fun v t m l => exists localstuple, Logic.and (enforce variables localstuple l) (tuple.apply (invariant v t m) localstuple))); eauto. intros vi ti mi li (?&X&Y). @@ -502,7 +527,7 @@ Section Loops. Lemma while_zero_iterations {e c t l} {m : mem} {post : _->_->_-> Prop} (HCond: expr m l e (eq (word.of_Z 0))) (HPost: post t m l) - : cmd fs (cmd.while e c) t m l post. + : cmd call (cmd.while e c) t m l post. Proof. eapply (while_localsmap (fun n t' m' l' => t' = t /\ m' = m /\ l' = l) (PeanoNat.Nat.lt_wf 0) 0%nat). 1: unfold split; auto. intros *. intros (? & ? & ?). subst. @@ -523,13 +548,13 @@ Section Loops. (Hpre : (P v0 t l * R0) m) (Hbody : forall v t m l R, (P v t l * R) m -> exists br, expr m l e (eq br) /\ - (word.unsigned br <> 0%Z -> cmd fs c t m l + (word.unsigned br <> 0%Z -> cmd call c t m l (fun t' m' l' => exists v' dR, (P v' t' l' * (R * dR)) m' /\ lt v' v /\ forall T L, Q v' T L * dR ==> Q v T L)) /\ (word.unsigned br = 0%Z -> (Q v t l * R) m)) (Hpost : forall t m l, (Q v0 t l * R0) m -> post t m l) - : cmd fs (cmd.while e c) t m l post. + : cmd call (cmd.while e c) t m l post. Proof. eapply wp_while. eexists measure, lt, (fun v t m l => exists R, (P v t l * R) m /\ diff --git a/bedrock2/src/bedrock2/ProgramLogic.v b/bedrock2/src/bedrock2/ProgramLogic.v index 378a28054..dca598f54 100644 --- a/bedrock2/src/bedrock2/ProgramLogic.v +++ b/bedrock2/src/bedrock2/ProgramLogic.v @@ -1,6 +1,7 @@ From coqutil.Tactics Require Import Tactics letexists eabstract rdelta reference_to_string ident_of_string. Require Import coqutil.Map.Interface. Require Import bedrock2.Syntax. +Require Import bedrock2.WP. Require Import bedrock2.WeakestPrecondition. Require Import bedrock2.WeakestPreconditionProperties. Require Import bedrock2.Loops. @@ -229,16 +230,14 @@ Ltac straightline := match goal with | _ => straightline_cleanup | |- program_logic_goal_for ?f _ => - enter f; - cbv beta delta [call]; - lazymatch goal with - | H: map.get ?functions ?fname = Some _ |- context[map.get ?functions ?fname] => - rewrite H; clear H + enter f; intros; + match goal with + | H: map.get ?functions ?fname = Some _ |- _ => + eapply start_func; [exact H | clear H] end; - intros; cbv match beta delta [WeakestPrecondition.func] | |- WeakestPrecondition.cmd _ (cmd.set ?s ?e) _ _ _ ?post => - unfold1_cmd_goal; + unfold1_cmd_goal; cbv beta match delta [cmd_body]; let __ := match s with String.String _ _ => idtac | String.EmptyString => idtac end in ident_of_constr_string_cps s ltac:(fun x => ensure_free x; @@ -250,7 +249,7 @@ Ltac straightline := | cmd.while _ _ => fail | cmd.cond _ _ _ => fail | cmd.interact _ _ _ => fail - | _ => apply_rule_for_command c + | _ => unfold1_cmd_goal; cbv beta match delta [cmd_body] end | |- @list_map _ _ (get _) _ _ => unfold1_list_map_goal; cbv beta match delta [list_map_body] | |- @list_map _ _ (expr _ _) _ _ => unfold1_list_map_goal; cbv beta match delta [list_map_body] diff --git a/bedrock2/src/bedrock2/WP.v b/bedrock2/src/bedrock2/WP.v new file mode 100644 index 000000000..45d3d1eff --- /dev/null +++ b/bedrock2/src/bedrock2/WP.v @@ -0,0 +1,122 @@ +Require Import Coq.ZArith.ZArith. +Require Import coqutil.Map.Interface. +Require coqutil.Map.SortedListString. +Require Import coqutil.Word.Interface coqutil.Word.Bitwidth. +Require Import bedrock2.Syntax bedrock2.Semantics. + +#[export] Instance env: map.map String.string Syntax.func := SortedListString.map _. +#[export] Instance env_ok: map.ok env := SortedListString.ok _. + +(* We want to make the definitions opaque to `hnf` (unfolds any definition, so a plain + definition doesn't work) and to `repeat split` (applies constructors of all + 1-constructor inductives, so a 1-constructor inductive wrapping exec doesn't + work). *) +Module Type WP_Sig. + Section WithParams. + Context {width: Z} {BW: Bitwidth width} {word: word.word width} + {mem: map.map word Byte.byte} + {locals: map.map String.string word}. + + Parameter wp_cmd : forall {ext_spec: ExtSpec} (e: env), + Syntax.cmd -> trace -> mem -> locals -> + (trace -> mem -> locals -> Prop) -> Prop. + Parameter mk_wp_cmd : forall {ext_spec: ExtSpec} (e: env) c t m l post, + (forall mc, exec e c t m l mc (fun t' m' l' mc' => post t' m' l')) -> + wp_cmd e c t m l post. + Parameter invert_wp_cmd: forall {ext_spec: ExtSpec} [e c t m l post], + wp_cmd e c t m l post -> + forall mc, exec e c t m l mc (fun t' m' l' mc' => post t' m' l'). + + Parameter wp_call : forall {locals: map.map String.string word} {ext_spec: ExtSpec}, + env -> String.string -> trace -> mem -> list word -> + (trace -> mem -> list word -> Prop) -> Prop. + Parameter mk_wp_call : + forall {ext_spec: ExtSpec} (e: env) fname argnames retnames body t m l args post, + map.get e fname = Some (argnames, retnames, body) -> + map.of_list_zip argnames args = Some l -> + wp_cmd e body t m l (fun t' m' l' => exists rets, + map.getmany_of_list l' retnames = Some rets /\ post t' m' rets) -> + wp_call e fname t m args post. + Parameter invert_wp_call : forall {ext_spec: ExtSpec} (e: env) fname t m args post, + wp_call e fname t m args post -> + exists argnames retnames body l, + map.get e fname = Some (argnames, retnames, body) /\ + map.of_list_zip argnames args = Some l /\ + wp_cmd e body t m l (fun t' m' l' => exists rets, + map.getmany_of_list l' retnames = Some rets /\ post t' m' rets). + End WithParams. +End WP_Sig. + +Module Export WP_Impl : WP_Sig. + Section WithParams. + Context {width: Z} {BW: Bitwidth width} {word: word.word width} + {mem: map.map word Byte.byte} + {locals: map.map String.string word} + {ext_spec: ExtSpec} + (e: env). + + Definition wp_cmd (c : Syntax.cmd) (t : trace) (m : mem) (l : locals) + (post : (trace -> mem -> locals -> Prop)) : Prop := + (forall mc, exec e c t m l mc (fun t' m' l' mc' => post t' m' l')). + + Lemma mk_wp_cmd c t m l post: + (forall mc, exec e c t m l mc (fun t' m' l' mc' => post t' m' l')) -> + wp_cmd c t m l post. + Proof. exact id. Qed. + + Lemma invert_wp_cmd c t m l post: + wp_cmd c t m l post -> + forall mc, exec e c t m l mc (fun t' m' l' mc' => post t' m' l'). + Proof. exact id. Qed. + + Definition wp_call fname t m args post := + exists argnames retnames body l, + map.get e fname = Some (argnames, retnames, body) /\ + map.of_list_zip argnames args = Some l /\ + wp_cmd body t m l (fun t' m' l' => exists rets, + map.getmany_of_list l' retnames = Some rets /\ post t' m' rets). + + Lemma mk_wp_call: forall fname argnames retnames body t m l args post, + map.get e fname = Some (argnames, retnames, body) -> + map.of_list_zip argnames args = Some l -> + wp_cmd body t m l (fun t' m' l' => exists rets, + map.getmany_of_list l' retnames = Some rets /\ post t' m' rets) -> + wp_call fname t m args post. + Proof. intros. unfold wp_call. eauto 8. Qed. + + Lemma invert_wp_call fname t m args post: + wp_call fname t m args post -> + exists argnames retnames body l, + map.get e fname = Some (argnames, retnames, body) /\ + map.of_list_zip argnames args = Some l /\ + wp_cmd body t m l (fun t' m' l' => exists rets, + map.getmany_of_list l' retnames = Some rets /\ post t' m' rets). + Proof. exact id. Qed. + End WithParams. +End WP_Impl. + +Section WithParams. + Context {width: Z} {BW: Bitwidth width} {word: word.word width} + {mem: map.map word Byte.byte} + {locals: map.map String.string word} + {ext_spec: ExtSpec} + (e: env). + + Lemma weaken_wp_cmd: forall c t m l (post1 post2: trace -> mem -> locals -> Prop), + (forall t' m' l', post1 t' m' l' -> post2 t' m' l') -> + wp_cmd e t m l c post1 -> wp_cmd e t m l c post2. + Proof. + intros. eapply mk_wp_cmd. intros. eapply invert_wp_cmd in H0. + eapply exec.weaken. 1: eassumption. eauto. + Qed. + + Lemma weaken_wp_call: forall f t m args (post1 post2: trace -> mem -> list word -> Prop), + (forall t' m' rets, post1 t' m' rets -> post2 t' m' rets) -> + wp_call e f t m args post1 -> wp_call e f t m args post2. + Proof. + intros. eapply invert_wp_call in H0. firstorder idtac. + eapply mk_wp_call; eauto. + eapply weaken_wp_cmd. 2: eassumption. firstorder eauto. + Qed. + +End WithParams. diff --git a/bedrock2/src/bedrock2/WeakestPrecondition.v b/bedrock2/src/bedrock2/WeakestPrecondition.v index b8468911b..2a34b2093 100644 --- a/bedrock2/src/bedrock2/WeakestPrecondition.v +++ b/bedrock2/src/bedrock2/WeakestPrecondition.v @@ -1,12 +1,7 @@ Require Import coqutil.Macros.subst coqutil.Macros.unique coqutil.Map.Interface coqutil.Map.OfListWord. Require Import Coq.ZArith.BinIntDef coqutil.Word.Interface coqutil.Word.Bitwidth. Require Import coqutil.dlet bedrock2.Syntax bedrock2.Semantics. - -Require Import coqutil.Map.Interface. -Require coqutil.Map.SortedListString. - -#[export] Instance env: map.map String.string Syntax.func := SortedListString.map _. -#[export] Instance env_ok: map.ok env := SortedListString.ok _. +Require Import bedrock2.WP. Section WeakestPrecondition. Context {width: Z} {BW: Bitwidth width} {word: word.word width} {mem: map.map word Byte.byte}. @@ -47,28 +42,6 @@ Section WeakestPrecondition. Fixpoint expr e := expr_body expr e. End WithMemAndLocals. - Ltac t := - repeat match goal with - | |- forall _, _ => progress intros - | H: exists _, _ |- _ => destruct H - | H: and _ _ |- _ => destruct H - | H: eq _ ?y |- _ => subst y - | _ => progress cbn in * - end; eauto. - - Lemma expr_sound: forall m l e mc post (H : expr m l e post), - exists v mc', Semantics.eval_expr m l e mc = Some (v, mc') /\ post v. - Proof. - induction e; t. - { destruct H. destruct H. eexists. eexists. rewrite H. eauto. } - { eapply IHe in H; t. cbv [load] in H0; t. rewrite H. rewrite H0. eauto. } - { eapply IHe in H; t. cbv [load] in H0; t. rewrite H. rewrite H0. eauto. } - { eapply IHe1 in H; t. eapply IHe2 in H0; t. rewrite H, H0; eauto. } - { eapply IHe1 in H; t. rewrite H. Tactics.destruct_one_match. - { eapply IHe3 in H0; t. } - { eapply IHe2 in H0; t. } } - Qed. - Section WithF. Context {A B} (f: A -> (B -> Prop) -> Prop). Definition list_map_body rec (xs : list A) (post : list B -> Prop) : Prop := @@ -82,210 +55,81 @@ Section WeakestPrecondition. Fixpoint list_map xs := list_map_body list_map xs. End WithF. - Lemma exprs_sound : forall m l args mc P, - list_map (expr m l) args P -> - exists x mc', Semantics.evaluate_call_args_log m l args mc = Some (x, mc') /\ P x. - Proof. - induction args; cbn; repeat (subst; t). - unfold Semantics.eval_expr in *. - eapply expr_sound in H; t; rewrite H. - eapply IHargs in H0; t; rewrite H0. - eauto. - Qed. - - Lemma getmany_sound: forall a l P, - list_map (get l) a P -> exists vs, map.getmany_of_list l a = Some vs /\ P vs. - Proof. - cbv [map.getmany_of_list]. - induction a; cbn; repeat (subst; t). - cbv [get] in H; t. - epose proof (IHa _ _ H0); clear IHa; t. - rewrite H. erewrite H1. eexists; split; eauto. - Qed. - - Definition dexpr m l e v := expr m l e (eq v). - Definition dexprs m l es vs := list_map (expr m l) es (eq vs). - - Section WithFunctionEnv. + Section WithFunctions. Context (e: env). - - Inductive cmd (c : Syntax.cmd) (t : trace) (m : mem) (l : locals) - (post : (trace -> mem -> locals -> Prop)) : Prop := - | mk_cmd (_ : forall mc, exec e c t m l mc (fun t' m' l' mc' => post t' m' l')). - - Lemma invert_cmd: forall c t m l post, - cmd c t m l post -> - forall mc, exec e c t m l mc (fun t' m' l' mc' => post t' m' l'). - Proof. intros. inversion H. apply H0. Qed. - - Definition func '(innames, outnames, c) (t : trace) (m : mem) (args : list word) - (post : trace -> mem -> list word -> Prop) := - exists l, map.of_list_zip innames args = Some l /\ - cmd c t m l (fun t m l => - list_map (get l) outnames (fun rets => - post t m rets)). - - Definition call (fname: String.string) := - match map.get e fname with - | Some fimpl => func fimpl - | None => fun _ _ _ _ => False - end. - - Implicit Type post : trace -> mem -> locals -> Prop. - - Ltac step := - match reverse goal with - | H: _ /\ _ |- _ => destruct H - | H: exists x, _ |- _ => let n := fresh x in destruct H as [n H] - | |- _ => progress unfold dlet, dexpr, store in * - | H: cmd _ _ _ _ _ |- _ => pose proof (invert_cmd _ _ _ _ _ H); clear H - | |- _ => constructor - | |- _ => assumption - | H: forall _: MetricLogging.MetricLog, _ |- _ => apply H - | |- _ => progress intros - | |- _ => progress subst - (* creates an evar for metrics, therefore needs to be applied from top to bottom, - so we need `match reverse` instead of `match` *) - | H: expr _ _ _ _ |- _ => eapply expr_sound in H - | |- _ => solve [econstructor; eauto] - end. - Ltac tac := repeat step. - - Lemma wp_skip: forall t m l post, post t m l -> cmd cmd.skip t m l post. - Proof. tac. Qed. - - Lemma wp_set: forall x ev t m l post, - (exists v, dexpr m l ev v /\ + Definition dexpr m l e v := expr m l e (eq v). + Definition dexprs m l es vs := list_map (expr m l) es (eq vs). + (* All cases except cmd.while and cmd.call can be denoted by structural recursion + over the syntax. + For cmd.while and cmd.call, we fall back to the operational semantics *) + Definition cmd_body (rec:_->_->_->_->_->Prop) (c : cmd) (t : trace) (m : mem) (l : locals) + (post : trace -> mem -> locals -> Prop) : Prop := + (* give value of each pure expression when stating its subproof *) + match c with + | cmd.skip => post t m l + | cmd.set x ev => + exists v, dexpr m l ev v /\ dlet! l := map.put l x v in - post t m l) -> - cmd (cmd.set x ev) t m l post. - Proof. tac. Qed. - - Lemma wp_unset: forall x t m l post, - (dlet! l := map.remove l x in - post t m l) -> - cmd (cmd.unset x) t m l post. - Proof. tac. Qed. - - Lemma wp_store: forall sz ea ev t m l post, - (exists a, dexpr m l ea a /\ + post t m l + | cmd.unset x => + dlet! l := map.remove l x in + post t m l + | cmd.store sz ea ev => + exists a, dexpr m l ea a /\ exists v, dexpr m l ev v /\ store sz m a v (fun m => - post t m l)) -> - cmd (cmd.store sz ea ev) t m l post. - Proof. tac. Qed. - - Lemma wp_stackalloc: forall x n c t m l post, - (Z.modulo n (bytes_per_word width) = 0 /\ + post t m l) + | cmd.stackalloc x n c => + Z.modulo n (bytes_per_word width) = 0 /\ forall a mStack mCombined, anybytes a n mStack -> map.split mCombined m mStack -> dlet! l := map.put l x a in - cmd c t mCombined l (fun t' mCombined' l' => + rec c t mCombined l (fun t' mCombined' l' => exists m' mStack', anybytes a n mStack' /\ map.split mCombined' m' mStack' /\ - post t' m' l')) -> - cmd (cmd.stackalloc x n c) t m l post. - Proof. tac. specialize H0 with (1 := H1) (2 := H2). tac. Qed. - - Lemma wp_cond: forall br ct cf t m l post, - (exists v, dexpr m l br v /\ - (word.unsigned v <> 0%Z -> cmd ct t m l post) /\ - (word.unsigned v = 0%Z -> cmd cf t m l post)) -> - cmd (cmd.cond br ct cf) t m l post. - Proof. - tac. destr.destr (Z.eqb (word.unsigned v0) 0). - - specialize H1 with (1 := E). tac. - - specialize H0 with (1 := E). tac. - Qed. - - Lemma wp_seq: forall c1 c2 t m l post, - cmd c1 t m l (fun t m l => cmd c2 t m l post) -> - cmd (cmd.seq c1 c2) t m l post. - Proof. - tac. eapply exec.weaken. - { econstructor. 1: eapply H0. tac. } - tac. - Qed. - - Lemma wp_while: forall e c t m l post, - (exists measure (lt:measure->measure->Prop) (inv:measure->trace->mem->locals->Prop), - Coq.Init.Wf.well_founded lt /\ - (exists v, inv v t m l) /\ - (forall v t m l, inv v t m l -> - exists b, dexpr m l e b /\ - (word.unsigned b <> 0%Z -> cmd c t m l (fun t' m l => - exists v', inv v' t' m l /\ lt v' v)) /\ - (word.unsigned b = 0%Z -> post t m l))) -> - cmd (cmd.while e c) t m l post. - Proof. - intros. destruct H as (measure & lt & inv & Hwf & HInit & Hbody). - destruct HInit as (v0 & HInit). - econstructor. intros. - revert t m l mc HInit. pattern v0. revert v0. - eapply (well_founded_ind Hwf). intros. - specialize Hbody with (1 := HInit). destruct Hbody as (b & Hb & Ht & Hf). - eapply expr_sound in Hb. destruct Hb as (b' & mc' & Hb & ?). subst b'. - destr.destr (Z.eqb (word.unsigned b) 0). - - specialize Hf with (1 := E). eapply exec.while_false; eassumption. - - specialize Ht with (1 := E). inversion Ht. clear Ht. - eapply exec.while_true; eauto. - cbv beta. intros * (v' & HInv & HLt). eauto. - Qed. - - Lemma wp_call: forall binds fname arges t m l post, - (exists args, dexprs m l arges args /\ - call fname t m args (fun t m rets => + post t' m' l') + | cmd.cond br ct cf => + exists v, dexpr m l br v /\ + (word.unsigned v <> 0%Z -> rec ct t m l post) /\ + (word.unsigned v = 0%Z -> rec cf t m l post) + | cmd.seq c1 c2 => + rec c1 t m l (fun t m l => rec c2 t m l post) + | cmd.while _ _ => wp_cmd e c t m l post + | cmd.call binds fname arges => + exists args, dexprs m l arges args /\ + wp_call e fname t m args (fun t m rets => exists l', map.putmany_of_list_zip binds rets l = Some l' /\ - post t m l')) -> - cmd (cmd.call binds fname arges) t m l post. - Proof. - tac. - unfold dexprs in *. - eapply exprs_sound in H. destruct H as (argvs & mc' & HEv & ?). subst argvs. - unfold call in *. - Tactics.destruct_one_match_hyp. 2: contradiction. - unfold func in *. - destruct f as ((argnames & retnames) & fbody). - destruct H0 as (l1 & Hl1 & Hbody). - inversion Hbody. clear Hbody. rename H into Hbody. - eapply exec.call; eauto. - cbv beta. intros. eapply getmany_sound. assumption. - Qed. - - Lemma wp_interact: forall binds action arges t m l post, - (exists args, dexprs m l arges args /\ + post t m l') + | cmd.interact binds action arges => + exists args, dexprs m l arges args /\ exists mKeep mGive, map.split m mKeep mGive /\ ext_spec t mGive action args (fun mReceive rets => exists l', map.putmany_of_list_zip binds rets l = Some l' /\ forall m', map.split m' mKeep mReceive -> - post (cons ((mGive, action, args), (mReceive, rets)) t) m' l')) -> - cmd (cmd.interact binds action arges) t m l post. - Proof. - tac. - eapply exprs_sound in H. destruct H as (argvs & mc' & HEv & ?). subst argvs. - tac. - Qed. - End WithFunctionEnv. + post (cons ((mGive, action, args), (mReceive, rets)) t) m' l') + end. + Fixpoint cmd c := cmd_body cmd c. + End WithFunctions. + + Definition func call '(innames, outnames, c) (t : trace) (m : mem) (args : list word) (post : trace -> mem -> list word -> Prop) := + exists l, map.of_list_zip innames args = Some l /\ + cmd call c t m l (fun t m l => + list_map (get l) outnames (fun rets => + post t m rets)). End WeakestPrecondition. +Notation call := wp_call. -Ltac apply_rule_for_command c := - lazymatch c with - | cmd.skip => eapply wp_skip - | cmd.set ?x ?ev => eapply wp_set - | cmd.unset ?x => eapply wp_unset - | cmd.store ?sz ?ea ?ev => eapply wp_store - | cmd.stackalloc ?x ?n ?c => eapply wp_stackalloc - | cmd.cond ?br ?ct ?cf => eapply wp_cond - | cmd.seq ?c1 ?c2 => eapply wp_seq - | cmd.while ?e ?c => eapply wp_while - | cmd.call ?binds ?fname ?arges => eapply wp_call - | cmd.interact ?binds ?action ?arges => eapply wp_interact +Ltac unfold1_cmd e := + lazymatch e with + @cmd ?width ?BW ?word ?mem ?locals ?ext_spec ?CA ?c ?t ?m ?l ?post => + let c := eval hnf in c in + constr:(@cmd_body width BW word mem locals ext_spec CA + (@cmd width BW word mem locals ext_spec CA) c t m l post) end. - Ltac unfold1_cmd_goal := - lazymatch goal with - | |- cmd _ ?c _ _ _ ?post => let c := eval hnf in c in apply_rule_for_command c - end. + let G := lazymatch goal with |- ?G => G end in + let G := unfold1_cmd G in + change G. Ltac unfold1_expr e := lazymatch e with diff --git a/bedrock2/src/bedrock2/WeakestPreconditionProperties.v b/bedrock2/src/bedrock2/WeakestPreconditionProperties.v index 29ffd9017..00e088826 100644 --- a/bedrock2/src/bedrock2/WeakestPreconditionProperties.v +++ b/bedrock2/src/bedrock2/WeakestPreconditionProperties.v @@ -1,6 +1,7 @@ Require Import coqutil.Macros.subst coqutil.Macros.unique coqutil.Map.Interface coqutil.Word.Properties. Require Import coqutil.Word.Bitwidth. Require bedrock2.WeakestPrecondition. +Require Import bedrock2.WP. Require Import Coq.Classes.Morphisms. @@ -79,7 +80,7 @@ Section WeakestPrecondition. (pointwise_relation _ (pointwise_relation _ (pointwise_relation _ Basics.impl))) ==> Basics.impl))))))) WeakestPrecondition.cmd. Proof using ext_spec_ok locals_ok mem_ok word_ok. - Admitted. (* + pose proof I. (* to keep naming *) cbv [Proper respectful pointwise_relation Basics.flip Basics.impl]; ind_on Syntax.cmd.cmd; cbn in *; cbv [dlet.dlet] in *; intuition (try typeclasses eauto with core). { destruct H1 as (?&?&?). eexists. split. @@ -95,32 +96,18 @@ Section WeakestPrecondition. { cbv [pointwise_relation Basics.impl]; intuition eauto 2. } { eauto. } } { eapply Proper_store; eauto; cbv [pointwise_relation Basics.impl]; eauto. } } } - { eapply H1; [ | | eapply H3; eassumption ]. - 2 : intros ? ? ? (?&?&?&?&?). all : eauto 7. } + { eapply H1. 2: eapply H3; eassumption. + intros ? ? ? (?&?&?&?&?). eauto 7. } { destruct H1 as (?&?&?). eexists. split. { eapply Proper_expr. { cbv [pointwise_relation Basics.impl]; intuition eauto 2. } { eauto. } } { intuition eauto 6. } } - { destruct H1 as (?&?&?&?&?&HH). - eassumption || eexists. - eassumption || eexists. - eassumption || eexists. - eassumption || eexists. { eassumption || eexists. } - eassumption || eexists. { eassumption || eexists. } - intros X Y Z T W. - specialize (HH X Y Z T W). - destruct HH as (?&?&?). eexists. split. - 1: eapply Proper_expr. - 1: cbv [pointwise_relation Basics.impl]. - all:intuition eauto 2. - - eapply H2; eauto; cbn; intros. - match goal with H:_ |- _ => destruct H as (?&?&?); solve[eauto] end. - - intuition eauto. } + { eapply weaken_wp_cmd; eassumption. } { destruct H1 as (?&?&?). eexists. split. { eapply Proper_list_map; eauto; try exact H4; cbv [respectful pointwise_relation Basics.impl]; intuition eauto 2. eapply Proper_expr; eauto. } - { eapply H. 2: eauto. + { eapply weaken_wp_call. 2: eassumption. cbv beta. (* COQBUG (performance), measured in Coq 8.9: "firstorder eauto" works, but takes ~100s and increases memory usage by 1.8GB. On the other hand, the line below takes just 5ms *) @@ -134,37 +121,7 @@ Section WeakestPrecondition. split; [assumption|]. eapply Semantics.ext_spec.weaken; [|solve[eassumption]]. intros ? ? (?&?&?); eauto 10. } } - Qed. *) - - Global Instance Proper_func : - Proper ( - (pointwise_relation _ ( - pointwise_relation _ ( - pointwise_relation _ ( - pointwise_relation _ ( - pointwise_relation _ ( - (pointwise_relation _ (pointwise_relation _ (pointwise_relation _ Basics.impl))) ==> - Basics.impl))))))) WeakestPrecondition.func. - Proof using word_ok mem_ok locals_ok ext_spec_ok. - Admitted. (* - cbv [Proper respectful pointwise_relation Basics.flip Basics.impl WeakestPrecondition.func]; intros. - destruct a. destruct p. - destruct H1; intuition idtac. - eexists. - split; [eauto|]. - eapply Proper_cmd; - cbv [Proper respectful pointwise_relation Basics.flip Basics.impl WeakestPrecondition.func]; - try solve [typeclasses eauto with core]. - intros. - eapply Proper_list_map; - cbv [Proper respectful pointwise_relation Basics.flip Basics.impl WeakestPrecondition.func]; - try solve [typeclasses eauto with core]. - - intros. - eapply Proper_get; - cbv [Proper respectful pointwise_relation Basics.flip Basics.impl WeakestPrecondition.func]; - eauto. - - eauto. - Qed. *) + Qed. Global Instance Proper_call : Proper ( @@ -176,15 +133,9 @@ Section WeakestPrecondition. (pointwise_relation _ (pointwise_relation _ (pointwise_relation _ Basics.impl))) ==> Basics.impl)))))))) WeakestPrecondition.call. Proof using word_ok mem_ok locals_ok ext_spec_ok. - Admitted. (* - cbv [Proper respectful pointwise_relation Basics.impl]; ind_on (list (String.string * (list String.string * list String.string * Syntax.cmd.cmd))); - cbn in *; intuition (try typeclasses eauto with core). - destruct a. - destruct (String.eqb s a1); eauto. - eapply Proper_func; - cbv [Proper respectful pointwise_relation Basics.flip Basics.impl WeakestPrecondition.func]; - eauto. - Qed. *) + cbv [Proper respectful pointwise_relation Basics.impl]. + intros. eapply weaken_wp_call; eassumption. + Qed. Ltac t := repeat match goal with @@ -248,6 +199,14 @@ Section WeakestPrecondition. + eapply IHe2. eassumption. Qed. + Lemma eval_expr_change_start_metrics: forall m l e mc1 mc1' v, + Semantics.eval_expr m l e mc1 = Some (v, mc1') -> + forall mc2, exists mc2', Semantics.eval_expr m l e mc2 = Some (v, mc2'). + Proof. + intros. eapply expr_complete in H. eapply expr_sound in H. + destruct H as (? & mc2' & H & ?). subst v. exists mc2'. exact H. + Qed. + Lemma sound_args : forall m l args mc P, WeakestPrecondition.list_map (WeakestPrecondition.expr m l) args P -> exists x mc', Semantics.evaluate_call_args_log m l args mc = Some (x, mc') /\ P x. @@ -273,10 +232,144 @@ Section WeakestPrecondition. all : cbv [respectful pointwise_relation Basics.impl WeakestPrecondition.get]; intros; cbv beta; t. Qed. - Lemma sound_cmd fs c t m l mc post - (H : WeakestPrecondition.cmd fs c t m l post) - : Semantics.exec fs c t m l mc (fun t' m' l' mc' => post t' m' l'). - Proof. eapply WeakestPrecondition.invert_cmd. exact H. Qed. + Local Notation semantics_call := (fun e n t m args post => + exists params rets fbody, map.get e n = Some (params, rets, fbody) /\ + exists lf, map.putmany_of_list_zip params args map.empty = Some lf /\ + forall mc', Semantics.exec e fbody t m lf mc' (fun t' m' st1 mc'' => + exists retvs, map.getmany_of_list st1 rets = Some retvs /\ + post t' m' retvs)). + + Local Hint Constructors Semantics.exec : core. + Lemma sound_cmd e c t m l mc post + (H:WeakestPrecondition.cmd e c t m l post) + : Semantics.exec e c t m l mc (fun t' m' l' mc' => post t' m' l'). + Proof. + ind_on Syntax.cmd; repeat (t; try match reverse goal with H : WeakestPrecondition.expr _ _ _ _ |- _ => eapply expr_sound in H end). + { destruct (BinInt.Z.eq_dec (Interface.word.unsigned x) (BinNums.Z0)) as [Hb|Hb]; cycle 1. + { econstructor; t. } + { eapply Semantics.exec.if_false; t. } } + { eapply invert_wp_cmd. assumption. } + { eapply invert_wp_call in H0. t. eapply sound_args in H; t. + eapply invert_wp_cmd in H2. t. } + { eapply sound_args in H; t. } + Qed. + + Lemma cmd_sound: forall e c t m l post, + WeakestPrecondition.cmd e c t m l post -> wp_cmd e c t m l post. + Proof. intros. eapply mk_wp_cmd. intros. eapply sound_cmd. assumption. Qed. + + Lemma sound_call' fs n t m args post (H : WeakestPrecondition.call fs n t m args post) + : semantics_call fs n t m args post. + Proof. + cbv beta. eapply invert_wp_call in H. + destruct H as (? & ? & ? & ? & ? & ? & ?). + do 4 eexists. 1: eassumption. + do 2 eexists. 1: eassumption. + eapply invert_wp_cmd. eassumption. + Qed. + + Lemma weaken_cmd: forall e c t m l (post1 post2: _->_->_->Prop), + WeakestPrecondition.cmd e c t m l post1 -> + (forall t m l, post1 t m l -> post2 t m l) -> + WeakestPrecondition.cmd e c t m l post2. + Proof. + intros. + eapply Proper_cmd. 2: eassumption. + cbv [RelationClasses.Reflexive Morphisms.pointwise_relation + Morphisms.respectful Basics.impl]. + assumption. + Qed. + + Lemma complete_args : forall m l args mc mc' vs, + Semantics.evaluate_call_args_log m l args mc = Some (vs, mc') -> + WeakestPrecondition.dexprs m l args vs. + Proof using word_ok. + induction args; cbn; repeat (subst; t). + 1: inversion H; reflexivity. + destruct_one_match_hyp. 2: discriminate. + destruct p as (v, mc''). + destruct_one_match_hyp. 2: discriminate. + destruct p as (tail, mc'''). + inversion H. subst mc''' vs. clear H. + eapply Proper_expr. 2: eapply expr_complete. 2: eassumption. + intros x ?. subst x. + eapply Proper_list_map. 3: eapply IHargs; eassumption. + { eapply Proper_expr. } + { intros ? ?. subst. reflexivity. } + Qed. + + Lemma complete_cmd: forall e c t m l mc post, + Semantics.exec e c t m l mc post -> + WeakestPrecondition.cmd e c t m l (fun t' m' l' => exists mc', post t' m' l' mc'). + Proof. + induction 1. + { eexists. eassumption. } + { eapply expr_complete in H. eexists. split. 1: exact H. + eexists. eassumption. } + { eexists. eauto. } + { eapply expr_complete in H. + eapply expr_complete in H0. + eexists. split. 1: eassumption. + eexists. split. 1: eassumption. + eexists. eauto. } + { split. 1: assumption. + intros * HA HSp. specialize H1 with (1 := HA) (2 := HSp). + unfold dlet.dlet. eapply weaken_cmd. 1: eapply H1. cbv beta. + clear. intros * (? & ? & ? & ? & ? & ?). eauto 8. } + { eexists. ssplit; intros; eauto using expr_complete; congruence. } + { eexists. ssplit; intros; eauto using expr_complete; congruence. } + { cbn. eapply weaken_cmd. + { eapply IHexec. } + cbv beta. intros *. intros (mc' & Hmid). + eapply H1. eassumption. } + { cbn. eapply mk_wp_cmd. intros. + eapply eval_expr_change_start_metrics in H. + destruct H as (mc2' & H). + eapply Semantics.exec.while_false; eauto. } + { rename IHexec into IH1, H3 into IH2. + cbn. eapply mk_wp_cmd. intros. + eapply eval_expr_change_start_metrics in H. + destruct H as (mc2' & H). + eapply Semantics.exec.while_true. + 1: eassumption. + 1: eassumption. + { eapply sound_cmd. eapply IH1. (* round-trip just to change metrics *) } + cbv beta. intros * (? & ?). + eapply sound_cmd. eapply IH2. (* round-trip just to change metrics *) eassumption. } + { cbn. eexists. split. + { eapply complete_args. eassumption. } + eapply mk_wp_call. 1,2: eassumption. + eapply mk_wp_cmd. intros. + eapply Semantics.exec.weaken. + { eapply sound_cmd in IHexec. eapply IHexec. (* round-trip just to change metrics *) } + cbv beta. intros * ? (? & Hmid). + specialize H3 with (1 := Hmid). destruct H3 as (retvs & G & ? & ? & ?). eauto 8. } + { cbn. eexists. split. + { eapply complete_args. eassumption. } + eexists _, _. split. 1: eassumption. + eapply Semantics.ext_spec.weaken. 2: eassumption. + intros m0 args0 Hmid. specialize H2 with (1 := Hmid). destruct H2 as (? & ? & ?). + eauto 8. } + Qed. + + Lemma cmd_complete: forall e c t m l post, + wp_cmd e c t m l post -> WeakestPrecondition.cmd e c t m l post. + Proof. + intros. eapply invert_wp_cmd in H. eapply complete_cmd in H. + eapply weaken_cmd. 1: exact H. + cbv beta. intros * (_ & ?). assumption. + Unshelve. repeat constructor. + Qed. + + Lemma start_func: forall e fname fimpl t m args post, + map.get e fname = Some fimpl -> + WeakestPrecondition.func e fimpl t m args post -> + wp_call e fname t m args post. + Proof. + intros * G. destruct fimpl as [[argnames retnames] body]. intros (? & ? & ?). + eapply mk_wp_call. 1,2: eassumption. eapply cmd_sound. + eapply weaken_cmd. 1: eassumption. cbv beta. intros. eapply sound_getmany. assumption. + Qed. (** Ad-hoc lemmas here? *) @@ -289,7 +382,6 @@ Section WeakestPrecondition. post (cons (map.empty, binds, args, (map.empty, rets)) t) m l0)) : WeakestPrecondition.cmd call (cmd.interact action binds arges) t m l post. Proof using word_ok mem_ok ext_spec_ok. - Admitted. (* exists args; split; [exact Hargs|]. exists m. exists map.empty. @@ -297,7 +389,7 @@ Section WeakestPrecondition. eapply ext_spec.weaken; [|eapply Hext]; intros ? ? [? [? []]]. subst a; subst. eexists; split; [eassumption|]. intros. eapply Properties.map.split_empty_r in H. subst. assumption. - Qed. *) + Qed. Lemma intersect_expr: forall m l e (post1 post2: word -> Prop), WeakestPrecondition.expr m l e post1 -> diff --git a/bedrock2/src/bedrock2Examples/ARPResponderProofs.v b/bedrock2/src/bedrock2Examples/ARPResponderProofs.v index 008081c0a..d4f52115a 100644 --- a/bedrock2/src/bedrock2Examples/ARPResponderProofs.v +++ b/bedrock2/src/bedrock2Examples/ARPResponderProofs.v @@ -11,6 +11,7 @@ Local Open Scope string_scope. Local Open Scope list_scope. Local Open Scope Z_s From bedrock2 Require Import Array Scalars Separation. From coqutil.Tactics Require Import letexists rdelta. +Require Import bedrock2.WeakestPrecondition. Local Notation bytes := (array scalar8 (word.of_Z 1)). Ltac seplog_use_array_load1 H i := @@ -20,17 +21,16 @@ Ltac seplog_use_array_load1 H i := change ((word.unsigned (word.of_Z 1) * Z.of_nat iNat)%Z) with i in *. -Local Instance spec_of_arp : spec_of "arp" := fun functions => - forall t m packet ethbuf len R, - (sep (array scalar8 (word.of_Z 1) ethbuf packet) R) m -> - word.unsigned len = Z.of_nat (length packet) -> - WeakestPrecondition.call functions "arp" t m [ethbuf; len] (fun T M rets => True). +Local Instance spec_of_arp : spec_of "arp" := + fnspec! "arp" ethbuf len / packet R, + { requires t m := (sep (array scalar8 (word.of_Z 1) ethbuf packet) R) m /\ + word.unsigned len = Z.of_nat (length packet); + ensures T M := True }. Local Hint Mode Word.Interface.word - : typeclass_instances. Goal program_logic_goal_for_function! arp. - eexists; split; repeat straightline. - 1: exact eq_refl. + repeat straightline. letexists; split; [solve[repeat straightline]|]; split; [|solve[repeat straightline]]; repeat straightline. eapply Properties.word.if_nonzero in H1. rewrite word.unsigned_ltu, word.unsigned_of_Z in H1. cbv [word.wrap] in H1. diff --git a/bedrock2/src/bedrock2Examples/FE310CompilerDemo.v b/bedrock2/src/bedrock2Examples/FE310CompilerDemo.v index ad4135054..08033dc22 100644 --- a/bedrock2/src/bedrock2Examples/FE310CompilerDemo.v +++ b/bedrock2/src/bedrock2Examples/FE310CompilerDemo.v @@ -50,6 +50,32 @@ Definition uart0_rxdata := 0x10013004. Definition uart0_txdata := 0x10013000. False end%list%bool. +Ltac u := + repeat match goal with + | H: exists _, _ |- _ => destruct H + | H: _ /\ _ |- _ => destruct H + | H: False |- _ => destruct H + end. + +#[global] Instance ext_spec_ok : ext_spec.ok ext_spec. +Proof. + split; cbv [ext_spec Morphisms.Proper Morphisms.respectful Morphisms.pointwise_relation Basics.impl]; intros. + all : repeat u; subst; eauto 8 using Properties.map.same_domain_refl. + { destr.destr (String.eqb act "MMInput"); + try destr.destr (String.eqb act "MMOutput"). + 3: { + exfalso. + repeat (Tactics.destruct_one_match_hyp; try (assumption || congruence)). } + { repeat ((Tactics.destruct_one_match_hyp; repeat u; eauto)). } + { repeat ((Tactics.destruct_one_match_hyp; repeat u; eauto)). } } + { destr.destr (String.eqb a "MMInput"); + try destr.destr (String.eqb a "MMOutput"). + 3: { + exfalso. + repeat (Tactics.destruct_one_match_hyp; try (assumption || congruence)). } + { repeat ((Tactics.destruct_one_match_hyp; repeat u; eauto)). } + { repeat ((Tactics.destruct_one_match_hyp; repeat u; eauto)). } } +Qed. Require Import bedrock2.NotationsCustomEntry. @@ -157,13 +183,18 @@ Local Instance mapok: map.ok mem := SortedListWord.ok Naive.word32 _. Local Instance wordok: word.ok word := Naive.word32_ok. +Local Instance localsok: map.ok locals := SortedListString.ok _. + Lemma swap_chars_over_uart_correct m : WeakestPrecondition.cmd map.empty swap_chars_over_uart nil m map.empty (fun t m l => True). Proof. repeat t. + eapply Loops.wp_while. eexists _, _, (fun v t _ l => exists p, map.of_list_zip ["running"; "prev"; "one"; "dot"]%string [v; p; word.of_Z(1); word.of_Z(46)] = Some l ); repeat t. + eapply Loops.wp_while. eexists _, _, (fun v t _ l => exists rxv, map.putmany_of_list_zip ["polling"; "rx"]%string [v; rxv] l0 = Some l); repeat t. + eapply Loops.wp_while. eexists _, _, (fun v t _ l => exists txv, map.putmany_of_list_zip ["polling"; "tx"]%string [v; txv] l0 = Some l); repeat t. eexists; split; repeat t. Defined. @@ -246,8 +277,10 @@ Lemma echo_server_correct m : (fun t m l => echo_server_spec t None). Proof. repeat t. + eapply Loops.wp_while. eexists _, _, (fun v t _ l => map.of_list_zip ["running"; "one"]%string [v; word.of_Z(1)] = Some l /\ echo_server_spec t None ); repeat t. { repeat split. admit. (* hfrosccfg*) } + eapply Loops.wp_while. eexists _, _, (fun v t _ l => exists rxv, map.putmany_of_list_zip ["polling"; "rx"]%string [v; rxv] l0 = Some l /\ if Z.eq_dec (word.unsigned (word.and rxv (word.of_Z (2^31)))) 0 then echo_server_spec t (Some rxv) diff --git a/bedrock2/src/bedrock2Examples/indirect_add.v b/bedrock2/src/bedrock2Examples/indirect_add.v index e59ef10d0..d17ce9116 100644 --- a/bedrock2/src/bedrock2Examples/indirect_add.v +++ b/bedrock2/src/bedrock2Examples/indirect_add.v @@ -50,7 +50,7 @@ Section WithParameters. cbv [f]. ecancel_assumption. Qed. - Example link_both : spec_of_indirect_add_twice (("indirect_add_twice",indirect_add_twice)::("indirect_add",indirect_add)::nil). + Example link_both : spec_of_indirect_add_twice (map.of_list (("indirect_add_twice",indirect_add_twice)::("indirect_add",indirect_add)::nil)). Proof. auto using indirect_add_twice_ok, indirect_add_ok. Qed. (* diff --git a/bedrock2/src/bedrock2Examples/lightbulb.v b/bedrock2/src/bedrock2Examples/lightbulb.v index 009a5f63f..de8b9f63c 100644 --- a/bedrock2/src/bedrock2Examples/lightbulb.v +++ b/bedrock2/src/bedrock2Examples/lightbulb.v @@ -610,24 +610,26 @@ Section WithParameters. Import SPI. - Definition function_impls := + Definition function_impls := map.of_list &[,lightbulb_init; lan9250_init; lan9250_wait_for_boot; lan9250_mac_write; lightbulb_loop; lightbulb_handle; recvEthernet; lan9250_writeword; lan9250_readword; spi_xchg; spi_write; spi_read]. + Local Ltac specapply s := eapply s; [reflexivity|..]. + Lemma link_lightbulb_loop : spec_of_lightbulb_loop function_impls. Proof. - eapply lightbulb_loop_ok; - (eapply recvEthernet_ok || eapply lightbulb_handle_ok); - eapply lan9250_readword_ok; eapply spi_xchg_ok; - (eapply spi_write_ok || eapply spi_read_ok). + specapply lightbulb_loop_ok; + (specapply recvEthernet_ok || specapply lightbulb_handle_ok); + specapply lan9250_readword_ok; specapply spi_xchg_ok; + (specapply spi_write_ok || specapply spi_read_ok). Qed. Lemma link_lightbulb_init : spec_of_lightbulb_init function_impls. Proof. - eapply lightbulb_init_ok; eapply lan9250_init_ok; - try (eapply lan9250_wait_for_boot_ok || eapply lan9250_mac_write_ok); - (eapply lan9250_readword_ok || eapply lan9250_writeword_ok); - eapply spi_xchg_ok; - (eapply spi_write_ok || eapply spi_read_ok). + specapply lightbulb_init_ok; specapply lan9250_init_ok; + try (specapply lan9250_wait_for_boot_ok || specapply lan9250_mac_write_ok); + (specapply lan9250_readword_ok || specapply lan9250_writeword_ok); + specapply spi_xchg_ok; + (specapply spi_write_ok || specapply spi_read_ok). Qed. End WithParameters. diff --git a/bedrock2/src/bedrock2Examples/memmove.v b/bedrock2/src/bedrock2Examples/memmove.v index 4aa826831..ae0af189b 100644 --- a/bedrock2/src/bedrock2Examples/memmove.v +++ b/bedrock2/src/bedrock2Examples/memmove.v @@ -385,6 +385,7 @@ Section WithParameters. cbv [program_logic_goal_for spec_of_memmove_array]; intros. eapply WeakestPreconditionProperties.Proper_call; cycle 1; [eapply memmove_ok|]; cbv [sepclause_of_map] in *. + { eassumption. } { intuition idtac. - seprewrite_in_by @ptsto_bytes.array1_iff_eq_of_list_word_at H0 ZnWords; eassumption. - seprewrite_in_by @ptsto_bytes.array1_iff_eq_of_list_word_at H ZnWords; eassumption. From 8fa2cc3bfbc939653ad9f3bb60e123aa73dcc13a Mon Sep 17 00:00:00 2001 From: Samuel Gruetter Date: Mon, 31 Jul 2023 21:27:24 -0400 Subject: [PATCH 07/15] hardcode env implementation in bedrock2.Semantics, and update compiler, LiveVerif, end2end --- LiveVerif/src/LiveVerif/LiveProgramLogic.v | 26 +++++----- LiveVerif/src/LiveVerif/LiveRules.v | 47 ++++++------------- bedrock2/src/bedrock2/FrameRule.v | 1 - bedrock2/src/bedrock2/ProgramLogic.v | 4 +- bedrock2/src/bedrock2/Semantics.v | 18 +++++-- bedrock2/src/bedrock2/WP.v | 31 ++++++++---- bedrock2/src/bedrock2Examples/Trace.v | 4 -- bedrock2/src/bedrock2Examples/memequal.v | 1 - bedrock2/src/bedrock2Examples/memmove.v | 1 - bedrock2/src/bedrock2Examples/memswap.v | 1 - compiler/src/compiler/ExprImp.v | 2 - compiler/src/compiler/ExprImpEventLoopSpec.v | 2 +- compiler/src/compiler/FlattenExpr.v | 2 - compiler/src/compiler/FlattenExprDef.v | 3 +- compiler/src/compiler/Pipeline.v | 21 +++++---- compiler/src/compiler/ToplevelLoop.v | 2 + .../src/compilerExamples/SoftmulCompile.v | 4 +- end2end/src/end2end/End2EndLightbulb.v | 34 +++++++++----- end2end/src/end2end/End2EndPipeline.v | 10 ++-- 19 files changed, 108 insertions(+), 106 deletions(-) diff --git a/LiveVerif/src/LiveVerif/LiveProgramLogic.v b/LiveVerif/src/LiveVerif/LiveProgramLogic.v index cac63dcd0..5265ba42f 100644 --- a/LiveVerif/src/LiveVerif/LiveProgramLogic.v +++ b/LiveVerif/src/LiveVerif/LiveProgramLogic.v @@ -42,22 +42,24 @@ Require Import bedrock2.LogSidecond. Definition functions_correct (* universally quantified abstract function list containing all functions: *) - (qfs: list (string * func)): + (qfs: Semantics.env): (* specs of a subset of functions for which to assert correctness *) - list (list (string * func) -> Prop (* spec_of mentioning function name *)) -> Prop := + list (Semantics.env -> Prop (* spec_of mentioning function name *)) -> Prop := List.Forall (fun spec => spec qfs). Definition function_with_callees: Type := - func * list (list (string * func) -> Prop (* spec_of mentioning function name *)). + func * list (Semantics.env -> Prop (* spec_of mentioning function name *)). Definition program_logic_goal_for(name: string)(f: function_with_callees) {spec: bedrock2.ProgramLogic.spec_of name}: Prop := match f with | (impl, callees) => forall functions, - functions_correct functions callees -> spec (cons (name, impl) functions) + map.get functions name = Some impl -> + functions_correct functions callees -> + spec functions end. -Definition nth_spec(specs: list (list (string * func) -> Prop))(n: nat) := +Definition nth_spec(specs: list (Semantics.env -> Prop))(n: nat) := Eval unfold List.nth in (List.nth n specs (fun _ => True)). Lemma nth_function_correct: forall fs n specs spec, @@ -143,22 +145,18 @@ Ltac start := subst evar; unfold program_logic_goal_for, spec; let fs := fresh "fs" in + let G := fresh "EnvContains" in let fs_ok := fresh "fs_ok" in - intros fs fs_ok; + intros fs G fs_ok; let nP := fresh "Scope0" in pose proof (mk_scope_marker FunctionParams) as nP; intros_until_trace; let nB := fresh "Scope0" in pose proof (mk_scope_marker FunctionBody) as nB; lazymatch goal with | |- forall (t : trace) (m : @map.rep (@word.rep _ _) Init.Byte.byte _), _ => intros end; - WeakestPrecondition.unfold1_call_goal; - cbv match beta delta [WeakestPrecondition.call_body]; - lazymatch goal with - | |- if ?test then ?T else _ => - replace test with true by reflexivity; change T - end; eapply prove_func; - [ lazymatch goal with + [ exact G + | lazymatch goal with | |- map.of_list_zip ?argnames_evar ?argvalues = Some ?locals_evar => let argnames := map_with_ltac varconstr_to_string argvalues in unify argnames_evar argnames; @@ -166,7 +164,7 @@ Ltac start := unify locals_evar (map.of_list kvs); reflexivity end - | ]; + | clear G ]; first [eapply simplify_no_return_post | eapply simplify_1retval_post]; pose_state stepping | |- _ => fail "goal needs to be of shape (@program_logic_goal_for ?fname ?evar ?spec)" diff --git a/LiveVerif/src/LiveVerif/LiveRules.v b/LiveVerif/src/LiveVerif/LiveRules.v index d67b558d0..69d83d6c3 100644 --- a/LiveVerif/src/LiveVerif/LiveRules.v +++ b/LiveVerif/src/LiveVerif/LiveRules.v @@ -356,31 +356,18 @@ Section WithParams. - assumption. Qed. - Ltac pose_env := - let env := fresh "env" in - unshelve epose (env := _ : map.map string (list string * list string * cmd)); - [ eapply SortedListString.map - | assert (env_ok: map.ok env) by apply SortedListString.ok; clearbody env ]. - Lemma WP_weaken_cmd: forall fs c t m l (post1 post2: _->_->_->Prop), - WeakestPrecondition.cmd (call fs) c t m l post1 -> + WeakestPrecondition.cmd fs c t m l post1 -> (forall t m l, post1 t m l -> post2 t m l) -> - WeakestPrecondition.cmd (call fs) c t m l post2. - Proof. - pose_env. intros. - eapply WeakestPreconditionProperties.Proper_cmd. 3: eassumption. - 1: eapply WeakestPreconditionProperties.Proper_call. - cbv [RelationClasses.Reflexive Morphisms.pointwise_relation - Morphisms.respectful Basics.impl]. - assumption. - Qed. + WeakestPrecondition.cmd fs c t m l post2. + Proof. eapply WeakestPreconditionProperties.weaken_cmd. Qed. - Inductive wp_cmd(fs: list (string * (list string * list string * cmd))) + Inductive wp_cmd(fs: Semantics.env) (c: cmd)(t: trace)(m: mem)(l: locals)(post: trace -> mem -> locals -> Prop): - Prop := mk_wp_cmd(_: WeakestPrecondition.cmd (call fs) c t m l post). + Prop := mk_wp_cmd(_: WeakestPrecondition.cmd fs c t m l post). Lemma invert_wp_cmd: forall fs c t m l post, - wp_cmd fs c t m l post -> WeakestPrecondition.cmd (call fs) c t m l post. + wp_cmd fs c t m l post -> WeakestPrecondition.cmd fs c t m l post. Proof. intros. inversion H; assumption. Qed. Lemma weaken_wp_cmd: forall fs c t m l (post1 post2: _->_->_->Prop), @@ -568,7 +555,7 @@ Section WithParams. all: eauto using weaken_wp_cmd. Qed. - Definition after_loop: list (string * (list string * list string * cmd)) -> + Definition after_loop: Semantics.env -> cmd -> trace -> mem -> locals -> (trace -> mem -> locals -> Prop) -> Prop := wp_cmd. Lemma wp_set: forall fs x e v t m l rest post, @@ -762,7 +749,7 @@ Section WithParams. True) : wp_cmd fs (cmd.seq (cmd.while e c) rest) t m l post. Proof. - econstructor. cbn. exists measure, lt, invariant. + econstructor. cbn. eapply wp_while. exists measure, lt, invariant. split. 1: assumption. split. 1: eauto. clear Hpre v0 t m l. @@ -805,7 +792,6 @@ Section WithParams. Proof. eapply wp_seq. econstructor. cbn. - pose_env. eapply tailrec_localsmap_1ghost with (P := fun v g t m l => pre (g, v, t, m, l)) (Q := fun v g t m l => post (g, v, t, m, l)). @@ -1000,9 +986,6 @@ Section WithParams. specialize (H Pre). clear Pre. eapply wp_seq. eapply wp_call0. 1: eassumption. - unshelve epose (env := _ : map.map string func). - 1: eapply SortedListString.map. - assert (env_ok: map.ok env) by apply SortedListString.ok. clearbody env. eapply WeakestPreconditionProperties.Proper_call. 2: eassumption. exact Impl. Qed. @@ -1017,20 +1000,18 @@ Section WithParams. eapply IHretnames; eassumption. Qed. - Lemma prove_func: forall fs argnames retnames body t m argvals l post, + Lemma prove_func: forall fs f argnames retnames body t m argvals l post, + map.get fs f = Some (argnames, retnames, body) -> map.of_list_zip argnames argvals = Some l -> wp_cmd fs body t m l (fun t' m' l' => exists retvals, map.getmany_of_list l' retnames = Some retvals /\ post t' m' retvals) -> - WeakestPrecondition.func (call fs) (argnames, retnames, body) t m argvals post. + WeakestPrecondition.call fs f t m argvals post. Proof. intros. - unfold func. - eexists. split. 1: eassumption. - eapply invert_wp_cmd. - eapply weaken_wp_cmd. 1: eassumption. - cbv beta. intros. fwd. - eapply cpsify_getmany_of_list; eassumption. + eapply WP.WP_Impl.mk_wp_call. 1,2: eassumption. eapply WP.WP_Impl.mk_wp_cmd. + intros. eapply invert_wp_cmd in H1. eapply WeakestPreconditionProperties.sound_cmd. + assumption. Qed. (* applied at beginning of void functions *) diff --git a/bedrock2/src/bedrock2/FrameRule.v b/bedrock2/src/bedrock2/FrameRule.v index 370f71397..6a621014a 100644 --- a/bedrock2/src/bedrock2/FrameRule.v +++ b/bedrock2/src/bedrock2/FrameRule.v @@ -16,7 +16,6 @@ Require Import Coq.Lists.List. Section semantics. Context {width: Z} {BW: Bitwidth width} {word: word.word width} {mem: map.map word byte}. Context {locals: map.map String.string word}. - Context {env: map.map String.string (list String.string * list String.string * cmd)}. Context {ext_spec: ExtSpec}. Context {mem_ok: map.ok mem} {word_ok: word.ok word}. diff --git a/bedrock2/src/bedrock2/ProgramLogic.v b/bedrock2/src/bedrock2/ProgramLogic.v index dca598f54..96adbc64a 100644 --- a/bedrock2/src/bedrock2/ProgramLogic.v +++ b/bedrock2/src/bedrock2/ProgramLogic.v @@ -7,7 +7,7 @@ Require Import bedrock2.WeakestPreconditionProperties. Require Import bedrock2.Loops. Require Import bedrock2.Map.SeparationLogic bedrock2.Scalars. -Definition spec_of (procname:String.string) := env -> Prop. +Definition spec_of (procname:String.string) := Semantics.env -> Prop. Existing Class spec_of. Module Import Coercions. @@ -57,7 +57,7 @@ Ltac program_logic_goal_for_function proc := let __ := constr:(proc : Syntax.func) in constr_string_basename_of_constr_reference_cps ltac:(Tactics.head proc) ltac:(fun fname => let spec := lazymatch constr:(_:spec_of fname) with ?s => s end in - exact (forall (functions : @map.rep _ _ env) (EnvContains : map.get functions fname = Some proc), ltac:( + exact (forall (functions : @map.rep _ _ Semantics.env) (EnvContains : map.get functions fname = Some proc), ltac:( let callees := eval cbv in (callees (snd proc)) in let s := assuming_correctness_of_in callees functions (spec functions) in exact s))). diff --git a/bedrock2/src/bedrock2/Semantics.v b/bedrock2/src/bedrock2/Semantics.v index 1820df16e..ffec59ea0 100644 --- a/bedrock2/src/bedrock2/Semantics.v +++ b/bedrock2/src/bedrock2/Semantics.v @@ -3,6 +3,7 @@ Require Import coqutil.Datatypes.PrimitivePair coqutil.Datatypes.HList. Require Import coqutil.Decidable. Require Import coqutil.Tactics.fwd. Require Import coqutil.Map.Properties. +Require coqutil.Map.SortedListString. Require Import bedrock2.Syntax coqutil.Map.Interface coqutil.Map.OfListWord. Require Import BinIntDef coqutil.Word.Interface coqutil.Word.Bitwidth. Require Import bedrock2.MetricLogging. @@ -78,10 +79,12 @@ Section binops. end. End binops. +#[export] Instance env: map.map String.string Syntax.func := SortedListString.map _. +#[export] Instance env_ok: map.ok env := SortedListString.ok _. + Section semantics. Context {width: Z} {BW: Bitwidth width} {word: word.word width} {mem: map.map word byte}. Context {locals: map.map String.string word}. - Context {env: map.map String.string (list String.string * list String.string * cmd)}. Context {ext_spec: ExtSpec}. Local Notation metrics := MetricLog. @@ -157,11 +160,11 @@ Section semantics. End WithMemAndLocals. End semantics. -Module exec. Section WithEnv. +Module exec. Section WithParams. Context {width: Z} {BW: Bitwidth width} {word: word.word width} {mem: map.map word byte}. Context {locals: map.map String.string word}. - Context {env: map.map String.string (list String.string * list String.string * cmd)}. Context {ext_spec: ExtSpec}. + Section WithEnv. Context (e: env). Local Notation metrics := MetricLog. @@ -369,4 +372,13 @@ Module exec. Section WithEnv. Qed. End WithEnv. + + Lemma extend_env: forall e1 e2, + map.extends e2 e1 -> + forall c t m l mc post, + exec e1 c t m l mc post -> + exec e2 c t m l mc post. + Proof. induction 2; try solve [econstructor; eauto]. Qed. + + End WithParams. End exec. Notation exec := exec.exec. diff --git a/bedrock2/src/bedrock2/WP.v b/bedrock2/src/bedrock2/WP.v index 45d3d1eff..5588d2014 100644 --- a/bedrock2/src/bedrock2/WP.v +++ b/bedrock2/src/bedrock2/WP.v @@ -1,12 +1,8 @@ Require Import Coq.ZArith.ZArith. Require Import coqutil.Map.Interface. -Require coqutil.Map.SortedListString. Require Import coqutil.Word.Interface coqutil.Word.Bitwidth. Require Import bedrock2.Syntax bedrock2.Semantics. -#[export] Instance env: map.map String.string Syntax.func := SortedListString.map _. -#[export] Instance env_ok: map.ok env := SortedListString.ok _. - (* We want to make the definitions opaque to `hnf` (unfolds any definition, so a plain definition doesn't work) and to `repeat split` (applies constructors of all 1-constructor inductives, so a 1-constructor inductive wrapping exec doesn't @@ -99,10 +95,9 @@ Section WithParams. Context {width: Z} {BW: Bitwidth width} {word: word.word width} {mem: map.map word Byte.byte} {locals: map.map String.string word} - {ext_spec: ExtSpec} - (e: env). + {ext_spec: ExtSpec}. - Lemma weaken_wp_cmd: forall c t m l (post1 post2: trace -> mem -> locals -> Prop), + Lemma weaken_wp_cmd: forall e c t m l (post1 post2: trace -> mem -> locals -> Prop), (forall t' m' l', post1 t' m' l' -> post2 t' m' l') -> wp_cmd e t m l c post1 -> wp_cmd e t m l c post2. Proof. @@ -110,7 +105,7 @@ Section WithParams. eapply exec.weaken. 1: eassumption. eauto. Qed. - Lemma weaken_wp_call: forall f t m args (post1 post2: trace -> mem -> list word -> Prop), + Lemma weaken_wp_call: forall e f t m args (post1 post2: trace -> mem -> list word -> Prop), (forall t' m' rets, post1 t' m' rets -> post2 t' m' rets) -> wp_call e f t m args post1 -> wp_call e f t m args post2. Proof. @@ -119,4 +114,24 @@ Section WithParams. eapply weaken_wp_cmd. 2: eassumption. firstorder eauto. Qed. + Lemma extend_env_wp_cmd: forall e1 e2, + map.extends e2 e1 -> + forall c t m l post, + wp_cmd e1 t m l c post -> + wp_cmd e2 t m l c post. + Proof. + intros. eapply mk_wp_cmd. intros. eapply invert_wp_cmd in H0. + eapply exec.extend_env; eassumption. + Qed. + + Lemma extend_env_wp_call: forall e1 e2, + map.extends e2 e1 -> + forall f t m args post, + wp_call e1 f t m args post -> + wp_call e2 f t m args post. + Proof. + intros. eapply invert_wp_call in H0. destruct H0 as (? & ? & ? & ? & ? & ? & ?). + eapply mk_wp_call; eauto. + eapply extend_env_wp_cmd; eauto. + Qed. End WithParams. diff --git a/bedrock2/src/bedrock2Examples/Trace.v b/bedrock2/src/bedrock2Examples/Trace.v index 39d44aa31..f7ebc23a5 100644 --- a/bedrock2/src/bedrock2Examples/Trace.v +++ b/bedrock2/src/bedrock2Examples/Trace.v @@ -139,7 +139,6 @@ Module SpiEth. write_byte b (((m, MMInput, [word.of_Z spi_tx_fifo]), (m, [x])) :: rest). Context {locals: map.map String.string word}. - Context {funname_env: forall T, map.map String.string T}. Instance ext_spec: ExtSpec := fun t mGive action (argvals: list word) (post: (mem -> list word -> Prop)) => @@ -238,7 +237,6 @@ Module Syscalls. (m, [ret1; ret2; err]))]. Context {locals: map.map String.string word}. - Context {funname_env: forall T, map.map String.string T}. Instance ext_spec: ExtSpec := fun t m action (argvals: list word) (post: (mem -> list word -> Prop)) => @@ -298,7 +296,6 @@ Module MMIOUsage. Context {word: word.word 32} {mem: map.map word Byte.byte} {mem_ok: map.ok mem}. Context {word_ok: word.ok word}. Context {locals: map.map String.string word}. - Context {funname_env: forall T, map.map String.string T}. Definition squarer_correct := @squarer_correct SpiEth.MMIOMacros. (*Check squarer_correct.*) @@ -311,7 +308,6 @@ Module SyscallsUsage. Context {word: word.word 32} {mem: map.map word Byte.byte} {mem_ok: map.ok mem}. Context {word_ok: word.ok word}. Context {locals: map.map String.string word}. - Context {funname_env: forall T, map.map String.string T}. Definition squarer_correct := @squarer_correct Syscalls.SyscallIOMacros. (*Check squarer_correct.*) diff --git a/bedrock2/src/bedrock2Examples/memequal.v b/bedrock2/src/bedrock2Examples/memequal.v index c18867845..41629648b 100644 --- a/bedrock2/src/bedrock2Examples/memequal.v +++ b/bedrock2/src/bedrock2Examples/memequal.v @@ -38,7 +38,6 @@ Section WithParameters. (r = 1 :>Z <-> xs = ys) }. Context {word_ok: word.ok word} {mem_ok: map.ok mem} {locals_ok : map.ok locals} - {env : map.map string (list string * list string * Syntax.cmd)} {env_ok : map.ok env} {ext_spec_ok : ext_spec.ok ext_spec}. Import coqutil.Tactics.letexists coqutil.Tactics.Tactics coqutil.Tactics.autoforward. diff --git a/bedrock2/src/bedrock2Examples/memmove.v b/bedrock2/src/bedrock2Examples/memmove.v index ae0af189b..757139543 100644 --- a/bedrock2/src/bedrock2Examples/memmove.v +++ b/bedrock2/src/bedrock2Examples/memmove.v @@ -53,7 +53,6 @@ Section WithParameters. Context {word_ok: word.ok word} {mem_ok: map.ok mem} {locals_ok : map.ok locals} - {env : map.map string (list string * list string * Syntax.cmd)} {env_ok : map.ok env} {ext_spec_ok : ext_spec.ok ext_spec}. Import coqutil.Tactics.letexists coqutil.Tactics.Tactics coqutil.Tactics.autoforward. diff --git a/bedrock2/src/bedrock2Examples/memswap.v b/bedrock2/src/bedrock2Examples/memswap.v index cd3af9e99..7292d7e76 100644 --- a/bedrock2/src/bedrock2Examples/memswap.v +++ b/bedrock2/src/bedrock2Examples/memswap.v @@ -41,7 +41,6 @@ Section WithParameters. ensures t' m := m =* ys$@x * xs$@y * R /\ t=t' }. Context {word_ok: word.ok word} {mem_ok: map.ok mem} {locals_ok : map.ok locals} - {env : map.map string (list string * list string * Syntax.cmd)} {env_ok : map.ok env} {ext_spec_ok : ext_spec.ok ext_spec}. Import coqutil.Tactics.letexists coqutil.Tactics.Tactics coqutil.Tactics.autoforward. diff --git a/compiler/src/compiler/ExprImp.v b/compiler/src/compiler/ExprImp.v index 60015aeab..899b8cb73 100644 --- a/compiler/src/compiler/ExprImp.v +++ b/compiler/src/compiler/ExprImp.v @@ -20,7 +20,6 @@ Open Scope Z_scope. Section ExprImp1. Context {width: Z} {BW: Bitwidth width} {word: word.word width} {mem: map.map word byte}. Context {locals: map.map String.string word}. - Context {env: map.map String.string (list String.string * list String.string * cmd)}. Context {ext_spec: ExtSpec}. Notation var := String.string (only parsing). @@ -377,7 +376,6 @@ Ltac invert_eval_cmd := Section ExprImp2. Context {width: Z} {BW: Bitwidth width} {word: word.word width} {mem: map.map word byte}. Context {locals: map.map String.string word}. - Context {env: map.map String.string (list String.string * list String.string * cmd)}. Context {ext_spec: ExtSpec}. Notation var := String.string (only parsing). diff --git a/compiler/src/compiler/ExprImpEventLoopSpec.v b/compiler/src/compiler/ExprImpEventLoopSpec.v index 777cd0a90..3b9ca998b 100644 --- a/compiler/src/compiler/ExprImpEventLoopSpec.v +++ b/compiler/src/compiler/ExprImpEventLoopSpec.v @@ -2,6 +2,7 @@ Require Import Coq.ZArith.ZArith. Require Coq.Strings.String. Require Import coqutil.Map.Interface coqutil.Word.Interface. Require Import bedrock2.MetricLogging. +Require Import bedrock2.Semantics. Require Import compiler.SeparationLogic. Require Import compiler.LowerPipeline. Require Import compiler.Pipeline. @@ -9,7 +10,6 @@ Require Import compiler.Pipeline. Section Params1. Context {width} {BW: Bitwidth width} {word: word.word width} {mem: map.map word Byte.byte}. Context {locals: map.map String.string word}. - Context {env: map.map String.string (list String.string * list String.string * Syntax.cmd)}. Context {ext_spec: Semantics.ExtSpec}. Set Implicit Arguments. diff --git a/compiler/src/compiler/FlattenExpr.v b/compiler/src/compiler/FlattenExpr.v index bc2e4611e..a5dd42349 100644 --- a/compiler/src/compiler/FlattenExpr.v +++ b/compiler/src/compiler/FlattenExpr.v @@ -25,14 +25,12 @@ Section FlattenExpr1. {word_ok: word.ok word} {locals: map.map String.string word} {mem: map.map word Byte.byte} - {ExprImp_env: map.map string (list string * list string * cmd)} {FlatImp_env: map.map string (list string * list string * FlatImp.stmt string)} {ext_spec: ExtSpec} {NGstate: Type} {NG: NameGen String.string NGstate} {locals_ok: map.ok locals} {mem_ok: map.ok mem} - {ExprImp_env_ok: map.ok ExprImp_env} {FlatImp_env_ok: map.ok FlatImp_env} {ext_spec_ok: ext_spec.ok ext_spec}. diff --git a/compiler/src/compiler/FlattenExprDef.v b/compiler/src/compiler/FlattenExprDef.v index 2fd8a8f4a..41ab0ee5d 100644 --- a/compiler/src/compiler/FlattenExprDef.v +++ b/compiler/src/compiler/FlattenExprDef.v @@ -21,7 +21,6 @@ Section FlattenExpr1. {word_ok: word.ok word} {locals: map.map String.string word} {mem: map.map word byte} - {ExprImp_env: map.map string (list string * list string * cmd)} {FlatImp_env: map.map string (list string * list string * FlatImp.stmt string)} {ext_spec: ExtSpec} {NGstate: Type} @@ -159,7 +158,7 @@ Section FlattenExpr1. let body' := fst (flattenStmt (freshNameGenState avoid) body) in Success (argnames, retnames, body'). - Definition flatten_functions: ExprImp_env -> result FlatImp_env := + Definition flatten_functions: Semantics.env -> result FlatImp_env := map.try_map_values flatten_function. End FlattenExpr1. diff --git a/compiler/src/compiler/Pipeline.v b/compiler/src/compiler/Pipeline.v index 6dd84f8b4..6996e63bd 100644 --- a/compiler/src/compiler/Pipeline.v +++ b/compiler/src/compiler/Pipeline.v @@ -140,10 +140,11 @@ Section WithWordAndMem. andb (Z.leb (-2048) x) (Z.ltb x 2048). Definition locals_based_call_spec{Var Cmd: Type}{locals: map.map Var word} - (Exec: string_keyed_map (list Var * list Var * Cmd) -> + {string_keyed_map: forall T: Type, map.map string T} + (Exec: string_keyed_map (list Var * list Var * Cmd)%type -> Cmd -> trace -> mem -> locals -> MetricLog -> (trace -> mem -> locals -> MetricLog -> Prop) -> Prop) - (e: string_keyed_map (list Var * list Var * Cmd))(f: string) + (e: string_keyed_map (list Var * list Var * Cmd)%type)(f: string) (t: trace)(m: mem)(argvals: list word) (post: trace -> mem -> list word -> Prop): Prop := exists argnames retnames fbody l, @@ -157,7 +158,7 @@ Section WithWordAndMem. fun '(argnames, retnames, body) => NoDup argnames /\ NoDup retnames. Definition SrcLang: Lang := {| - Program := string_keyed_map (list string * list string * Syntax.cmd); + Program := Semantics.env; Valid := map.forall_values ExprImp.valid_fun; Call := locals_based_call_spec Semantics.exec; |}. @@ -220,7 +221,7 @@ Section WithWordAndMem. Lemma flattening_correct: phase_correct SrcLang FlatWithStrVars flatten_functions. Proof. unfold SrcLang, FlatWithStrVars. - split; cbn. + split; cbn -[flatten_functions]. { unfold map.forall_values, ParamsNoDup. intros. destruct v as ((argnames & retnames) & body). eapply flatten_functions_NoDup; try eassumption. @@ -434,7 +435,7 @@ Section WithWordAndMem. Qed. Definition composed_compile: - string_keyed_map (list string * list string * cmd) -> + Semantics.env -> result (list Instruction * string_keyed_map Z * Z) := (compose_phases flatten_functions (compose_phases (useimmediate_functions is5BitImmediate is12BitImmediate) @@ -481,8 +482,8 @@ Section WithWordAndMem. ExprImp.valid_funs (map.of_list fs). Proof. unfold valid_funs. induction fs; intros. - - simpl in H0. rewrite map.get_empty in H0. discriminate. - - destruct a as (name & body). simpl in H0. rewrite map.get_put_dec in H0. fwd. + - cbn [map.of_list] in H0. rewrite map.get_empty in H0. discriminate. + - destruct a as (name & body). cbn [map.of_list] in H0. rewrite map.get_put_dec in H0. fwd. destruct_one_match_hyp. + fwd. eapply valid_src_fun_correct. eassumption. + eapply IHfs; eassumption. @@ -501,7 +502,8 @@ Section WithWordAndMem. valid_src_funs functions = true -> compile functions = Success (instrs, finfo, req_stack_size) -> (exists (argnames retnames: list string) (fbody: cmd) l, - map.get (map.of_list functions) fname = Some (argnames, retnames, fbody) /\ + map.get (map.of_list (map := Semantics.env) functions) fname = + Some (argnames, retnames, fbody) /\ map.of_list_zip argnames argvals = Some l /\ forall mc, Semantics.exec (map.of_list functions) fbody t mH l mc @@ -573,7 +575,7 @@ Section WithWordAndMem. valid_src_funs fs = true -> NoDup (map fst fs) -> compile fs = Success (instrs, finfo, req_stack_size) -> - WeakestPrecondition.call fs fname t mH argvals post -> + WeakestPrecondition.call (map.of_list fs) fname t mH argvals post -> map.get (map.of_list finfo) fname = Some f_rel_pos -> req_stack_size <= word.unsigned (word.sub stack_hi stack_lo) / bytes_per_word -> word.unsigned (word.sub stack_hi stack_lo) mod bytes_per_word = 0 -> @@ -594,7 +596,6 @@ Section WithWordAndMem. intros. let H := hyp WeakestPrecondition.call in rename H into WP. eapply WeakestPreconditionProperties.sound_call' in WP. - 2: { eapply map.all_gets_from_map_of_NoDup_list; assumption. } fwd. edestruct compiler_correct with (argvals := argvals) (post := post) as (f_rel_pos' & G & C); try eassumption. diff --git a/compiler/src/compiler/ToplevelLoop.v b/compiler/src/compiler/ToplevelLoop.v index 590fac9f0..7b82edff5 100644 --- a/compiler/src/compiler/ToplevelLoop.v +++ b/compiler/src/compiler/ToplevelLoop.v @@ -221,6 +221,8 @@ Section Pipeline1. apply Zmod_0_l. Qed. + Local Arguments map.get : simpl never. + Lemma establish_ll_inv: forall (initial: MetricRiscvMachine), initial_conditions initial -> ll_inv initial. diff --git a/compiler/src/compilerExamples/SoftmulCompile.v b/compiler/src/compilerExamples/SoftmulCompile.v index f583afc32..9b4fb45c6 100644 --- a/compiler/src/compilerExamples/SoftmulCompile.v +++ b/compiler/src/compilerExamples/SoftmulCompile.v @@ -649,9 +649,9 @@ Section Riscv. unfold isXAddr4, isXAddr1. ssplit; eapply In_word_seq; try ZnWords. Qed. - Lemma link_softmul_bedrock2: spec_of_softmul funimplsList. + Lemma link_softmul_bedrock2: spec_of_softmul (map.of_list funimplsList). Proof. - eapply softmul_ok. eapply rpmul.rpmul_ok. + eapply softmul_ok. 1: reflexivity. eapply rpmul.rpmul_ok. reflexivity. Qed. Import FunctionalExtensionality PropExtensionality. diff --git a/end2end/src/end2end/End2EndLightbulb.v b/end2end/src/end2end/End2EndLightbulb.v index 1bb255cf4..7b93641a6 100644 --- a/end2end/src/end2end/End2EndLightbulb.v +++ b/end2end/src/end2end/End2EndLightbulb.v @@ -76,13 +76,13 @@ Definition loop := ("loop", ([]: list string, []: list string, (cmd.call ["err"] "lightbulb_loop" [expr.literal buffer_addr]))). -Definition prog := init :: loop :: lightbulb.function_impls. +Definition prog := map.putmany_of_list (init :: loop :: nil) lightbulb.function_impls. (* Before running this command, it might be a good idea to do "Print Assumptions lightbulb_insts_unevaluated." and to check if there are any axioms which could block the computation. *) Definition lightbulb_compiled: list Decode.Instruction * list (string * Z) * Z. - let r := eval cbv in (ToplevelLoop.compile_prog MMIO.compile_ext_call ml prog) in + let r := eval cbv in (ToplevelLoop.compile_prog MMIO.compile_ext_call ml (map.tuples prog)) in lazymatch r with | Success ?x => exact x end. @@ -110,7 +110,7 @@ Definition required_stack_space: Z. Defined. Definition compilation_result: - ToplevelLoop.compile_prog MMIO.compile_ext_call ml prog = + ToplevelLoop.compile_prog MMIO.compile_ext_call ml (map.tuples prog) = Success (lightbulb_insts, function_positions, required_stack_space). Proof. reflexivity. Qed. @@ -182,7 +182,7 @@ Proof. intros *. intro KB. specialize Q with (stack_size_in_bytes := stack_size_in_bytes). specialize_first Q mem0. - specialize_first Q prog. + specialize_first Q (map.tuples prog). specialize_first Q open_constr:(eq_refl). specialize_first Q open_constr:(eq_refl). specialize_first Q open_constr:(eq_refl). @@ -190,7 +190,7 @@ Proof. specialize_first Q (Zkeyed_map (KamiWord.word 32)). specialize_first Q (Zkeyed_map_ok (KamiWord.word 32)). specialize_first Q mem_ok. - specialize Q with (13 := KB). (* TODO add bigger numbers to coqutil.Tactics.forward.specialize_first *) + specialize Q with (12 := KB). (* TODO add bigger numbers to coqutil.Tactics.forward.specialize_first *) (* specialize_first Q KB. *) specialize_first Q compilation_result. @@ -216,8 +216,6 @@ Proof. } eapply Q; clear Q. - cbv. intuition discriminate. - - clear. cbv. - repeat econstructor; intro; repeat match goal with H: In _ _|-_=> destruct H end; discriminate. - intros. clear KB mem0. simp. unfold SPI.mmio_trace_abstraction_relation in *. unfold id in *. @@ -225,9 +223,14 @@ Proof. - reflexivity. - (* establish invariant *) repeat ProgramLogic.straightline. - refine (WeakestPreconditionProperties.Proper_call _ _ _ _ _ _ _ _ _); - [|exact (link_lightbulb_init m nil)]. - + refine (WeakestPreconditionProperties.Proper_call _ _ _ _ _ _ _ _ _). + 2: { + unfold prog. eapply WP.extend_env_wp_call. 2: exact (link_lightbulb_init m nil). + rewrite map.of_list_tuples. + intros k f G. unfold map.putmany_of_list, init, loop. + rewrite ?map.get_put_dec. + repeat destruct_one_match; subst; try discriminate G. assumption. + } intros ? ? ? ?. repeat ProgramLogic.straightline. unfold LowerPipeline.mem_available, hl_inv, isReady, goodTrace, goodHlTrace, buffer_addr, ml, End2EndPipeline.ml, code_start, heap_start, heap_pastend, Lift1Prop.ex1 in *; Simp.simp. @@ -266,9 +269,14 @@ Proof. specialize_first P Hp0p0. specialize_first P t0. specialize_first P Hp0p1. - refine (WeakestPreconditionProperties.Proper_call _ _ _ _ _ _ _ _ _); - [|exact P]; clear P. - + refine (WeakestPreconditionProperties.Proper_call _ _ _ _ _ _ _ _ _). + 2: { + unfold prog. eapply WP.extend_env_wp_call. 2: exact P. + rewrite map.of_list_tuples. + intros k f G. unfold map.putmany_of_list, init, loop. + rewrite ?map.get_put_dec. + repeat destruct_one_match; subst; try discriminate G. assumption. + } intros ? ? ? ?. Simp.simp. repeat ProgramLogic.straightline. diff --git a/end2end/src/end2end/End2EndPipeline.v b/end2end/src/end2end/End2EndPipeline.v index 428d97667..a6652ba4e 100644 --- a/end2end/src/end2end/End2EndPipeline.v +++ b/end2end/src/end2end/End2EndPipeline.v @@ -199,8 +199,6 @@ Section Connect. Definition bedrock2Inv := (fun t m l => forall mc, hl_inv spec t m l mc). - Let funspecs := WeakestPrecondition.call funimplsList. - Hypothesis goodTrace_implies_related_to_Events: forall (t: list LogItem), spec.(goodTrace) t -> exists t': list Event, traces_related t' t. @@ -298,10 +296,10 @@ Section Connect. forall init_code loop_body, map.get (map.of_list funimplsList) "init"%string = Some ([], [], init_code) -> (forall m, LowerPipeline.mem_available ml.(heap_start) ml.(heap_pastend) m -> - WeakestPrecondition.cmd funspecs init_code [] m map.empty bedrock2Inv) -> + WeakestPrecondition.cmd (map.of_list funimplsList) init_code [] m map.empty bedrock2Inv) -> map.get (map.of_list funimplsList) "loop"%string = Some ([], [], loop_body) -> (forall t m l, bedrock2Inv t m l -> - WeakestPrecondition.cmd funspecs loop_body t m l bedrock2Inv) -> + WeakestPrecondition.cmd (map.of_list funimplsList) loop_body t m l bedrock2Inv) -> (* Assumptions on the compiler level: *) forall (instrs: list Instruction) positions (required_stack_space: Z), compile_prog compile_ext_call ml funimplsList = Success (instrs, positions, required_stack_space) -> @@ -371,12 +369,12 @@ Section Connect. rewrite heap_start_agree in H; rewrite heap_pastend_agree in H end. - refine (WeakestPreconditionProperties.sound_cmd _ _ _ _ _ _ _ _ _); eauto. + refine (WeakestPreconditionProperties.sound_cmd _ _ _ _ _ _ _ _); eauto. -- simpl. clear. intros. unfold bedrock2Inv in *. eauto. * exact GetLoop. * intros. unfold bedrock2Inv in *. eapply ExprImp.weaken_exec. - -- refine (WeakestPreconditionProperties.sound_cmd _ _ _ _ _ _ _ _ _); eauto. + -- refine (WeakestPreconditionProperties.sound_cmd _ _ _ _ _ _ _ _); eauto. -- simpl. clear. intros. eauto. + assumption. + assumption. From a20ca4d766ce1b622c4942c90d79e59cadc2d9dc Mon Sep 17 00:00:00 2001 From: Samuel Gruetter Date: Wed, 2 Aug 2023 19:06:54 -0400 Subject: [PATCH 08/15] add back program/Proper_program because it's used by rupicola --- bedrock2/src/bedrock2/WeakestPrecondition.v | 2 ++ .../src/bedrock2/WeakestPreconditionProperties.v | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/bedrock2/src/bedrock2/WeakestPrecondition.v b/bedrock2/src/bedrock2/WeakestPrecondition.v index 2a34b2093..0e2f48972 100644 --- a/bedrock2/src/bedrock2/WeakestPrecondition.v +++ b/bedrock2/src/bedrock2/WeakestPrecondition.v @@ -116,6 +116,8 @@ Section WeakestPrecondition. cmd call c t m l (fun t m l => list_map (get l) outnames (fun rets => post t m rets)). + + Definition program := cmd. End WeakestPrecondition. Notation call := wp_call. diff --git a/bedrock2/src/bedrock2/WeakestPreconditionProperties.v b/bedrock2/src/bedrock2/WeakestPreconditionProperties.v index 00e088826..cb0e9ba06 100644 --- a/bedrock2/src/bedrock2/WeakestPreconditionProperties.v +++ b/bedrock2/src/bedrock2/WeakestPreconditionProperties.v @@ -137,6 +137,22 @@ Section WeakestPrecondition. intros. eapply weaken_wp_call; eassumption. Qed. + Global Instance Proper_program : + Proper ( + pointwise_relation _ ( + pointwise_relation _ ( + pointwise_relation _ ( + pointwise_relation _ ( + pointwise_relation _ ( + (pointwise_relation _ (pointwise_relation _ (pointwise_relation _ Basics.impl))) ==> + Basics.impl)))))) WeakestPrecondition.program. + Proof using word_ok mem_ok locals_ok ext_spec_ok. + cbv [Proper respectful pointwise_relation Basics.impl WeakestPrecondition.program]; intros. + eapply Proper_cmd; + cbv [Proper respectful pointwise_relation Basics.flip Basics.impl WeakestPrecondition.func]; + try solve [typeclasses eauto with core]. + Qed. + Ltac t := repeat match goal with | |- forall _, _ => progress intros From 54e32e11cd6786c0ac0a1f7a480d33fe01eba3b2 Mon Sep 17 00:00:00 2001 From: Samuel Gruetter Date: Wed, 2 Aug 2023 19:08:01 -0400 Subject: [PATCH 09/15] cp Semantics.v MetricSemantics.v --- bedrock2/src/bedrock2/MetricSemantics.v | 384 ++++++++++++++++++++++++ 1 file changed, 384 insertions(+) create mode 100644 bedrock2/src/bedrock2/MetricSemantics.v diff --git a/bedrock2/src/bedrock2/MetricSemantics.v b/bedrock2/src/bedrock2/MetricSemantics.v new file mode 100644 index 000000000..ffec59ea0 --- /dev/null +++ b/bedrock2/src/bedrock2/MetricSemantics.v @@ -0,0 +1,384 @@ +Require Import coqutil.sanity coqutil.Macros.subst coqutil.Macros.unique coqutil.Byte. +Require Import coqutil.Datatypes.PrimitivePair coqutil.Datatypes.HList. +Require Import coqutil.Decidable. +Require Import coqutil.Tactics.fwd. +Require Import coqutil.Map.Properties. +Require coqutil.Map.SortedListString. +Require Import bedrock2.Syntax coqutil.Map.Interface coqutil.Map.OfListWord. +Require Import BinIntDef coqutil.Word.Interface coqutil.Word.Bitwidth. +Require Import bedrock2.MetricLogging. +Require Export bedrock2.Memory. + +Require Import Coq.Lists.List. + +(* BW is not needed on the rhs, but helps infer width *) +Definition trace{width: Z}{BW: Bitwidth width}{word: word.word width}{mem: map.map word byte} := + list ((mem * String.string * list word) * (mem * list word)). + +Definition ExtSpec{width: Z}{BW: Bitwidth width}{word: word.word width}{mem: map.map word byte} := + (* Given a trace of what happened so far, + the given-away memory, an action label and a list of function call arguments, *) + trace -> mem -> String.string -> list word -> + (* and a postcondition on the received memory and function call results, *) + (mem -> list word -> Prop) -> + (* tells if this postcondition will hold *) + Prop. + +Existing Class ExtSpec. + +Module ext_spec. + Class ok{width: Z}{BW: Bitwidth width}{word: word.word width}{mem: map.map word byte} + {ext_spec: ExtSpec}: Prop := + { + (* The action name and arguments uniquely determine the footprint of the given-away memory. *) + unique_mGive_footprint: forall t1 t2 mGive1 mGive2 a args + (post1 post2: mem -> list word -> Prop), + ext_spec t1 mGive1 a args post1 -> + ext_spec t2 mGive2 a args post2 -> + map.same_domain mGive1 mGive2; + + weaken :> forall t mGive act args, + Morphisms.Proper + (Morphisms.respectful + (Morphisms.pointwise_relation Interface.map.rep + (Morphisms.pointwise_relation (list word) Basics.impl)) Basics.impl) + (ext_spec t mGive act args); + + intersect: forall t mGive a args + (post1 post2: mem -> list word -> Prop), + ext_spec t mGive a args post1 -> + ext_spec t mGive a args post2 -> + ext_spec t mGive a args (fun mReceive resvals => + post1 mReceive resvals /\ post2 mReceive resvals); + }. +End ext_spec. +Arguments ext_spec.ok {_ _ _ _} _. + +Section binops. + Context {width : Z} {word : Word.Interface.word width}. + Definition interp_binop (bop : bopname) : word -> word -> word := + match bop with + | bopname.add => word.add + | bopname.sub => word.sub + | bopname.mul => word.mul + | bopname.mulhuu => word.mulhuu + | bopname.divu => word.divu + | bopname.remu => word.modu + | bopname.and => word.and + | bopname.or => word.or + | bopname.xor => word.xor + | bopname.sru => word.sru + | bopname.slu => word.slu + | bopname.srs => word.srs + | bopname.lts => fun a b => + if word.lts a b then word.of_Z 1 else word.of_Z 0 + | bopname.ltu => fun a b => + if word.ltu a b then word.of_Z 1 else word.of_Z 0 + | bopname.eq => fun a b => + if word.eqb a b then word.of_Z 1 else word.of_Z 0 + end. +End binops. + +#[export] Instance env: map.map String.string Syntax.func := SortedListString.map _. +#[export] Instance env_ok: map.ok env := SortedListString.ok _. + +Section semantics. + Context {width: Z} {BW: Bitwidth width} {word: word.word width} {mem: map.map word byte}. + Context {locals: map.map String.string word}. + Context {ext_spec: ExtSpec}. + + Local Notation metrics := MetricLog. + + (* this is the expr evaluator that is used to verify execution time, the just-correctness-oriented version is below *) + Section WithMemAndLocals. + Context (m : mem) (l : locals). + + Local Notation "' x <- a | y ; f" := (match a with x => f | _ => y end) + (right associativity, at level 70, x pattern). + + Fixpoint eval_expr (e : expr) (mc : metrics) : option (word * metrics) := + match e with + | expr.literal v => Some (word.of_Z v, addMetricInstructions 8 + (addMetricLoads 8 mc)) + | expr.var x => match map.get l x with + | Some v => Some (v, addMetricInstructions 1 + (addMetricLoads 2 mc)) + | None => None + end + | expr.inlinetable aSize t index => + 'Some (index', mc') <- eval_expr index mc | None; + 'Some v <- load aSize (map.of_list_word t) index' | None; + Some (v, (addMetricInstructions 3 + (addMetricLoads 4 + (addMetricJumps 1 mc')))) + | expr.load aSize a => + 'Some (a', mc') <- eval_expr a mc | None; + 'Some v <- load aSize m a' | None; + Some (v, addMetricInstructions 1 + (addMetricLoads 2 mc')) + | expr.op op e1 e2 => + 'Some (v1, mc') <- eval_expr e1 mc | None; + 'Some (v2, mc'') <- eval_expr e2 mc' | None; + Some (interp_binop op v1 v2, addMetricInstructions 2 + (addMetricLoads 2 mc'')) + | expr.ite c e1 e2 => + 'Some (vc, mc') <- eval_expr c mc | None; + eval_expr (if word.eqb vc (word.of_Z 0) then e2 else e1) + (addMetricInstructions 2 + (addMetricLoads 2 + (addMetricJumps 1 mc'))) + end. + + Fixpoint eval_expr_old (e : expr) : option word := + match e with + | expr.literal v => Some (word.of_Z v) + | expr.var x => map.get l x + | expr.inlinetable aSize t index => + 'Some index' <- eval_expr_old index | None; + load aSize (map.of_list_word t) index' + | expr.load aSize a => + 'Some a' <- eval_expr_old a | None; + load aSize m a' + | expr.op op e1 e2 => + 'Some v1 <- eval_expr_old e1 | None; + 'Some v2 <- eval_expr_old e2 | None; + Some (interp_binop op v1 v2) + | expr.ite c e1 e2 => + 'Some vc <- eval_expr_old c | None; + eval_expr_old (if word.eqb vc (word.of_Z 0) then e2 else e1) + end. + + Fixpoint evaluate_call_args_log (arges : list expr) (mc : metrics) := + match arges with + | e :: tl => + 'Some (v, mc') <- eval_expr e mc | None; + 'Some (args, mc'') <- evaluate_call_args_log tl mc' | None; + Some (v :: args, mc'') + | _ => Some (nil, mc) + end. + + End WithMemAndLocals. +End semantics. + +Module exec. Section WithParams. + Context {width: Z} {BW: Bitwidth width} {word: word.word width} {mem: map.map word byte}. + Context {locals: map.map String.string word}. + Context {ext_spec: ExtSpec}. + Section WithEnv. + Context (e: env). + + Local Notation metrics := MetricLog. + + Implicit Types post : trace -> mem -> locals -> metrics -> Prop. (* COQBUG(unification finds Type instead of Prop and fails to downgrade *) + Inductive exec : + cmd -> trace -> mem -> locals -> metrics -> + (trace -> mem -> locals -> metrics -> Prop) -> Prop := + | skip + t m l mc post + (_ : post t m l mc) + : exec cmd.skip t m l mc post + | set x e + t m l mc post + v mc' (_ : eval_expr m l e mc = Some (v, mc')) + (_ : post t m (map.put l x v) (addMetricInstructions 1 + (addMetricLoads 1 mc'))) + : exec (cmd.set x e) t m l mc post + | unset x + t m l mc post + (_ : post t m (map.remove l x) mc) + : exec (cmd.unset x) t m l mc post + | store sz ea ev + t m l mc post + a mc' (_ : eval_expr m l ea mc = Some (a, mc')) + v mc'' (_ : eval_expr m l ev mc' = Some (v, mc'')) + m' (_ : store sz m a v = Some m') + (_ : post t m' l (addMetricInstructions 1 + (addMetricLoads 1 + (addMetricStores 1 mc'')))) + : exec (cmd.store sz ea ev) t m l mc post + | stackalloc x n body + t mSmall l mc post + (_ : Z.modulo n (bytes_per_word width) = 0) + (_ : forall a mStack mCombined, + anybytes a n mStack -> + map.split mCombined mSmall mStack -> + exec body t mCombined (map.put l x a) (addMetricInstructions 1 (addMetricLoads 1 mc)) + (fun t' mCombined' l' mc' => + exists mSmall' mStack', + anybytes a n mStack' /\ + map.split mCombined' mSmall' mStack' /\ + post t' mSmall' l' mc')) + : exec (cmd.stackalloc x n body) t mSmall l mc post + | if_true t m l mc e c1 c2 post + v mc' (_ : eval_expr m l e mc = Some (v, mc')) + (_ : word.unsigned v <> 0) + (_ : exec c1 t m l (addMetricInstructions 2 + (addMetricLoads 2 + (addMetricJumps 1 mc'))) post) + : exec (cmd.cond e c1 c2) t m l mc post + | if_false e c1 c2 + t m l mc post + v mc' (_ : eval_expr m l e mc = Some (v, mc')) + (_ : word.unsigned v = 0) + (_ : exec c2 t m l (addMetricInstructions 2 + (addMetricLoads 2 + (addMetricJumps 1 mc'))) post) + : exec (cmd.cond e c1 c2) t m l mc post + | seq c1 c2 + t m l mc post + mid (_ : exec c1 t m l mc mid) + (_ : forall t' m' l' mc', mid t' m' l' mc' -> exec c2 t' m' l' mc' post) + : exec (cmd.seq c1 c2) t m l mc post + | while_false e c + t m l mc post + v mc' (_ : eval_expr m l e mc = Some (v, mc')) + (_ : word.unsigned v = 0) + (_ : post t m l (addMetricInstructions 1 + (addMetricLoads 1 + (addMetricJumps 1 mc')))) + : exec (cmd.while e c) t m l mc post + | while_true e c + t m l mc post + v mc' (_ : eval_expr m l e mc = Some (v, mc')) + (_ : word.unsigned v <> 0) + mid (_ : exec c t m l mc' mid) + (_ : forall t' m' l' mc'', mid t' m' l' mc'' -> + exec (cmd.while e c) t' m' l' (addMetricInstructions 2 + (addMetricLoads 2 + (addMetricJumps 1 mc''))) post) + : exec (cmd.while e c) t m l mc post + | call binds fname arges + t m l mc post + params rets fbody (_ : map.get e fname = Some (params, rets, fbody)) + args mc' (_ : evaluate_call_args_log m l arges mc = Some (args, mc')) + lf (_ : map.of_list_zip params args = Some lf) + mid (_ : exec fbody t m lf (addMetricInstructions 100 (addMetricJumps 100 (addMetricLoads 100 (addMetricStores 100 mc')))) mid) + (_ : forall t' m' st1 mc'', mid t' m' st1 mc'' -> + exists retvs, map.getmany_of_list st1 rets = Some retvs /\ + exists l', map.putmany_of_list_zip binds retvs l = Some l' /\ + post t' m' l' (addMetricInstructions 100 (addMetricJumps 100 (addMetricLoads 100 (addMetricStores 100 mc''))))) + : exec (cmd.call binds fname arges) t m l mc post + | interact binds action arges + t m l mc post + mKeep mGive (_: map.split m mKeep mGive) + args mc' (_ : evaluate_call_args_log m l arges mc = Some (args, mc')) + mid (_ : ext_spec t mGive action args mid) + (_ : forall mReceive resvals, mid mReceive resvals -> + exists l', map.putmany_of_list_zip binds resvals l = Some l' /\ + forall m', map.split m' mKeep mReceive -> + post (cons ((mGive, action, args), (mReceive, resvals)) t) m' l' + (addMetricInstructions 1 + (addMetricStores 1 + (addMetricLoads 2 mc')))) + : exec (cmd.interact binds action arges) t m l mc post + . + + Context {word_ok: word.ok word} {mem_ok: map.ok mem} {ext_spec_ok: ext_spec.ok ext_spec}. + + Lemma weaken: forall t l m mc s post1, + exec s t m l mc post1 -> + forall post2: _ -> _ -> _ -> _ -> Prop, + (forall t' m' l' mc', post1 t' m' l' mc' -> post2 t' m' l' mc') -> + exec s t m l mc post2. + Proof. + induction 1; intros; try solve [econstructor; eauto]. + - eapply stackalloc. 1: assumption. + intros. + eapply H1; eauto. + intros. fwd. eauto 10. + - eapply call. + 4: eapply IHexec. + all: eauto. + intros. + edestruct H3 as (? & ? & ? & ? & ?); [eassumption|]. + eauto 10. + - eapply interact; try eassumption. + intros. + edestruct H2 as (? & ? & ?); [eassumption|]. + eauto 10. + Qed. + + Lemma intersect: forall t l m mc s post1, + exec s t m l mc post1 -> + forall post2, + exec s t m l mc post2 -> + exec s t m l mc (fun t' m' l' mc' => post1 t' m' l' mc' /\ post2 t' m' l' mc'). + Proof. + induction 1; + intros; + match goal with + | H: exec _ _ _ _ _ _ |- _ => inversion H; subst; clear H + end; + try match goal with + | H1: ?e = Some (?x1, ?y1, ?z1), H2: ?e = Some (?x2, ?y2, ?z2) |- _ => + replace x2 with x1 in * by congruence; + replace y2 with y1 in * by congruence; + replace z2 with z1 in * by congruence; + clear x2 y2 z2 H2 + end; + repeat match goal with + | H1: ?e = Some (?v1, ?mc1), H2: ?e = Some (?v2, ?mc2) |- _ => + replace v2 with v1 in * by congruence; + replace mc2 with mc1 in * by congruence; clear H2 + end; + repeat match goal with + | H1: ?e = Some ?v1, H2: ?e = Some ?v2 |- _ => + replace v2 with v1 in * by congruence; clear H2 + end; + try solve [econstructor; eauto | exfalso; congruence]. + + - econstructor. 1: eassumption. + intros. + rename H0 into Ex1, H12 into Ex2. + eapply weaken. 1: eapply H1. 1,2: eassumption. + 1: eapply Ex2. 1,2: eassumption. + cbv beta. + intros. fwd. + lazymatch goal with + | A: map.split _ _ _, B: map.split _ _ _ |- _ => + specialize @map.split_diff with (4 := A) (5 := B) as P + end. + edestruct P; try typeclasses eauto. 2: subst; eauto 10. + eapply anybytes_unique_domain; eassumption. + - econstructor. + + eapply IHexec. exact H5. (* not H *) + + simpl. intros *. intros [? ?]. eauto. + - eapply while_true. 1, 2: eassumption. + + eapply IHexec. exact H9. (* not H1 *) + + simpl. intros *. intros [? ?]. eauto. + - eapply call. 1, 2, 3: eassumption. + + eapply IHexec. exact H16. (* not H2 *) + + simpl. intros *. intros [? ?]. + edestruct H3 as (? & ? & ? & ? & ?); [eassumption|]. + edestruct H17 as (? & ? & ? & ? & ?); [eassumption|]. + repeat match goal with + | H1: ?e = Some ?v1, H2: ?e = Some ?v2 |- _ => + replace v2 with v1 in * by congruence; clear H2 + end. + eauto 10. + - pose proof ext_spec.unique_mGive_footprint as P. + specialize P with (1 := H1) (2 := H14). + destruct (map.split_diff P H H7). subst mKeep0 mGive0. clear H7. + eapply interact. 1,2: eassumption. + + eapply ext_spec.intersect; [ exact H1 | exact H14 ]. + + simpl. intros *. intros [? ?]. + edestruct H2 as (? & ? & ?); [eassumption|]. + edestruct H15 as (? & ? & ?); [eassumption|]. + repeat match goal with + | H1: ?e = Some ?v1, H2: ?e = Some ?v2 |- _ => + replace v2 with v1 in * by congruence; clear H2 + end. + eauto 10. + Qed. + + End WithEnv. + + Lemma extend_env: forall e1 e2, + map.extends e2 e1 -> + forall c t m l mc post, + exec e1 c t m l mc post -> + exec e2 c t m l mc post. + Proof. induction 2; try solve [econstructor; eauto]. Qed. + + End WithParams. +End exec. Notation exec := exec.exec. From 4eed032a3232c97378401d260830c3e4fddd6f1a Mon Sep 17 00:00:00 2001 From: Samuel Gruetter Date: Thu, 3 Aug 2023 13:05:01 -0400 Subject: [PATCH 10/15] bedrock2.Semantics is now metrics-free, and metrics are in MetricSemantics --- PyLevelLang/src/PyLevelLang/Compile.v | 34 +-- bedrock2/src/bedrock2/FrameRule.v | 6 +- bedrock2/src/bedrock2/Loops.v | 4 +- bedrock2/src/bedrock2/MetricSemantics.v | 242 +++++++++------ bedrock2/src/bedrock2/Semantics.v | 289 +++++++----------- bedrock2/src/bedrock2/WP.v | 43 +-- .../bedrock2/WeakestPreconditionProperties.v | 100 ++---- bedrock2/src/bedrock2Examples/Trace.v | 2 +- .../indirect_add_heapletwise.v | 4 +- compiler/src/compiler/ExprImp.v | 14 +- compiler/src/compiler/ExprImpEventLoopSpec.v | 4 +- compiler/src/compiler/FlattenExpr.v | 8 +- compiler/src/compiler/Pipeline.v | 15 +- .../src/compilerExamples/SoftmulCompile.v | 2 +- end2end/src/end2end/End2EndPipeline.v | 6 +- 15 files changed, 358 insertions(+), 415 deletions(-) diff --git a/PyLevelLang/src/PyLevelLang/Compile.v b/PyLevelLang/src/PyLevelLang/Compile.v index 6c0eef5ad..9bae55529 100644 --- a/PyLevelLang/src/PyLevelLang/Compile.v +++ b/PyLevelLang/src/PyLevelLang/Compile.v @@ -136,8 +136,8 @@ Section WithMap. Lemma eval_map_extends_locals : forall e (m : mem) (l l' : locals') w, map.extends l' l -> - eval_expr_old m l e = Some w -> - eval_expr_old m l' e = Some w. + eval_expr m l e = Some w -> + eval_expr m l' e = Some w. Proof. induction e; intros m l l' w H Hl. - (* Syntax.expr.literal *) @@ -148,47 +148,47 @@ Section WithMap. - (* Syntax.expr.inlinetable *) simpl in Hl. simpl. specialize IHe with (m := m) (1 := H). - destruct (eval_expr_old m l e); try easy. + destruct (eval_expr m l e); try easy. specialize IHe with (w := r) (1 := eq_refl). now rewrite IHe. - (* Syntax.expr.load *) simpl in Hl. simpl. specialize IHe with (m := m) (1 := H). - destruct (eval_expr_old m l e); try easy. + destruct (eval_expr m l e); try easy. specialize IHe with (w := r) (1 := eq_refl). now rewrite IHe. - (* Syntax.expr.op *) simpl in Hl. simpl. - destruct (eval_expr_old m l e1) as [r1 |] eqn:H1; try easy. - destruct (eval_expr_old m l e2) as [r2 |] eqn:H2; try easy. + destruct (eval_expr m l e1) as [r1 |] eqn:H1; try easy. + destruct (eval_expr m l e2) as [r2 |] eqn:H2; try easy. specialize IHe1 with (m := m) (w := r1) (1 := H) (2 := H1). specialize IHe2 with (m := m) (w := r2) (1 := H) (2 := H2). now rewrite IHe1, IHe2. - (* Syntax.expr.ite *) simpl in Hl. simpl. - destruct (eval_expr_old m l e1) as [r1 |] eqn:H1; try easy. + destruct (eval_expr m l e1) as [r1 |] eqn:H1; try easy. specialize IHe1 with (m := m) (w := r1) (1 := H) (2 := H1). rewrite IHe1. destruct word.eqb. - + destruct (eval_expr_old m l e3) as [r3 |] eqn:H3; try easy. + + destruct (eval_expr m l e3) as [r3 |] eqn:H3; try easy. apply IHe3 with (l' := l') in H3; try assumption. now rewrite H3. - + destruct (eval_expr_old m l e2) as [r2 |] eqn:H2; try easy. + + destruct (eval_expr m l e2) as [r2 |] eqn:H2; try easy. apply IHe2 with (l' := l') in H2; try assumption. now rewrite H2. Qed. Lemma compile_correct : forall {t} (e : expr t) (c : Syntax.cmd) (e' : Syntax.expr), wf map.empty e -> - compile_expr e = Success (c, e') -> forall tr m l mc, - exec map.empty c tr m l mc (fun tr' m' l' mc' => exists (w : word), - eval_expr_old m' l' e' = Some w /\ + compile_expr e = Success (c, e') -> forall tr m l, + exec map.empty c tr m l (fun tr' m' l' => exists (w : word), + eval_expr m' l' e' = Some w /\ value_relation (interp_expr map.empty e) w /\ m' = m /\ map.extends l' l ). Proof. - intros t. induction e; intros c e' He He' tr m l mc; try easy. + intros t. induction e; intros c e' He He' tr m l; try easy. - (* EAtom a *) unfold compile_expr in He'. fwd. @@ -218,7 +218,7 @@ Section WithMap. specialize IHe with (2 := eq_refl); eapply exec.weaken; [ now apply IHe |]; cbv beta; - intros tr' m' l' mc' Hw; + intros tr' m' l' Hw; fwd; eexists; ssplit; @@ -253,11 +253,11 @@ Section WithMap. specialize IHe2 with (2 := eq_refl); eapply exec.seq; [ now apply IHe1 |]; cbv beta; - intros tr' m' l' mc' Hw; + intros tr' m' l' Hw; fwd; eapply exec.weaken; [ now apply IHe2 |]; cbv beta; - intros tr'' m'' l'' mc'' Hw'; + intros tr'' m'' l'' Hw'; fwd; eexists; ssplit; @@ -265,7 +265,7 @@ Section WithMap. apply eval_map_extends_locals with (l' := l'') in Hwp0; [| assumption]; now rewrite Hwp0 - | + | | reflexivity | now apply extends_trans with l' ]. 1-9: diff --git a/bedrock2/src/bedrock2/FrameRule.v b/bedrock2/src/bedrock2/FrameRule.v index 6a621014a..7ca6b059f 100644 --- a/bedrock2/src/bedrock2/FrameRule.v +++ b/bedrock2/src/bedrock2/FrameRule.v @@ -8,7 +8,7 @@ Require Import coqutil.Map.Interface coqutil.Map.Properties coqutil.Map.OfListWo Require Import coqutil.Word.Interface coqutil.Word.Bitwidth. Require Import bedrock2.MetricLogging. Require Import bedrock2.Memory bedrock2.ptsto_bytes bedrock2.Map.Separation. -Require Import bedrock2.Semantics. +Require Import bedrock2.Semantics bedrock2.MetricSemantics. Require Import bedrock2.Map.DisjointUnion bedrock2.Map.split_alt. Require Import Coq.Lists.List. @@ -126,8 +126,8 @@ Section semantics. Lemma frame_evaluate_call_args_log: forall l mSmall mBig mAdd arges mc (args: list word) mc', mmap.split mBig mSmall mAdd -> - evaluate_call_args_log mSmall l arges mc = Some (args, mc') -> - evaluate_call_args_log mBig l arges mc = Some (args, mc'). + eval_call_args mSmall l arges mc = Some (args, mc') -> + eval_call_args mBig l arges mc = Some (args, mc'). Proof. induction arges; cbn; intros. - assumption. diff --git a/bedrock2/src/bedrock2/Loops.v b/bedrock2/src/bedrock2/Loops.v index 5761c6313..25f60cec9 100644 --- a/bedrock2/src/bedrock2/Loops.v +++ b/bedrock2/src/bedrock2/Loops.v @@ -33,10 +33,10 @@ Section Loops. intros. destruct H as (measure & lt & inv & Hwf & HInit & Hbody). destruct HInit as (v0 & HInit). apply mk_wp_cmd. intros. - revert t m l mc HInit. pattern v0. revert v0. + revert t m l HInit. pattern v0. revert v0. eapply (well_founded_ind Hwf). intros. specialize Hbody with (1 := HInit). destruct Hbody as (b & Hb & Ht & Hf). - eapply expr_sound in Hb. destruct Hb as (b' & mc' & Hb & ?). subst b'. + eapply expr_sound in Hb. destruct Hb as (b' & Hb & ?). subst b'. destr.destr (Z.eqb (word.unsigned b) 0). - specialize Hf with (1 := E). eapply exec.while_false; eassumption. - specialize Ht with (1 := E). eapply sound_cmd in Ht. diff --git a/bedrock2/src/bedrock2/MetricSemantics.v b/bedrock2/src/bedrock2/MetricSemantics.v index ffec59ea0..7a0eb7527 100644 --- a/bedrock2/src/bedrock2/MetricSemantics.v +++ b/bedrock2/src/bedrock2/MetricSemantics.v @@ -1,86 +1,14 @@ -Require Import coqutil.sanity coqutil.Macros.subst coqutil.Macros.unique coqutil.Byte. -Require Import coqutil.Datatypes.PrimitivePair coqutil.Datatypes.HList. -Require Import coqutil.Decidable. +Require Import coqutil.sanity coqutil.Byte. Require Import coqutil.Tactics.fwd. Require Import coqutil.Map.Properties. Require coqutil.Map.SortedListString. Require Import bedrock2.Syntax coqutil.Map.Interface coqutil.Map.OfListWord. Require Import BinIntDef coqutil.Word.Interface coqutil.Word.Bitwidth. -Require Import bedrock2.MetricLogging. Require Export bedrock2.Memory. - Require Import Coq.Lists.List. - -(* BW is not needed on the rhs, but helps infer width *) -Definition trace{width: Z}{BW: Bitwidth width}{word: word.word width}{mem: map.map word byte} := - list ((mem * String.string * list word) * (mem * list word)). - -Definition ExtSpec{width: Z}{BW: Bitwidth width}{word: word.word width}{mem: map.map word byte} := - (* Given a trace of what happened so far, - the given-away memory, an action label and a list of function call arguments, *) - trace -> mem -> String.string -> list word -> - (* and a postcondition on the received memory and function call results, *) - (mem -> list word -> Prop) -> - (* tells if this postcondition will hold *) - Prop. - -Existing Class ExtSpec. - -Module ext_spec. - Class ok{width: Z}{BW: Bitwidth width}{word: word.word width}{mem: map.map word byte} - {ext_spec: ExtSpec}: Prop := - { - (* The action name and arguments uniquely determine the footprint of the given-away memory. *) - unique_mGive_footprint: forall t1 t2 mGive1 mGive2 a args - (post1 post2: mem -> list word -> Prop), - ext_spec t1 mGive1 a args post1 -> - ext_spec t2 mGive2 a args post2 -> - map.same_domain mGive1 mGive2; - - weaken :> forall t mGive act args, - Morphisms.Proper - (Morphisms.respectful - (Morphisms.pointwise_relation Interface.map.rep - (Morphisms.pointwise_relation (list word) Basics.impl)) Basics.impl) - (ext_spec t mGive act args); - - intersect: forall t mGive a args - (post1 post2: mem -> list word -> Prop), - ext_spec t mGive a args post1 -> - ext_spec t mGive a args post2 -> - ext_spec t mGive a args (fun mReceive resvals => - post1 mReceive resvals /\ post2 mReceive resvals); - }. -End ext_spec. -Arguments ext_spec.ok {_ _ _ _} _. - -Section binops. - Context {width : Z} {word : Word.Interface.word width}. - Definition interp_binop (bop : bopname) : word -> word -> word := - match bop with - | bopname.add => word.add - | bopname.sub => word.sub - | bopname.mul => word.mul - | bopname.mulhuu => word.mulhuu - | bopname.divu => word.divu - | bopname.remu => word.modu - | bopname.and => word.and - | bopname.or => word.or - | bopname.xor => word.xor - | bopname.sru => word.sru - | bopname.slu => word.slu - | bopname.srs => word.srs - | bopname.lts => fun a b => - if word.lts a b then word.of_Z 1 else word.of_Z 0 - | bopname.ltu => fun a b => - if word.ltu a b then word.of_Z 1 else word.of_Z 0 - | bopname.eq => fun a b => - if word.eqb a b then word.of_Z 1 else word.of_Z 0 - end. -End binops. - -#[export] Instance env: map.map String.string Syntax.func := SortedListString.map _. -#[export] Instance env_ok: map.ok env := SortedListString.ok _. +Require Import bedrock2.MetricLogging. +Require Import bedrock2.Semantics. +Require Import Coq.Lists.List. Section semantics. Context {width: Z} {BW: Bitwidth width} {word: word.word width} {mem: map.map word byte}. @@ -89,7 +17,6 @@ Section semantics. Local Notation metrics := MetricLog. - (* this is the expr evaluator that is used to verify execution time, the just-correctness-oriented version is below *) Section WithMemAndLocals. Context (m : mem) (l : locals). @@ -129,30 +56,11 @@ Section semantics. (addMetricJumps 1 mc'))) end. - Fixpoint eval_expr_old (e : expr) : option word := - match e with - | expr.literal v => Some (word.of_Z v) - | expr.var x => map.get l x - | expr.inlinetable aSize t index => - 'Some index' <- eval_expr_old index | None; - load aSize (map.of_list_word t) index' - | expr.load aSize a => - 'Some a' <- eval_expr_old a | None; - load aSize m a' - | expr.op op e1 e2 => - 'Some v1 <- eval_expr_old e1 | None; - 'Some v2 <- eval_expr_old e2 | None; - Some (interp_binop op v1 v2) - | expr.ite c e1 e2 => - 'Some vc <- eval_expr_old c | None; - eval_expr_old (if word.eqb vc (word.of_Z 0) then e2 else e1) - end. - - Fixpoint evaluate_call_args_log (arges : list expr) (mc : metrics) := + Fixpoint eval_call_args (arges : list expr) (mc : metrics) := match arges with | e :: tl => 'Some (v, mc') <- eval_expr e mc | None; - 'Some (args, mc'') <- evaluate_call_args_log tl mc' | None; + 'Some (args, mc'') <- eval_call_args tl mc' | None; Some (v :: args, mc'') | _ => Some (nil, mc) end. @@ -169,7 +77,7 @@ Module exec. Section WithParams. Local Notation metrics := MetricLog. - Implicit Types post : trace -> mem -> locals -> metrics -> Prop. (* COQBUG(unification finds Type instead of Prop and fails to downgrade *) + Implicit Types post : trace -> mem -> locals -> metrics -> Prop. (* COQBUG: unification finds Type instead of Prop and fails to downgrade *) Inductive exec : cmd -> trace -> mem -> locals -> metrics -> (trace -> mem -> locals -> metrics -> Prop) -> Prop := @@ -250,7 +158,7 @@ Module exec. Section WithParams. | call binds fname arges t m l mc post params rets fbody (_ : map.get e fname = Some (params, rets, fbody)) - args mc' (_ : evaluate_call_args_log m l arges mc = Some (args, mc')) + args mc' (_ : eval_call_args m l arges mc = Some (args, mc')) lf (_ : map.of_list_zip params args = Some lf) mid (_ : exec fbody t m lf (addMetricInstructions 100 (addMetricJumps 100 (addMetricLoads 100 (addMetricStores 100 mc')))) mid) (_ : forall t' m' st1 mc'', mid t' m' st1 mc'' -> @@ -261,7 +169,7 @@ Module exec. Section WithParams. | interact binds action arges t m l mc post mKeep mGive (_: map.split m mKeep mGive) - args mc' (_ : evaluate_call_args_log m l arges mc = Some (args, mc')) + args mc' (_ : eval_call_args m l arges mc = Some (args, mc')) mid (_ : ext_spec t mGive action args mid) (_ : forall mReceive resvals, mid mReceive resvals -> exists l', map.putmany_of_list_zip binds resvals l = Some l' /\ @@ -382,3 +290,135 @@ Module exec. Section WithParams. End WithParams. End exec. Notation exec := exec.exec. + +Section WithParams. + Context {width: Z} {BW: Bitwidth width} {word: word.word width} {mem: map.map word byte}. + Context {locals: map.map String.string word}. + Context {ext_spec: ExtSpec}. + + Implicit Types (l: locals) (m: mem). + + Definition call e fname t m args mc post := + exists argnames retnames body, + map.get e fname = Some (argnames, retnames, body) /\ + exists l, map.of_list_zip argnames args = Some l /\ + exec e body t m l mc (fun t' m' l' mc' => exists rets, + map.getmany_of_list l' retnames = Some rets /\ post t' m' rets mc'). + + Lemma of_metrics_free_eval_expr: forall m l e v, + Semantics.eval_expr m l e = Some v -> + forall mc, exists mc', MetricSemantics.eval_expr m l e mc = Some (v, mc'). + Proof. + induction e; cbn; intros; + repeat match goal with + | H: Some _ = Some _ |- _ => eapply Option.eq_of_eq_Some in H; subst + | H: _ = Some _ |- _ => rewrite H + | IH: forall _, Some _ = Some _ -> _ |- _ => specialize IH with (1 := eq_refl) + | IH: forall _: MetricLog, exists _: MetricLog, eval_expr ?m ?l ?e _ = Some _ + |- context[eval_expr ?m ?l ?e ?mc] => specialize (IH mc) + | |- _ => progress fwd + | |- _ => Tactics.destruct_one_match + end; + eauto. + Qed. + + Lemma to_metrics_free_eval_expr: forall m l e mc v mc', + MetricSemantics.eval_expr m l e mc = Some (v, mc') -> + Semantics.eval_expr m l e = Some v. + Proof. + induction e; cbn; intros; fwd; + repeat match goal with + | IH: forall _ _ _, eval_expr _ _ _ _ = _ -> _, H: eval_expr _ _ _ _ = _ |- _ => + specialize IH with (1 := H) + | H: _ = Some _ |- _ => rewrite H + | |- _ => Tactics.destruct_one_match + end; + try congruence. + Qed. + + Lemma of_metrics_free_eval_call_args: forall m l arges args, + Semantics.eval_call_args m l arges = Some args -> + forall mc, exists mc', MetricSemantics.eval_call_args m l arges mc = Some (args, mc'). + Proof. + induction arges; cbn; intros. + - eapply Option.eq_of_eq_Some in H. subst. eauto. + - fwd. + eapply of_metrics_free_eval_expr in E. destruct E as (mc' & E). rewrite E. + specialize IHarges with (1 := eq_refl). specialize (IHarges mc'). + destruct IHarges as (mc'' & IH). rewrite IH. eauto. + Qed. + + Lemma to_metrics_free_eval_call_args: forall m l arges mc args mc', + MetricSemantics.eval_call_args m l arges mc = Some (args, mc') -> + Semantics.eval_call_args m l arges = Some args. + Proof. + induction arges; cbn; intros. + - congruence. + - fwd. + eapply to_metrics_free_eval_expr in E. rewrite E. + specialize IHarges with (1 := E0). rewrite IHarges. reflexivity. + Qed. + + Context (e: env). + + Lemma of_metrics_free: forall c t m l post, + Semantics.exec e c t m l post -> + forall mc, MetricSemantics.exec e c t m l mc (fun t' m' l' _ => post t' m' l'). + Proof. + induction 1; intros; + repeat match reverse goal with + | H: Semantics.eval_expr _ _ _ = Some _ |- _ => + eapply of_metrics_free_eval_expr in H; destruct H as (? & H) + | H: Semantics.eval_call_args _ _ _ = Some _ |- _ => + eapply of_metrics_free_eval_call_args in H; destruct H as (? & H) + end; + try solve [econstructor; eauto]. + Qed. + + Lemma to_metrics_free: forall c t m l mc post, + MetricSemantics.exec e c t m l mc post -> + Semantics.exec e c t m l (fun t' m' l' => exists mc', post t' m' l' mc'). + Proof. + induction 1; intros; + repeat match reverse goal with + | H: eval_expr _ _ _ _ = Some _ |- _ => + eapply to_metrics_free_eval_expr in H + | H: eval_call_args _ _ _ _ = Some _ |- _ => + eapply to_metrics_free_eval_call_args in H + end; + try solve [econstructor; eauto]. + { econstructor. 1: eauto. + intros. + eapply Semantics.exec.weaken. 1: eapply H1. all: eauto. + cbv beta. + clear. firstorder idtac. } + { econstructor. + 1: eapply IHexec. + cbv beta. intros. + fwd. + eapply H1. eassumption. } + { econstructor; [ eassumption .. | ]. + cbv beta. intros. fwd. eapply H3. eassumption. } + { econstructor. 1-4: eassumption. + cbv beta. intros. fwd. specialize H3 with (1 := H4). fwd. eauto 10. } + { econstructor. 1-3: eassumption. + intros. specialize H2 with (1 := H3). fwd. eauto. } + Qed. + + Lemma of_metrics_free_call: forall f t m args post, + Semantics.call e f t m args post -> + forall mc, call e f t m args mc (fun t' m' rets _ => post t' m' rets). + Proof. + unfold call, Semantics.call. intros. fwd. eauto 10 using of_metrics_free. + Qed. + + Lemma to_metrics_free_call: forall f t m args mc post, + call e f t m args mc post -> + Semantics.call e f t m args (fun t' m' rets => exists mc', post t' m' rets mc'). + Proof. + unfold call, Semantics.call. intros. fwd. + do 4 eexists. 1: eassumption. do 2 eexists. 1: eassumption. + eapply Semantics.exec.weaken. 1: eapply to_metrics_free. 1: eassumption. + cbv beta. clear. firstorder idtac. + Qed. +End WithParams. diff --git a/bedrock2/src/bedrock2/Semantics.v b/bedrock2/src/bedrock2/Semantics.v index ffec59ea0..2c1e357c3 100644 --- a/bedrock2/src/bedrock2/Semantics.v +++ b/bedrock2/src/bedrock2/Semantics.v @@ -1,14 +1,10 @@ -Require Import coqutil.sanity coqutil.Macros.subst coqutil.Macros.unique coqutil.Byte. -Require Import coqutil.Datatypes.PrimitivePair coqutil.Datatypes.HList. -Require Import coqutil.Decidable. +Require Import coqutil.sanity coqutil.Byte. Require Import coqutil.Tactics.fwd. Require Import coqutil.Map.Properties. Require coqutil.Map.SortedListString. Require Import bedrock2.Syntax coqutil.Map.Interface coqutil.Map.OfListWord. Require Import BinIntDef coqutil.Word.Interface coqutil.Word.Bitwidth. -Require Import bedrock2.MetricLogging. Require Export bedrock2.Memory. - Require Import Coq.Lists.List. (* BW is not needed on the rhs, but helps infer width *) @@ -87,74 +83,39 @@ Section semantics. Context {locals: map.map String.string word}. Context {ext_spec: ExtSpec}. - Local Notation metrics := MetricLog. - (* this is the expr evaluator that is used to verify execution time, the just-correctness-oriented version is below *) Section WithMemAndLocals. Context (m : mem) (l : locals). - Local Notation "' x <- a | y ; f" := (match a with x => f | _ => y end) - (right associativity, at level 70, x pattern). + Local Notation "x <- a ; f" := (match a with Some x => f | None => None end) + (right associativity, at level 70). - Fixpoint eval_expr (e : expr) (mc : metrics) : option (word * metrics) := - match e with - | expr.literal v => Some (word.of_Z v, addMetricInstructions 8 - (addMetricLoads 8 mc)) - | expr.var x => match map.get l x with - | Some v => Some (v, addMetricInstructions 1 - (addMetricLoads 2 mc)) - | None => None - end - | expr.inlinetable aSize t index => - 'Some (index', mc') <- eval_expr index mc | None; - 'Some v <- load aSize (map.of_list_word t) index' | None; - Some (v, (addMetricInstructions 3 - (addMetricLoads 4 - (addMetricJumps 1 mc')))) - | expr.load aSize a => - 'Some (a', mc') <- eval_expr a mc | None; - 'Some v <- load aSize m a' | None; - Some (v, addMetricInstructions 1 - (addMetricLoads 2 mc')) - | expr.op op e1 e2 => - 'Some (v1, mc') <- eval_expr e1 mc | None; - 'Some (v2, mc'') <- eval_expr e2 mc' | None; - Some (interp_binop op v1 v2, addMetricInstructions 2 - (addMetricLoads 2 mc'')) - | expr.ite c e1 e2 => - 'Some (vc, mc') <- eval_expr c mc | None; - eval_expr (if word.eqb vc (word.of_Z 0) then e2 else e1) - (addMetricInstructions 2 - (addMetricLoads 2 - (addMetricJumps 1 mc'))) - end. - - Fixpoint eval_expr_old (e : expr) : option word := + Fixpoint eval_expr (e : expr) : option word := match e with | expr.literal v => Some (word.of_Z v) | expr.var x => map.get l x | expr.inlinetable aSize t index => - 'Some index' <- eval_expr_old index | None; + index' <- eval_expr index; load aSize (map.of_list_word t) index' | expr.load aSize a => - 'Some a' <- eval_expr_old a | None; + a' <- eval_expr a; load aSize m a' | expr.op op e1 e2 => - 'Some v1 <- eval_expr_old e1 | None; - 'Some v2 <- eval_expr_old e2 | None; + v1 <- eval_expr e1; + v2 <- eval_expr e2; Some (interp_binop op v1 v2) | expr.ite c e1 e2 => - 'Some vc <- eval_expr_old c | None; - eval_expr_old (if word.eqb vc (word.of_Z 0) then e2 else e1) + vc <- eval_expr c; + eval_expr (if word.eqb vc (word.of_Z 0) then e2 else e1) end. - Fixpoint evaluate_call_args_log (arges : list expr) (mc : metrics) := + Fixpoint eval_call_args (arges : list expr) := match arges with | e :: tl => - 'Some (v, mc') <- eval_expr e mc | None; - 'Some (args, mc'') <- evaluate_call_args_log tl mc' | None; - Some (v :: args, mc'') - | _ => Some (nil, mc) + v <- eval_expr e; + args <- eval_call_args tl; + Some (v :: args) + | _ => Some nil end. End WithMemAndLocals. @@ -167,119 +128,89 @@ Module exec. Section WithParams. Section WithEnv. Context (e: env). - Local Notation metrics := MetricLog. - - Implicit Types post : trace -> mem -> locals -> metrics -> Prop. (* COQBUG(unification finds Type instead of Prop and fails to downgrade *) - Inductive exec : - cmd -> trace -> mem -> locals -> metrics -> - (trace -> mem -> locals -> metrics -> Prop) -> Prop := - | skip - t m l mc post - (_ : post t m l mc) - : exec cmd.skip t m l mc post - | set x e - t m l mc post - v mc' (_ : eval_expr m l e mc = Some (v, mc')) - (_ : post t m (map.put l x v) (addMetricInstructions 1 - (addMetricLoads 1 mc'))) - : exec (cmd.set x e) t m l mc post - | unset x - t m l mc post - (_ : post t m (map.remove l x) mc) - : exec (cmd.unset x) t m l mc post - | store sz ea ev - t m l mc post - a mc' (_ : eval_expr m l ea mc = Some (a, mc')) - v mc'' (_ : eval_expr m l ev mc' = Some (v, mc'')) - m' (_ : store sz m a v = Some m') - (_ : post t m' l (addMetricInstructions 1 - (addMetricLoads 1 - (addMetricStores 1 mc'')))) - : exec (cmd.store sz ea ev) t m l mc post - | stackalloc x n body - t mSmall l mc post - (_ : Z.modulo n (bytes_per_word width) = 0) - (_ : forall a mStack mCombined, + Implicit Types post : trace -> mem -> locals -> Prop. (* COQBUG: unification finds Type instead of Prop and fails to downgrade *) + Inductive exec: cmd -> trace -> mem -> locals -> + (trace -> mem -> locals -> Prop) -> Prop := + | skip: forall t m l post, + post t m l -> + exec cmd.skip t m l post + | set: forall x e t m l post v, + eval_expr m l e = Some v -> + post t m (map.put l x v) -> + exec (cmd.set x e) t m l post + | unset: forall x t m l post, + post t m (map.remove l x) -> + exec (cmd.unset x) t m l post + | store: forall sz ea ev t m l post a v m', + eval_expr m l ea = Some a -> + eval_expr m l ev = Some v -> + store sz m a v = Some m' -> + post t m' l -> + exec (cmd.store sz ea ev) t m l post + | stackalloc: forall x n body t mSmall l post, + Z.modulo n (bytes_per_word width) = 0 -> + (forall a mStack mCombined, anybytes a n mStack -> map.split mCombined mSmall mStack -> - exec body t mCombined (map.put l x a) (addMetricInstructions 1 (addMetricLoads 1 mc)) - (fun t' mCombined' l' mc' => + exec body t mCombined (map.put l x a) + (fun t' mCombined' l' => exists mSmall' mStack', anybytes a n mStack' /\ map.split mCombined' mSmall' mStack' /\ - post t' mSmall' l' mc')) - : exec (cmd.stackalloc x n body) t mSmall l mc post - | if_true t m l mc e c1 c2 post - v mc' (_ : eval_expr m l e mc = Some (v, mc')) - (_ : word.unsigned v <> 0) - (_ : exec c1 t m l (addMetricInstructions 2 - (addMetricLoads 2 - (addMetricJumps 1 mc'))) post) - : exec (cmd.cond e c1 c2) t m l mc post - | if_false e c1 c2 - t m l mc post - v mc' (_ : eval_expr m l e mc = Some (v, mc')) - (_ : word.unsigned v = 0) - (_ : exec c2 t m l (addMetricInstructions 2 - (addMetricLoads 2 - (addMetricJumps 1 mc'))) post) - : exec (cmd.cond e c1 c2) t m l mc post - | seq c1 c2 - t m l mc post - mid (_ : exec c1 t m l mc mid) - (_ : forall t' m' l' mc', mid t' m' l' mc' -> exec c2 t' m' l' mc' post) - : exec (cmd.seq c1 c2) t m l mc post - | while_false e c - t m l mc post - v mc' (_ : eval_expr m l e mc = Some (v, mc')) - (_ : word.unsigned v = 0) - (_ : post t m l (addMetricInstructions 1 - (addMetricLoads 1 - (addMetricJumps 1 mc')))) - : exec (cmd.while e c) t m l mc post - | while_true e c - t m l mc post - v mc' (_ : eval_expr m l e mc = Some (v, mc')) - (_ : word.unsigned v <> 0) - mid (_ : exec c t m l mc' mid) - (_ : forall t' m' l' mc'', mid t' m' l' mc'' -> - exec (cmd.while e c) t' m' l' (addMetricInstructions 2 - (addMetricLoads 2 - (addMetricJumps 1 mc''))) post) - : exec (cmd.while e c) t m l mc post - | call binds fname arges - t m l mc post - params rets fbody (_ : map.get e fname = Some (params, rets, fbody)) - args mc' (_ : evaluate_call_args_log m l arges mc = Some (args, mc')) - lf (_ : map.of_list_zip params args = Some lf) - mid (_ : exec fbody t m lf (addMetricInstructions 100 (addMetricJumps 100 (addMetricLoads 100 (addMetricStores 100 mc')))) mid) - (_ : forall t' m' st1 mc'', mid t' m' st1 mc'' -> + post t' mSmall' l')) -> + exec (cmd.stackalloc x n body) t mSmall l post + | if_true: forall t m l e c1 c2 post v, + eval_expr m l e = Some v -> + word.unsigned v <> 0 -> + exec c1 t m l post -> + exec (cmd.cond e c1 c2) t m l post + | if_false: forall e c1 c2 t m l post v, + eval_expr m l e = Some v -> + word.unsigned v = 0 -> + exec c2 t m l post -> + exec (cmd.cond e c1 c2) t m l post + | seq: forall c1 c2 t m l post mid, + exec c1 t m l mid -> + (forall t' m' l', mid t' m' l' -> exec c2 t' m' l' post) -> + exec (cmd.seq c1 c2) t m l post + | while_false: forall e c t m l post v, + eval_expr m l e = Some v -> + word.unsigned v = 0 -> + post t m l -> + exec (cmd.while e c) t m l post + | while_true: forall e c t m l post v mid, + eval_expr m l e = Some v -> + word.unsigned v <> 0 -> + exec c t m l mid -> + (forall t' m' l', mid t' m' l' -> exec (cmd.while e c) t' m' l' post) -> + exec (cmd.while e c) t m l post + | call: forall binds fname arges t m l post params rets fbody args lf mid, + map.get e fname = Some (params, rets, fbody) -> + eval_call_args m l arges = Some args -> + map.of_list_zip params args = Some lf -> + exec fbody t m lf mid -> + (forall t' m' st1, mid t' m' st1 -> exists retvs, map.getmany_of_list st1 rets = Some retvs /\ exists l', map.putmany_of_list_zip binds retvs l = Some l' /\ - post t' m' l' (addMetricInstructions 100 (addMetricJumps 100 (addMetricLoads 100 (addMetricStores 100 mc''))))) - : exec (cmd.call binds fname arges) t m l mc post - | interact binds action arges - t m l mc post - mKeep mGive (_: map.split m mKeep mGive) - args mc' (_ : evaluate_call_args_log m l arges mc = Some (args, mc')) - mid (_ : ext_spec t mGive action args mid) - (_ : forall mReceive resvals, mid mReceive resvals -> + post t' m' l') -> + exec (cmd.call binds fname arges) t m l post + | interact: forall binds action arges args t m l post mKeep mGive mid, + map.split m mKeep mGive -> + eval_call_args m l arges = Some args -> + ext_spec t mGive action args mid -> + (forall mReceive resvals, mid mReceive resvals -> exists l', map.putmany_of_list_zip binds resvals l = Some l' /\ forall m', map.split m' mKeep mReceive -> - post (cons ((mGive, action, args), (mReceive, resvals)) t) m' l' - (addMetricInstructions 1 - (addMetricStores 1 - (addMetricLoads 2 mc')))) - : exec (cmd.interact binds action arges) t m l mc post - . + post (cons ((mGive, action, args), (mReceive, resvals)) t) m' l') -> + exec (cmd.interact binds action arges) t m l post. Context {word_ok: word.ok word} {mem_ok: map.ok mem} {ext_spec_ok: ext_spec.ok ext_spec}. - Lemma weaken: forall t l m mc s post1, - exec s t m l mc post1 -> - forall post2: _ -> _ -> _ -> _ -> Prop, - (forall t' m' l' mc', post1 t' m' l' mc' -> post2 t' m' l' mc') -> - exec s t m l mc post2. + Lemma weaken: forall t l m s post1, + exec s t m l post1 -> + forall post2, + (forall t' m' l', post1 t' m' l' -> post2 t' m' l') -> + exec s t m l post2. Proof. induction 1; intros; try solve [econstructor; eauto]. - eapply stackalloc. 1: assumption. @@ -298,16 +229,16 @@ Module exec. Section WithParams. eauto 10. Qed. - Lemma intersect: forall t l m mc s post1, - exec s t m l mc post1 -> + Lemma intersect: forall t l m s post1, + exec s t m l post1 -> forall post2, - exec s t m l mc post2 -> - exec s t m l mc (fun t' m' l' mc' => post1 t' m' l' mc' /\ post2 t' m' l' mc'). + exec s t m l post2 -> + exec s t m l (fun t' m' l' => post1 t' m' l' /\ post2 t' m' l'). Proof. induction 1; intros; match goal with - | H: exec _ _ _ _ _ _ |- _ => inversion H; subst; clear H + | H: exec _ _ _ _ _ |- _ => inversion H; subst; clear H end; try match goal with | H1: ?e = Some (?x1, ?y1, ?z1), H2: ?e = Some (?x2, ?y2, ?z2) |- _ => @@ -317,9 +248,8 @@ Module exec. Section WithParams. clear x2 y2 z2 H2 end; repeat match goal with - | H1: ?e = Some (?v1, ?mc1), H2: ?e = Some (?v2, ?mc2) |- _ => - replace v2 with v1 in * by congruence; - replace mc2 with mc1 in * by congruence; clear H2 + | H1: ?e = Some ?v1, H2: ?e = Some ?v2 |- _ => + replace v2 with v1 in * by congruence; clear H2 end; repeat match goal with | H1: ?e = Some ?v1, H2: ?e = Some ?v2 |- _ => @@ -329,7 +259,7 @@ Module exec. Section WithParams. - econstructor. 1: eassumption. intros. - rename H0 into Ex1, H12 into Ex2. + rename H0 into Ex1, H11 into Ex2. eapply weaken. 1: eapply H1. 1,2: eassumption. 1: eapply Ex2. 1,2: eassumption. cbv beta. @@ -347,23 +277,23 @@ Module exec. Section WithParams. + eapply IHexec. exact H9. (* not H1 *) + simpl. intros *. intros [? ?]. eauto. - eapply call. 1, 2, 3: eassumption. - + eapply IHexec. exact H16. (* not H2 *) + + eapply IHexec. exact H15. (* not H2 *) + simpl. intros *. intros [? ?]. edestruct H3 as (? & ? & ? & ? & ?); [eassumption|]. - edestruct H17 as (? & ? & ? & ? & ?); [eassumption|]. + edestruct H16 as (? & ? & ? & ? & ?); [eassumption|]. repeat match goal with | H1: ?e = Some ?v1, H2: ?e = Some ?v2 |- _ => replace v2 with v1 in * by congruence; clear H2 end. eauto 10. - pose proof ext_spec.unique_mGive_footprint as P. - specialize P with (1 := H1) (2 := H14). + specialize P with (1 := H1) (2 := H13). destruct (map.split_diff P H H7). subst mKeep0 mGive0. clear H7. eapply interact. 1,2: eassumption. - + eapply ext_spec.intersect; [ exact H1 | exact H14 ]. + + eapply ext_spec.intersect; [ exact H1 | exact H13 ]. + simpl. intros *. intros [? ?]. edestruct H2 as (? & ? & ?); [eassumption|]. - edestruct H15 as (? & ? & ?); [eassumption|]. + edestruct H14 as (? & ? & ?); [eassumption|]. repeat match goal with | H1: ?e = Some ?v1, H2: ?e = Some ?v2 |- _ => replace v2 with v1 in * by congruence; clear H2 @@ -375,10 +305,25 @@ Module exec. Section WithParams. Lemma extend_env: forall e1 e2, map.extends e2 e1 -> - forall c t m l mc post, - exec e1 c t m l mc post -> - exec e2 c t m l mc post. + forall c t m l post, + exec e1 c t m l post -> + exec e2 c t m l post. Proof. induction 2; try solve [econstructor; eauto]. Qed. End WithParams. End exec. Notation exec := exec.exec. + +Section WithParams. + Context {width: Z} {BW: Bitwidth width} {word: word.word width} {mem: map.map word byte}. + Context {locals: map.map String.string word}. + Context {ext_spec: ExtSpec}. + + Implicit Types (l: locals) (m: mem). + + Definition call e fname t m args post := + exists argnames retnames body, + map.get e fname = Some (argnames, retnames, body) /\ + exists l, map.of_list_zip argnames args = Some l /\ + exec e body t m l (fun t' m' l' => exists rets, + map.getmany_of_list l' retnames = Some rets /\ post t' m' rets). +End WithParams. diff --git a/bedrock2/src/bedrock2/WP.v b/bedrock2/src/bedrock2/WP.v index 5588d2014..f8f2779a6 100644 --- a/bedrock2/src/bedrock2/WP.v +++ b/bedrock2/src/bedrock2/WP.v @@ -1,6 +1,7 @@ Require Import Coq.ZArith.ZArith. Require Import coqutil.Map.Interface. Require Import coqutil.Word.Interface coqutil.Word.Bitwidth. +Require Import coqutil.Tactics.fwd. Require Import bedrock2.Syntax bedrock2.Semantics. (* We want to make the definitions opaque to `hnf` (unfolds any definition, so a plain @@ -17,11 +18,11 @@ Module Type WP_Sig. Syntax.cmd -> trace -> mem -> locals -> (trace -> mem -> locals -> Prop) -> Prop. Parameter mk_wp_cmd : forall {ext_spec: ExtSpec} (e: env) c t m l post, - (forall mc, exec e c t m l mc (fun t' m' l' mc' => post t' m' l')) -> + exec e c t m l post -> wp_cmd e c t m l post. Parameter invert_wp_cmd: forall {ext_spec: ExtSpec} [e c t m l post], wp_cmd e c t m l post -> - forall mc, exec e c t m l mc (fun t' m' l' mc' => post t' m' l'). + exec e c t m l post. Parameter wp_call : forall {locals: map.map String.string word} {ext_spec: ExtSpec}, env -> String.string -> trace -> mem -> list word -> @@ -48,46 +49,34 @@ Module Export WP_Impl : WP_Sig. Context {width: Z} {BW: Bitwidth width} {word: word.word width} {mem: map.map word Byte.byte} {locals: map.map String.string word} - {ext_spec: ExtSpec} - (e: env). + {ext_spec: ExtSpec}. - Definition wp_cmd (c : Syntax.cmd) (t : trace) (m : mem) (l : locals) - (post : (trace -> mem -> locals -> Prop)) : Prop := - (forall mc, exec e c t m l mc (fun t' m' l' mc' => post t' m' l')). + Definition wp_cmd := exec. - Lemma mk_wp_cmd c t m l post: - (forall mc, exec e c t m l mc (fun t' m' l' mc' => post t' m' l')) -> - wp_cmd c t m l post. + Lemma mk_wp_cmd e c t m l post: exec e c t m l post -> wp_cmd e c t m l post. Proof. exact id. Qed. - Lemma invert_wp_cmd c t m l post: - wp_cmd c t m l post -> - forall mc, exec e c t m l mc (fun t' m' l' mc' => post t' m' l'). + Lemma invert_wp_cmd e c t m l post: wp_cmd e c t m l post -> exec e c t m l post. Proof. exact id. Qed. - Definition wp_call fname t m args post := - exists argnames retnames body l, - map.get e fname = Some (argnames, retnames, body) /\ - map.of_list_zip argnames args = Some l /\ - wp_cmd body t m l (fun t' m' l' => exists rets, - map.getmany_of_list l' retnames = Some rets /\ post t' m' rets). + Definition wp_call := call. - Lemma mk_wp_call: forall fname argnames retnames body t m l args post, + Lemma mk_wp_call: forall e fname argnames retnames body t m l args post, map.get e fname = Some (argnames, retnames, body) -> map.of_list_zip argnames args = Some l -> - wp_cmd body t m l (fun t' m' l' => exists rets, + wp_cmd e body t m l (fun t' m' l' => exists rets, map.getmany_of_list l' retnames = Some rets /\ post t' m' rets) -> - wp_call fname t m args post. - Proof. intros. unfold wp_call. eauto 8. Qed. + wp_call e fname t m args post. + Proof. unfold wp_call, call, wp_cmd. intros. eauto 10. Qed. - Lemma invert_wp_call fname t m args post: - wp_call fname t m args post -> + Lemma invert_wp_call e fname t m args post: + wp_call e fname t m args post -> exists argnames retnames body l, map.get e fname = Some (argnames, retnames, body) /\ map.of_list_zip argnames args = Some l /\ - wp_cmd body t m l (fun t' m' l' => exists rets, + wp_cmd e body t m l (fun t' m' l' => exists rets, map.getmany_of_list l' retnames = Some rets /\ post t' m' rets). - Proof. exact id. Qed. + Proof. unfold wp_call, call, wp_cmd. intros. fwd. eauto 10. Qed. End WithParams. End WP_Impl. diff --git a/bedrock2/src/bedrock2/WeakestPreconditionProperties.v b/bedrock2/src/bedrock2/WeakestPreconditionProperties.v index cb0e9ba06..fc25c07fe 100644 --- a/bedrock2/src/bedrock2/WeakestPreconditionProperties.v +++ b/bedrock2/src/bedrock2/WeakestPreconditionProperties.v @@ -164,11 +164,10 @@ Section WeakestPrecondition. | _ => progress cbv [dlet.dlet WeakestPrecondition.dexpr WeakestPrecondition.dexprs WeakestPrecondition.store] in * end; eauto. - Lemma expr_sound: forall m l e mc post (H : WeakestPrecondition.expr m l e post), - exists v mc', Semantics.eval_expr m l e mc = Some (v, mc') /\ post v. + Lemma expr_sound: forall m l e post (H : WeakestPrecondition.expr m l e post), + exists v, Semantics.eval_expr m l e = Some v /\ post v. Proof using word_ok. induction e; t. - { destruct H. destruct H. eexists. eexists. rewrite H. eauto. } { eapply IHe in H; t. cbv [WeakestPrecondition.load] in H0; t. rewrite H. rewrite H0. eauto. } { eapply IHe in H; t. cbv [WeakestPrecondition.load] in H0; t. rewrite H. rewrite H0. eauto. } { eapply IHe1 in H; t. eapply IHe2 in H0; t. rewrite H, H0; eauto. } @@ -179,56 +178,43 @@ Section WeakestPrecondition. Import ZArith coqutil.Tactics.Tactics. - Lemma expr_complete: forall m l e mc v mc', - Semantics.eval_expr m l e mc = Some (v, mc') -> + Lemma expr_complete: forall m l e v, + Semantics.eval_expr m l e = Some v -> WeakestPrecondition.dexpr m l e v. Proof using word_ok. induction e; cbn; intros. - inversion_clear H. reflexivity. - - destruct_one_match_hyp. 2: discriminate. inversion H. subst r. - eexists. eauto. + - eexists. eauto. - repeat (destruct_one_match_hyp; try discriminate; []). - inversion H. subst r0 mc'. clear H. eapply Proper_expr. - 2: { eapply IHe. eassumption. } + 2: { eapply IHe. reflexivity. } intros addr ?. subst r. unfold WeakestPrecondition.load. eauto. - repeat (destruct_one_match_hyp; try discriminate; []). - inversion H. subst r0 mc'. clear H. eapply Proper_expr. - 2: { eapply IHe. eassumption. } + 2: { eapply IHe. reflexivity. } intros addr ?. subst r. unfold WeakestPrecondition.load. eauto. - repeat (destruct_one_match_hyp; try discriminate; []). - inversion H. subst v mc'. clear H. eapply Proper_expr. - 2: { eapply IHe1. eassumption. } + 2: { eapply IHe1. reflexivity. } intros v1 ?. subst r. eapply Proper_expr. - 2: { eapply IHe2. eassumption. } + 2: { eapply IHe2. reflexivity. } intros v2 ?. subst r0. - reflexivity. + congruence. - repeat (destruct_one_match_hyp; try discriminate; []). eapply Proper_expr. - 2: { eapply IHe1. eassumption. } + 2: { eapply IHe1. reflexivity. } intros vc ?. subst r. destr (word.eqb vc (word.of_Z 0)). + eapply IHe3. eassumption. + eapply IHe2. eassumption. Qed. - Lemma eval_expr_change_start_metrics: forall m l e mc1 mc1' v, - Semantics.eval_expr m l e mc1 = Some (v, mc1') -> - forall mc2, exists mc2', Semantics.eval_expr m l e mc2 = Some (v, mc2'). - Proof. - intros. eapply expr_complete in H. eapply expr_sound in H. - destruct H as (? & mc2' & H & ?). subst v. exists mc2'. exact H. - Qed. - - Lemma sound_args : forall m l args mc P, + Lemma sound_args : forall m l args P, WeakestPrecondition.list_map (WeakestPrecondition.expr m l) args P -> - exists x mc', Semantics.evaluate_call_args_log m l args mc = Some (x, mc') /\ P x. + exists x, Semantics.eval_call_args m l args = Some x /\ P x. Proof using word_ok. induction args; cbn; repeat (subst; t). - unfold Semantics.eval_expr in *. eapply expr_sound in H; t; rewrite H. eapply IHargs in H0; t; rewrite H0. eauto. @@ -248,17 +234,9 @@ Section WeakestPrecondition. all : cbv [respectful pointwise_relation Basics.impl WeakestPrecondition.get]; intros; cbv beta; t. Qed. - Local Notation semantics_call := (fun e n t m args post => - exists params rets fbody, map.get e n = Some (params, rets, fbody) /\ - exists lf, map.putmany_of_list_zip params args map.empty = Some lf /\ - forall mc', Semantics.exec e fbody t m lf mc' (fun t' m' st1 mc'' => - exists retvs, map.getmany_of_list st1 rets = Some retvs /\ - post t' m' retvs)). - Local Hint Constructors Semantics.exec : core. - Lemma sound_cmd e c t m l mc post - (H:WeakestPrecondition.cmd e c t m l post) - : Semantics.exec e c t m l mc (fun t' m' l' mc' => post t' m' l'). + Lemma sound_cmd e c t m l post (H: WeakestPrecondition.cmd e c t m l post) + : Semantics.exec e c t m l post. Proof. ind_on Syntax.cmd; repeat (t; try match reverse goal with H : WeakestPrecondition.expr _ _ _ _ |- _ => eapply expr_sound in H end). { destruct (BinInt.Z.eq_dec (Interface.word.unsigned x) (BinNums.Z0)) as [Hb|Hb]; cycle 1. @@ -275,7 +253,7 @@ Section WeakestPrecondition. Proof. intros. eapply mk_wp_cmd. intros. eapply sound_cmd. assumption. Qed. Lemma sound_call' fs n t m args post (H : WeakestPrecondition.call fs n t m args post) - : semantics_call fs n t m args post. + : Semantics.call fs n t m args post. Proof. cbv beta. eapply invert_wp_call in H. destruct H as (? & ? & ? & ? & ? & ? & ?). @@ -296,33 +274,31 @@ Section WeakestPrecondition. assumption. Qed. - Lemma complete_args : forall m l args mc mc' vs, - Semantics.evaluate_call_args_log m l args mc = Some (vs, mc') -> + Lemma complete_args : forall m l args vs, + Semantics.eval_call_args m l args = Some vs -> WeakestPrecondition.dexprs m l args vs. Proof using word_ok. induction args; cbn; repeat (subst; t). 1: inversion H; reflexivity. destruct_one_match_hyp. 2: discriminate. - destruct p as (v, mc''). destruct_one_match_hyp. 2: discriminate. - destruct p as (tail, mc'''). - inversion H. subst mc''' vs. clear H. + inversion H. subst vs. clear H. eapply Proper_expr. 2: eapply expr_complete. 2: eassumption. intros x ?. subst x. - eapply Proper_list_map. 3: eapply IHargs; eassumption. + eapply Proper_list_map. 3: eapply IHargs; reflexivity. { eapply Proper_expr. } { intros ? ?. subst. reflexivity. } Qed. - Lemma complete_cmd: forall e c t m l mc post, - Semantics.exec e c t m l mc post -> - WeakestPrecondition.cmd e c t m l (fun t' m' l' => exists mc', post t' m' l' mc'). + Lemma complete_cmd: forall e c t m l post, + Semantics.exec e c t m l post -> + WeakestPrecondition.cmd e c t m l post. Proof. induction 1. - { eexists. eassumption. } + { eassumption. } { eapply expr_complete in H. eexists. split. 1: exact H. - eexists. eassumption. } - { eexists. eauto. } + eassumption. } + { eauto. } { eapply expr_complete in H. eapply expr_complete in H0. eexists. split. 1: eassumption. @@ -331,35 +307,26 @@ Section WeakestPrecondition. { split. 1: assumption. intros * HA HSp. specialize H1 with (1 := HA) (2 := HSp). unfold dlet.dlet. eapply weaken_cmd. 1: eapply H1. cbv beta. - clear. intros * (? & ? & ? & ? & ? & ?). eauto 8. } + clear. intros * (? & ? & ? & ? & ?). eauto 8. } { eexists. ssplit; intros; eauto using expr_complete; congruence. } { eexists. ssplit; intros; eauto using expr_complete; congruence. } { cbn. eapply weaken_cmd. { eapply IHexec. } - cbv beta. intros *. intros (mc' & Hmid). + cbv beta. intros. eapply H1. eassumption. } { cbn. eapply mk_wp_cmd. intros. - eapply eval_expr_change_start_metrics in H. - destruct H as (mc2' & H). eapply Semantics.exec.while_false; eauto. } { rename IHexec into IH1, H3 into IH2. cbn. eapply mk_wp_cmd. intros. - eapply eval_expr_change_start_metrics in H. - destruct H as (mc2' & H). - eapply Semantics.exec.while_true. - 1: eassumption. - 1: eassumption. - { eapply sound_cmd. eapply IH1. (* round-trip just to change metrics *) } - cbv beta. intros * (? & ?). - eapply sound_cmd. eapply IH2. (* round-trip just to change metrics *) eassumption. } + eapply Semantics.exec.while_true; eassumption. } { cbn. eexists. split. { eapply complete_args. eassumption. } eapply mk_wp_call. 1,2: eassumption. eapply mk_wp_cmd. intros. eapply Semantics.exec.weaken. - { eapply sound_cmd in IHexec. eapply IHexec. (* round-trip just to change metrics *) } - cbv beta. intros * ? (? & Hmid). - specialize H3 with (1 := Hmid). destruct H3 as (retvs & G & ? & ? & ?). eauto 8. } + { eassumption. } + cbv beta. intros. + specialize H3 with (1 := H4). destruct H3 as (retvs & G & ? & ? & ?). eauto 8. } { cbn. eexists. split. { eapply complete_args. eassumption. } eexists _, _. split. 1: eassumption. @@ -373,8 +340,7 @@ Section WeakestPrecondition. Proof. intros. eapply invert_wp_cmd in H. eapply complete_cmd in H. eapply weaken_cmd. 1: exact H. - cbv beta. intros * (_ & ?). assumption. - Unshelve. repeat constructor. + cbv beta. intros. assumption. Qed. Lemma start_func: forall e fname fimpl t m args post, diff --git a/bedrock2/src/bedrock2Examples/Trace.v b/bedrock2/src/bedrock2Examples/Trace.v index f7ebc23a5..03731bba6 100644 --- a/bedrock2/src/bedrock2Examples/Trace.v +++ b/bedrock2/src/bedrock2Examples/Trace.v @@ -6,7 +6,7 @@ Require Import coqutil.Map.Interface coqutil.Map.Properties. Require Import coqutil.Tactics.Tactics. Require Import Coq.Strings.String. Require Import bedrock2.TracePredicate. Import TracePredicateNotations. -Require Import bedrock2.Semantics. +Require Import bedrock2.Semantics bedrock2.MetricSemantics. Require Import bedrock2.Syntax. Require Import bedrock2.NotationsCustomEntry. diff --git a/bedrock2/src/bedrock2Examples/indirect_add_heapletwise.v b/bedrock2/src/bedrock2Examples/indirect_add_heapletwise.v index 788588e65..58f19e5e1 100644 --- a/bedrock2/src/bedrock2Examples/indirect_add_heapletwise.v +++ b/bedrock2/src/bedrock2Examples/indirect_add_heapletwise.v @@ -177,12 +177,12 @@ H15 : (scalar a0 (word.add va vb) ⋆ (scalar out vout ⋆ R))%sep a2 (calleePre: Prop) (calleePost callerPost: trace -> mem -> list word -> Prop), (* definition-site format: *) - (calleePre -> call funs f t m args calleePost) -> + (calleePre -> WeakestPrecondition.call funs f t m args calleePost) -> (* use-site format: *) (calleePre /\ enable_frame_trick (forall t' m' rets, calleePost t' m' rets -> callerPost t' m' rets)) -> (* conclusion: *) - call funs f t m args callerPost. + WeakestPrecondition.call funs f t m args callerPost. Proof. intros. destruct H0. eapply WeakestPreconditionProperties.Proper_call; eauto. Qed. diff --git a/compiler/src/compiler/ExprImp.v b/compiler/src/compiler/ExprImp.v index 899b8cb73..fc08821ab 100644 --- a/compiler/src/compiler/ExprImp.v +++ b/compiler/src/compiler/ExprImp.v @@ -11,7 +11,7 @@ Require Import coqutil.Decidable. Require Import coqutil.Datatypes.PropSet. Require Import riscv.Platform.MetricLogging. Require Import coqutil.Tactics.Simp. -Import Semantics. +Require Import bedrock2.Semantics bedrock2.MetricSemantics. (*Local Set Ltac Profiling.*) @@ -41,7 +41,7 @@ Section ExprImp1. Context (e: env). Definition eval_expr(m: mem)(st: locals)(e: expr): result word := - match eval_expr_old m st e with + match Semantics.eval_expr m st e with | Some v => Success v | None => error:("evaluation of expression" e "failed") end. @@ -155,8 +155,8 @@ Section ExprImp1. Lemma invert_eval_store: forall fuel initialSt initialM a v final aSize, eval_cmd (S fuel) initialSt initialM (cmd.store aSize a v) = Success final -> - exists av vv finalM, eval_expr_old initialM initialSt a = Some av /\ - eval_expr_old initialM initialSt v = Some vv /\ + exists av vv finalM, Semantics.eval_expr initialM initialSt a = Some av /\ + Semantics.eval_expr initialM initialSt v = Some vv /\ store aSize initialM av vv = Some finalM /\ final = (initialSt, finalM). Proof. inversion_lemma. Qed. @@ -168,7 +168,7 @@ Section ExprImp1. Lemma invert_eval_set: forall f st1 m1 p2 x e, eval_cmd (S f) st1 m1 (cmd.set x e) = Success p2 -> - exists v, eval_expr_old m1 st1 e = Some v /\ p2 = (map.put st1 x v, m1). + exists v, Semantics.eval_expr m1 st1 e = Some v /\ p2 = (map.put st1 x v, m1). Proof. inversion_lemma. Qed. Lemma invert_eval_unset: forall f st1 m1 p2 x, @@ -179,7 +179,7 @@ Section ExprImp1. Lemma invert_eval_cond: forall f st1 m1 p2 cond bThen bElse, eval_cmd (S f) st1 m1 (cmd.cond cond bThen bElse) = Success p2 -> exists cv, - eval_expr_old m1 st1 cond = Some cv /\ + Semantics.eval_expr m1 st1 cond = Some cv /\ (cv <> word.of_Z 0 /\ eval_cmd f st1 m1 bThen = Success p2 \/ cv = word.of_Z 0 /\ eval_cmd f st1 m1 bElse = Success p2). Proof. inversion_lemma. Qed. @@ -187,7 +187,7 @@ Section ExprImp1. Lemma invert_eval_while: forall st1 m1 p3 f cond body, eval_cmd (S f) st1 m1 (cmd.while cond body) = Success p3 -> exists cv, - eval_expr_old m1 st1 cond = Some cv /\ + Semantics.eval_expr m1 st1 cond = Some cv /\ (cv <> word.of_Z 0 /\ (exists st2 m2, eval_cmd f st1 m1 body = Success (st2, m2) /\ eval_cmd f st2 m2 (cmd.while cond body) = Success p3) \/ cv = word.of_Z 0 /\ p3 = (st1, m1)). diff --git a/compiler/src/compiler/ExprImpEventLoopSpec.v b/compiler/src/compiler/ExprImpEventLoopSpec.v index 3b9ca998b..6d6d480f4 100644 --- a/compiler/src/compiler/ExprImpEventLoopSpec.v +++ b/compiler/src/compiler/ExprImpEventLoopSpec.v @@ -40,12 +40,12 @@ Section Params1. get_init_code: map.get (map.of_list e) init_f = Some (nil, nil, init_code); init_code_correct: forall m0 mc0, mem_available spec.(datamem_start) spec.(datamem_pastend) m0 -> - Semantics.exec (map.of_list e) init_code nil m0 map.empty mc0 (hl_inv spec); + MetricSemantics.exec (map.of_list e) init_code nil m0 map.empty mc0 (hl_inv spec); loop_body: Syntax.cmd.cmd; get_loop_body: map.get (map.of_list e) loop_f = Some (nil, nil, loop_body); loop_body_correct: forall t m l mc, hl_inv spec t m l mc -> - Semantics.exec (map.of_list e) loop_body t m l mc (hl_inv spec); + MetricSemantics.exec (map.of_list e) loop_body t m l mc (hl_inv spec); }. End Params1. diff --git a/compiler/src/compiler/FlattenExpr.v b/compiler/src/compiler/FlattenExpr.v index a5dd42349..39ac81e16 100644 --- a/compiler/src/compiler/FlattenExpr.v +++ b/compiler/src/compiler/FlattenExpr.v @@ -7,7 +7,7 @@ Require Import coqutil.Decidable. Require Import coqutil.Word.Bitwidth. Require Import bedrock2.Syntax. Require Import bedrock2.MetricLogging. -Require Import bedrock2.Semantics. +Require Import bedrock2.Semantics bedrock2.MetricSemantics. Require Import coqutil.Macros.unique. Require Import Coq.Bool.Bool. Require Import coqutil.Datatypes.PropSet. @@ -521,7 +521,7 @@ Section FlattenExpr1. map.extends lL lH -> map.undef_on lH (allFreshVars ngs1) -> disjoint (ExprImp.allVars_exprs es) (allFreshVars ngs1) -> - evaluate_call_args_log m lH es initialMcH = Some (resVals, finalMcH) -> + eval_call_args m lH es initialMcH = Some (resVals, finalMcH) -> (* List.option_all (List.map (eval_expr m lH) es) = Some resVals -> *) FlatImp.exec fenv s t m lL initialMcL (fun t' m' lL' finalMcL => t' = t /\ m' = m /\ @@ -683,7 +683,7 @@ Section FlattenExpr1. Lemma flattenStmt_correct_aux: forall eH eL, flatten_functions eH = Success eL -> forall eH0 sH t m mcH lH post, - Semantics.exec eH0 sH t m lH mcH post -> + MetricSemantics.exec eH0 sH t m lH mcH post -> eH0 = eH -> forall ngs ngs' sL lL mcL, flattenStmt ngs sH = (sL, ngs') -> @@ -929,7 +929,7 @@ Section FlattenExpr1. Lemma flattenStmt_correct: forall eH eL sH sL lL t m mc post, flatten_functions eH = Success eL -> ExprImp2FlatImp sH = sL -> - Semantics.exec eH sH t m map.empty mc post -> + MetricSemantics.exec eH sH t m map.empty mc post -> FlatImp.exec eL sL t m lL mc (fun t' m' lL' mcL' => exists lH' mcH', post t' m' lH' mcH' /\ map.extends lL' lH' /\ diff --git a/compiler/src/compiler/Pipeline.v b/compiler/src/compiler/Pipeline.v index 6996e63bd..52a8883bd 100644 --- a/compiler/src/compiler/Pipeline.v +++ b/compiler/src/compiler/Pipeline.v @@ -160,7 +160,7 @@ Section WithWordAndMem. Definition SrcLang: Lang := {| Program := Semantics.env; Valid := map.forall_values ExprImp.valid_fun; - Call := locals_based_call_spec Semantics.exec; + Call := locals_based_call_spec MetricSemantics.exec; |}. (* | *) (* | FlattenExpr *) @@ -506,7 +506,7 @@ Section WithWordAndMem. Some (argnames, retnames, fbody) /\ map.of_list_zip argnames argvals = Some l /\ forall mc, - Semantics.exec (map.of_list functions) fbody t mH l mc + MetricSemantics.exec (map.of_list functions) fbody t mH l mc (fun t' m' l' mc' => exists retvals: list word, map.getmany_of_list l' retnames = Some retvals /\ post t' m' retvals)) -> @@ -596,12 +596,13 @@ Section WithWordAndMem. intros. let H := hyp WeakestPrecondition.call in rename H into WP. eapply WeakestPreconditionProperties.sound_call' in WP. - fwd. - edestruct compiler_correct with (argvals := argvals) (post := post) as (f_rel_pos' & G & C); + edestruct compiler_correct with (fname := fname) (argvals := argvals) (post := post) as (f_rel_pos' & G & C); try eassumption. - - intros. - unfold map.of_list_zip in *. eauto 10. - - eapply C; clear C; try assumption; try congruence. + 2: { eapply C; clear C; try assumption; try congruence; try eassumption. } + intros. + unfold Semantics.call in WP. fwd. + do 5 eexists. 1: eassumption. split. 1: eassumption. + intros. eapply MetricSemantics.of_metrics_free. assumption. Qed. End WithMoreParams. diff --git a/compiler/src/compilerExamples/SoftmulCompile.v b/compiler/src/compilerExamples/SoftmulCompile.v index 9b4fb45c6..81cab55d2 100644 --- a/compiler/src/compilerExamples/SoftmulCompile.v +++ b/compiler/src/compilerExamples/SoftmulCompile.v @@ -727,7 +727,7 @@ Section Riscv. initial.(pc); getLog := [] |}; - getMetrics := MetricLogging.EmptyMetricLog + getMetrics := riscv.Platform.MetricLogging.EmptyMetricLog |}). 2: reflexivity. 2: { diff --git a/end2end/src/end2end/End2EndPipeline.v b/end2end/src/end2end/End2EndPipeline.v index a6652ba4e..abee97136 100644 --- a/end2end/src/end2end/End2EndPipeline.v +++ b/end2end/src/end2end/End2EndPipeline.v @@ -369,12 +369,14 @@ Section Connect. rewrite heap_start_agree in H; rewrite heap_pastend_agree in H end. - refine (WeakestPreconditionProperties.sound_cmd _ _ _ _ _ _ _ _); eauto. + eapply MetricSemantics.of_metrics_free. + eapply WeakestPreconditionProperties.sound_cmd; eauto. -- simpl. clear. intros. unfold bedrock2Inv in *. eauto. * exact GetLoop. * intros. unfold bedrock2Inv in *. eapply ExprImp.weaken_exec. - -- refine (WeakestPreconditionProperties.sound_cmd _ _ _ _ _ _ _ _); eauto. + -- eapply MetricSemantics.of_metrics_free. + eapply WeakestPreconditionProperties.sound_cmd; eauto. -- simpl. clear. intros. eauto. + assumption. + assumption. From c0efbad89b8fe3a9fe3d896e901505a2d804280c Mon Sep 17 00:00:00 2001 From: Samuel Gruetter Date: Fri, 4 Aug 2023 13:37:18 -0400 Subject: [PATCH 11/15] refinement lemmas for induction over command syntax --- bedrock2/src/bedrock2/Refinement.v | 46 ++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 bedrock2/src/bedrock2/Refinement.v diff --git a/bedrock2/src/bedrock2/Refinement.v b/bedrock2/src/bedrock2/Refinement.v new file mode 100644 index 000000000..43862902a --- /dev/null +++ b/bedrock2/src/bedrock2/Refinement.v @@ -0,0 +1,46 @@ +(* These lemmas can be useful when proving a refinement and induction over the + statement rather than over its exec derivation is preferred *) + +Require Import Coq.ZArith.ZArith. +Require Import coqutil.Word.Bitwidth. +Require Import coqutil.Map.Interface. +Require Import bedrock2.Syntax bedrock2.Semantics. + +Section WithParams. + Context {width: Z} {BW: Bitwidth width} {word: word.word width}. + Context {mem: map.map word Byte.byte}. + Context {locals: map.map String.string word}. + Context {ext_spec: bedrock2.Semantics.ExtSpec}. + + Definition refinement(c1 c2: cmd) := forall functions t m l post, + Semantics.exec.exec functions c1 t m l post -> + Semantics.exec.exec functions c2 t m l post. + + Lemma refinement_while: forall test body1 body2, + refinement body1 body2 -> + refinement (cmd.while test body1) (cmd.while test body2). + Proof. + unfold refinement. intros * R *. + remember (cmd.while test body1) as c1. intros. revert Heqc1. + induction H; intros; subst; inversion Heqc1; subst. + - eapply Semantics.exec.while_false; eassumption. + - eapply Semantics.exec.while_true; try eassumption. + { unfold refinement in R. + eapply R. eassumption. } + intros. + eapply H3; eauto. + Qed. + + Lemma refinement_seq: forall c1 c2 c1' c2', + refinement c1 c1' -> + refinement c2 c2' -> + refinement (cmd.seq c1 c2) (cmd.seq c1' c2'). + Proof. + intros * R1 R2 functions t m l post H. + unfold refinement in *. + inversion H. subst. clear H. + eapply Semantics.exec.seq. + - eapply R1. eassumption. + - intros * Hmid. eapply R2. eauto. + Qed. +End WithParams. From 6faf7a0e064aab66feb1e32e44e5d2a901adc01e Mon Sep 17 00:00:00 2001 From: Samuel Gruetter Date: Sun, 6 Aug 2023 13:36:08 -0400 Subject: [PATCH 12/15] delete WP.v (opaque Module), only LAN9250 needed fixing --- LiveVerif/src/LiveVerif/LiveRules.v | 5 +- bedrock2/src/bedrock2/Loops.v | 7 +- bedrock2/src/bedrock2/MetricSemantics.v | 25 ++++ bedrock2/src/bedrock2/ProgramLogic.v | 1 - bedrock2/src/bedrock2/Semantics.v | 26 +++- bedrock2/src/bedrock2/WP.v | 126 ------------------ bedrock2/src/bedrock2/WeakestPrecondition.v | 7 +- .../bedrock2/WeakestPreconditionProperties.v | 46 ++----- bedrock2/src/bedrock2Examples/LAN9250.v | 9 ++ compiler/src/compiler/Pipeline.v | 1 - end2end/src/end2end/End2EndLightbulb.v | 4 +- 11 files changed, 79 insertions(+), 178 deletions(-) delete mode 100644 bedrock2/src/bedrock2/WP.v diff --git a/LiveVerif/src/LiveVerif/LiveRules.v b/LiveVerif/src/LiveVerif/LiveRules.v index 69d83d6c3..2fa46d7ed 100644 --- a/LiveVerif/src/LiveVerif/LiveRules.v +++ b/LiveVerif/src/LiveVerif/LiveRules.v @@ -1009,8 +1009,9 @@ Section WithParams. WeakestPrecondition.call fs f t m argvals post. Proof. intros. - eapply WP.WP_Impl.mk_wp_call. 1,2: eassumption. eapply WP.WP_Impl.mk_wp_cmd. - intros. eapply invert_wp_cmd in H1. eapply WeakestPreconditionProperties.sound_cmd. + do 4 eexists. 1: eassumption. do 2 eexists. 1: eassumption. + eapply invert_wp_cmd in H1. + eapply WeakestPreconditionProperties.sound_cmd. assumption. Qed. diff --git a/bedrock2/src/bedrock2/Loops.v b/bedrock2/src/bedrock2/Loops.v index 25f60cec9..e2bc84e9c 100644 --- a/bedrock2/src/bedrock2/Loops.v +++ b/bedrock2/src/bedrock2/Loops.v @@ -6,7 +6,7 @@ Require Import coqutil.Map.Properties. Require Import coqutil.Tactics.destr. From bedrock2 Require Import Map.Separation Map.SeparationLogic. From bedrock2 Require Import Syntax Semantics Markers. -From bedrock2 Require Import WeakestPrecondition WeakestPreconditionProperties WP. +From bedrock2 Require Import WeakestPrecondition WeakestPreconditionProperties. Section Loops. Context {width: Z} {BW: Bitwidth width} {word: word.word width} {mem: map.map word Byte.byte}. @@ -28,11 +28,10 @@ Section Loops. (word.unsigned b <> 0%Z -> cmd call c t m l (fun t' m l => exists v', inv v' t' m l /\ lt v' v)) /\ (word.unsigned b = 0%Z -> post t m l))) -> - wp_cmd call (cmd.while e c) t m l post. + cmd call (cmd.while e c) t m l post. Proof. intros. destruct H as (measure & lt & inv & Hwf & HInit & Hbody). destruct HInit as (v0 & HInit). - apply mk_wp_cmd. intros. revert t m l HInit. pattern v0. revert v0. eapply (well_founded_ind Hwf). intros. specialize Hbody with (1 := HInit). destruct Hbody as (b & Hb & Ht & Hf). @@ -41,7 +40,7 @@ Section Loops. - specialize Hf with (1 := E). eapply exec.while_false; eassumption. - specialize Ht with (1 := E). eapply sound_cmd in Ht. eapply exec.while_true; eauto. - cbv beta. intros * (v' & HInv & HLt). eauto. + cbv beta. intros * (v' & HInv & HLt). eapply sound_cmd. eauto. Qed. Lemma tailrec_localsmap_1ghost diff --git a/bedrock2/src/bedrock2/MetricSemantics.v b/bedrock2/src/bedrock2/MetricSemantics.v index 7a0eb7527..51565d555 100644 --- a/bedrock2/src/bedrock2/MetricSemantics.v +++ b/bedrock2/src/bedrock2/MetricSemantics.v @@ -305,6 +305,31 @@ Section WithParams. exec e body t m l mc (fun t' m' l' mc' => exists rets, map.getmany_of_list l' retnames = Some rets /\ post t' m' rets mc'). + Lemma weaken_call: forall e fname t m args mc post1, + call e fname t m args mc post1 -> + forall (post2: trace -> mem -> list word -> MetricLog -> Prop), + (forall t' m' rets mc', post1 t' m' rets mc' -> post2 t' m' rets mc') -> + call e fname t m args mc post2. + Proof. + unfold call. intros. fwd. + do 4 eexists. 1: eassumption. + do 2 eexists. 1: eassumption. + eapply exec.weaken. 1: eassumption. + cbv beta. clear -H0. intros. fwd. eauto. + Qed. + + Lemma extend_env_call: forall e1 e2, + map.extends e2 e1 -> + forall f t m rets mc post, + call e1 f t m rets mc post -> + call e2 f t m rets mc post. + Proof. + unfold call. intros. fwd. repeat eexists. + - eapply H. eassumption. + - eassumption. + - eapply exec.extend_env; eassumption. + Qed. + Lemma of_metrics_free_eval_expr: forall m l e v, Semantics.eval_expr m l e = Some v -> forall mc, exists mc', MetricSemantics.eval_expr m l e mc = Some (v, mc'). diff --git a/bedrock2/src/bedrock2/ProgramLogic.v b/bedrock2/src/bedrock2/ProgramLogic.v index 96adbc64a..009f465a4 100644 --- a/bedrock2/src/bedrock2/ProgramLogic.v +++ b/bedrock2/src/bedrock2/ProgramLogic.v @@ -1,7 +1,6 @@ From coqutil.Tactics Require Import Tactics letexists eabstract rdelta reference_to_string ident_of_string. Require Import coqutil.Map.Interface. Require Import bedrock2.Syntax. -Require Import bedrock2.WP. Require Import bedrock2.WeakestPrecondition. Require Import bedrock2.WeakestPreconditionProperties. Require Import bedrock2.Loops. diff --git a/bedrock2/src/bedrock2/Semantics.v b/bedrock2/src/bedrock2/Semantics.v index 2c1e357c3..0fb71d63c 100644 --- a/bedrock2/src/bedrock2/Semantics.v +++ b/bedrock2/src/bedrock2/Semantics.v @@ -318,7 +318,7 @@ Section WithParams. Context {locals: map.map String.string word}. Context {ext_spec: ExtSpec}. - Implicit Types (l: locals) (m: mem). + Implicit Types (l: locals) (m: mem) (post: trace -> mem -> list word -> Prop). Definition call e fname t m args post := exists argnames retnames body, @@ -326,4 +326,28 @@ Section WithParams. exists l, map.of_list_zip argnames args = Some l /\ exec e body t m l (fun t' m' l' => exists rets, map.getmany_of_list l' retnames = Some rets /\ post t' m' rets). + + Lemma weaken_call: forall e fname t m args post1, + call e fname t m args post1 -> + forall post2, (forall t' m' rets, post1 t' m' rets -> post2 t' m' rets) -> + call e fname t m args post2. + Proof. + unfold call. intros. fwd. + do 4 eexists. 1: eassumption. + do 2 eexists. 1: eassumption. + eapply exec.weaken. 1: eassumption. + cbv beta. clear -H0. intros. fwd. eauto. + Qed. + + Lemma extend_env_call: forall e1 e2, + map.extends e2 e1 -> + forall f t m rets post, + call e1 f t m rets post -> + call e2 f t m rets post. + Proof. + unfold call. intros. fwd. repeat eexists. + - eapply H. eassumption. + - eassumption. + - eapply exec.extend_env; eassumption. + Qed. End WithParams. diff --git a/bedrock2/src/bedrock2/WP.v b/bedrock2/src/bedrock2/WP.v deleted file mode 100644 index f8f2779a6..000000000 --- a/bedrock2/src/bedrock2/WP.v +++ /dev/null @@ -1,126 +0,0 @@ -Require Import Coq.ZArith.ZArith. -Require Import coqutil.Map.Interface. -Require Import coqutil.Word.Interface coqutil.Word.Bitwidth. -Require Import coqutil.Tactics.fwd. -Require Import bedrock2.Syntax bedrock2.Semantics. - -(* We want to make the definitions opaque to `hnf` (unfolds any definition, so a plain - definition doesn't work) and to `repeat split` (applies constructors of all - 1-constructor inductives, so a 1-constructor inductive wrapping exec doesn't - work). *) -Module Type WP_Sig. - Section WithParams. - Context {width: Z} {BW: Bitwidth width} {word: word.word width} - {mem: map.map word Byte.byte} - {locals: map.map String.string word}. - - Parameter wp_cmd : forall {ext_spec: ExtSpec} (e: env), - Syntax.cmd -> trace -> mem -> locals -> - (trace -> mem -> locals -> Prop) -> Prop. - Parameter mk_wp_cmd : forall {ext_spec: ExtSpec} (e: env) c t m l post, - exec e c t m l post -> - wp_cmd e c t m l post. - Parameter invert_wp_cmd: forall {ext_spec: ExtSpec} [e c t m l post], - wp_cmd e c t m l post -> - exec e c t m l post. - - Parameter wp_call : forall {locals: map.map String.string word} {ext_spec: ExtSpec}, - env -> String.string -> trace -> mem -> list word -> - (trace -> mem -> list word -> Prop) -> Prop. - Parameter mk_wp_call : - forall {ext_spec: ExtSpec} (e: env) fname argnames retnames body t m l args post, - map.get e fname = Some (argnames, retnames, body) -> - map.of_list_zip argnames args = Some l -> - wp_cmd e body t m l (fun t' m' l' => exists rets, - map.getmany_of_list l' retnames = Some rets /\ post t' m' rets) -> - wp_call e fname t m args post. - Parameter invert_wp_call : forall {ext_spec: ExtSpec} (e: env) fname t m args post, - wp_call e fname t m args post -> - exists argnames retnames body l, - map.get e fname = Some (argnames, retnames, body) /\ - map.of_list_zip argnames args = Some l /\ - wp_cmd e body t m l (fun t' m' l' => exists rets, - map.getmany_of_list l' retnames = Some rets /\ post t' m' rets). - End WithParams. -End WP_Sig. - -Module Export WP_Impl : WP_Sig. - Section WithParams. - Context {width: Z} {BW: Bitwidth width} {word: word.word width} - {mem: map.map word Byte.byte} - {locals: map.map String.string word} - {ext_spec: ExtSpec}. - - Definition wp_cmd := exec. - - Lemma mk_wp_cmd e c t m l post: exec e c t m l post -> wp_cmd e c t m l post. - Proof. exact id. Qed. - - Lemma invert_wp_cmd e c t m l post: wp_cmd e c t m l post -> exec e c t m l post. - Proof. exact id. Qed. - - Definition wp_call := call. - - Lemma mk_wp_call: forall e fname argnames retnames body t m l args post, - map.get e fname = Some (argnames, retnames, body) -> - map.of_list_zip argnames args = Some l -> - wp_cmd e body t m l (fun t' m' l' => exists rets, - map.getmany_of_list l' retnames = Some rets /\ post t' m' rets) -> - wp_call e fname t m args post. - Proof. unfold wp_call, call, wp_cmd. intros. eauto 10. Qed. - - Lemma invert_wp_call e fname t m args post: - wp_call e fname t m args post -> - exists argnames retnames body l, - map.get e fname = Some (argnames, retnames, body) /\ - map.of_list_zip argnames args = Some l /\ - wp_cmd e body t m l (fun t' m' l' => exists rets, - map.getmany_of_list l' retnames = Some rets /\ post t' m' rets). - Proof. unfold wp_call, call, wp_cmd. intros. fwd. eauto 10. Qed. - End WithParams. -End WP_Impl. - -Section WithParams. - Context {width: Z} {BW: Bitwidth width} {word: word.word width} - {mem: map.map word Byte.byte} - {locals: map.map String.string word} - {ext_spec: ExtSpec}. - - Lemma weaken_wp_cmd: forall e c t m l (post1 post2: trace -> mem -> locals -> Prop), - (forall t' m' l', post1 t' m' l' -> post2 t' m' l') -> - wp_cmd e t m l c post1 -> wp_cmd e t m l c post2. - Proof. - intros. eapply mk_wp_cmd. intros. eapply invert_wp_cmd in H0. - eapply exec.weaken. 1: eassumption. eauto. - Qed. - - Lemma weaken_wp_call: forall e f t m args (post1 post2: trace -> mem -> list word -> Prop), - (forall t' m' rets, post1 t' m' rets -> post2 t' m' rets) -> - wp_call e f t m args post1 -> wp_call e f t m args post2. - Proof. - intros. eapply invert_wp_call in H0. firstorder idtac. - eapply mk_wp_call; eauto. - eapply weaken_wp_cmd. 2: eassumption. firstorder eauto. - Qed. - - Lemma extend_env_wp_cmd: forall e1 e2, - map.extends e2 e1 -> - forall c t m l post, - wp_cmd e1 t m l c post -> - wp_cmd e2 t m l c post. - Proof. - intros. eapply mk_wp_cmd. intros. eapply invert_wp_cmd in H0. - eapply exec.extend_env; eassumption. - Qed. - - Lemma extend_env_wp_call: forall e1 e2, - map.extends e2 e1 -> - forall f t m args post, - wp_call e1 f t m args post -> - wp_call e2 f t m args post. - Proof. - intros. eapply invert_wp_call in H0. destruct H0 as (? & ? & ? & ? & ? & ? & ?). - eapply mk_wp_call; eauto. - eapply extend_env_wp_cmd; eauto. - Qed. -End WithParams. diff --git a/bedrock2/src/bedrock2/WeakestPrecondition.v b/bedrock2/src/bedrock2/WeakestPrecondition.v index 0e2f48972..af40307cd 100644 --- a/bedrock2/src/bedrock2/WeakestPrecondition.v +++ b/bedrock2/src/bedrock2/WeakestPrecondition.v @@ -1,7 +1,6 @@ Require Import coqutil.Macros.subst coqutil.Macros.unique coqutil.Map.Interface coqutil.Map.OfListWord. Require Import Coq.ZArith.BinIntDef coqutil.Word.Interface coqutil.Word.Bitwidth. Require Import coqutil.dlet bedrock2.Syntax bedrock2.Semantics. -Require Import bedrock2.WP. Section WeakestPrecondition. Context {width: Z} {BW: Bitwidth width} {word: word.word width} {mem: map.map word Byte.byte}. @@ -94,10 +93,10 @@ Section WeakestPrecondition. (word.unsigned v = 0%Z -> rec cf t m l post) | cmd.seq c1 c2 => rec c1 t m l (fun t m l => rec c2 t m l post) - | cmd.while _ _ => wp_cmd e c t m l post + | cmd.while _ _ => Semantics.exec e c t m l post | cmd.call binds fname arges => exists args, dexprs m l arges args /\ - wp_call e fname t m args (fun t m rets => + Semantics.call e fname t m args (fun t m rets => exists l', map.putmany_of_list_zip binds rets l = Some l' /\ post t m l') | cmd.interact binds action arges => @@ -119,7 +118,7 @@ Section WeakestPrecondition. Definition program := cmd. End WeakestPrecondition. -Notation call := wp_call. +Notation call := Semantics.call (only parsing). Ltac unfold1_cmd e := lazymatch e with diff --git a/bedrock2/src/bedrock2/WeakestPreconditionProperties.v b/bedrock2/src/bedrock2/WeakestPreconditionProperties.v index fc25c07fe..d8a36d614 100644 --- a/bedrock2/src/bedrock2/WeakestPreconditionProperties.v +++ b/bedrock2/src/bedrock2/WeakestPreconditionProperties.v @@ -1,7 +1,6 @@ Require Import coqutil.Macros.subst coqutil.Macros.unique coqutil.Map.Interface coqutil.Word.Properties. Require Import coqutil.Word.Bitwidth. Require bedrock2.WeakestPrecondition. -Require Import bedrock2.WP. Require Import Coq.Classes.Morphisms. @@ -103,11 +102,11 @@ Section WeakestPrecondition. { cbv [pointwise_relation Basics.impl]; intuition eauto 2. } { eauto. } } { intuition eauto 6. } } - { eapply weaken_wp_cmd; eassumption. } + { eapply Semantics.exec.weaken; eassumption. } { destruct H1 as (?&?&?). eexists. split. { eapply Proper_list_map; eauto; try exact H4; cbv [respectful pointwise_relation Basics.impl]; intuition eauto 2. eapply Proper_expr; eauto. } - { eapply weaken_wp_call. 2: eassumption. cbv beta. + { eapply Semantics.weaken_call. 1: eassumption. cbv beta. (* COQBUG (performance), measured in Coq 8.9: "firstorder eauto" works, but takes ~100s and increases memory usage by 1.8GB. On the other hand, the line below takes just 5ms *) @@ -134,7 +133,7 @@ Section WeakestPrecondition. Basics.impl)))))))) WeakestPrecondition.call. Proof using word_ok mem_ok locals_ok ext_spec_ok. cbv [Proper respectful pointwise_relation Basics.impl]. - intros. eapply weaken_wp_call; eassumption. + intros. eapply Semantics.weaken_call; eassumption. Qed. Global Instance Proper_program : @@ -242,26 +241,10 @@ Section WeakestPrecondition. { destruct (BinInt.Z.eq_dec (Interface.word.unsigned x) (BinNums.Z0)) as [Hb|Hb]; cycle 1. { econstructor; t. } { eapply Semantics.exec.if_false; t. } } - { eapply invert_wp_cmd. assumption. } - { eapply invert_wp_call in H0. t. eapply sound_args in H; t. - eapply invert_wp_cmd in H2. t. } + { inversion H0. t. eapply sound_args in H; t. } { eapply sound_args in H; t. } Qed. - Lemma cmd_sound: forall e c t m l post, - WeakestPrecondition.cmd e c t m l post -> wp_cmd e c t m l post. - Proof. intros. eapply mk_wp_cmd. intros. eapply sound_cmd. assumption. Qed. - - Lemma sound_call' fs n t m args post (H : WeakestPrecondition.call fs n t m args post) - : Semantics.call fs n t m args post. - Proof. - cbv beta. eapply invert_wp_call in H. - destruct H as (? & ? & ? & ? & ? & ? & ?). - do 4 eexists. 1: eassumption. - do 2 eexists. 1: eassumption. - eapply invert_wp_cmd. eassumption. - Qed. - Lemma weaken_cmd: forall e c t m l (post1 post2: _->_->_->Prop), WeakestPrecondition.cmd e c t m l post1 -> (forall t m l, post1 t m l -> post2 t m l) -> @@ -314,15 +297,12 @@ Section WeakestPrecondition. { eapply IHexec. } cbv beta. intros. eapply H1. eassumption. } - { cbn. eapply mk_wp_cmd. intros. - eapply Semantics.exec.while_false; eauto. } + { cbn. eapply Semantics.exec.while_false; eauto. } { rename IHexec into IH1, H3 into IH2. - cbn. eapply mk_wp_cmd. intros. - eapply Semantics.exec.while_true; eassumption. } + cbn. eapply Semantics.exec.while_true; eassumption. } { cbn. eexists. split. { eapply complete_args. eassumption. } - eapply mk_wp_call. 1,2: eassumption. - eapply mk_wp_cmd. intros. + unfold Semantics.call. do 4 eexists. 1: eassumption. do 2 eexists. 1: eassumption. eapply Semantics.exec.weaken. { eassumption. } cbv beta. intros. @@ -335,21 +315,13 @@ Section WeakestPrecondition. eauto 8. } Qed. - Lemma cmd_complete: forall e c t m l post, - wp_cmd e c t m l post -> WeakestPrecondition.cmd e c t m l post. - Proof. - intros. eapply invert_wp_cmd in H. eapply complete_cmd in H. - eapply weaken_cmd. 1: exact H. - cbv beta. intros. assumption. - Qed. - Lemma start_func: forall e fname fimpl t m args post, map.get e fname = Some fimpl -> WeakestPrecondition.func e fimpl t m args post -> - wp_call e fname t m args post. + WeakestPrecondition.call e fname t m args post. Proof. intros * G. destruct fimpl as [[argnames retnames] body]. intros (? & ? & ?). - eapply mk_wp_call. 1,2: eassumption. eapply cmd_sound. + do 4 eexists. 1: eassumption. do 2 eexists. 1: eassumption. eapply sound_cmd. eapply weaken_cmd. 1: eassumption. cbv beta. intros. eapply sound_getmany. assumption. Qed. diff --git a/bedrock2/src/bedrock2Examples/LAN9250.v b/bedrock2/src/bedrock2Examples/LAN9250.v index aa52b4f31..75a7852f3 100644 --- a/bedrock2/src/bedrock2Examples/LAN9250.v +++ b/bedrock2/src/bedrock2Examples/LAN9250.v @@ -781,6 +781,15 @@ Section WithParameters. Import symmetry autoforward. + Local Ltac no_call := + lazymatch goal with + | |- Semantics.call _ _ _ _ _ _ => fail + | |- _ => idtac + end. + + Local Ltac original_esplit := esplit. + Local Ltac esplit := no_call; original_esplit. + Lemma lan9250_tx_ok : program_logic_goal_for_function! lan9250_tx. Proof. diff --git a/compiler/src/compiler/Pipeline.v b/compiler/src/compiler/Pipeline.v index 52a8883bd..338c5d72d 100644 --- a/compiler/src/compiler/Pipeline.v +++ b/compiler/src/compiler/Pipeline.v @@ -595,7 +595,6 @@ Section WithWordAndMem. Proof. intros. let H := hyp WeakestPrecondition.call in rename H into WP. - eapply WeakestPreconditionProperties.sound_call' in WP. edestruct compiler_correct with (fname := fname) (argvals := argvals) (post := post) as (f_rel_pos' & G & C); try eassumption. 2: { eapply C; clear C; try assumption; try congruence; try eassumption. } diff --git a/end2end/src/end2end/End2EndLightbulb.v b/end2end/src/end2end/End2EndLightbulb.v index 7b93641a6..dd1299817 100644 --- a/end2end/src/end2end/End2EndLightbulb.v +++ b/end2end/src/end2end/End2EndLightbulb.v @@ -225,7 +225,7 @@ Proof. repeat ProgramLogic.straightline. refine (WeakestPreconditionProperties.Proper_call _ _ _ _ _ _ _ _ _). 2: { - unfold prog. eapply WP.extend_env_wp_call. 2: exact (link_lightbulb_init m nil). + unfold prog. eapply Semantics.extend_env_call. 2: exact (link_lightbulb_init m nil). rewrite map.of_list_tuples. intros k f G. unfold map.putmany_of_list, init, loop. rewrite ?map.get_put_dec. @@ -271,7 +271,7 @@ Proof. specialize_first P Hp0p1. refine (WeakestPreconditionProperties.Proper_call _ _ _ _ _ _ _ _ _). 2: { - unfold prog. eapply WP.extend_env_wp_call. 2: exact P. + unfold prog. eapply Semantics.extend_env_call. 2: exact P. rewrite map.of_list_tuples. intros k f G. unfold map.putmany_of_list, init, loop. rewrite ?map.get_put_dec. From fb4def221d851fcfd7ededdafb68e1e55d108ee8 Mon Sep 17 00:00:00 2001 From: Samuel Gruetter Date: Sun, 6 Aug 2023 17:39:45 -0400 Subject: [PATCH 13/15] LiveVerif: wp_cmd is exec instead of WeakestPrecondition.cmd --- LiveVerif/src/LiveVerif/LiveRules.v | 160 +++++++++++++--------------- 1 file changed, 73 insertions(+), 87 deletions(-) diff --git a/LiveVerif/src/LiveVerif/LiveRules.v b/LiveVerif/src/LiveVerif/LiveRules.v index 2fa46d7ed..f402f90cd 100644 --- a/LiveVerif/src/LiveVerif/LiveRules.v +++ b/LiveVerif/src/LiveVerif/LiveRules.v @@ -15,6 +15,8 @@ Require Import bedrock2.ZnWords. Require Import bedrock2.SepLib. Require Import bedrock2.enable_frame_trick. +Notation wp_cmd := Semantics.exec (only parsing). + (* A let-binding using an equality instead of :=, living in Prop. Equivalent to (exists x, x = rhs /\ body x). We don't use regular exists to make the intention recognizable by tactics. @@ -356,26 +358,6 @@ Section WithParams. - assumption. Qed. - Lemma WP_weaken_cmd: forall fs c t m l (post1 post2: _->_->_->Prop), - WeakestPrecondition.cmd fs c t m l post1 -> - (forall t m l, post1 t m l -> post2 t m l) -> - WeakestPrecondition.cmd fs c t m l post2. - Proof. eapply WeakestPreconditionProperties.weaken_cmd. Qed. - - Inductive wp_cmd(fs: Semantics.env) - (c: cmd)(t: trace)(m: mem)(l: locals)(post: trace -> mem -> locals -> Prop): - Prop := mk_wp_cmd(_: WeakestPrecondition.cmd fs c t m l post). - - Lemma invert_wp_cmd: forall fs c t m l post, - wp_cmd fs c t m l post -> WeakestPrecondition.cmd fs c t m l post. - Proof. intros. inversion H; assumption. Qed. - - Lemma weaken_wp_cmd: forall fs c t m l (post1 post2: _->_->_->Prop), - wp_cmd fs c t m l post1 -> - (forall t m l, post1 t m l -> post2 t m l) -> - wp_cmd fs c t m l post2. - Proof. intros. constructor. inversion H. eapply WP_weaken_cmd; eassumption. Qed. - Lemma wp_skip: forall fs t m l (post: trace -> mem -> locals -> Prop), post t m l -> wp_cmd fs cmd.skip t m l post. @@ -384,11 +366,7 @@ Section WithParams. Lemma wp_seq: forall fs c1 c2 t m l post, wp_cmd fs c1 t m l (fun t' m' l' => wp_cmd fs c2 t' m' l' post) -> wp_cmd fs (cmd.seq c1 c2) t m l post. - Proof. - intros. constructor. cbn. inversion H. clear H. - eapply WP_weaken_cmd. 1: eassumption. cbv beta. intros. - inversion H. assumption. - Qed. + Proof. intros. econstructor; eauto. Qed. Fixpoint update_locals(keys: list string)(vals: list word) (l: locals)(post: locals -> Prop) := @@ -416,8 +394,9 @@ Section WithParams. post t m (map.put l x v) -> wp_cmd fs (cmd.set x e) t m l post. Proof. - intros. inversion H; clear H. econstructor. - cbn -[map.put]. eexists. split. 1: eassumption. unfold dlet.dlet. assumption. + intros. inversion H; clear H. + eapply WeakestPreconditionProperties.expr_sound in H1. fwd. + econstructor; eassumption. Qed. Lemma wp_set0: forall fs x e v t m l rest post, @@ -436,14 +415,20 @@ Section WithParams. wp_cmd fs (cmd.seq (cmd.store access_size.word ea ev) rest) t m l post. Proof. intros. inversion H; clear H. inversion H0; clear H0. - constructor. hnf. - eexists. split. 1: eassumption. + eapply WeakestPreconditionProperties.expr_sound in H3. fwd. + eapply WeakestPreconditionProperties.expr_sound in H. fwd. + eapply exec.seq with (mid := fun t' m' l' => t' = t /\ l' = l /\ _). + 2: { + intros * (? & ? & HM). subst. eapply H2. exact HM. + } unfold anyval in H1. eapply sep_ex1_l in H1. destruct H1 as (v_old & H1). - eexists. split. 1: eassumption. - unfold store. unfold uintptr, Scalars.scalar in *. - eapply Scalars.store_of_sep. 1: eassumption. - intros. eapply H2. assumption. + eapply Scalars.store_of_sep in H1. + { destruct H1 as (m' & ? & HP). + econstructor; try eassumption. + ssplit. 1,2: reflexivity. + exact HP. } + intros ?. exact id. Qed. Lemma wp_store_uint0: forall fs sz ea ev a v R t m l rest (post: _->_->_->Prop), @@ -456,26 +441,39 @@ Section WithParams. wp_cmd fs (cmd.seq (cmd.store sz ea ev) rest) t m l post. Proof. intros. inversion H; clear H. inversion H0; clear H0. - constructor. hnf. - eexists. split. 1: eassumption. + eapply WeakestPreconditionProperties.expr_sound in H4. fwd. + eapply WeakestPreconditionProperties.expr_sound in H. fwd. + eapply exec.seq with (mid := fun t' m' l' => t' = t /\ l' = l /\ _). + 2: { + intros * (? & ? & HM). subst. eapply H3. exact HM. + } unfold anyval in H2. eapply sep_ex1_l in H2. destruct H2 as (v_old & H2). - eexists. split. 1: eassumption. - unfold store. unfold uint in H2. eapply sep_assoc in H2. eapply sep_emp_l in H2. destruct H2 as (B & M). - eapply Scalars.store_of_sep. - - unfold Scalars.truncated_word, Scalars.truncated_scalar. - destruct sz; cbn in *; - rewrite <- (word.unsigned_of_Z_nowrap v_old) in M - by (destruct width_cases as [W|W]; rewrite W in *; lia); - try exact M. - eqapply M. f_equal. - destruct width_cases as [W|W]; rewrite W in *; reflexivity. - - intros. eapply H3. unfold uint. eapply sep_assoc. eapply sep_emp_l. + pose proof Scalars.store_of_sep as P. + unfold Scalars.truncated_word, Scalars.truncated_scalar in P. + specialize (P sz v0 (word.of_Z v_old)). + replace (Z.to_nat (nbits_to_nbytes (access_size_to_nbits sz))) with + (bytes_per (width := width) sz) in M. + 2: { + destruct sz; cbn; try reflexivity. + destruct width_cases as [W | W]; rewrite W; reflexivity. + } + rewrite word.unsigned_of_Z_nowrap in P. + 2: { + destruct width_cases as [W|W]; rewrite W in *; destruct sz; lia. + } + eapply P in M. + { destruct M as (m' & ? & HP). + econstructor; try eassumption. + ssplit. 1,2: reflexivity. + exact HP. } + { clear P. + intros. unfold uint. eapply sep_assoc. eapply sep_emp_l. split. 1: assumption. unfold Scalars.truncated_word, Scalars.truncated_scalar in *. destruct sz; try assumption. - eqapply H0. clear -BW word_ok. - destruct width_cases as [W|W]; subst width; reflexivity. + eqapply H. clear -BW word_ok. + destruct width_cases as [W|W]; subst width; reflexivity. } Qed. Definition merge_locals(c: bool): @@ -531,12 +529,11 @@ Section WithParams. (word.unsigned b = 0 -> wp_cmd fs els t m l post) -> wp_cmd fs (cmd.cond c thn els) t m l post. Proof. - intros. inversion H; clear H. constructor. hnf. - eexists. split. 1: eassumption. - split; intro A; - match goal with - | H: _ -> _ |- _ => specialize (H A); inversion H; clear H; assumption - end. + intros. inversion H; clear H. + eapply WeakestPreconditionProperties.expr_sound in H2. fwd. + destr (word.unsigned v =? 0). + - eapply exec.if_false; eauto. + - eapply exec.if_true; eauto. Qed. Lemma wp_if0: forall fs c thn els rest b Q1 Q2 t m l post, @@ -552,7 +549,7 @@ Section WithParams. all: intro A; match goal with | H: _ -> _ |- _ => specialize (H A) end. - all: eauto using weaken_wp_cmd. + all: eauto using exec.weaken. Qed. Definition after_loop: Semantics.env -> @@ -582,7 +579,7 @@ Section WithParams. wp_cmd fs rest t m l (fun t' m' l' => post t' m' (map.remove l' x)) -> wp_cmd fs (cmd.seq rest (cmd.unset x)) t m l post. Proof. - intros. eapply wp_seq. eapply weaken_wp_cmd. 1: eassumption. + intros. eapply wp_seq. eapply exec.weaken. 1: eassumption. cbv beta. intros. eapply wp_unset00. assumption. Qed. @@ -749,7 +746,7 @@ Section WithParams. True) : wp_cmd fs (cmd.seq (cmd.while e c) rest) t m l post. Proof. - econstructor. cbn. eapply wp_while. exists measure, lt, invariant. + eapply wp_seq. eapply wp_while. exists measure, lt, invariant. split. 1: assumption. split. 1: eauto. clear Hpre v0 t m l. @@ -759,9 +756,10 @@ Section WithParams. inversion Hbody. subst. clear Hbody. inversion H. clear H. eexists. split. 1: eassumption. unfold bool_expr_branches in *. apply proj1 in H1. split. - - intro NE. rewrite word.eqb_ne in H1. 1: eapply H1. intro C. subst v0. + - intro NE. eapply WeakestPreconditionProperties.complete_cmd. + rewrite word.eqb_ne in H1. 1: eapply H1. intro C. subst v0. apply NE. apply word.unsigned_of_Z_0. - - intro E. rewrite word.eqb_eq in H1. 1: eapply invert_wp_cmd; eapply H1. + - intro E. rewrite word.eqb_eq in H1. 1: eapply H1. eapply word.unsigned_inj. rewrite word.unsigned_of_Z_0. exact E. Qed. @@ -790,8 +788,7 @@ Section WithParams. (Hrest: forall t m l, post (g0, v0, t, m, l) -> wp_cmd fs rest t m l finalpost) : wp_cmd fs (cmd.seq (cmd.while e c) rest) t0 m0 l0 finalpost. Proof. - eapply wp_seq. - econstructor. cbn. + eapply wp_seq. eapply WeakestPreconditionProperties.sound_cmd. eapply tailrec_localsmap_1ghost with (P := fun v g t m l => pre (g, v, t, m, l)) (Q := fun v g t m l => post (g, v, t, m, l)). @@ -807,8 +804,7 @@ Section WithParams. eexists. split. 1: eassumption. unfold loop_body_marker in *. split; intro Hv; destruct_one_match_hyp. - - apply proj1 in HAgain. inversion HAgain. eapply WP_weaken_cmd. 1: eassumption. - cbv beta. intros *. exact id. + - apply proj1 in HAgain. eapply WeakestPreconditionProperties.complete_cmd. assumption. - exfalso. apply Hv. apply word.unsigned_of_Z_0. - exfalso. apply E. eapply word.unsigned_inj. rewrite Hv. symmetry. apply word.unsigned_of_Z_0. @@ -904,7 +900,7 @@ Section WithParams. 1: assumption. split. 1: constructor. apply proj2 in H3. unfold loop_body_marker in *. apply proj1 in H3. split. 2: constructor. - eapply weaken_wp_cmd. 1: eassumption. + eapply Semantics.exec.weaken. 1: eassumption. cbv beta. clear H3. intros. fwd. inversion H2. subst. clear H2. unfold bool_expr_branches in *. apply proj1 in H5. destr (word.eqb v2 (word.of_Z 0)); simpl in *. @@ -925,9 +921,6 @@ Section WithParams. { assumption. } Qed. - Definition dexprs(m: mem)(l: locals): list expr -> list word -> Prop := - List.Forall2 (dexpr m l). - Inductive dexprs1(m: mem)(l: locals)(es: list expr)(vs: list word)(P: Prop): Prop := | mk_dexprs1(Hde: dexprs m l es vs)(Hp: P). @@ -940,19 +933,12 @@ Section WithParams. Proof. intros. inversion H; clear H. inversion Hp. clear Hp. - constructor. 2: assumption. constructor. 1: assumption. assumption. - Qed. - - Lemma cpsify_dexprs: forall m l es vs (post: list word -> Prop), - dexprs m l es vs -> - post vs -> - list_map (WeakestPrecondition.expr m l) es post. - Proof. - induction es; intros. - - cbn in *. inversion H. subst. assumption. - - cbn in *. inversion H. subst. clear H. - inversion H3. clear H3. unfold WeakestPrecondition.dexpr in H. - eapply weaken_expr. 1: eassumption. intros. subst. eapply IHes; eassumption. + constructor. 2: assumption. inversion Hde. unfold WeakestPrecondition.dexpr in *. + cbn. eapply weaken_expr. 1: eassumption. intros. subst. + unfold dexprs in Hde0. eapply WeakestPreconditionProperties.Proper_list_map. + 3: eassumption. + { intros ? ? ? ? ? . eapply weaken_expr. 1: eassumption. assumption. } + { intros ? ?. subst. reflexivity. } Qed. Lemma wp_call0 fs t m l fname resnames es vs (post: trace -> mem -> locals -> Prop): @@ -961,9 +947,11 @@ Section WithParams. exists l', map.putmany_of_list_zip resnames rets l = Some l' /\ post t' m' l') -> wp_cmd fs (cmd.call resnames fname es) t m l post. Proof. - intros. - constructor. cbn. exists vs. split. 2: assumption. - unfold WeakestPrecondition.dexprs. eapply cpsify_dexprs. 1: eassumption. reflexivity. + intros. unfold call in *. fwd. + unfold dexprs, WeakestPrecondition.dexprs in *. + eapply WeakestPreconditionProperties.sound_args in H. fwd. + econstructor; try eassumption. + cbv beta. intros *. exact id. Qed. Lemma wp_call: forall fs fname t m resnames arges argvs l rest @@ -1010,8 +998,6 @@ Section WithParams. Proof. intros. do 4 eexists. 1: eassumption. do 2 eexists. 1: eassumption. - eapply invert_wp_cmd in H1. - eapply WeakestPreconditionProperties.sound_cmd. assumption. Qed. @@ -1023,7 +1009,7 @@ Section WithParams. map.getmany_of_list l' nil = Some retvals /\ (retvals = nil /\ P t' m')). Proof. - intros. eapply weaken_wp_cmd. 1: eassumption. + intros. eapply Semantics.exec.weaken. 1: eassumption. cbv beta. intros. fwd. eexists. split. 1: reflexivity. auto. Qed. @@ -1042,7 +1028,7 @@ Section WithParams. map.getmany_of_list l' (cons RETNAME nil) = Some retvals /\ (exists retv, retvals = cons retv nil /\ P t' m' retv)). Proof. - intros. eapply weaken_wp_cmd. 1: eassumption. + intros. eapply Semantics.exec.weaken. 1: eassumption. intros. inversion H0. subst. clear H0. eexists. split. { simpl. unfold map.getmany_of_list. simpl. rewrite G. reflexivity. From 5ff215e051073819364f1e79fa09d2db22836758 Mon Sep 17 00:00:00 2001 From: Samuel Gruetter Date: Thu, 10 Aug 2023 20:31:53 -0400 Subject: [PATCH 14/15] env doesn't really need to be an Instance, it seems --- bedrock2/src/bedrock2/Semantics.v | 2 +- bedrock2/src/bedrock2Examples/Trace.v | 1 - compiler/src/compiler/ExprImpEventLoopSpec.v | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/bedrock2/src/bedrock2/Semantics.v b/bedrock2/src/bedrock2/Semantics.v index 0fb71d63c..28f773eb9 100644 --- a/bedrock2/src/bedrock2/Semantics.v +++ b/bedrock2/src/bedrock2/Semantics.v @@ -75,7 +75,7 @@ Section binops. end. End binops. -#[export] Instance env: map.map String.string Syntax.func := SortedListString.map _. +Definition env: map.map String.string Syntax.func := SortedListString.map _. #[export] Instance env_ok: map.ok env := SortedListString.ok _. Section semantics. diff --git a/bedrock2/src/bedrock2Examples/Trace.v b/bedrock2/src/bedrock2Examples/Trace.v index 03731bba6..495cf29d5 100644 --- a/bedrock2/src/bedrock2Examples/Trace.v +++ b/bedrock2/src/bedrock2Examples/Trace.v @@ -20,7 +20,6 @@ Module Import IOMacros. word :> Word.Interface.word width; mem :> map.map word Byte.byte; locals :> map.map String.string word; - env :> map.map String.string (list String.string * list String.string * cmd); ext_spec :> ExtSpec; (* macros to be inlined to read or write a word diff --git a/compiler/src/compiler/ExprImpEventLoopSpec.v b/compiler/src/compiler/ExprImpEventLoopSpec.v index 6d6d480f4..9fd056417 100644 --- a/compiler/src/compiler/ExprImpEventLoopSpec.v +++ b/compiler/src/compiler/ExprImpEventLoopSpec.v @@ -37,12 +37,12 @@ Section Params1. { funs_valid: valid_src_funs e = true; init_code: Syntax.cmd.cmd; - get_init_code: map.get (map.of_list e) init_f = Some (nil, nil, init_code); + get_init_code: map.get (map.of_list e : env) init_f = Some (nil, nil, init_code); init_code_correct: forall m0 mc0, mem_available spec.(datamem_start) spec.(datamem_pastend) m0 -> MetricSemantics.exec (map.of_list e) init_code nil m0 map.empty mc0 (hl_inv spec); loop_body: Syntax.cmd.cmd; - get_loop_body: map.get (map.of_list e) loop_f = Some (nil, nil, loop_body); + get_loop_body: map.get (map.of_list e : env) loop_f = Some (nil, nil, loop_body); loop_body_correct: forall t m l mc, hl_inv spec t m l mc -> MetricSemantics.exec (map.of_list e) loop_body t m l mc (hl_inv spec); From 535eec4265a842eca5591da884062b2a45cb09dc Mon Sep 17 00:00:00 2001 From: Samuel Gruetter Date: Thu, 10 Aug 2023 20:44:58 -0400 Subject: [PATCH 15/15] fix argument order in refinement --- bedrock2/src/bedrock2/Refinement.v | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/bedrock2/src/bedrock2/Refinement.v b/bedrock2/src/bedrock2/Refinement.v index 43862902a..236866e3b 100644 --- a/bedrock2/src/bedrock2/Refinement.v +++ b/bedrock2/src/bedrock2/Refinement.v @@ -12,32 +12,32 @@ Section WithParams. Context {locals: map.map String.string word}. Context {ext_spec: bedrock2.Semantics.ExtSpec}. - Definition refinement(c1 c2: cmd) := forall functions t m l post, + Definition refines(c2 c1: cmd) := forall functions t m l post, Semantics.exec.exec functions c1 t m l post -> Semantics.exec.exec functions c2 t m l post. Lemma refinement_while: forall test body1 body2, - refinement body1 body2 -> - refinement (cmd.while test body1) (cmd.while test body2). + refines body2 body1 -> + refines (cmd.while test body2) (cmd.while test body1). Proof. - unfold refinement. intros * R *. + unfold refines. intros * R *. remember (cmd.while test body1) as c1. intros. revert Heqc1. induction H; intros; subst; inversion Heqc1; subst. - eapply Semantics.exec.while_false; eassumption. - eapply Semantics.exec.while_true; try eassumption. - { unfold refinement in R. + { unfold refines in R. eapply R. eassumption. } intros. eapply H3; eauto. Qed. Lemma refinement_seq: forall c1 c2 c1' c2', - refinement c1 c1' -> - refinement c2 c2' -> - refinement (cmd.seq c1 c2) (cmd.seq c1' c2'). + refines c1' c1 -> + refines c2' c2 -> + refines (cmd.seq c1' c2') (cmd.seq c1 c2). Proof. intros * R1 R2 functions t m l post H. - unfold refinement in *. + unfold refines in *. inversion H. subst. clear H. eapply Semantics.exec.seq. - eapply R1. eassumption.