summaryrefslogtreecommitdiff
path: root/lib/coq/Hoare.v
diff options
context:
space:
mode:
authorBrian Campbell2019-08-22 16:16:24 +0100
committerBrian Campbell2019-08-22 16:16:44 +0100
commitf150ceef798659156d8ed38c59591c44065f042e (patch)
tree3e163f22082028719cde5f01aa3ed9d58ab466fa /lib/coq/Hoare.v
parentc7975a53294d6c7ca9cfce7931489ba3f2bc35c8 (diff)
Coq: tactics to do rewrites under state monad, simple wp computation
Diffstat (limited to 'lib/coq/Hoare.v')
-rw-r--r--lib/coq/Hoare.v71
1 files changed, 69 insertions, 2 deletions
diff --git a/lib/coq/Hoare.v b/lib/coq/Hoare.v
index d23ff322..49b3afbb 100644
--- a/lib/coq/Hoare.v
+++ b/lib/coq/Hoare.v
@@ -1,4 +1,4 @@
-Require Import String ZArith.
+Require Import String ZArith Setoid Morphisms Equivalence.
Require Import Sail2_state_monad Sail2_prompt Sail2_state Sail2_state_monad_lemmas.
Require Import Sail2_state_lemmas.
@@ -425,7 +425,7 @@ Lemma PrePostE_bindS_unit Regs A Ety (P : predS Regs) (m : monadS Regs unit Ety)
apply PrePost_bindS_unit.
Qed.
-Lemma PrePostE_readS (*[PrePostE_atomI, intro]:*) Regs A Ety (P : predS Regs) f (Q : result A Ety -> predS Regs) E :
+Lemma PrePostE_readS (*[PrePostE_atomI, intro]:*) Regs A Ety f (Q : A -> predS Regs) E :
PrePostE (Ety := Ety) (fun s => Q (f s) s) (readS f) Q E.
unfold PrePostE, PrePost, readS.
intros s Pre [a | e] s' [[= <- <-] | []].
@@ -445,6 +445,16 @@ Lemma PrePostE_if_branch (*[PrePostE_compositeI]:*) Regs A Ety (b : bool) (f g :
destruct b; auto.
Qed.
+Lemma PrePostE_if_sum_branch (*[PrePostE_compositeI]:*) Regs A Ety X Y (b : sumbool X Y) (f g : monadS Regs A Ety) Pf Pg Q E :
+ (forall H : X, b = left H -> PrePostE Pf f Q E) ->
+ (forall H : Y, b = right H -> PrePostE Pg g Q E) ->
+ PrePostE (if b then Pf else Pg) (if b then f else g) Q E.
+intros HX HY.
+destruct b as [H | H].
+* apply (HX H). reflexivity.
+* apply (HY H). reflexivity.
+Qed.
+
Lemma PrePostE_if Regs A Ety (b : bool) (f g : monadS Regs A Ety) P Q E :
(b = true -> PrePostE P f Q E) ->
(b = false -> PrePostE P g Q E) ->
@@ -808,3 +818,60 @@ eapply PrePostE_bindS with (R := fun _ s => forall x, List.In x xs -> Q x s).
apply PrePostE_choose_boolsS_any.
intuition.
Qed.
+
+(* Setoid rewriting *)
+
+Local Open Scope equiv_scope.
+
+Add Parametric Morphism {Regs A Ety} : (@PrePost Regs A Ety)
+ with signature eq ==> equiv ==> eq ==> iff
+ as PrePost_morphism.
+intros.
+unfold PrePost.
+split; intros H' s.
+* rewrite <- (H s). apply H'.
+* rewrite -> (H s). apply H'.
+Qed.
+
+Add Parametric Morphism {Regs A Ety} : (@PrePostE Regs A Ety)
+ with signature eq ==> equiv ==> eq ==> eq ==> iff
+ as PrePostE_morphism.
+intros.
+unfold PrePostE.
+rewrite H.
+reflexivity.
+Qed.
+
+(* Applying rewrites in a Hoare quadruple. For example, [PrePostE_rewrite liftState]
+ will push liftState through all of the monad operations. *)
+
+Lemma PrePostE_code_rw {Regs A Ety} P {Q : A -> predS Regs} {E : ex Ety -> predS Regs} {m m'} :
+ m === m' ->
+ PrePostE P m' Q E ->
+ PrePostE P m Q E.
+intro H.
+rewrite H.
+auto.
+Qed.
+
+Ltac PrePostE_rewrite db := (eapply PrePostE_code_rw; [ statecong db | ]).
+Tactic Notation "PrePostE_rewrite" ident(db) := PrePostE_rewrite db.
+
+(* Attempt to do a weakest precondition calculation step. Assumes that goal has
+ a metavariable for the precondition. *)
+
+Ltac PrePostE_step :=
+ match goal with
+ | |- PrePostE _ (bindS _ _) _ _ => eapply PrePostE_bindS; intros
+ (* The precondition will often have the form (?R x), and Coq's higher-order
+ unification will try to unify x and a if we don't explicitly tell it to
+ use Q to form the precondition to unify with P. *)
+ | |- PrePostE ?P (returnS ?a) ?Q _ => apply (PrePostE_returnS _ _ _ Q)
+ | |- PrePostE _ (if _ then _ else _) _ _ =>
+ first
+ [ eapply PrePostE_if_branch; intros
+ | eapply PrePostE_if_sum_branch; intros
+ ]
+ | |- PrePostE _ (readS _) _ _ => apply PrePostE_readS
+ | |- PrePostE _ (assert_expS _ _) _ _ => apply PrePostE_assert_expS
+ end.