(* *********************************************************************)
(*                                                                     *)
(*              The Compcert verified compiler                         *)
(*                                                                     *)
(*          Xavier Leroy, INRIA Paris                                  *)
(*                                                                     *)
(*  Copyright Institut National de Recherche en Informatique et en     *)
(*  Automatique.  All rights reserved.  This file is distributed       *)
(*  under the terms of the GNU General Public License as published by  *)
(*  the Free Software Foundation, either version 2 of the License, or  *)
(*  (at your option) any later version.  This file is also distributed *)
(*  under the terms of the INRIA Non-Commercial License Agreement.     *)
(*                                                                     *)
(* *********************************************************************)
(** Assertions on memory states, in the style of separation logic *)
(** This library defines a number of useful logical assertions about CompCert memory states, such as "block [b] at offset [ofs] contains value [v]".  Assertions can be grouped using a separating conjunction operator in the style of separation logic.  Currently, this library is used only in module [Stackingproof] to reason about the shapes of stack frames generated during the [Stacking] pass.  This is not a full-fledged separation logic because there is no program logic (Hoare triples) to speak of.  Also, there is no general frame rule; instead, a weak form of the frame rule is provided by the lemmas that help us reason about the logical assertions. *)
(** * Assertions about memory *)
(** An assertion is composed of: - a predicate over memory states (of type [mem -> Prop]) - a set of (block, offset) memory locations that represents the memory footprint of the assertion - a proof that the predicate is invariant by changes of memory outside of the footprint - a proof that the footprint contains only valid memory blocks.  This presentation (where the footprint is part of the assertion) makes it possible to define separating conjunction without explicitly defining a separation algebra over CompCert memory states (i.e. the notion of splitting a memory state into two disjoint halves).  *)
Record massert : Type := {
m_pred : mem -> Prop;
m_footprint: block -> Z -> Prop;
m_invar: forall m m', m_pred m -> Mem.unchanged_on m_footprint m m' -> m_pred m';
m_valid: forall m b ofs, m_pred m -> m_footprint b ofs -> Mem.valid_block m b
}.
Notation "m |= p" := (m_pred p m) (at level 74, no associativity) : sep_scope.
(** Implication and logical equivalence between memory predicates *)
Definition massert_imp (P Q: massert) : Prop :=
(forall m, m_pred P m -> m_pred Q m) /\ (forall b ofs, m_footprint Q b ofs -> m_footprint P b ofs).
Definition massert_eqv (P Q: massert) : Prop :=
massert_imp P Q /\ massert_imp Q P.
Remark massert_imp_refl: forall p, massert_imp p p.
Remark massert_imp_trans: forall p q r, massert_imp p q -> massert_imp q r -> massert_imp p r.
Remark massert_eqv_refl: forall p, massert_eqv p p.
Remark massert_eqv_sym: forall p q, massert_eqv p q -> massert_eqv q p.
Remark massert_eqv_trans: forall p q r, massert_eqv p q -> massert_eqv q r -> massert_eqv p r.
(** Record [massert_eqv] and [massert_imp] as relations so that they can be used by rewriting tactics. *)
Add Relation massert massert_imp
reflexivity proved by massert_imp_refl
transitivity proved by massert_imp_trans
as massert_imp_prel.
Add Relation massert massert_eqv
reflexivity proved by massert_eqv_refl
symmetry proved by massert_eqv_sym
transitivity proved by massert_eqv_trans
as massert_eqv_prel.
Add Morphism m_pred
with signature massert_imp ==> eq ==> impl
as m_pred_morph_1.
Add Morphism m_pred
with signature massert_eqv ==> eq ==> iff
as m_pred_morph_2.
Hint Resolve massert_imp_refl massert_eqv_refl.
(** * Separating conjunction *)
Definition disjoint_footprint (P Q: massert) : Prop :=
forall b ofs, m_footprint P b ofs -> m_footprint Q b ofs -> False.
Program Definition sepconj (P Q: massert) : massert := {|
m_pred := fun m => m_pred P m /\ m_pred Q m /\ disjoint_footprint P Q;
m_footprint := fun b ofs => m_footprint P b ofs \/ m_footprint Q b ofs
|}.
Next Obligation.
repeat split; auto.
apply (m_invar P) with m; auto. eapply Mem.unchanged_on_implies; eauto. simpl; auto.
apply (m_invar Q) with m; auto. eapply Mem.unchanged_on_implies; eauto. simpl; auto.
Qed.
Next Obligation.
destruct H0; [eapply (m_valid P) | eapply (m_valid Q)]; eauto.
Qed.
Add Morphism sepconj
with signature massert_imp ==> massert_imp ==> massert_imp
as sepconj_morph_1.
Add Morphism sepconj
with signature massert_eqv ==> massert_eqv ==> massert_eqv
as sepconj_morph_2.
Infix "**" := sepconj (at level 60, right associativity) : sep_scope.
Local Open Scope sep_scope.

(* Specifications: *)
Lemma sep_imp:
forall P P' Q Q' m,
m |= P ** Q -> massert_imp P P' -> massert_imp Q Q' -> m |= P' ** Q'.
Lemma sep_comm_1:
forall P Q,  massert_imp (P ** Q) (Q ** P).
Lemma sep_comm:
forall P Q, massert_eqv (P ** Q) (Q ** P).
Lemma sep_assoc_1:
forall P Q R, massert_imp ((P ** Q) ** R) (P ** (Q ** R)).
Lemma sep_assoc_2:
forall P Q R, massert_imp (P ** (Q ** R)) ((P ** Q) ** R).
Lemma sep_assoc:
forall P Q R, massert_eqv ((P ** Q) ** R) (P ** (Q ** R)).
Lemma sep_swap:
forall P Q R, massert_eqv (P ** Q ** R) (Q ** P ** R).