From 00bfef44ed5ef07c63879a10530f6333079ee6db Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Mon, 6 May 2019 18:20:03 +0200 Subject: [PATCH 01/28] Start to extend heaplang with atomic resolution. --- theories/heap_lang/lang.v | 40 ++++++------ theories/heap_lang/lifting.v | 111 +++++++++++++++++++++++++++++++- theories/heap_lang/metatheory.v | 9 ++- theories/heap_lang/tactics.v | 4 +- 4 files changed, 138 insertions(+), 26 deletions(-) diff --git a/theories/heap_lang/lang.v b/theories/heap_lang/lang.v index 9edced2d4..0c5c3fbd4 100644 --- a/theories/heap_lang/lang.v +++ b/theories/heap_lang/lang.v @@ -14,13 +14,15 @@ Set Default Proof Using "Type". useless unless the user let-expands [b]. - For prophecy variables, we annotate the reduction steps with an "observation" - and tweak adequacy such that WP knows all future observations. There is + and tweak adequacy such that WP knows all future observations. There is another possible choice: Use non-deterministic choice when creating a prophecy - variable ([NewProph]), and when resolving it ([ResolveProph]) make the - program diverge unless the variable matches. That, however, requires an + variable ([NewProph]), and when resolving it ([Resolve]) make the + program diverge unless the variable matches. That, however, requires an erasure proof that this endless loop does not make specifications useless. -*) +If [e] is an expression that executes physically atomically, then so does +[Resolve e p v]. This second expression behaves exactly as [e], except that +it aditionally resolves the prophecy variable [p] to the value [v]. *) Delimit Scope expr_scope with E. Delimit Scope val_scope with V. @@ -72,7 +74,7 @@ Inductive expr := | FAA (e1 : expr) (e2 : expr) (* Prophecy *) | NewProph - | ResolveProph (e1 : expr) (e2 : expr) + | Resolve (e0 : expr) (e1 : expr) (e2 : expr) with val := | LitV (l : base_lit) | RecV (f x : binder) (e : expr) @@ -181,8 +183,8 @@ Proof. | FAA e1 e2, FAA e1' e2' => cast_if_and (decide (e1 = e1')) (decide (e2 = e2')) | NewProph, NewProph => left _ - | ResolveProph e1 e2, ResolveProph e1' e2' => - cast_if_and (decide (e1 = e1')) (decide (e2 = e2')) + | Resolve e0 e1 e2, Resolve e0' e1' e2' => + cast_if_and3 (decide (e0 = e0')) (decide (e1 = e1')) (decide (e2 = e2')) | _, _ => right _ end with gov (v1 v2 : val) {struct v1} : Decision (v1 = v2) := @@ -255,7 +257,7 @@ Proof. | CAS e0 e1 e2 => GenNode 16 [go e0; go e1; go e2] | FAA e1 e2 => GenNode 17 [go e1; go e2] | NewProph => GenNode 18 [] - | ResolveProph e1 e2 => GenNode 19 [go e1; go e2] + | Resolve e0 e1 e2 => GenNode 19 [go e0; go e1; go e2] end with gov v := match v with @@ -290,7 +292,7 @@ Proof. | GenNode 16 [e0; e1; e2] => CAS (go e0) (go e1) (go e2) | GenNode 17 [e1; e2] => FAA (go e1) (go e2) | GenNode 18 [] => NewProph - | GenNode 19 [e1; e2] => ResolveProph (go e1) (go e2) + | GenNode 19 [e0; e1; e2] => Resolve (go e0) (go e1) (go e2) | _ => Val $ LitV LitUnit (* dummy *) end with gov v := @@ -347,8 +349,8 @@ Inductive ectx_item := | CasRCtx (e0 : expr) (e1 : expr) | FaaLCtx (v2 : val) | FaaRCtx (e1 : expr) - | ProphLCtx (v2 : val) - | ProphRCtx (e1 : expr). + | ResolveLCtx (e : expr) (v2 : val) + | ResolveRCtx (e : expr) (e1 : expr). Definition fill_item (Ki : ectx_item) (e : expr) : expr := match Ki with @@ -375,8 +377,8 @@ Definition fill_item (Ki : ectx_item) (e : expr) : expr := | CasRCtx e0 e1 => CAS e0 e1 e | FaaLCtx v2 => FAA e (Val v2) | FaaRCtx e1 => FAA e1 e - | ProphLCtx v2 => ResolveProph e (of_val v2) - | ProphRCtx e1 => ResolveProph e1 e + | ResolveLCtx ex v2 => Resolve ex e (Val v2) + | ResolveRCtx ex e1 => Resolve ex e1 e end. (** Substitution *) @@ -403,7 +405,7 @@ Fixpoint subst (x : string) (v : val) (e : expr) : expr := | CAS e0 e1 e2 => CAS (subst x v e0) (subst x v e1) (subst x v e2) | FAA e1 e2 => FAA (subst x v e1) (subst x v e2) | NewProph => NewProph - | ResolveProph e1 e2 => ResolveProph (subst x v e1) (subst x v e2) + | Resolve ex e1 e2 => Resolve (subst x v ex) (subst x v e1) (subst x v e2) end. Definition subst' (mx : binder) (v : val) : expr → expr := @@ -587,10 +589,10 @@ Inductive head_step : expr → state → list observation → expr → state → [] (Val $ LitV $ LitProphecy p) (state_upd_used_proph_id ({[ p ]} ∪) σ) [] - | ResolveProphS p v σ : - head_step (ResolveProph (Val $ LitV $ LitProphecy p) (Val v)) σ - [(p, v)] - (Val $ LitV LitUnit) σ []. + | ResolveS p v e σ w σ' κs ts : + head_step e σ κs (Val v) σ' ts → + head_step (Resolve e (Val $ LitV $ LitProphecy p) (Val w)) σ + (κs ++ [(p, w)]) (Val v) σ' ts. (** Basic properties about the language *) Instance fill_item_inj Ki : Inj (=) (=) (fill_item Ki). @@ -657,3 +659,5 @@ Notation Alloc e := (AllocN (Val $ LitV $ LitInt 1) e) (only parsing). (* Skip should be atomic, we sometimes open invariants around it. Hence, we need to explicitly use LamV instead of e.g., Seq. *) Notation Skip := (App (Val $ LamV BAnon (Val $ LitV LitUnit)) (Val $ LitV LitUnit)). + +Notation ResolveProph e1 e2 := (Resolve Skip e1 e2) (only parsing). diff --git a/theories/heap_lang/lifting.v b/theories/heap_lang/lifting.v index 514c533d8..78588a307 100644 --- a/theories/heap_lang/lifting.v +++ b/theories/heap_lang/lifting.v @@ -9,6 +9,41 @@ From iris.proofmode Require Import tactics. From stdpp Require Import fin_maps. Set Default Proof Using "Type". +(* TODO: move elsewhere. *) +Lemma app_non_empty_last A (l : list A) : l ≠ [] → ∃ l' x, l = l' ++ [x]. +Proof. + induction l; intro H; first by exfalso. + destruct (decide (l = [])) as [->|NEq]. + + exists [], a. reflexivity. + + apply IHl in NEq as [l' [x IH]]. exists (a :: l'), x. by rewrite IH. +Qed. + +(* TODO: move elsewhere. *) +Lemma app_singleton_non_empty A (l : list A) x : l ++ [x] ≠ []. +Proof. case l; discriminate. Qed. + +(* TODO: move elsewhere. *) +Lemma to_val_fill_some K e v : to_val (fill K e) = Some v → K = [] ∧ e = Val v. +Proof. + intro H. destruct K. { simpl in H. apply of_to_val in H. done. } + exfalso. assert (to_val e ≠ None) as HH. + { intro A. eapply (fill_not_val (e0 :: K)) in A. rewrite A in H. inversion H. } + unfold to_val in HH. simpl in HH. destruct e; try done. clear HH. + assert (to_val (fill (e0 :: K) (Val v0)) = None) as G. + { clear H v. rename e0 into e. rename v0 into v. + destruct e; simpl; apply fill_not_val; done. } + rewrite G in H. inversion H. +Qed. + +(* TODO: move elsewhere. *) +Lemma prim_step_val_is_head_step e σ1 κs w σ2 efs : + prim_step e σ1 κs (Val w) σ2 efs → head_step e σ1 κs (Val w) σ2 efs. +Proof. + intro H. destruct H as [K e1 e2 H1 H2]. + assert (to_val (fill K e2) = Some w) as H3; first by rewrite -H2. + apply to_val_fill_some in H3 as [-> ->]. simpl in H1. subst e. done. +Qed. + Class heapG Σ := HeapG { heapG_invG : invG Σ; heapG_gen_heapG :> gen_heapG loc val Σ; @@ -83,8 +118,15 @@ Instance skip_atomic s : Atomic s Skip. Proof. solve_atomic. Qed. Instance new_proph_atomic s : Atomic s NewProph. Proof. solve_atomic. Qed. +Instance proph_resolve_atomic s e v1 v2 : + Atomic s e → Atomic s (Resolve e (Val v1) (Val v2)). +Proof. + intro H. apply ectx_language_atomic. + - inversion 1. eapply H. apply head_prim_step. done. + - apply ectxi_language_sub_redexes_are_values; intros [] **; naive_solver. +Qed. Instance resolve_proph_atomic s v1 v2 : Atomic s (ResolveProph (Val v1) (Val v2)). -Proof. solve_atomic. Qed. +Proof. by apply proph_resolve_atomic, skip_atomic. Qed. Local Ltac solve_exec_safe := intros; subst; do 3 eexists; econstructor; eauto. Local Ltac solve_exec_puredet := simpl; intros; by inv_head_step. @@ -412,6 +454,73 @@ Proof. iApply "HΦ". iFrame. Qed. +(* TODO: cleanup / move elsewhere? *) +Lemma wp_resolve_aux s E e Φ p v vs : + Atomic StronglyAtomic e → language.to_val e = None → + WP e @ s; E {{ r, Φ r }} -∗ proph p vs -∗ + WP Resolve e (Val $ LitV $ LitProphecy p) (Val v) @ s; E + {{ r, Φ r ∗ ∃ vs', ⌜vs = v::vs'⌝ ∗ proph p vs' }}. +Proof. + iIntros (A He) "WPe Hp". rewrite !wp_unfold /wp_pre He; simpl. + iIntros (σ1 κ κs n) "H". iCombine "WPe" "H" as "H". + iAssert (|={E}=> ⌜match s with + | NotStuck => reducible (Resolve e (Val (LitV (LitProphecy p))) (Val v)) σ1 + | MaybeStuck => True + end⌝ ∗ _)%I with "[H]" as "XXX". + { iApply fupd_plain_keep_l. iSplitR "H"; last iExact "H". iIntros "[WPe [Hσ Hκ]]". + iApply fupd_plain_mask_empty. iMod ("WPe" $! σ1 κ κs n with "[$Hσ $Hκ]") as "[Hs WPe]". + iModIntro. iDestruct "Hs" as "%". iPureIntro. induction s; last done. + destruct H as [κs2 [e2 [σ2 [efs H]]]]. econstructor. exists e2, σ2, efs. + econstructor. instantiate (2 := []). reflexivity. reflexivity. + assert (is_Some (to_val e2)) as He2. + { unfold Atomic in A. specialize A with σ1 e2 κs2 σ2 efs. apply A. apply H. } + unfold is_Some in He2. destruct He2 as [w He2]. apply of_to_val in He2. subst e2. + constructor. instantiate (1 := κs2). apply prim_step_val_is_head_step. done. } + iMod "XXX" as "[$ [WPe [Hσ Hκ]]]". + destruct (decide (κ = [])) as [->|HNeq]. + - iMod ("WPe" $! σ1 [] κs n with "[$Hσ $Hκ]") as "[Hs WPe]". iModIntro. + iIntros (e2 σ2 efs step). exfalso. + assert (reducible (Resolve e (Val (LitV (LitProphecy p))) (Val v)) σ1) as HHH. + { exists [], e2, σ2, efs. exact step. } apply prim_head_reducible in HHH. + 2: { apply ectxi_language_sub_redexes_are_values; intros [] **; naive_solver. } + apply head_reducible_prim_step in step; last done. clear HHH. inversion step. + destruct κs0; simpl in H4; discriminate H4. + - apply app_non_empty_last in HNeq as [κs' [o ->]]. destruct o as [p' v']. rewrite -app_assoc. + iMod ("WPe" $! σ1 _ _ n with "[$Hσ $Hκ]") as "[Hs WPe]". + iIntros "!>" (e2 σ2 efs step). + assert (reducible (Resolve e (Val (LitV (LitProphecy p))) (Val v)) σ1) as HHH. + { exists (κs' ++ [(p',v')]), e2, σ2, efs. exact step. } apply prim_head_reducible in HHH. + 2: { apply ectxi_language_sub_redexes_are_values; intros [] **; naive_solver. } + apply head_reducible_prim_step in step; last done. clear HHH. inversion step; simpl in *. + assert (κs0 = κs' ∧ p = p' ∧ v = v') as [W1 [W2 W3]]. { apply app_inj_2 in H4; last done. + destruct H4 as [H41 H42]. split; first done. inversion H42. done. } + subst p' v' κs0. iMod ("WPe" $! (Val v0) σ2 efs with "[%]") as "WPe". + { econstructor. instantiate (2 := []). reflexivity. simpl; reflexivity. done. } + iModIntro. iNext. iMod "WPe" as "[[$ Hκ] WPe]". + iMod (proph_map_resolve_proph p v κs with "[$Hκ $Hp]") as (vs') "[% [$ HPost]]". + subst vs. iModIntro. simpl. rewrite !wp_unfold /wp_pre; simpl. + iDestruct "WPe" as "[HΦ $]". iMod "HΦ". iFrame. iModIntro. + iExists vs'. by iFrame. +Qed. + +(* +Lemma wp_resolve se e s E P r Q p vs v : + Atomic se e → + {{{ P }}} e @ s; E {{{ RET r; Q }}} → + {{{ P ∗ proph p vs }}} + Resolve e (Val $ LitV $ LitProphecy p) (Val v) @ s; E + {{{ vs', RET r; Q ∗ ⌜vs = v::vs'⌝ ∗ proph p vs' }}}. +*) + +(* +Lemma wp_resolve se e P vs1 r Q vs2 p v : + Atomic se e → + {{{ P ∗ proph p vs1 }}} e {{{ RET r; Q ∗ proph p vs2 }}} → + {{{ P ∗ proph p vs1 }}} + Resolve e (Val $ LitV $ LitProphecy p) (Val v) + {{{ vs, RET r; Q ∗ ⌜vs2 = v::vs⌝ ∗ proph p vs }}}. +*) + End lifting. Notation "l ↦∗ vs" := (array l vs) diff --git a/theories/heap_lang/metatheory.v b/theories/heap_lang/metatheory.v index 523d29c75..660fbbd51 100644 --- a/theories/heap_lang/metatheory.v +++ b/theories/heap_lang/metatheory.v @@ -12,10 +12,9 @@ Fixpoint is_closed_expr (X : list string) (e : expr) : bool := | Rec f x e => is_closed_expr (f :b: x :b: X) e | UnOp _ e | Fst e | Snd e | InjL e | InjR e | Fork e | Load e => is_closed_expr X e - | App e1 e2 | BinOp _ e1 e2 | Pair e1 e2 | AllocN e1 e2 | Store e1 e2 | FAA e1 e2 - | ResolveProph e1 e2 => + | App e1 e2 | BinOp _ e1 e2 | Pair e1 e2 | AllocN e1 e2 | Store e1 e2 | FAA e1 e2 => is_closed_expr X e1 && is_closed_expr X e2 - | If e0 e1 e2 | Case e0 e1 e2 | CAS e0 e1 e2 => + | If e0 e1 e2 | Case e0 e1 e2 | CAS e0 e1 e2 | Resolve e0 e1 e2 => is_closed_expr X e0 && is_closed_expr X e1 && is_closed_expr X e2 | NewProph => true end @@ -130,7 +129,7 @@ Lemma head_step_is_closed e1 σ1 obs e2 σ2 es : map_Forall (λ _ v, is_closed_val v) σ2.(heap). Proof. intros Cl1 Clσ1 STEP. - destruct STEP; simpl in *; split_and!; + induction STEP; simpl in *; split_and!; try apply map_Forall_insert_2; try by naive_solver. - subst. repeat apply is_closed_subst'; naive_solver. - unfold un_op_eval in *. repeat case_match; naive_solver. @@ -173,7 +172,7 @@ Fixpoint subst_map (vs : gmap string val) (e : expr) : expr := | CAS e0 e1 e2 => CAS (subst_map vs e0) (subst_map vs e1) (subst_map vs e2) | FAA e1 e2 => FAA (subst_map vs e1) (subst_map vs e2) | NewProph => NewProph - | ResolveProph e1 e2 => ResolveProph (subst_map vs e1) (subst_map vs e2) + | Resolve e0 e1 e2 => Resolve (subst_map vs e0) (subst_map vs e1) (subst_map vs e2) end. Lemma subst_map_empty e : subst_map ∅ e = e. diff --git a/theories/heap_lang/tactics.v b/theories/heap_lang/tactics.v index 400da8c11..dd586631b 100644 --- a/theories/heap_lang/tactics.v +++ b/theories/heap_lang/tactics.v @@ -32,6 +32,6 @@ Ltac reshape_expr e tac := | CAS ?e0 ?e1 ?e2 => go (CasRCtx e0 e1 :: K) e2 | FAA ?e (Val ?v) => go (FaaLCtx v :: K) e | FAA ?e1 ?e2 => go (FaaRCtx e1 :: K) e2 - | ResolveProph ?e (Val ?v) => go (ProphLCtx v :: K) e - | ResolveProph ?e1 ?e2 => go (ProphRCtx e1 :: K) e2 + | Resolve ?e (Val ?v) => go (ResolveLCtx v :: K) e + | Resolve ?e1 ?e2 => go (ResolveRCtx e1 :: K) e2 end in go (@nil ectx_item) e. -- GitLab From 867db0dda6b47942f7ac1099f3c3c587b12d0e46 Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Mon, 13 May 2019 14:54:05 +0200 Subject: [PATCH 02/28] Observation with pairs of values (result, resolved). --- theories/base_logic/lib/proph_map.v | 25 +++++++++++----------- theories/heap_lang/lang.v | 9 +++++--- theories/heap_lang/lib/coin_flip.v | 10 ++++----- theories/heap_lang/lifting.v | 33 +++++++++++++++++------------ 4 files changed, 43 insertions(+), 34 deletions(-) diff --git a/theories/base_logic/lib/proph_map.v b/theories/base_logic/lib/proph_map.v index c1a990384..d10910666 100644 --- a/theories/base_logic/lib/proph_map.v +++ b/theories/base_logic/lib/proph_map.v @@ -4,14 +4,14 @@ From iris.proofmode Require Import tactics. Set Default Proof Using "Type". Import uPred. -Local Notation proph_map P V := (gmap P (list V)). -Definition proph_val_list (P V : Type) := list (P * V). +Local Notation proph_map P V := (gmap P (list (V * V))). +Definition proph_val_list (P V : Type) := list (P * (V * V)). Definition proph_mapUR (P V : Type) `{Countable P} : ucmraT := - gmapUR P $ exclR $ listC $ leibnizC V. + gmapUR P $ exclR $ listC $ prodC (leibnizC V) (leibnizC V). Definition to_proph_map {P V} `{Countable P} (pvs : proph_map P V) : proph_mapUR P V := - fmap (λ vs, Excl (vs : list (leibnizC V))) pvs. + fmap (λ vs, Excl (vs : list (prodC (leibnizC V) (leibnizC V)))) pvs. (** The CMRA we need. *) Class proph_mapG (P V : Type) (Σ : gFunctors) `{Countable P} := ProphMapG { @@ -37,7 +37,7 @@ Section definitions. Implicit Types p : P. (** The list of resolves for [p] in [pvs]. *) - Fixpoint proph_list_resolves pvs p : list V := + Fixpoint proph_list_resolves pvs p : list (V * V) := match pvs with | [] => [] | (q,v)::pvs => if decide (p = q) then v :: proph_list_resolves pvs p @@ -52,7 +52,7 @@ Section definitions. dom (gset _) R ⊆ ps⌝ ∗ own (proph_map_name pG) (● (to_proph_map R)))%I. - Definition proph_def (p : P) (vs : list V) : iProp Σ := + Definition proph_def (p : P) (vs : list (V * V)) : iProp Σ := own (proph_map_name pG) (◯ {[p := Excl vs]}). Definition proph_aux : seal (@proph_def). by eexists. Qed. @@ -81,14 +81,14 @@ End list_resolves. Section to_proph_map. Context (P V : Type) `{Countable P}. Implicit Types p : P. - Implicit Types vs : list V. + Implicit Types vs : list (V * V). Implicit Types R : proph_map P V. Lemma to_proph_map_valid R : ✓ to_proph_map R. Proof. intros l. rewrite lookup_fmap. by case (R !! l). Qed. - Lemma to_proph_map_insert p vs R : - to_proph_map (<[p := vs]> R) = <[p := Excl (vs: list (leibnizC V))]> (to_proph_map R). + Lemma to_proph_map_insert p (vs : list (prodC (leibnizC V) (leibnizC V))) R : + to_proph_map (<[p := vs]> R) = <[p := Excl vs]> (to_proph_map R). Proof. by rewrite /to_proph_map fmap_insert. Qed. Lemma to_proph_map_delete p R : @@ -119,8 +119,8 @@ Qed. Section proph_map. Context `{proph_mapG P V Σ}. Implicit Types p : P. - Implicit Types v : V. - Implicit Types vs : list V. + Implicit Types v : V * V. + Implicit Types vs : list (V * V). Implicit Types R : proph_map P V. Implicit Types ps : gset P. @@ -159,7 +159,8 @@ Section proph_map. iMod (own_update_2 with "H● Hp") as "[H● H◯]". { eapply auth_update. apply: singleton_local_update. - by rewrite /to_proph_map lookup_fmap HR. - - by apply (exclusive_local_update _ (Excl (proph_list_resolves pvs p : list (leibnizC V)))). } + - by apply (exclusive_local_update _ (Excl + (proph_list_resolves pvs p : list (prodC (leibnizC V) (leibnizC V))))). } rewrite /to_proph_map -fmap_insert. iModIntro. iExists (proph_list_resolves pvs p). iFrame. iSplitR. - iPureIntro. done. diff --git a/theories/heap_lang/lang.v b/theories/heap_lang/lang.v index 0c5c3fbd4..a7e28c958 100644 --- a/theories/heap_lang/lang.v +++ b/theories/heap_lang/lang.v @@ -74,7 +74,7 @@ Inductive expr := | FAA (e1 : expr) (e2 : expr) (* Prophecy *) | NewProph - | Resolve (e0 : expr) (e1 : expr) (e2 : expr) + | Resolve (e0 : expr) (e1 : expr) (e2 : expr) (* wrapped expr, proph, val *) with val := | LitV (l : base_lit) | RecV (f x : binder) (e : expr) @@ -85,7 +85,10 @@ with val := Bind Scope expr_scope with expr. Bind Scope val_scope with val. -Definition observation : Set := proph_id * val. +(** An observation associates a prophecy variable (identifier) to a pair of +values. The first value is the one that is returned by the (atomic) operation +during which the prophecy resolution happened. *) +Definition observation : Set := proph_id * (val * val). Notation of_val := Val (only parsing). @@ -592,7 +595,7 @@ Inductive head_step : expr → state → list observation → expr → state → | ResolveS p v e σ w σ' κs ts : head_step e σ κs (Val v) σ' ts → head_step (Resolve e (Val $ LitV $ LitProphecy p) (Val w)) σ - (κs ++ [(p, w)]) (Val v) σ' ts. + (κs ++ [(p, (v, w))]) (Val v) σ' ts. (** Basic properties about the language *) Instance fill_item_inj Ki : Inj (=) (=) (fill_item Ki). diff --git a/theories/heap_lang/lib/coin_flip.v b/theories/heap_lang/lib/coin_flip.v index 2f76409d2..08545fa3b 100644 --- a/theories/heap_lang/lib/coin_flip.v +++ b/theories/heap_lang/lib/coin_flip.v @@ -61,10 +61,10 @@ Section coinflip. iModIntro. wp_seq. done. Qed. - Definition val_list_to_bool (v : list val) : bool := - match v with - | LitV (LitBool b) :: _ => b - | _ => true + Definition extract_bool (l : list (val * val)) : bool := + match l with + | (_, LitV (LitBool b)) :: _ => b + | _ => true end. Lemma lateChoice_spec (x: loc) : @@ -81,7 +81,7 @@ Section coinflip. iMod "AU" as "[Hl [_ Hclose]]". iDestruct "Hl" as (v') "Hl". wp_store. - iMod ("Hclose" $! (val_list_to_bool v) with "[Hl]") as "HΦ"; first by eauto. + iMod ("Hclose" $! (extract_bool v) with "[Hl]") as "HΦ"; first by eauto. iModIntro. wp_apply rand_spec; try done. iIntros (b') "_". wp_apply (wp_resolve_proph with "Hp"). diff --git a/theories/heap_lang/lifting.v b/theories/heap_lang/lifting.v index 78588a307..c1750f0f0 100644 --- a/theories/heap_lang/lifting.v +++ b/theories/heap_lang/lifting.v @@ -443,12 +443,12 @@ Qed. Lemma wp_resolve_proph s E p vs v : {{{ proph p vs }}} ResolveProph (Val $ LitV $ LitProphecy p) (Val v) @ s; E - {{{ vs', RET (LitV LitUnit); ⌜vs = v::vs'⌝ ∗ proph p vs' }}}. + {{{ vs', RET (LitV LitUnit); ⌜vs = (LitV LitUnit, v)::vs'⌝ ∗ proph p vs' }}}. Proof. iIntros (Φ) "Hp HΦ". iApply wp_lift_atomic_head_step_no_fork; auto. iIntros (σ1 κ κs n) "[Hσ HR] !>". iSplit; first by eauto. iNext; iIntros (v2 σ2 efs Hstep). inv_head_step. - iMod (proph_map_resolve_proph p v κs with "[HR Hp]") as "HPost"; first by iFrame. + iMod (proph_map_resolve_proph p (LitV LitUnit, v) κs with "[HR Hp]") as "HPost"; first by iFrame. iModIntro. iFrame. iSplitR; first done. iDestruct "HPost" as (vs') "[HEq [HR Hp]]". iFrame. iApply "HΦ". iFrame. @@ -459,7 +459,7 @@ Lemma wp_resolve_aux s E e Φ p v vs : Atomic StronglyAtomic e → language.to_val e = None → WP e @ s; E {{ r, Φ r }} -∗ proph p vs -∗ WP Resolve e (Val $ LitV $ LitProphecy p) (Val v) @ s; E - {{ r, Φ r ∗ ∃ vs', ⌜vs = v::vs'⌝ ∗ proph p vs' }}. + {{ r, Φ r ∗ ∃ vs', ⌜vs = (r, v)::vs'⌝ ∗ proph p vs' }}. Proof. iIntros (A He) "WPe Hp". rewrite !wp_unfold /wp_pre He; simpl. iIntros (σ1 κ κs n) "H". iCombine "WPe" "H" as "H". @@ -474,8 +474,9 @@ Proof. econstructor. instantiate (2 := []). reflexivity. reflexivity. assert (is_Some (to_val e2)) as He2. { unfold Atomic in A. specialize A with σ1 e2 κs2 σ2 efs. apply A. apply H. } - unfold is_Some in He2. destruct He2 as [w He2]. apply of_to_val in He2. subst e2. - constructor. instantiate (1 := κs2). apply prim_step_val_is_head_step. done. } + unfold is_Some in He2. destruct He2 as [w He2]. apply of_to_val in He2. + instantiate (1 := κs2 ++ [(p, (match to_val e2 with Some w => w | _ => v end, v))]). + subst e2. simpl. constructor. apply prim_step_val_is_head_step. done. } iMod "XXX" as "[$ [WPe [Hσ Hκ]]]". destruct (decide (κ = [])) as [->|HNeq]. - iMod ("WPe" $! σ1 [] κs n with "[$Hσ $Hκ]") as "[Hs WPe]". iModIntro. @@ -485,31 +486,35 @@ Proof. 2: { apply ectxi_language_sub_redexes_are_values; intros [] **; naive_solver. } apply head_reducible_prim_step in step; last done. clear HHH. inversion step. destruct κs0; simpl in H4; discriminate H4. - - apply app_non_empty_last in HNeq as [κs' [o ->]]. destruct o as [p' v']. rewrite -app_assoc. - iMod ("WPe" $! σ1 _ _ n with "[$Hσ $Hκ]") as "[Hs WPe]". + - apply app_non_empty_last in HNeq as [κs' [o ->]]. destruct o as [p' [w' v']]. + rewrite -app_assoc. iMod ("WPe" $! σ1 _ _ n with "[$Hσ $Hκ]") as "[Hs WPe]". iIntros "!>" (e2 σ2 efs step). assert (reducible (Resolve e (Val (LitV (LitProphecy p))) (Val v)) σ1) as HHH. - { exists (κs' ++ [(p',v')]), e2, σ2, efs. exact step. } apply prim_head_reducible in HHH. + { exists (κs' ++ [(p',(w',v'))]), e2, σ2, efs. exact step. } apply prim_head_reducible in HHH. 2: { apply ectxi_language_sub_redexes_are_values; intros [] **; naive_solver. } apply head_reducible_prim_step in step; last done. clear HHH. inversion step; simpl in *. - assert (κs0 = κs' ∧ p = p' ∧ v = v') as [W1 [W2 W3]]. { apply app_inj_2 in H4; last done. - destruct H4 as [H41 H42]. split; first done. inversion H42. done. } - subst p' v' κs0. iMod ("WPe" $! (Val v0) σ2 efs with "[%]") as "WPe". + assert (κs0 = κs' ∧ p = p' ∧ v = v' ∧ v0 = w') as [W1 [W2 [W3 W4]]]. + { apply app_inj_2 in H4; last done. destruct H4 as [H41 H42]. split; first done. + inversion H42. done. } + subst p' v' w' κs0. iMod ("WPe" $! (Val v0) σ2 efs with "[%]") as "WPe". { econstructor. instantiate (2 := []). reflexivity. simpl; reflexivity. done. } iModIntro. iNext. iMod "WPe" as "[[$ Hκ] WPe]". - iMod (proph_map_resolve_proph p v κs with "[$Hκ $Hp]") as (vs') "[% [$ HPost]]". + iMod (proph_map_resolve_proph p (v0,v) κs with "[$Hκ $Hp]") as (vs') "[% [$ HPost]]". subst vs. iModIntro. simpl. rewrite !wp_unfold /wp_pre; simpl. iDestruct "WPe" as "[HΦ $]". iMod "HΦ". iFrame. iModIntro. iExists vs'. by iFrame. Qed. (* -Lemma wp_resolve se e s E P r Q p vs v : - Atomic se e → +Lemma wp_resolve e s E P r Q p vs v : + Atomic StronglyAtomic e → language.to_val e = None → {{{ P }}} e @ s; E {{{ RET r; Q }}} → {{{ P ∗ proph p vs }}} Resolve e (Val $ LitV $ LitProphecy p) (Val v) @ s; E {{{ vs', RET r; Q ∗ ⌜vs = v::vs'⌝ ∗ proph p vs' }}}. +Proof. + iIntros (A He TTe Φ) "[P Hp] HΦ". iDestruct TTe as "#TTe"; clear TTe. + iDestruct ("TTe" with "P") as "He". instantiate (1 := Φ). *) (* -- GitLab From 141baad96477d7f07aa4d2c5a90e7765e6dedaa7 Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Mon, 13 May 2019 15:30:11 +0200 Subject: [PATCH 03/28] Cleaning up (unused lemma + use lemma from Coq stdlib). --- theories/heap_lang/lifting.v | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/theories/heap_lang/lifting.v b/theories/heap_lang/lifting.v index c1750f0f0..1bda07cb4 100644 --- a/theories/heap_lang/lifting.v +++ b/theories/heap_lang/lifting.v @@ -1,3 +1,4 @@ +From Coq.Lists Require Import List. (* used for lemma "exists_last" *) From iris.algebra Require Import auth gmap. From iris.base_logic Require Export gen_heap. From iris.base_logic.lib Require Export proph_map. @@ -9,19 +10,6 @@ From iris.proofmode Require Import tactics. From stdpp Require Import fin_maps. Set Default Proof Using "Type". -(* TODO: move elsewhere. *) -Lemma app_non_empty_last A (l : list A) : l ≠ [] → ∃ l' x, l = l' ++ [x]. -Proof. - induction l; intro H; first by exfalso. - destruct (decide (l = [])) as [->|NEq]. - + exists [], a. reflexivity. - + apply IHl in NEq as [l' [x IH]]. exists (a :: l'), x. by rewrite IH. -Qed. - -(* TODO: move elsewhere. *) -Lemma app_singleton_non_empty A (l : list A) x : l ++ [x] ≠ []. -Proof. case l; discriminate. Qed. - (* TODO: move elsewhere. *) Lemma to_val_fill_some K e v : to_val (fill K e) = Some v → K = [] ∧ e = Val v. Proof. @@ -486,7 +474,7 @@ Proof. 2: { apply ectxi_language_sub_redexes_are_values; intros [] **; naive_solver. } apply head_reducible_prim_step in step; last done. clear HHH. inversion step. destruct κs0; simpl in H4; discriminate H4. - - apply app_non_empty_last in HNeq as [κs' [o ->]]. destruct o as [p' [w' v']]. + - apply exists_last in HNeq as [κs' [o ->]]. destruct o as [p' [w' v']]. rewrite -app_assoc. iMod ("WPe" $! σ1 _ _ n with "[$Hσ $Hκ]") as "[Hs WPe]". iIntros "!>" (e2 σ2 efs step). assert (reducible (Resolve e (Val (LitV (LitProphecy p))) (Val v)) σ1) as HHH. -- GitLab From 567a21a6f4189453233306b43b45e34908409140 Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Mon, 13 May 2019 16:21:03 +0200 Subject: [PATCH 04/28] New statement of Resolve's lifting lemma. --- theories/heap_lang/lifting.v | 41 +++++++++--------------------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/theories/heap_lang/lifting.v b/theories/heap_lang/lifting.v index 1bda07cb4..3798dd3fb 100644 --- a/theories/heap_lang/lifting.v +++ b/theories/heap_lang/lifting.v @@ -442,14 +442,14 @@ Proof. iApply "HΦ". iFrame. Qed. -(* TODO: cleanup / move elsewhere? *) -Lemma wp_resolve_aux s E e Φ p v vs : - Atomic StronglyAtomic e → language.to_val e = None → - WP e @ s; E {{ r, Φ r }} -∗ proph p vs -∗ - WP Resolve e (Val $ LitV $ LitProphecy p) (Val v) @ s; E - {{ r, Φ r ∗ ∃ vs', ⌜vs = (r, v)::vs'⌝ ∗ proph p vs' }}. +Lemma wp_resolve s E e Φ p v vs : + Atomic StronglyAtomic e → + language.to_val e = None → + proph p vs -∗ + WP e @ s; E {{ r, ∀ vs', ⌜vs = (r, v)::vs'⌝ -∗ proph p vs' -∗ Φ r }} -∗ + WP Resolve e (Val $ LitV $ LitProphecy p) (Val v) @ s; E {{ Φ }}. Proof. - iIntros (A He) "WPe Hp". rewrite !wp_unfold /wp_pre He; simpl. + iIntros (A He) "Hp WPe". rewrite !wp_unfold /wp_pre He; simpl. iIntros (σ1 κ κs n) "H". iCombine "WPe" "H" as "H". iAssert (|={E}=> ⌜match s with | NotStuck => reducible (Resolve e (Val (LitV (LitProphecy p))) (Val v)) σ1 @@ -457,7 +457,7 @@ Proof. end⌝ ∗ _)%I with "[H]" as "XXX". { iApply fupd_plain_keep_l. iSplitR "H"; last iExact "H". iIntros "[WPe [Hσ Hκ]]". iApply fupd_plain_mask_empty. iMod ("WPe" $! σ1 κ κs n with "[$Hσ $Hκ]") as "[Hs WPe]". - iModIntro. iDestruct "Hs" as "%". iPureIntro. induction s; last done. + iModIntro. iDestruct "Hs" as "%". iPureIntro. destruct s; last done. destruct H as [κs2 [e2 [σ2 [efs H]]]]. econstructor. exists e2, σ2, efs. econstructor. instantiate (2 := []). reflexivity. reflexivity. assert (is_Some (to_val e2)) as He2. @@ -489,31 +489,10 @@ Proof. iModIntro. iNext. iMod "WPe" as "[[$ Hκ] WPe]". iMod (proph_map_resolve_proph p (v0,v) κs with "[$Hκ $Hp]") as (vs') "[% [$ HPost]]". subst vs. iModIntro. simpl. rewrite !wp_unfold /wp_pre; simpl. - iDestruct "WPe" as "[HΦ $]". iMod "HΦ". iFrame. iModIntro. - iExists vs'. by iFrame. + iDestruct "WPe" as "[HΦ $]". iMod "HΦ". iFrame. iModIntro. simplify_eq. + iApply "HΦ"; first done. iFrame. Qed. -(* -Lemma wp_resolve e s E P r Q p vs v : - Atomic StronglyAtomic e → language.to_val e = None → - {{{ P }}} e @ s; E {{{ RET r; Q }}} → - {{{ P ∗ proph p vs }}} - Resolve e (Val $ LitV $ LitProphecy p) (Val v) @ s; E - {{{ vs', RET r; Q ∗ ⌜vs = v::vs'⌝ ∗ proph p vs' }}}. -Proof. - iIntros (A He TTe Φ) "[P Hp] HΦ". iDestruct TTe as "#TTe"; clear TTe. - iDestruct ("TTe" with "P") as "He". instantiate (1 := Φ). -*) - -(* -Lemma wp_resolve se e P vs1 r Q vs2 p v : - Atomic se e → - {{{ P ∗ proph p vs1 }}} e {{{ RET r; Q ∗ proph p vs2 }}} → - {{{ P ∗ proph p vs1 }}} - Resolve e (Val $ LitV $ LitProphecy p) (Val v) - {{{ vs, RET r; Q ∗ ⌜vs2 = v::vs⌝ ∗ proph p vs }}}. -*) - End lifting. Notation "l ↦∗ vs" := (array l vs) -- GitLab From d10cbc5dac7691350d25462ccb624a783610cc90 Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Mon, 13 May 2019 17:10:25 +0200 Subject: [PATCH 05/28] Use spec of Resolve for (legacy) ResolveProph. --- theories/heap_lang/lifting.v | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/theories/heap_lang/lifting.v b/theories/heap_lang/lifting.v index 3798dd3fb..9d1fff0c3 100644 --- a/theories/heap_lang/lifting.v +++ b/theories/heap_lang/lifting.v @@ -428,20 +428,6 @@ Proof. iModIntro; iSplit=> //. iFrame. by iApply "HΦ". Qed. -Lemma wp_resolve_proph s E p vs v : - {{{ proph p vs }}} - ResolveProph (Val $ LitV $ LitProphecy p) (Val v) @ s; E - {{{ vs', RET (LitV LitUnit); ⌜vs = (LitV LitUnit, v)::vs'⌝ ∗ proph p vs' }}}. -Proof. - iIntros (Φ) "Hp HΦ". iApply wp_lift_atomic_head_step_no_fork; auto. - iIntros (σ1 κ κs n) "[Hσ HR] !>". iSplit; first by eauto. - iNext; iIntros (v2 σ2 efs Hstep). inv_head_step. - iMod (proph_map_resolve_proph p (LitV LitUnit, v) κs with "[HR Hp]") as "HPost"; first by iFrame. - iModIntro. iFrame. iSplitR; first done. - iDestruct "HPost" as (vs') "[HEq [HR Hp]]". iFrame. - iApply "HΦ". iFrame. -Qed. - Lemma wp_resolve s E e Φ p v vs : Atomic StronglyAtomic e → language.to_val e = None → @@ -450,8 +436,9 @@ Lemma wp_resolve s E e Φ p v vs : WP Resolve e (Val $ LitV $ LitProphecy p) (Val v) @ s; E {{ Φ }}. Proof. iIntros (A He) "Hp WPe". rewrite !wp_unfold /wp_pre He; simpl. - iIntros (σ1 κ κs n) "H". iCombine "WPe" "H" as "H". - iAssert (|={E}=> ⌜match s with + iIntros (σ1 κ κs n) "H". + (* TODO cleaning up from here. *) + iCombine "WPe" "H" as "H". iAssert (|={E}=> ⌜match s with | NotStuck => reducible (Resolve e (Val (LitV (LitProphecy p))) (Val v)) σ1 | MaybeStuck => True end⌝ ∗ _)%I with "[H]" as "XXX". @@ -493,6 +480,23 @@ Proof. iApply "HΦ"; first done. iFrame. Qed. +Lemma wp_skip s E Φ : ▷ Φ (LitV LitUnit) -∗ WP Skip @ s; E {{ Φ }}. +Proof. + iIntros "HΦ". iApply wp_lift_atomic_head_step_no_fork; auto. + iIntros (σ1 κ κs n) "Hσ". iModIntro. iSplit. + - iPureIntro. eexists _, _, _, _. by constructor. + - iIntros (e2 σ2 efs S) "!>". inversion S. simplify_eq. by iFrame. +Qed. + +Lemma wp_resolve_proph s E p vs v : + {{{ proph p vs }}} + ResolveProph (Val $ LitV $ LitProphecy p) (Val v) @ s; E + {{{ vs', RET (LitV LitUnit); ⌜vs = (LitV LitUnit, v)::vs'⌝ ∗ proph p vs' }}}. +Proof. + iIntros (Φ) "Hp HΦ". iApply (wp_resolve with "Hp"); first done. + iApply wp_skip. iNext. iIntros (vs') "HEq Hp". iApply "HΦ". iFrame. +Qed. + End lifting. Notation "l ↦∗ vs" := (array l vs) -- GitLab From 296cb5b421c9577697ea30dfd737a0836ad16f11 Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Mon, 13 May 2019 18:23:05 +0200 Subject: [PATCH 06/28] Cleaning up new reduction lemmas for heaplang. --- theories/heap_lang/lang.v | 16 ++++++++++++++++ theories/heap_lang/lifting.v | 24 +----------------------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/theories/heap_lang/lang.v b/theories/heap_lang/lang.v index a7e28c958..6a02d692b 100644 --- a/theories/heap_lang/lang.v +++ b/theories/heap_lang/lang.v @@ -649,6 +649,22 @@ Canonical Structure heap_lang := LanguageOfEctx heap_ectx_lang. (* Prefer heap_lang names over ectx_language names. *) Export heap_lang. +Lemma to_val_fill_some K e v : to_val (fill K e) = Some v → K = [] ∧ e = Val v. +Proof. + intro H. destruct K as [|i K]. { apply of_to_val in H. done. } exfalso. + assert (to_val e ≠ None) as He. { intro A. rewrite fill_not_val in H; done. } + destruct e; try done. assert (to_val (fill (i :: K) (Val v0)) = None) as G. + { clear H v. destruct i; simpl; apply fill_not_val; done. } simplify_eq. +Qed. + +Lemma prim_step_to_val_is_head_step e σ1 κs w σ2 efs : + prim_step e σ1 κs (Val w) σ2 efs → head_step e σ1 κs (Val w) σ2 efs. +Proof. + intro H. destruct H as [K e1 e2 H1 H2]. + assert (to_val (fill K e2) = Some w) as H3; first by rewrite -H2. + apply to_val_fill_some in H3 as [-> ->]. subst e. done. +Qed. + (** Define some derived forms. *) Notation Lam x e := (Rec BAnon x e) (only parsing). Notation Let x e1 e2 := (App (Lam x e2) e1) (only parsing). diff --git a/theories/heap_lang/lifting.v b/theories/heap_lang/lifting.v index 9d1fff0c3..52bb69991 100644 --- a/theories/heap_lang/lifting.v +++ b/theories/heap_lang/lifting.v @@ -10,28 +10,6 @@ From iris.proofmode Require Import tactics. From stdpp Require Import fin_maps. Set Default Proof Using "Type". -(* TODO: move elsewhere. *) -Lemma to_val_fill_some K e v : to_val (fill K e) = Some v → K = [] ∧ e = Val v. -Proof. - intro H. destruct K. { simpl in H. apply of_to_val in H. done. } - exfalso. assert (to_val e ≠ None) as HH. - { intro A. eapply (fill_not_val (e0 :: K)) in A. rewrite A in H. inversion H. } - unfold to_val in HH. simpl in HH. destruct e; try done. clear HH. - assert (to_val (fill (e0 :: K) (Val v0)) = None) as G. - { clear H v. rename e0 into e. rename v0 into v. - destruct e; simpl; apply fill_not_val; done. } - rewrite G in H. inversion H. -Qed. - -(* TODO: move elsewhere. *) -Lemma prim_step_val_is_head_step e σ1 κs w σ2 efs : - prim_step e σ1 κs (Val w) σ2 efs → head_step e σ1 κs (Val w) σ2 efs. -Proof. - intro H. destruct H as [K e1 e2 H1 H2]. - assert (to_val (fill K e2) = Some w) as H3; first by rewrite -H2. - apply to_val_fill_some in H3 as [-> ->]. simpl in H1. subst e. done. -Qed. - Class heapG Σ := HeapG { heapG_invG : invG Σ; heapG_gen_heapG :> gen_heapG loc val Σ; @@ -451,7 +429,7 @@ Proof. { unfold Atomic in A. specialize A with σ1 e2 κs2 σ2 efs. apply A. apply H. } unfold is_Some in He2. destruct He2 as [w He2]. apply of_to_val in He2. instantiate (1 := κs2 ++ [(p, (match to_val e2 with Some w => w | _ => v end, v))]). - subst e2. simpl. constructor. apply prim_step_val_is_head_step. done. } + subst e2. simpl. constructor. apply prim_step_to_val_is_head_step. done. } iMod "XXX" as "[$ [WPe [Hσ Hκ]]]". destruct (decide (κ = [])) as [->|HNeq]. - iMod ("WPe" $! σ1 [] κs n with "[$Hσ $Hκ]") as "[Hs WPe]". iModIntro. -- GitLab From 44047eb0459f67adcf376a5e125afc53f8406dba Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Tue, 14 May 2019 11:43:31 +0200 Subject: [PATCH 07/28] Proof cleanup (lifting lemma for Resolve). --- theories/heap_lang/lifting.v | 83 ++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/theories/heap_lang/lifting.v b/theories/heap_lang/lifting.v index 52bb69991..b6d529f4c 100644 --- a/theories/heap_lang/lifting.v +++ b/theories/heap_lang/lifting.v @@ -406,6 +406,18 @@ Proof. iModIntro; iSplit=> //. iFrame. by iApply "HΦ". Qed. +Lemma resolve_reducible e σ p v : + Atomic StronglyAtomic e → reducible e σ → + reducible (Resolve e (Val (LitV (LitProphecy p))) (Val v)) σ. +Proof. + intros A [κ [e' [σ' [efs H]]]]. econstructor. exists e', σ', efs. econstructor. + instantiate (2 := []). reflexivity. reflexivity. assert (∃w, Val w = e') as [w <-]. + { unfold Atomic in A. apply (A σ e' κ σ' efs) in H. unfold is_Some in H. + destruct H as [w H]. exists w. simpl in H. by apply (of_to_val _ _ H). } + instantiate (1 := κ ++ [(p, (match to_val e' with Some w => w | _ => v end, v))]). + simpl. constructor. by apply prim_step_to_val_is_head_step. +Qed. + Lemma wp_resolve s E e Φ p v vs : Atomic StronglyAtomic e → language.to_val e = None → @@ -413,49 +425,36 @@ Lemma wp_resolve s E e Φ p v vs : WP e @ s; E {{ r, ∀ vs', ⌜vs = (r, v)::vs'⌝ -∗ proph p vs' -∗ Φ r }} -∗ WP Resolve e (Val $ LitV $ LitProphecy p) (Val v) @ s; E {{ Φ }}. Proof. - iIntros (A He) "Hp WPe". rewrite !wp_unfold /wp_pre He; simpl. - iIntros (σ1 κ κs n) "H". - (* TODO cleaning up from here. *) - iCombine "WPe" "H" as "H". iAssert (|={E}=> ⌜match s with - | NotStuck => reducible (Resolve e (Val (LitV (LitProphecy p))) (Val v)) σ1 - | MaybeStuck => True - end⌝ ∗ _)%I with "[H]" as "XXX". - { iApply fupd_plain_keep_l. iSplitR "H"; last iExact "H". iIntros "[WPe [Hσ Hκ]]". - iApply fupd_plain_mask_empty. iMod ("WPe" $! σ1 κ κs n with "[$Hσ $Hκ]") as "[Hs WPe]". - iModIntro. iDestruct "Hs" as "%". iPureIntro. destruct s; last done. - destruct H as [κs2 [e2 [σ2 [efs H]]]]. econstructor. exists e2, σ2, efs. - econstructor. instantiate (2 := []). reflexivity. reflexivity. - assert (is_Some (to_val e2)) as He2. - { unfold Atomic in A. specialize A with σ1 e2 κs2 σ2 efs. apply A. apply H. } - unfold is_Some in He2. destruct He2 as [w He2]. apply of_to_val in He2. - instantiate (1 := κs2 ++ [(p, (match to_val e2 with Some w => w | _ => v end, v))]). - subst e2. simpl. constructor. apply prim_step_to_val_is_head_step. done. } - iMod "XXX" as "[$ [WPe [Hσ Hκ]]]". - destruct (decide (κ = [])) as [->|HNeq]. - - iMod ("WPe" $! σ1 [] κs n with "[$Hσ $Hκ]") as "[Hs WPe]". iModIntro. + iIntros (A He) "Hp WPe". rewrite !wp_unfold /wp_pre He. inv_head_step. + iIntros (σ1 κ κs n) "[Hσ Hκ]". destruct (decide (κ = [])) as [->|HNeq]. + - iMod ("WPe" $! σ1 [] κs n with "[$Hσ $Hκ]") as "[Hs WPe]". iModIntro. iSplit. + { iDestruct "Hs" as "%". iPureIntro. destruct s; last done. by apply resolve_reducible. } iIntros (e2 σ2 efs step). exfalso. - assert (reducible (Resolve e (Val (LitV (LitProphecy p))) (Val v)) σ1) as HHH. - { exists [], e2, σ2, efs. exact step. } apply prim_head_reducible in HHH. - 2: { apply ectxi_language_sub_redexes_are_values; intros [] **; naive_solver. } - apply head_reducible_prim_step in step; last done. clear HHH. inversion step. - destruct κs0; simpl in H4; discriminate H4. - - apply exists_last in HNeq as [κs' [o ->]]. destruct o as [p' [w' v']]. - rewrite -app_assoc. iMod ("WPe" $! σ1 _ _ n with "[$Hσ $Hκ]") as "[Hs WPe]". - iIntros "!>" (e2 σ2 efs step). - assert (reducible (Resolve e (Val (LitV (LitProphecy p))) (Val v)) σ1) as HHH. - { exists (κs' ++ [(p',(w',v'))]), e2, σ2, efs. exact step. } apply prim_head_reducible in HHH. - 2: { apply ectxi_language_sub_redexes_are_values; intros [] **; naive_solver. } - apply head_reducible_prim_step in step; last done. clear HHH. inversion step; simpl in *. - assert (κs0 = κs' ∧ p = p' ∧ v = v' ∧ v0 = w') as [W1 [W2 [W3 W4]]]. - { apply app_inj_2 in H4; last done. destruct H4 as [H41 H42]. split; first done. - inversion H42. done. } - subst p' v' w' κs0. iMod ("WPe" $! (Val v0) σ2 efs with "[%]") as "WPe". - { econstructor. instantiate (2 := []). reflexivity. simpl; reflexivity. done. } - iModIntro. iNext. iMod "WPe" as "[[$ Hκ] WPe]". - iMod (proph_map_resolve_proph p (v0,v) κs with "[$Hκ $Hp]") as (vs') "[% [$ HPost]]". - subst vs. iModIntro. simpl. rewrite !wp_unfold /wp_pre; simpl. - iDestruct "WPe" as "[HΦ $]". iMod "HΦ". iFrame. iModIntro. simplify_eq. - iApply "HΦ"; first done. iFrame. + assert (reducible (Resolve e (Val (LitV (LitProphecy p))) (Val v)) σ1) as R. + { exists [], e2, σ2, efs. exact step. } + apply prim_head_reducible in R. + + apply head_reducible_prim_step in step; last done. inv_head_step. + destruct κs0; simpl in H4; discriminate H4. + + apply ectxi_language_sub_redexes_are_values; intros [] **; naive_solver. + - apply exists_last in HNeq as [κ' [[p' [w' v']] ->]]. rewrite -app_assoc. + iMod ("WPe" $! σ1 _ _ n with "[$Hσ $Hκ]") as "[Hs WPe]". iModIntro. iSplit. + { iDestruct "Hs" as "%". iPureIntro. destruct s; last done. by apply resolve_reducible. } + iIntros (e2 σ2 efs step). + assert (reducible (Resolve e (Val (LitV (LitProphecy p))) (Val v)) σ1) as R. + { exists (κ' ++ [(p',(w',v'))]), e2, σ2, efs. exact step. } + apply prim_head_reducible in R. + + apply head_reducible_prim_step in step; last done. inversion step; simpl in *. + assert (κs0 = κ' ∧ p = p' ∧ v = v' ∧ v0 = w') as [Eq1 [Eq2 [Eq3 Eq4]]]. + { apply app_inj_2 in H4; last done. destruct H4 as [H41 H42]. + split; first done. by inversion H42. } + subst p' v' w' κs0. iMod ("WPe" $! (Val v0) σ2 efs with "[%]") as "WPe". + { econstructor. instantiate (2 := []). reflexivity. simpl; reflexivity. done. } + iModIntro. iNext. iMod "WPe" as "[[$ Hκ] WPe]". + iMod (proph_map_resolve_proph p (v0,v) κs with "[$Hκ $Hp]") as (vs') "[% [$ HPost]]". + subst vs. iModIntro. simpl. rewrite !wp_unfold /wp_pre; simpl. + iDestruct "WPe" as "[HΦ $]". iMod "HΦ". iFrame. iModIntro. simplify_eq. + iApply "HΦ"; first done. iFrame. + + apply ectxi_language_sub_redexes_are_values; intros [] **; naive_solver. Qed. Lemma wp_skip s E Φ : ▷ Φ (LitV LitUnit) -∗ WP Skip @ s; E {{ Φ }}. -- GitLab From 553a4c1eb37807a19d08c55da26430016a3f8b65 Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Wed, 15 May 2019 10:29:27 +0200 Subject: [PATCH 08/28] Revert changes in proph_map and use parameter. --- theories/base_logic/lib/proph_map.v | 25 ++++++++++++------------- theories/heap_lang/adequacy.v | 4 ++-- theories/heap_lang/lifting.v | 2 +- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/theories/base_logic/lib/proph_map.v b/theories/base_logic/lib/proph_map.v index d10910666..c1a990384 100644 --- a/theories/base_logic/lib/proph_map.v +++ b/theories/base_logic/lib/proph_map.v @@ -4,14 +4,14 @@ From iris.proofmode Require Import tactics. Set Default Proof Using "Type". Import uPred. -Local Notation proph_map P V := (gmap P (list (V * V))). -Definition proph_val_list (P V : Type) := list (P * (V * V)). +Local Notation proph_map P V := (gmap P (list V)). +Definition proph_val_list (P V : Type) := list (P * V). Definition proph_mapUR (P V : Type) `{Countable P} : ucmraT := - gmapUR P $ exclR $ listC $ prodC (leibnizC V) (leibnizC V). + gmapUR P $ exclR $ listC $ leibnizC V. Definition to_proph_map {P V} `{Countable P} (pvs : proph_map P V) : proph_mapUR P V := - fmap (λ vs, Excl (vs : list (prodC (leibnizC V) (leibnizC V)))) pvs. + fmap (λ vs, Excl (vs : list (leibnizC V))) pvs. (** The CMRA we need. *) Class proph_mapG (P V : Type) (Σ : gFunctors) `{Countable P} := ProphMapG { @@ -37,7 +37,7 @@ Section definitions. Implicit Types p : P. (** The list of resolves for [p] in [pvs]. *) - Fixpoint proph_list_resolves pvs p : list (V * V) := + Fixpoint proph_list_resolves pvs p : list V := match pvs with | [] => [] | (q,v)::pvs => if decide (p = q) then v :: proph_list_resolves pvs p @@ -52,7 +52,7 @@ Section definitions. dom (gset _) R ⊆ ps⌝ ∗ own (proph_map_name pG) (● (to_proph_map R)))%I. - Definition proph_def (p : P) (vs : list (V * V)) : iProp Σ := + Definition proph_def (p : P) (vs : list V) : iProp Σ := own (proph_map_name pG) (◯ {[p := Excl vs]}). Definition proph_aux : seal (@proph_def). by eexists. Qed. @@ -81,14 +81,14 @@ End list_resolves. Section to_proph_map. Context (P V : Type) `{Countable P}. Implicit Types p : P. - Implicit Types vs : list (V * V). + Implicit Types vs : list V. Implicit Types R : proph_map P V. Lemma to_proph_map_valid R : ✓ to_proph_map R. Proof. intros l. rewrite lookup_fmap. by case (R !! l). Qed. - Lemma to_proph_map_insert p (vs : list (prodC (leibnizC V) (leibnizC V))) R : - to_proph_map (<[p := vs]> R) = <[p := Excl vs]> (to_proph_map R). + Lemma to_proph_map_insert p vs R : + to_proph_map (<[p := vs]> R) = <[p := Excl (vs: list (leibnizC V))]> (to_proph_map R). Proof. by rewrite /to_proph_map fmap_insert. Qed. Lemma to_proph_map_delete p R : @@ -119,8 +119,8 @@ Qed. Section proph_map. Context `{proph_mapG P V Σ}. Implicit Types p : P. - Implicit Types v : V * V. - Implicit Types vs : list (V * V). + Implicit Types v : V. + Implicit Types vs : list V. Implicit Types R : proph_map P V. Implicit Types ps : gset P. @@ -159,8 +159,7 @@ Section proph_map. iMod (own_update_2 with "H● Hp") as "[H● H◯]". { eapply auth_update. apply: singleton_local_update. - by rewrite /to_proph_map lookup_fmap HR. - - by apply (exclusive_local_update _ (Excl - (proph_list_resolves pvs p : list (prodC (leibnizC V) (leibnizC V))))). } + - by apply (exclusive_local_update _ (Excl (proph_list_resolves pvs p : list (leibnizC V)))). } rewrite /to_proph_map -fmap_insert. iModIntro. iExists (proph_list_resolves pvs p). iFrame. iSplitR. - iPureIntro. done. diff --git a/theories/heap_lang/adequacy.v b/theories/heap_lang/adequacy.v index 217ca2cae..6f13fbb39 100644 --- a/theories/heap_lang/adequacy.v +++ b/theories/heap_lang/adequacy.v @@ -8,10 +8,10 @@ Set Default Proof Using "Type". Class heapPreG Σ := HeapPreG { heap_preG_iris :> invPreG Σ; heap_preG_heap :> gen_heapPreG loc val Σ; - heap_preG_proph :> proph_mapPreG proph_id val Σ + heap_preG_proph :> proph_mapPreG proph_id (val * val) Σ }. -Definition heapΣ : gFunctors := #[invΣ; gen_heapΣ loc val; proph_mapΣ proph_id val]. +Definition heapΣ : gFunctors := #[invΣ; gen_heapΣ loc val; proph_mapΣ proph_id (val * val)]. Instance subG_heapPreG {Σ} : subG heapΣ Σ → heapPreG Σ. Proof. solve_inG. Qed. diff --git a/theories/heap_lang/lifting.v b/theories/heap_lang/lifting.v index b6d529f4c..9d0414b59 100644 --- a/theories/heap_lang/lifting.v +++ b/theories/heap_lang/lifting.v @@ -13,7 +13,7 @@ Set Default Proof Using "Type". Class heapG Σ := HeapG { heapG_invG : invG Σ; heapG_gen_heapG :> gen_heapG loc val Σ; - heapG_proph_mapG :> proph_mapG proph_id val Σ + heapG_proph_mapG :> proph_mapG proph_id (val * val) Σ }. Instance heapG_irisG `{!heapG Σ} : irisG heap_lang Σ := { -- GitLab From 2da7dbef5f43feeb0f28ebae0e668129535e015d Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Wed, 15 May 2019 11:04:58 +0200 Subject: [PATCH 09/28] Add comments related to Resolve heap_lang. --- theories/heap_lang/lang.v | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/theories/heap_lang/lang.v b/theories/heap_lang/lang.v index 6a02d692b..03dadac04 100644 --- a/theories/heap_lang/lang.v +++ b/theories/heap_lang/lang.v @@ -86,8 +86,10 @@ Bind Scope expr_scope with expr. Bind Scope val_scope with val. (** An observation associates a prophecy variable (identifier) to a pair of -values. The first value is the one that is returned by the (atomic) operation -during which the prophecy resolution happened. *) +values. The first value is the one that was returned by the (atomic) operation +during which the prophecy resolution happened (typically, a boolean when the +wrapped operation is a CAS). The second value is the one that the prophecy +variable was actually resolved to. *) Definition observation : Set := proph_id * (val * val). Notation of_val := Val (only parsing). @@ -355,6 +357,15 @@ Inductive ectx_item := | ResolveLCtx (e : expr) (v2 : val) | ResolveRCtx (e : expr) (e1 : expr). +(** The first argument of [Resolve] is never evaluated through the contextual +closure of reduction. Its evaluation (in one step, to a value) is done while +taking a head reduction step. As a consequence, one should make sure that the +expression [e] indeed reduces to a value atomically (i.e., in one step). + +Note that the expression [Resolve (CAS #l #n (#n + #1)) p v] will not reduce +as one would expect. A workaroud it do use some let-normalization, which in +the above case yields [let: "x" := #n + #1 in Resolve (CAS #l #n "x") p v]. *) + Definition fill_item (Ki : ectx_item) (e : expr) : expr := match Ki with | AppLCtx v2 => App e (of_val v2) @@ -649,6 +660,11 @@ Canonical Structure heap_lang := LanguageOfEctx heap_ectx_lang. (* Prefer heap_lang names over ectx_language names. *) Export heap_lang. +(* The following lemma does not seem to be provable using the current axioms +of [ectxi_language]. The current proof requires a case analysis over context +items ([destruct i] on the last line), which in all cases yields a non-value. +To prove this lemma for [ectxi_language] in general, we would require that a +term of the form [fill_item i e] is never a value if [e] is not a value. *) Lemma to_val_fill_some K e v : to_val (fill K e) = Some v → K = [] ∧ e = Val v. Proof. intro H. destruct K as [|i K]. { apply of_to_val in H. done. } exfalso. -- GitLab From c1f02a16751fef0ee3103a2003d1bc38c3626dea Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Wed, 15 May 2019 11:17:34 +0200 Subject: [PATCH 10/28] Say why strong atomicity is needed in the lifting lemma of Resolve. --- theories/heap_lang/lifting.v | 3 +++ 1 file changed, 3 insertions(+) diff --git a/theories/heap_lang/lifting.v b/theories/heap_lang/lifting.v index 9d0414b59..2126f603a 100644 --- a/theories/heap_lang/lifting.v +++ b/theories/heap_lang/lifting.v @@ -406,6 +406,9 @@ Proof. iModIntro; iSplit=> //. iFrame. by iApply "HΦ". Qed. +(* In the following, strong atomicity is required due to the fact that [e] must +be able to make a head step for [Resolve e _ _] not to be (head) stuck. *) + Lemma resolve_reducible e σ p v : Atomic StronglyAtomic e → reducible e σ → reducible (Resolve e (Val (LitV (LitProphecy p))) (Val v)) σ. -- GitLab From 5042e95106087487732c9303783e3fee2299e624 Mon Sep 17 00:00:00 2001 From: Ralf Jung <jung@mpi-sws.org> Date: Fri, 17 May 2019 16:59:21 +0200 Subject: [PATCH 11/28] clean up proofs a bit --- theories/heap_lang/lifting.v | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/theories/heap_lang/lifting.v b/theories/heap_lang/lifting.v index 2126f603a..816886a34 100644 --- a/theories/heap_lang/lifting.v +++ b/theories/heap_lang/lifting.v @@ -413,11 +413,12 @@ Lemma resolve_reducible e σ p v : Atomic StronglyAtomic e → reducible e σ → reducible (Resolve e (Val (LitV (LitProphecy p))) (Val v)) σ. Proof. - intros A [κ [e' [σ' [efs H]]]]. econstructor. exists e', σ', efs. econstructor. - instantiate (2 := []). reflexivity. reflexivity. assert (∃w, Val w = e') as [w <-]. + intros A [κ [e' [σ' [efs H]]]]. + exists (κ ++ [(p, (match to_val e' with Some w => w | _ => v end, v))]), e', σ', efs. + eapply Ectx_step with (K:=[]); try done. + assert (∃w, Val w = e') as [w <-]. { unfold Atomic in A. apply (A σ e' κ σ' efs) in H. unfold is_Some in H. destruct H as [w H]. exists w. simpl in H. by apply (of_to_val _ _ H). } - instantiate (1 := κ ++ [(p, (match to_val e' with Some w => w | _ => v end, v))]). simpl. constructor. by apply prim_step_to_val_is_head_step. Qed. @@ -437,7 +438,7 @@ Proof. { exists [], e2, σ2, efs. exact step. } apply prim_head_reducible in R. + apply head_reducible_prim_step in step; last done. inv_head_step. - destruct κs0; simpl in H4; discriminate H4. + match goal with H: ?κs ++ _ = [] |- _ => destruct κs; simpl in H; discriminate end. + apply ectxi_language_sub_redexes_are_values; intros [] **; naive_solver. - apply exists_last in HNeq as [κ' [[p' [w' v']] ->]]. rewrite -app_assoc. iMod ("WPe" $! σ1 _ _ n with "[$Hσ $Hκ]") as "[Hs WPe]". iModIntro. iSplit. @@ -446,14 +447,13 @@ Proof. assert (reducible (Resolve e (Val (LitV (LitProphecy p))) (Val v)) σ1) as R. { exists (κ' ++ [(p',(w',v'))]), e2, σ2, efs. exact step. } apply prim_head_reducible in R. - + apply head_reducible_prim_step in step; last done. inversion step; simpl in *. - assert (κs0 = κ' ∧ p = p' ∧ v = v' ∧ v0 = w') as [Eq1 [Eq2 [Eq3 Eq4]]]. - { apply app_inj_2 in H4; last done. destruct H4 as [H41 H42]. - split; first done. by inversion H42. } - subst p' v' w' κs0. iMod ("WPe" $! (Val v0) σ2 efs with "[%]") as "WPe". - { econstructor. instantiate (2 := []). reflexivity. simpl; reflexivity. done. } + + apply head_reducible_prim_step in step; last done. inv_head_step. + match goal with H: _ ++ _ = _ ++ _ |- _ => + apply app_inj_2 in H; last done; destruct H as [-> [=-> -> ->]] end. + iMod ("WPe" $! (Val w') σ2 efs with "[%]") as "WPe". + { eexists [] _ _. reflexivity. simpl; reflexivity. done. } iModIntro. iNext. iMod "WPe" as "[[$ Hκ] WPe]". - iMod (proph_map_resolve_proph p (v0,v) κs with "[$Hκ $Hp]") as (vs') "[% [$ HPost]]". + iMod (proph_map_resolve_proph p' (w',v') κs with "[$Hκ $Hp]") as (vs') "[% [$ HPost]]". subst vs. iModIntro. simpl. rewrite !wp_unfold /wp_pre; simpl. iDestruct "WPe" as "[HΦ $]". iMod "HΦ". iFrame. iModIntro. simplify_eq. iApply "HΦ"; first done. iFrame. -- GitLab From cbc0951bf6cbf15c6f5bc8918857e570811647f3 Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Wed, 29 May 2019 11:09:03 +0200 Subject: [PATCH 12/28] Implement Jacques-Henry's proposal (need cleanup) --- theories/heap_lang/lang.v | 21 +++++--- theories/heap_lang/lifting.v | 97 +++++++++++++++++++++++++++--------- theories/heap_lang/tactics.v | 5 +- 3 files changed, 89 insertions(+), 34 deletions(-) diff --git a/theories/heap_lang/lang.v b/theories/heap_lang/lang.v index 03dadac04..290b311d6 100644 --- a/theories/heap_lang/lang.v +++ b/theories/heap_lang/lang.v @@ -354,8 +354,9 @@ Inductive ectx_item := | CasRCtx (e0 : expr) (e1 : expr) | FaaLCtx (v2 : val) | FaaRCtx (e1 : expr) - | ResolveLCtx (e : expr) (v2 : val) - | ResolveRCtx (e : expr) (e1 : expr). + | ResolveLCtx (ctx : ectx_item) (v1 : val) (v2 : val) + | ResolveMCtx (e0 : expr) (v2 : val) + | ResolveRCtx (e0 : expr) (e1 : expr). (** The first argument of [Resolve] is never evaluated through the contextual closure of reduction. Its evaluation (in one step, to a value) is done while @@ -366,7 +367,7 @@ Note that the expression [Resolve (CAS #l #n (#n + #1)) p v] will not reduce as one would expect. A workaroud it do use some let-normalization, which in the above case yields [let: "x" := #n + #1 in Resolve (CAS #l #n "x") p v]. *) -Definition fill_item (Ki : ectx_item) (e : expr) : expr := +Fixpoint fill_item (Ki : ectx_item) (e : expr) : expr := match Ki with | AppLCtx v2 => App e (of_val v2) | AppRCtx e1 => App e1 e @@ -391,7 +392,8 @@ Definition fill_item (Ki : ectx_item) (e : expr) : expr := | CasRCtx e0 e1 => CAS e0 e1 e | FaaLCtx v2 => FAA e (Val v2) | FaaRCtx e1 => FAA e1 e - | ResolveLCtx ex v2 => Resolve ex e (Val v2) + | ResolveLCtx K v1 v2 => Resolve (fill_item K e) (Val v1) (Val v2) + | ResolveMCtx ex v2 => Resolve ex e (Val v2) | ResolveRCtx ex e1 => Resolve ex e1 e end. @@ -610,23 +612,26 @@ Inductive head_step : expr → state → list observation → expr → state → (** Basic properties about the language *) Instance fill_item_inj Ki : Inj (=) (=) (fill_item Ki). -Proof. destruct Ki; intros ???; simplify_eq/=; auto with f_equal. Qed. +Proof. induction Ki; intros ???; simplify_eq/=; auto with f_equal. Qed. Lemma fill_item_val Ki e : is_Some (to_val (fill_item Ki e)) → is_Some (to_val e). -Proof. intros [v ?]. destruct Ki; simplify_option_eq; eauto. Qed. +Proof. intros [v ?]. induction Ki; simplify_option_eq; eauto. Qed. Lemma val_head_stuck e1 σ1 κ e2 σ2 efs : head_step e1 σ1 κ e2 σ2 efs → to_val e1 = None. Proof. destruct 1; naive_solver. Qed. Lemma head_ctx_step_val Ki e σ1 κ e2 σ2 efs : head_step (fill_item Ki e) σ1 κ e2 σ2 efs → is_Some (to_val e). -Proof. destruct Ki; inversion_clear 1; simplify_option_eq; by eauto. Qed. +Proof. revert κ e2. induction Ki; inversion_clear 1; simplify_option_eq; eauto. Qed. Lemma fill_item_no_val_inj Ki1 Ki2 e1 e2 : to_val e1 = None → to_val e2 = None → fill_item Ki1 e1 = fill_item Ki2 e2 → Ki1 = Ki2. -Proof. destruct Ki1, Ki2; intros; by simplify_eq. Qed. +Proof. + revert Ki1. induction Ki2; induction Ki1; intros; simplify_eq; try done. + f_equal. eapply IHKi2; done. +Qed. Lemma alloc_fresh v n σ : let l := fresh_locs (dom (gset loc) σ.(heap)) n in diff --git a/theories/heap_lang/lifting.v b/theories/heap_lang/lifting.v index 816886a34..d1433dfb3 100644 --- a/theories/heap_lang/lifting.v +++ b/theories/heap_lang/lifting.v @@ -84,12 +84,43 @@ Instance skip_atomic s : Atomic s Skip. Proof. solve_atomic. Qed. Instance new_proph_atomic s : Atomic s NewProph. Proof. solve_atomic. Qed. + +Lemma fill_app {Λ} Ks1 Ks2 e : @fill Λ (Ks1 ++ Ks2) e = @fill Λ Ks2 (@fill Λ Ks1 e). +Proof. rewrite /fill foldl_app //. Qed. + +Lemma irreducible_resolve e v1 v2 σ : + irreducible e σ → irreducible (Resolve e (Val v1) (Val v2)) σ. +Proof. + intros H κs ** [Ks e1' e2' Hfill -> step]. simpl in *. + induction Ks as [|K Ks _] using rev_ind; simpl in Hfill. + - subst e1'. inversion step. eapply H. by apply head_prim_step. + - rewrite fill_app /= in Hfill. destruct K; inversion Hfill; subst; clear Hfill. + + apply (H κs (fill_item K (foldl (flip fill_item) e2' Ks)) σ' efs). + econstructor 1 with (K := Ks ++ [K]); last done; simpl; by rewrite fill_app. + + assert (to_val (fill Ks e1') = Some v1); first by rewrite -H2 //. + apply to_val_fill_some in H0. destruct H0 as [-> ->]. inversion step. + + assert (to_val (fill Ks e1') = Some v2); first by rewrite -H3 //. + apply to_val_fill_some in H0. destruct H0 as [-> ->]. inversion step. +Qed. + Instance proph_resolve_atomic s e v1 v2 : Atomic s e → Atomic s (Resolve e (Val v1) (Val v2)). Proof. - intro H. apply ectx_language_atomic. - - inversion 1. eapply H. apply head_prim_step. done. - - apply ectxi_language_sub_redexes_are_values; intros [] **; naive_solver. + rename e into e1. intros H σ1 e2 κ σ2 efs [Ks e1' e2' Hfill -> step]. + simpl in *. induction Ks as [|K Ks _] using rev_ind; simpl in Hfill. + - subst. inversion_clear step. by apply (H σ1 (Val v) κs σ2 efs), head_prim_step. + - rewrite fill_app. rewrite fill_app in Hfill. + destruct K; inversion Hfill; clear Hfill; subst. + + refine (_ (H σ1 (fill (Ks ++ [K]) e2') _ σ2 efs _)); last first. + econstructor 1 with (K := Ks ++ [K]); try done. simpl. by rewrite fill_app. + destruct s; intro Hs; simpl in *. + * destruct Hs as [v Hs]. apply to_val_fill_some in Hs. + destruct Hs as [Contra _]. destruct Ks; inversion Contra. + * apply irreducible_resolve. rewrite fill_app in Hs. done. + + induction Ks as [|K Ks _] using rev_ind. { simpl in H2. subst. inversion step. } + rewrite fill_app in H2. simpl in H2. destruct K; inversion H2. + + induction Ks as [|K Ks _] using rev_ind. { simpl in H3. subst. inversion step. } + rewrite fill_app in H3. simpl in H3. destruct K; inversion H3. Qed. Instance resolve_proph_atomic s v1 v2 : Atomic s (ResolveProph (Val v1) (Val v2)). Proof. by apply proph_resolve_atomic, skip_atomic. Qed. @@ -422,6 +453,32 @@ Proof. simpl. constructor. by apply prim_step_to_val_is_head_step. Qed. +Lemma step_resolve e p v σ1 κ e2 σ2 efs : + Atomic StronglyAtomic e → + prim_step (Resolve e (Val p) (Val v)) σ1 κ e2 σ2 efs → + head_step (Resolve e (Val p) (Val v)) σ1 κ e2 σ2 efs. +Proof. + intros A [Ks e1' e2' Hfill -> step]. simpl in *. + induction Ks as [|K Ks _] using rev_ind. + + simpl in *. subst. inversion step. subst. constructor. done. + + rewrite fill_app /= in Hfill. destruct K; inversion Hfill; subst; clear Hfill. + - rewrite fill_app /=. + assert (fill_item K (fill Ks e1') = fill (Ks ++ [K]) e1') as Eq1; first by rewrite fill_app. + assert (fill_item K (fill Ks e2') = fill (Ks ++ [K]) e2') as Eq2; first by rewrite fill_app. + rewrite Eq1 in A. + assert (is_Some (to_val (fill (Ks ++ [K]) e2'))) as He2'. { + refine (A σ1 _ κ σ2 efs _). + refine (Ectx_step (fill (Ks ++ [K]) e1') σ1 κ + (fill (Ks ++ [K]) e2') σ2 efs (Ks ++ [K]) e1' e2' eq_refl eq_refl step). + } + unfold is_Some in He2'. destruct He2' as [v HEq]. apply to_val_fill_some in HEq. + destruct HEq as [Contra _]. destruct Ks; done. + - assert (to_val (fill Ks e1') = Some p); first by rewrite -H1 //. + apply to_val_fill_some in H. destruct H as [-> ->]. inversion step. + - assert (to_val (fill Ks e1') = Some v); first by rewrite -H2 //. + apply to_val_fill_some in H. destruct H as [-> ->]. inversion step. +Qed. + Lemma wp_resolve s E e Φ p v vs : Atomic StronglyAtomic e → language.to_val e = None → @@ -433,31 +490,23 @@ Proof. iIntros (σ1 κ κs n) "[Hσ Hκ]". destruct (decide (κ = [])) as [->|HNeq]. - iMod ("WPe" $! σ1 [] κs n with "[$Hσ $Hκ]") as "[Hs WPe]". iModIntro. iSplit. { iDestruct "Hs" as "%". iPureIntro. destruct s; last done. by apply resolve_reducible. } - iIntros (e2 σ2 efs step). exfalso. - assert (reducible (Resolve e (Val (LitV (LitProphecy p))) (Val v)) σ1) as R. - { exists [], e2, σ2, efs. exact step. } - apply prim_head_reducible in R. - + apply head_reducible_prim_step in step; last done. inv_head_step. - match goal with H: ?κs ++ _ = [] |- _ => destruct κs; simpl in H; discriminate end. - + apply ectxi_language_sub_redexes_are_values; intros [] **; naive_solver. + iIntros (e2 σ2 efs step). exfalso. apply step_resolve in step; last done. inversion step. + destruct κs0; inversion H4. - apply exists_last in HNeq as [κ' [[p' [w' v']] ->]]. rewrite -app_assoc. iMod ("WPe" $! σ1 _ _ n with "[$Hσ $Hκ]") as "[Hs WPe]". iModIntro. iSplit. { iDestruct "Hs" as "%". iPureIntro. destruct s; last done. by apply resolve_reducible. } iIntros (e2 σ2 efs step). - assert (reducible (Resolve e (Val (LitV (LitProphecy p))) (Val v)) σ1) as R. - { exists (κ' ++ [(p',(w',v'))]), e2, σ2, efs. exact step. } - apply prim_head_reducible in R. - + apply head_reducible_prim_step in step; last done. inv_head_step. - match goal with H: _ ++ _ = _ ++ _ |- _ => - apply app_inj_2 in H; last done; destruct H as [-> [=-> -> ->]] end. - iMod ("WPe" $! (Val w') σ2 efs with "[%]") as "WPe". - { eexists [] _ _. reflexivity. simpl; reflexivity. done. } - iModIntro. iNext. iMod "WPe" as "[[$ Hκ] WPe]". - iMod (proph_map_resolve_proph p' (w',v') κs with "[$Hκ $Hp]") as (vs') "[% [$ HPost]]". - subst vs. iModIntro. simpl. rewrite !wp_unfold /wp_pre; simpl. - iDestruct "WPe" as "[HΦ $]". iMod "HΦ". iFrame. iModIntro. simplify_eq. - iApply "HΦ"; first done. iFrame. - + apply ectxi_language_sub_redexes_are_values; intros [] **; naive_solver. + apply step_resolve in step; last done. inversion step. + match goal with H: _ ++ _ = _ ++ _ |- _ => + apply app_inj_2 in H; last done; destruct H as [-> [=-> -> ->]] end. + subst. + iMod ("WPe" $! (Val w') σ2 efs with "[%]") as "WPe". + { eexists [] _ _. reflexivity. simpl; reflexivity. done. } + iModIntro. iNext. iMod "WPe" as "[[$ Hκ] WPe]". + iMod (proph_map_resolve_proph p' (w',v') κs with "[$Hκ $Hp]") as (vs') "[% [$ HPost]]". + subst vs. iModIntro. simpl. rewrite !wp_unfold /wp_pre; simpl. + iDestruct "WPe" as "[HΦ $]". iMod "HΦ". iFrame. iModIntro. simplify_eq. + iApply "HΦ"; first done. iFrame. Qed. Lemma wp_skip s E Φ : ▷ Φ (LitV LitUnit) -∗ WP Skip @ s; E {{ Φ }}. diff --git a/theories/heap_lang/tactics.v b/theories/heap_lang/tactics.v index dd586631b..36179e28b 100644 --- a/theories/heap_lang/tactics.v +++ b/theories/heap_lang/tactics.v @@ -32,6 +32,7 @@ Ltac reshape_expr e tac := | CAS ?e0 ?e1 ?e2 => go (CasRCtx e0 e1 :: K) e2 | FAA ?e (Val ?v) => go (FaaLCtx v :: K) e | FAA ?e1 ?e2 => go (FaaRCtx e1 :: K) e2 - | Resolve ?e (Val ?v) => go (ResolveLCtx v :: K) e - | Resolve ?e1 ?e2 => go (ResolveRCtx e1 :: K) e2 + | Resolve ?ex (Val ?v1) (Val ?v2) => go (ResolveLCtx v1 v2 :: K) ex + | Resolve ?ex ?e1 (Val ?v2) => go (ResolveMCtx ex v2 :: K) e1 + | Resolve ?ex ?e1 ?e2 => go (ResolveRCtx ex e1 :: K) e2 end in go (@nil ectx_item) e. -- GitLab From e53f1992ffb01ba5f501b36f0ed3a4093043d46e Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Thu, 30 May 2019 01:26:37 +0200 Subject: [PATCH 13/28] Cleanup of proofs + failed attempt for [reshape_expr]. --- theories/heap_lang/lang.v | 28 ++++++++++----- theories/heap_lang/lifting.v | 69 ++++++++++++------------------------ theories/heap_lang/tactics.v | 40 ++++++++++++++++++++- 3 files changed, 81 insertions(+), 56 deletions(-) diff --git a/theories/heap_lang/lang.v b/theories/heap_lang/lang.v index 290b311d6..92400c95e 100644 --- a/theories/heap_lang/lang.v +++ b/theories/heap_lang/lang.v @@ -358,14 +358,11 @@ Inductive ectx_item := | ResolveMCtx (e0 : expr) (v2 : val) | ResolveRCtx (e0 : expr) (e1 : expr). -(** The first argument of [Resolve] is never evaluated through the contextual -closure of reduction. Its evaluation (in one step, to a value) is done while -taking a head reduction step. As a consequence, one should make sure that the -expression [e] indeed reduces to a value atomically (i.e., in one step). - -Note that the expression [Resolve (CAS #l #n (#n + #1)) p v] will not reduce -as one would expect. A workaroud it do use some let-normalization, which in -the above case yields [let: "x" := #n + #1 in Resolve (CAS #l #n "x") p v]. *) +(** The first argument of [Resolve] is not completely evaluated (down to a +value) by contextual closure: no head steps (i.e., surface reductions) are +taken. This means that [Resolve (CAS #l #n (#n + #1)) #p #v] will evaluate +to [Resolve (CAS #l #n #(n + 1)) #p #v] using context steps, but no further +step will be taken (by the contextual closure). *) Fixpoint fill_item (Ki : ectx_item) (e : expr) : expr := match Ki with @@ -686,6 +683,21 @@ Proof. apply to_val_fill_some in H3 as [-> ->]. subst e. done. Qed. +Lemma irreducible_resolve e v1 v2 σ : + irreducible e σ → irreducible (Resolve e (Val v1) (Val v2)) σ. +Proof. + intros H κs ** [Ks e1' e2' Hfill -> step]. simpl in *. + induction Ks as [|K Ks _] using rev_ind; simpl in Hfill. + - subst e1'. inversion step. eapply H. by apply head_prim_step. + - rewrite fill_app /= in Hfill. destruct K; inversion Hfill; subst; clear Hfill. + + apply (H κs (fill_item K (foldl (flip fill_item) e2' Ks)) σ' efs). + econstructor 1 with (K := Ks ++ [K]); last done; simpl; by rewrite fill_app. + + assert (to_val (fill Ks e1') = Some v1); first by rewrite -H2 //. + apply to_val_fill_some in H0. destruct H0 as [-> ->]. inversion step. + + assert (to_val (fill Ks e1') = Some v2); first by rewrite -H3 //. + apply to_val_fill_some in H0. destruct H0 as [-> ->]. inversion step. +Qed. + (** Define some derived forms. *) Notation Lam x e := (Rec BAnon x e) (only parsing). Notation Let x e1 e2 := (App (Lam x e2) e1) (only parsing). diff --git a/theories/heap_lang/lifting.v b/theories/heap_lang/lifting.v index d1433dfb3..973ce60f4 100644 --- a/theories/heap_lang/lifting.v +++ b/theories/heap_lang/lifting.v @@ -85,24 +85,6 @@ Proof. solve_atomic. Qed. Instance new_proph_atomic s : Atomic s NewProph. Proof. solve_atomic. Qed. -Lemma fill_app {Λ} Ks1 Ks2 e : @fill Λ (Ks1 ++ Ks2) e = @fill Λ Ks2 (@fill Λ Ks1 e). -Proof. rewrite /fill foldl_app //. Qed. - -Lemma irreducible_resolve e v1 v2 σ : - irreducible e σ → irreducible (Resolve e (Val v1) (Val v2)) σ. -Proof. - intros H κs ** [Ks e1' e2' Hfill -> step]. simpl in *. - induction Ks as [|K Ks _] using rev_ind; simpl in Hfill. - - subst e1'. inversion step. eapply H. by apply head_prim_step. - - rewrite fill_app /= in Hfill. destruct K; inversion Hfill; subst; clear Hfill. - + apply (H κs (fill_item K (foldl (flip fill_item) e2' Ks)) σ' efs). - econstructor 1 with (K := Ks ++ [K]); last done; simpl; by rewrite fill_app. - + assert (to_val (fill Ks e1') = Some v1); first by rewrite -H2 //. - apply to_val_fill_some in H0. destruct H0 as [-> ->]. inversion step. - + assert (to_val (fill Ks e1') = Some v2); first by rewrite -H3 //. - apply to_val_fill_some in H0. destruct H0 as [-> ->]. inversion step. -Qed. - Instance proph_resolve_atomic s e v1 v2 : Atomic s e → Atomic s (Resolve e (Val v1) (Val v2)). Proof. @@ -114,14 +96,14 @@ Proof. + refine (_ (H σ1 (fill (Ks ++ [K]) e2') _ σ2 efs _)); last first. econstructor 1 with (K := Ks ++ [K]); try done. simpl. by rewrite fill_app. destruct s; intro Hs; simpl in *. - * destruct Hs as [v Hs]. apply to_val_fill_some in Hs. - destruct Hs as [Contra _]. destruct Ks; inversion Contra. - * apply irreducible_resolve. rewrite fill_app in Hs. done. + * destruct Hs as [v Hs]. apply to_val_fill_some in Hs. by destruct Hs, Ks. + * apply irreducible_resolve. by rewrite fill_app in Hs. + induction Ks as [|K Ks _] using rev_ind. { simpl in H2. subst. inversion step. } rewrite fill_app in H2. simpl in H2. destruct K; inversion H2. + induction Ks as [|K Ks _] using rev_ind. { simpl in H3. subst. inversion step. } rewrite fill_app in H3. simpl in H3. destruct K; inversion H3. Qed. + Instance resolve_proph_atomic s v1 v2 : Atomic s (ResolveProph (Val v1) (Val v2)). Proof. by apply proph_resolve_atomic, skip_atomic. Qed. @@ -460,19 +442,16 @@ Lemma step_resolve e p v σ1 κ e2 σ2 efs : Proof. intros A [Ks e1' e2' Hfill -> step]. simpl in *. induction Ks as [|K Ks _] using rev_ind. - + simpl in *. subst. inversion step. subst. constructor. done. + + simpl in *. subst. inversion step. by constructor. + rewrite fill_app /= in Hfill. destruct K; inversion Hfill; subst; clear Hfill. - - rewrite fill_app /=. - assert (fill_item K (fill Ks e1') = fill (Ks ++ [K]) e1') as Eq1; first by rewrite fill_app. - assert (fill_item K (fill Ks e2') = fill (Ks ++ [K]) e2') as Eq2; first by rewrite fill_app. - rewrite Eq1 in A. - assert (is_Some (to_val (fill (Ks ++ [K]) e2'))) as He2'. { - refine (A σ1 _ κ σ2 efs _). - refine (Ectx_step (fill (Ks ++ [K]) e1') σ1 κ - (fill (Ks ++ [K]) e2') σ2 efs (Ks ++ [K]) e1' e2' eq_refl eq_refl step). - } - unfold is_Some in He2'. destruct He2' as [v HEq]. apply to_val_fill_some in HEq. - destruct HEq as [Contra _]. destruct Ks; done. + - assert (fill_item K (fill Ks e1') = fill (Ks ++ [K]) e1') as Eq1; + first by rewrite fill_app. + assert (fill_item K (fill Ks e2') = fill (Ks ++ [K]) e2') as Eq2; + first by rewrite fill_app. + rewrite fill_app /=. rewrite Eq1 in A. + assert (is_Some (to_val (fill (Ks ++ [K]) e2'))) as H. + { apply (A σ1 _ κ σ2 efs). eapply Ectx_step with (K0 := Ks ++ [K]); done. } + destruct H as [v H]. apply to_val_fill_some in H. by destruct H, Ks. - assert (to_val (fill Ks e1') = Some p); first by rewrite -H1 //. apply to_val_fill_some in H. destruct H as [-> ->]. inversion step. - assert (to_val (fill Ks e1') = Some v); first by rewrite -H2 //. @@ -486,27 +465,23 @@ Lemma wp_resolve s E e Φ p v vs : WP e @ s; E {{ r, ∀ vs', ⌜vs = (r, v)::vs'⌝ -∗ proph p vs' -∗ Φ r }} -∗ WP Resolve e (Val $ LitV $ LitProphecy p) (Val v) @ s; E {{ Φ }}. Proof. - iIntros (A He) "Hp WPe". rewrite !wp_unfold /wp_pre He. inv_head_step. + iIntros (A He) "Hp WPe". rewrite !wp_unfold /wp_pre He. simpl in *. iIntros (σ1 κ κs n) "[Hσ Hκ]". destruct (decide (κ = [])) as [->|HNeq]. - iMod ("WPe" $! σ1 [] κs n with "[$Hσ $Hκ]") as "[Hs WPe]". iModIntro. iSplit. - { iDestruct "Hs" as "%". iPureIntro. destruct s; last done. by apply resolve_reducible. } - iIntros (e2 σ2 efs step). exfalso. apply step_resolve in step; last done. inversion step. - destruct κs0; inversion H4. + { iDestruct "Hs" as "%". iPureIntro. destruct s; [ by apply resolve_reducible | done]. } + iIntros (e2 σ2 efs step). exfalso. apply step_resolve in step; last done. + inversion step. match goal with H: ?κs ++ [_] = [] |- _ => by destruct κs end. - apply exists_last in HNeq as [κ' [[p' [w' v']] ->]]. rewrite -app_assoc. iMod ("WPe" $! σ1 _ _ n with "[$Hσ $Hκ]") as "[Hs WPe]". iModIntro. iSplit. - { iDestruct "Hs" as "%". iPureIntro. destruct s; last done. by apply resolve_reducible. } - iIntros (e2 σ2 efs step). - apply step_resolve in step; last done. inversion step. + { iDestruct "Hs" as "%". iPureIntro. destruct s; [ by apply resolve_reducible | done]. } + iIntros (e2 σ2 efs step). apply step_resolve in step; last done. inversion step. match goal with H: _ ++ _ = _ ++ _ |- _ => - apply app_inj_2 in H; last done; destruct H as [-> [=-> -> ->]] end. - subst. - iMod ("WPe" $! (Val w') σ2 efs with "[%]") as "WPe". - { eexists [] _ _. reflexivity. simpl; reflexivity. done. } + apply app_inj_2 in H; last done; destruct H as [-> [=-> -> ->]] end. subst. + iMod ("WPe" $! (Val w') σ2 efs with "[%]") as "WPe". { eexists [] _ _; try done. } iModIntro. iNext. iMod "WPe" as "[[$ Hκ] WPe]". iMod (proph_map_resolve_proph p' (w',v') κs with "[$Hκ $Hp]") as (vs') "[% [$ HPost]]". - subst vs. iModIntro. simpl. rewrite !wp_unfold /wp_pre; simpl. - iDestruct "WPe" as "[HΦ $]". iMod "HΦ". iFrame. iModIntro. simplify_eq. - iApply "HΦ"; first done. iFrame. + subst vs. iModIntro. rewrite !wp_unfold /wp_pre /=. + iDestruct "WPe" as "[HΦ $]". iMod "HΦ". iModIntro. iApply "HΦ"; [ done | iFrame ]. Qed. Lemma wp_skip s E Φ : ▷ Φ (LitV LitUnit) -∗ WP Skip @ s; E {{ Φ }}. diff --git a/theories/heap_lang/tactics.v b/theories/heap_lang/tactics.v index 36179e28b..051901cf4 100644 --- a/theories/heap_lang/tactics.v +++ b/theories/heap_lang/tactics.v @@ -32,7 +32,45 @@ Ltac reshape_expr e tac := | CAS ?e0 ?e1 ?e2 => go (CasRCtx e0 e1 :: K) e2 | FAA ?e (Val ?v) => go (FaaLCtx v :: K) e | FAA ?e1 ?e2 => go (FaaRCtx e1 :: K) e2 - | Resolve ?ex (Val ?v1) (Val ?v2) => go (ResolveLCtx v1 v2 :: K) ex + | Resolve ?ex (Val ?v1) (Val ?v2) => fail 0 "reshape_expr: not implemented" (* FIXME *) | Resolve ?ex ?e1 (Val ?v2) => go (ResolveMCtx ex v2 :: K) e1 | Resolve ?ex ?e1 ?e2 => go (ResolveRCtx ex e1 :: K) e2 end in go (@nil ectx_item) e. + +(* Failed attempt. +Definition build_ResolveLCtx Ki pairs := + fold_right (fun p i => ResolveLCtx i p.1 p.2) pairs Ki. + +Ltac reshape_expr e tac := + let rec go K vs e := + match e with + | _ => match vs with nil => tac K e | _ => () end + | App ?e (Val ?v) => go (build_ResolveLCtx (AppLCtx v) vs :: K) nil e + | App ?e1 ?e2 => go (build_ResolveLCtx (AppRCtx e1) vs :: K) nil e2 + | UnOp ?op ?e => go (build_ResolveLCtx (UnOpCtx op) vs :: K) nil e + | BinOp ?op ?e (Val ?v) => go (build_ResolveLCtx (BinOpLCtx op v) vs :: K) nil e + | BinOp ?op ?e1 ?e2 => go (build_ResolveLCtx (BinOpRCtx op e1) vs :: K) nil e2 + | If ?e0 ?e1 ?e2 => go (build_ResolveLCtx (IfCtx e1 e2) vs :: K) nil e0 + | Pair ?e (Val ?v) => go (build_ResolveLCtx (PairLCtx v) vs :: K) nil e + | Pair ?e1 ?e2 => go (build_ResolveLCtx (PairRCtx e1) vs :: K) nil e2 + | Fst ?e => go (build_ResolveLCtx FstCtx vs :: K) nil e + | Snd ?e => go (build_ResolveLCtx SndCtx vs :: K) nil e + | InjL ?e => go (build_ResolveLCtx InjLCtx vs :: K) nil e + | InjR ?e => go (build_ResolveLCtx InjRCtx vs :: K) nil e + | Case ?e0 ?e1 ?e2 => go (build_ResolveLCtx (CaseCtx e1 e2) vs :: K) nil e0 + | Alloc ?e => go (build_ResolveLCtx AllocCtx vs :: K) nil e + | Load ?e => go (build_ResolveLCtx LoadCtx vs :: K) nil e + | Store ?e (Val ?v) => go (build_ResolveLCtx (StoreLCtx v) vs :: K) nil e + | Store ?e1 ?e2 => go (build_ResolveLCtx (StoreRCtx e1) vs :: K) nil e2 + | CAS ?e0 (Val ?v1) (Val ?v2) => go (build_ResolveLCtx (CasLCtx v1 v2) vs :: K) nil e0 + | CAS ?e0 ?e1 (Val ?v2) => go (build_ResolveLCtx (CasMCtx e0 v2) vs :: K) nil e1 + | CAS ?e0 ?e1 ?e2 => go (build_ResolveLCtx (CasRCtx e0 e1) vs :: K) nil e2 + | FAA ?e (Val ?v) => go (build_ResolveLCtx (FaaLCtx v) vs :: K) nil e + | FAA ?e1 ?e2 => go (build_ResolveLCtx (FaaRCtx e1) vs :: K) nil e2 + | Resolve ?ex (Val ?v1) (Val ?v2) => go K ((v1,v2) :: vs) ex + | Resolve ?ex ?e1 (Val ?v2) => go (build_ResolveLCtx (ResolveMCtx ex v2) vs :: K) nil e1 + | Resolve ?ex ?e1 ?e2 => go (build_ResolveLCtx (ResolveRCtx ex e1) vs :: K) nil e2 + end + in + go (@nil ectx_item) (@nil (list (val * val))) e. +*) -- GitLab From 22398d20a84bb56cce9e53d1bd8ca2f471c8b8f9 Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Thu, 30 May 2019 13:11:39 +0200 Subject: [PATCH 14/28] Fix for [reshape_expr] given by Robbert. --- theories/heap_lang/tactics.v | 95 ++++++++++++------------------------ 1 file changed, 32 insertions(+), 63 deletions(-) diff --git a/theories/heap_lang/tactics.v b/theories/heap_lang/tactics.v index 051901cf4..d9597a4e4 100644 --- a/theories/heap_lang/tactics.v +++ b/theories/heap_lang/tactics.v @@ -5,72 +5,41 @@ Import heap_lang. (** The tactic [reshape_expr e tac] decomposes the expression [e] into an evaluation context [K] and a subexpression [e']. It calls the tactic [tac K e'] for each possible decomposition until [tac] succeeds. *) -Ltac reshape_expr e tac := - let rec go K e := - match e with - | _ => tac K e - | App ?e (Val ?v) => go (AppLCtx v :: K) e - | App ?e1 ?e2 => go (AppRCtx e1 :: K) e2 - | UnOp ?op ?e => go (UnOpCtx op :: K) e - | BinOp ?op ?e (Val ?v) => go (BinOpLCtx op v :: K) e - | BinOp ?op ?e1 ?e2 => go (BinOpRCtx op e1 :: K) e2 - | If ?e0 ?e1 ?e2 => go (IfCtx e1 e2 :: K) e0 - | Pair ?e (Val ?v) => go (PairLCtx v :: K) e - | Pair ?e1 ?e2 => go (PairRCtx e1 :: K) e2 - | Fst ?e => go (FstCtx :: K) e - | Snd ?e => go (SndCtx :: K) e - | InjL ?e => go (InjLCtx :: K) e - | InjR ?e => go (InjRCtx :: K) e - | Case ?e0 ?e1 ?e2 => go (CaseCtx e1 e2 :: K) e0 - | AllocN ?e (Val ?v) => go (AllocNLCtx v :: K) e - | AllocN ?e1 ?e2 => go (AllocNRCtx e1 :: K) e2 - | Load ?e => go (LoadCtx :: K) e - | Store ?e (Val ?v) => go (StoreLCtx v :: K) e - | Store ?e1 ?e2 => go (StoreRCtx e1 :: K) e2 - | CAS ?e0 (Val ?v1) (Val ?v2) => go (CasLCtx v1 v2 :: K) e0 - | CAS ?e0 ?e1 (Val ?v2) => go (CasMCtx e0 v2 :: K) e1 - | CAS ?e0 ?e1 ?e2 => go (CasRCtx e0 e1 :: K) e2 - | FAA ?e (Val ?v) => go (FaaLCtx v :: K) e - | FAA ?e1 ?e2 => go (FaaRCtx e1 :: K) e2 - | Resolve ?ex (Val ?v1) (Val ?v2) => fail 0 "reshape_expr: not implemented" (* FIXME *) - | Resolve ?ex ?e1 (Val ?v2) => go (ResolveMCtx ex v2 :: K) e1 - | Resolve ?ex ?e1 ?e2 => go (ResolveRCtx ex e1 :: K) e2 - end in go (@nil ectx_item) e. - -(* Failed attempt. -Definition build_ResolveLCtx Ki pairs := - fold_right (fun p i => ResolveLCtx i p.1 p.2) pairs Ki. - Ltac reshape_expr e tac := let rec go K vs e := match e with - | _ => match vs with nil => tac K e | _ => () end - | App ?e (Val ?v) => go (build_ResolveLCtx (AppLCtx v) vs :: K) nil e - | App ?e1 ?e2 => go (build_ResolveLCtx (AppRCtx e1) vs :: K) nil e2 - | UnOp ?op ?e => go (build_ResolveLCtx (UnOpCtx op) vs :: K) nil e - | BinOp ?op ?e (Val ?v) => go (build_ResolveLCtx (BinOpLCtx op v) vs :: K) nil e - | BinOp ?op ?e1 ?e2 => go (build_ResolveLCtx (BinOpRCtx op e1) vs :: K) nil e2 - | If ?e0 ?e1 ?e2 => go (build_ResolveLCtx (IfCtx e1 e2) vs :: K) nil e0 - | Pair ?e (Val ?v) => go (build_ResolveLCtx (PairLCtx v) vs :: K) nil e - | Pair ?e1 ?e2 => go (build_ResolveLCtx (PairRCtx e1) vs :: K) nil e2 - | Fst ?e => go (build_ResolveLCtx FstCtx vs :: K) nil e - | Snd ?e => go (build_ResolveLCtx SndCtx vs :: K) nil e - | InjL ?e => go (build_ResolveLCtx InjLCtx vs :: K) nil e - | InjR ?e => go (build_ResolveLCtx InjRCtx vs :: K) nil e - | Case ?e0 ?e1 ?e2 => go (build_ResolveLCtx (CaseCtx e1 e2) vs :: K) nil e0 - | Alloc ?e => go (build_ResolveLCtx AllocCtx vs :: K) nil e - | Load ?e => go (build_ResolveLCtx LoadCtx vs :: K) nil e - | Store ?e (Val ?v) => go (build_ResolveLCtx (StoreLCtx v) vs :: K) nil e - | Store ?e1 ?e2 => go (build_ResolveLCtx (StoreRCtx e1) vs :: K) nil e2 - | CAS ?e0 (Val ?v1) (Val ?v2) => go (build_ResolveLCtx (CasLCtx v1 v2) vs :: K) nil e0 - | CAS ?e0 ?e1 (Val ?v2) => go (build_ResolveLCtx (CasMCtx e0 v2) vs :: K) nil e1 - | CAS ?e0 ?e1 ?e2 => go (build_ResolveLCtx (CasRCtx e0 e1) vs :: K) nil e2 - | FAA ?e (Val ?v) => go (build_ResolveLCtx (FaaLCtx v) vs :: K) nil e - | FAA ?e1 ?e2 => go (build_ResolveLCtx (FaaRCtx e1) vs :: K) nil e2 + | _ => lazymatch vs with [] => tac K e | _ => fail end + | App ?e (Val ?v) => go_resolve (AppLCtx v) vs K e + | App ?e1 ?e2 => go_resolve (AppRCtx e1) vs K e2 + | UnOp ?op ?e => go_resolve (UnOpCtx op) vs K e + | BinOp ?op ?e (Val ?v) => go_resolve (BinOpLCtx op v) vs K e + | BinOp ?op ?e1 ?e2 => go_resolve (BinOpRCtx op e1) vs K e2 + | If ?e0 ?e1 ?e2 => go_resolve (IfCtx e1 e2) vs K e0 + | Pair ?e (Val ?v) => go_resolve (PairLCtx v) vs K e + | Pair ?e1 ?e2 => go_resolve (PairRCtx e1) vs K e2 + | Fst ?e => go_resolve FstCtx vs K e + | Snd ?e => go_resolve SndCtx vs K e + | InjL ?e => go_resolve InjLCtx vs K e + | InjR ?e => go_resolve InjRCtx vs K e + | Case ?e0 ?e1 ?e2 => go_resolve (CaseCtx e1 e2) vs K e0 + | AllocN ?e (Val ?v) => go_resolve (AllocNLCtx v) vs K e + | AllocN ?e1 ?e2 => go_resolve (AllocNRCtx e1) vs K e2 + | Load ?e => go_resolve LoadCtx vs K e + | Store ?e (Val ?v) => go_resolve (StoreLCtx v) vs K e + | Store ?e1 ?e2 => go_resolve (StoreRCtx e1) vs K e2 + | CAS ?e0 (Val ?v1) (Val ?v2) => go_resolve (CasLCtx v1 v2) vs K e0 + | CAS ?e0 ?e1 (Val ?v2) => go_resolve (CasMCtx e0 v2) vs K e1 + | CAS ?e0 ?e1 ?e2 => go_resolve (CasRCtx e0 e1) vs K e2 + | FAA ?e (Val ?v) => go_resolve (FaaLCtx v) vs K e + | FAA ?e1 ?e2 => go_resolve (FaaRCtx e1) vs K e2 | Resolve ?ex (Val ?v1) (Val ?v2) => go K ((v1,v2) :: vs) ex - | Resolve ?ex ?e1 (Val ?v2) => go (build_ResolveLCtx (ResolveMCtx ex v2) vs :: K) nil e1 - | Resolve ?ex ?e1 ?e2 => go (build_ResolveLCtx (ResolveRCtx ex e1) vs :: K) nil e2 + | Resolve ?ex ?e1 (Val ?v2) => go_resolve (ResolveMCtx ex v2) vs K e1 + | Resolve ?ex ?e1 ?e2 => go_resolve (ResolveRCtx ex e1) vs K e2 + end + with go_resolve Ki vs K e := + lazymatch vs with + | [] => go (Ki :: K) (@nil (val * val)) e + | (?v1,?v2) :: ?vs => go_resolve (ResolveLCtx Ki v1 v2) vs K e end in - go (@nil ectx_item) (@nil (list (val * val))) e. -*) + go (@nil ectx_item) (@nil (val * val)) e. -- GitLab From 80ea7c7b82d7f2061f6f9361ee410bd8a8bf2ebe Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Thu, 30 May 2019 15:36:48 +0200 Subject: [PATCH 15/28] Cleanup: applying some MR comments. --- theories/heap_lang/lang.v | 32 +++++++++++++++++--------------- theories/heap_lang/lifting.v | 6 +++--- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/theories/heap_lang/lang.v b/theories/heap_lang/lang.v index 92400c95e..3964ffa6c 100644 --- a/theories/heap_lang/lang.v +++ b/theories/heap_lang/lang.v @@ -358,13 +358,14 @@ Inductive ectx_item := | ResolveMCtx (e0 : expr) (v2 : val) | ResolveRCtx (e0 : expr) (e1 : expr). -(** The first argument of [Resolve] is not completely evaluated (down to a -value) by contextual closure: no head steps (i.e., surface reductions) are -taken. This means that [Resolve (CAS #l #n (#n + #1)) #p #v] will evaluate -to [Resolve (CAS #l #n #(n + 1)) #p #v] using context steps, but no further -step will be taken (by the contextual closure). *) - -Fixpoint fill_item (Ki : ectx_item) (e : expr) : expr := +(** Contextual closure will only reduce [e] in [Resolve e (Val _) (Val _)] if +the local context of [e] is non-empty. As a consequence, the first argument of +[Resolve] is not completely evaluated (down to a value) by contextual closure: +no head steps (i.e., surface reductions) are taken. This means that contextual +closure will reduce [Resolve (CAS #l #n (#n + #1)) #p #v] into [Resolve (CAS +#l #n #(n+1)) #p #v], but it cannot context-step any further. *) + +Fixpoint fill_item (Ki : ectx_item) (e : expr) : expr := match Ki with | AppLCtx v2 => App e (of_val v2) | AppRCtx e1 => App e1 e @@ -625,10 +626,7 @@ Proof. revert κ e2. induction Ki; inversion_clear 1; simplify_option_eq; eauto Lemma fill_item_no_val_inj Ki1 Ki2 e1 e2 : to_val e1 = None → to_val e2 = None → fill_item Ki1 e1 = fill_item Ki2 e2 → Ki1 = Ki2. -Proof. - revert Ki1. induction Ki2; induction Ki1; intros; simplify_eq; try done. - f_equal. eapply IHKi2; done. -Qed. +Proof. revert Ki1. induction Ki2, Ki1; naive_solver eauto with f_equal. Qed. Lemma alloc_fresh v n σ : let l := fresh_locs (dom (gset loc) σ.(heap)) n in @@ -669,10 +667,14 @@ To prove this lemma for [ectxi_language] in general, we would require that a term of the form [fill_item i e] is never a value if [e] is not a value. *) Lemma to_val_fill_some K e v : to_val (fill K e) = Some v → K = [] ∧ e = Val v. Proof. - intro H. destruct K as [|i K]. { apply of_to_val in H. done. } exfalso. - assert (to_val e ≠ None) as He. { intro A. rewrite fill_not_val in H; done. } - destruct e; try done. assert (to_val (fill (i :: K) (Val v0)) = None) as G. - { clear H v. destruct i; simpl; apply fill_not_val; done. } simplify_eq. + intro H. destruct K as [|i K]; first by apply of_to_val in H. exfalso. + assert (to_val e ≠ None) as He. + { intro A. by rewrite fill_not_val in H. } + assert (∃ w, e = Val w) as [w ->]. + { destruct e; try done; eauto. } + assert (to_val (fill (i :: K) (Val w)) = None). + { destruct i; simpl; apply fill_not_val; done. } + by simplify_eq. Qed. Lemma prim_step_to_val_is_head_step e σ1 κs w σ2 efs : diff --git a/theories/heap_lang/lifting.v b/theories/heap_lang/lifting.v index 973ce60f4..270f654ab 100644 --- a/theories/heap_lang/lifting.v +++ b/theories/heap_lang/lifting.v @@ -426,8 +426,8 @@ Lemma resolve_reducible e σ p v : Atomic StronglyAtomic e → reducible e σ → reducible (Resolve e (Val (LitV (LitProphecy p))) (Val v)) σ. Proof. - intros A [κ [e' [σ' [efs H]]]]. - exists (κ ++ [(p, (match to_val e' with Some w => w | _ => v end, v))]), e', σ', efs. + intros A (κ & e' & σ' & efs & H). + exists (κ ++ [(p, (default v (to_val e'), v))]), e', σ', efs. eapply Ectx_step with (K:=[]); try done. assert (∃w, Val w = e') as [w <-]. { unfold Atomic in A. apply (A σ e' κ σ' efs) in H. unfold is_Some in H. @@ -489,7 +489,7 @@ Proof. iIntros "HΦ". iApply wp_lift_atomic_head_step_no_fork; auto. iIntros (σ1 κ κs n) "Hσ". iModIntro. iSplit. - iPureIntro. eexists _, _, _, _. by constructor. - - iIntros (e2 σ2 efs S) "!>". inversion S. simplify_eq. by iFrame. + - iIntros (e2 σ2 efs step) "!>". inversion step. simplify_eq. by iFrame. Qed. Lemma wp_resolve_proph s E p vs v : -- GitLab From 4a6a72e708fb1724b604200177c33554290f4358 Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Thu, 30 May 2019 15:41:47 +0200 Subject: [PATCH 16/28] More cleanup, avoid [language.to_val]. --- theories/heap_lang/lifting.v | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/theories/heap_lang/lifting.v b/theories/heap_lang/lifting.v index 270f654ab..39ae8f415 100644 --- a/theories/heap_lang/lifting.v +++ b/theories/heap_lang/lifting.v @@ -460,12 +460,12 @@ Qed. Lemma wp_resolve s E e Φ p v vs : Atomic StronglyAtomic e → - language.to_val e = None → + to_val e = None → proph p vs -∗ WP e @ s; E {{ r, ∀ vs', ⌜vs = (r, v)::vs'⌝ -∗ proph p vs' -∗ Φ r }} -∗ WP Resolve e (Val $ LitV $ LitProphecy p) (Val v) @ s; E {{ Φ }}. Proof. - iIntros (A He) "Hp WPe". rewrite !wp_unfold /wp_pre He. simpl in *. + iIntros (A He) "Hp WPe". rewrite !wp_unfold /wp_pre /= He. simpl in *. iIntros (σ1 κ κs n) "[Hσ Hκ]". destruct (decide (κ = [])) as [->|HNeq]. - iMod ("WPe" $! σ1 [] κs n with "[$Hσ $Hκ]") as "[Hs WPe]". iModIntro. iSplit. { iDestruct "Hs" as "%". iPureIntro. destruct s; [ by apply resolve_reducible | done]. } -- GitLab From 3ee217df5c23138dda475dbe25fefcb6e03fb962 Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Thu, 30 May 2019 15:56:34 +0200 Subject: [PATCH 17/28] Explanations in [reshape_expr]. --- theories/heap_lang/tactics.v | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/theories/heap_lang/tactics.v b/theories/heap_lang/tactics.v index d9597a4e4..08a7d464d 100644 --- a/theories/heap_lang/tactics.v +++ b/theories/heap_lang/tactics.v @@ -6,6 +6,14 @@ Import heap_lang. evaluation context [K] and a subexpression [e']. It calls the tactic [tac K e'] for each possible decomposition until [tac] succeeds. *) Ltac reshape_expr e tac := + (* Note that the current context is spread into a list of fully-constructed + items [K], and a list of pairs of values [vs] that is only non-empty if + a [ResolveLCtx] item (possibly with several levels)is in the process of + being constructed. The construction is trigerred by calling [go_resolve] + whenever a new, non-[ResolveLCtx] item is constructed. In that case, the + accumulated elements of [vs] (if any) can be used to produce the expected + [ResolveLCtx] context: a sequence of [ResolveLCtx] with elements of [vs] + terminated with the non-[ResolveLCtx] item initially fed to [go_resolve]. *) let rec go K vs e := match e with | _ => lazymatch vs with [] => tac K e | _ => fail end -- GitLab From 26243e6b9b2a6add00511008329c0f920cde44e0 Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Thu, 30 May 2019 17:48:29 +0200 Subject: [PATCH 18/28] Tests for Resolve. --- tests/heap_lang_proph.ref | 0 tests/heap_lang_proph.v | 89 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 tests/heap_lang_proph.ref create mode 100644 tests/heap_lang_proph.v diff --git a/tests/heap_lang_proph.ref b/tests/heap_lang_proph.ref new file mode 100644 index 000000000..e69de29bb diff --git a/tests/heap_lang_proph.v b/tests/heap_lang_proph.v new file mode 100644 index 000000000..f563d457f --- /dev/null +++ b/tests/heap_lang_proph.v @@ -0,0 +1,89 @@ +From iris.program_logic Require Export weakestpre total_weakestpre. +From iris.heap_lang Require Import lang adequacy proofmode notation. +From iris.heap_lang Require Import lang. +Set Default Proof Using "Type". + +Section tests. + Context `{!heapG Σ}. + Implicit Types P Q : iProp Σ. + Implicit Types Φ : val → iProp Σ. + + Definition CAS_resolve e1 e2 e3 p v := + Resolve (CAS e1 e2 e3) p v. + + Lemma wp_cas_suc_resolve s E (l : loc) (p : proph_id) (vs : list (val * val)) (v1 v2 v : val) : + vals_cas_compare_safe v1 v1 → + {{{ proph p vs ∗ ▷ l ↦ v1 }}} + CAS_resolve #l v1 v2 #p v @ s; E + {{{ RET #true ; ∃ vs', ⌜vs = (#true, v)::vs'⌝ ∗ proph p vs' ∗ l ↦ v2 }}}. + Proof. + iIntros (Hcmp Φ) "[Hp Hl] HΦ". + wp_apply (wp_resolve with "Hp"); first done. + assert (val_is_unboxed v1) as Hv1; first by destruct Hcmp. + wp_cas_suc. iIntros (vs' ->) "Hp". + iApply "HΦ". eauto with iFrame. + Qed. + + Lemma wp_cas_fail_resolve s E (l : loc) (p : proph_id) (vs : list (val * val)) (v' v1 v2 v : val) : + v' ≠ v1 → vals_cas_compare_safe v' v1 → + {{{ proph p vs ∗ ▷ l ↦ v' }}} + CAS_resolve #l v1 v2 #p v @ s; E + {{{ RET #false ; ∃ vs', ⌜vs = (#false, v)::vs'⌝ ∗ proph p vs' ∗ l ↦ v' }}}. + Proof. + iIntros (NEq Hcmp Φ) "[Hp Hl] HΦ". + wp_apply (wp_resolve with "Hp"); first done. + wp_cas_fail. iIntros (vs' ->) "Hp". + iApply "HΦ". eauto with iFrame. + Qed. + + Lemma test_resolve1 E (l : loc) (n : Z) (p : proph_id) (vs : list (val * val)) (v : val) : + l ↦ #n -∗ + proph p vs -∗ + WP Resolve (CAS #l #n (#n + #1)) #p v @ E {{ v, ⌜v = #true⌝ ∗ ∃vs, proph p vs ∗ l ↦ #(n+1) }}%I. + Proof. + iIntros "Hl Hp". wp_pures. wp_apply (wp_resolve with "Hp"); first done. + wp_cas_suc. iIntros (ws ->) "Hp". eauto with iFrame. + Qed. + + Instance alloc_atomic s op v1 v2 : Atomic s (BinOp op (Val v1) (Val v2)). + Proof. + apply strongly_atomic_atomic, ectx_language_atomic. + - inversion 1; naive_solver. + - apply ectxi_language_sub_redexes_are_values; intros [] **; naive_solver. + Qed. + + Lemma test_resolve2 E (l : loc) (n m : Z) (p : proph_id) (vs : list (val * val)) : + proph p vs -∗ + WP Resolve (#n + #m - (#n + #m)) #p #() @ E {{ v, ⌜v = #0⌝ ∗ ∃vs, proph p vs }}%I. + Proof. + iIntros "Hp". wp_pures. wp_apply (wp_resolve with "Hp"); first done. + wp_pures. iIntros (ws ->) "Hp". rewrite Z.sub_diag. eauto with iFrame. + Qed. + + Lemma test_resolve3 s E (p1 p2 : proph_id) (vs1 vs2 : list (val * val)) (n : Z) : + {{{ proph p1 vs1 ∗ proph p2 vs2 }}} + Resolve (Resolve (#n - #n) #p2 #2) #p1 #1 @ s; E + {{{ RET #0 ; ∃ vs1' vs2', ⌜vs1 = (#0, #1)::vs1' ∧ vs2 = (#0, #2)::vs2'⌝ ∗ proph p1 vs1' ∗ proph p2 vs2' }}}. + Proof. + iIntros (Φ) "[Hp1 Hp2] HΦ". + wp_apply (wp_resolve with "Hp1"); first done. + wp_apply (wp_resolve with "Hp2"); first done. + wp_op. + iIntros (vs2' ->) "Hp2". iIntros (vs1' ->) "Hp1". rewrite Z.sub_diag. + iApply "HΦ". iExists vs1', vs2'. eauto with iFrame. + Qed. + + Lemma test_resolve4 s E (p1 p2 : proph_id) (vs1 vs2 : list (val * val)) (n : Z) : + {{{ proph p1 vs1 ∗ proph p2 vs2 }}} + Resolve (Resolve (#n - #n) ((λ: "x", "x") #p2) (#0 + #2)) ((λ: "x", "x") #p1) (#0 + #1) @ s; E + {{{ RET #0 ; ∃ vs1' vs2', ⌜vs1 = (#0, #1)::vs1' ∧ vs2 = (#0, #2)::vs2'⌝ ∗ proph p1 vs1' ∗ proph p2 vs2' }}}. + Proof. + iIntros (Φ) "[Hp1 Hp2] HΦ". + wp_apply (wp_resolve with "Hp1"); first done. + wp_apply (wp_resolve with "Hp2"); first done. + wp_op. + iIntros (vs2' ->) "Hp2". iIntros (vs1' ->) "Hp1". rewrite Z.sub_diag. + iApply "HΦ". iExists vs1', vs2'. eauto with iFrame. + Qed. + +End tests. -- GitLab From 3f5f403dbad48db62fc3454aa708d1e8881192d1 Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Thu, 30 May 2019 23:00:15 +0200 Subject: [PATCH 19/28] Move Atomic instance to lifting.v --- tests/heap_lang_proph.v | 9 +-------- theories/heap_lang/lifting.v | 2 ++ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/tests/heap_lang_proph.v b/tests/heap_lang_proph.v index f563d457f..d5e2cbbc5 100644 --- a/tests/heap_lang_proph.v +++ b/tests/heap_lang_proph.v @@ -45,14 +45,7 @@ Section tests. wp_cas_suc. iIntros (ws ->) "Hp". eauto with iFrame. Qed. - Instance alloc_atomic s op v1 v2 : Atomic s (BinOp op (Val v1) (Val v2)). - Proof. - apply strongly_atomic_atomic, ectx_language_atomic. - - inversion 1; naive_solver. - - apply ectxi_language_sub_redexes_are_values; intros [] **; naive_solver. - Qed. - - Lemma test_resolve2 E (l : loc) (n m : Z) (p : proph_id) (vs : list (val * val)) : + Lemma test_resolve2 E (l : loc) (n m : Z) (p : proph_id) (vs : list (val * val)) : proph p vs -∗ WP Resolve (#n + #m - (#n + #m)) #p #() @ E {{ v, ⌜v = #0⌝ ∗ ∃vs, proph p vs }}%I. Proof. diff --git a/theories/heap_lang/lifting.v b/theories/heap_lang/lifting.v index 39ae8f415..4deb629e2 100644 --- a/theories/heap_lang/lifting.v +++ b/theories/heap_lang/lifting.v @@ -84,6 +84,8 @@ Instance skip_atomic s : Atomic s Skip. Proof. solve_atomic. Qed. Instance new_proph_atomic s : Atomic s NewProph. Proof. solve_atomic. Qed. +Instance binop_atomic s op v1 v2 : Atomic s (BinOp op (Val v1) (Val v2)). +Proof. solve_atomic. Qed. Instance proph_resolve_atomic s e v1 v2 : Atomic s e → Atomic s (Resolve e (Val v1) (Val v2)). -- GitLab From d9c8aa634b5e867fe6e26c5d19bf370413807215 Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Fri, 31 May 2019 10:29:03 +0200 Subject: [PATCH 20/28] Get rid of some generated hypothesis name. --- theories/heap_lang/lang.v | 15 ++++++++------- theories/heap_lang/lifting.v | 21 +++++++++++---------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/theories/heap_lang/lang.v b/theories/heap_lang/lang.v index 3964ffa6c..0644ac397 100644 --- a/theories/heap_lang/lang.v +++ b/theories/heap_lang/lang.v @@ -691,13 +691,14 @@ Proof. intros H κs ** [Ks e1' e2' Hfill -> step]. simpl in *. induction Ks as [|K Ks _] using rev_ind; simpl in Hfill. - subst e1'. inversion step. eapply H. by apply head_prim_step. - - rewrite fill_app /= in Hfill. destruct K; inversion Hfill; subst; clear Hfill. - + apply (H κs (fill_item K (foldl (flip fill_item) e2' Ks)) σ' efs). - econstructor 1 with (K := Ks ++ [K]); last done; simpl; by rewrite fill_app. - + assert (to_val (fill Ks e1') = Some v1); first by rewrite -H2 //. - apply to_val_fill_some in H0. destruct H0 as [-> ->]. inversion step. - + assert (to_val (fill Ks e1') = Some v2); first by rewrite -H3 //. - apply to_val_fill_some in H0. destruct H0 as [-> ->]. inversion step. + - rewrite fill_app /= in Hfill. + destruct K; (inversion Hfill; subst; clear Hfill; try + match goal with | H : Val ?v = fill Ks ?e |- _ => + (assert (to_val (fill Ks e) = Some v) as HEq; first by rewrite -H //); + apply to_val_fill_some in HEq; destruct HEq as [-> ->]; inversion step + end). + apply (H κs (fill_item K (foldl (flip fill_item) e2' Ks)) σ' efs). + econstructor 1 with (K := Ks ++ [K]); last done; simpl; by rewrite fill_app. Qed. (** Define some derived forms. *) diff --git a/theories/heap_lang/lifting.v b/theories/heap_lang/lifting.v index 4deb629e2..d812fcd81 100644 --- a/theories/heap_lang/lifting.v +++ b/theories/heap_lang/lifting.v @@ -94,16 +94,17 @@ Proof. simpl in *. induction Ks as [|K Ks _] using rev_ind; simpl in Hfill. - subst. inversion_clear step. by apply (H σ1 (Val v) κs σ2 efs), head_prim_step. - rewrite fill_app. rewrite fill_app in Hfill. - destruct K; inversion Hfill; clear Hfill; subst. - + refine (_ (H σ1 (fill (Ks ++ [K]) e2') _ σ2 efs _)); last first. - econstructor 1 with (K := Ks ++ [K]); try done. simpl. by rewrite fill_app. - destruct s; intro Hs; simpl in *. - * destruct Hs as [v Hs]. apply to_val_fill_some in Hs. by destruct Hs, Ks. - * apply irreducible_resolve. by rewrite fill_app in Hs. - + induction Ks as [|K Ks _] using rev_ind. { simpl in H2. subst. inversion step. } - rewrite fill_app in H2. simpl in H2. destruct K; inversion H2. - + induction Ks as [|K Ks _] using rev_ind. { simpl in H3. subst. inversion step. } - rewrite fill_app in H3. simpl in H3. destruct K; inversion H3. + destruct K; (inversion Hfill; clear Hfill; subst; try + match goal with | H : Val ?v = fill Ks ?e |- _ => + induction Ks as [|K Ks _] using rev_ind; + [ simpl in H; subst; inversion step + | rewrite fill_app in H; simpl in H; destruct K; inversion H ] + end). + refine (_ (H σ1 (fill (Ks ++ [K]) e2') _ σ2 efs _)); last first. + econstructor 1 with (K := Ks ++ [K]); try done. simpl. by rewrite fill_app. + destruct s; intro Hs; simpl in *. + + destruct Hs as [v Hs]. apply to_val_fill_some in Hs. by destruct Hs, Ks. + + apply irreducible_resolve. by rewrite fill_app in Hs. Qed. Instance resolve_proph_atomic s v1 v2 : Atomic s (ResolveProph (Val v1) (Val v2)). -- GitLab From 5f7312b531033571a2b21f1749912d55e5881be7 Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Fri, 31 May 2019 13:02:29 +0200 Subject: [PATCH 21/28] Clarify comment in [theories/heap_lang/lang.v]. --- theories/heap_lang/lang.v | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/theories/heap_lang/lang.v b/theories/heap_lang/lang.v index 0644ac397..40928f21c 100644 --- a/theories/heap_lang/lang.v +++ b/theories/heap_lang/lang.v @@ -660,11 +660,11 @@ Canonical Structure heap_lang := LanguageOfEctx heap_ectx_lang. (* Prefer heap_lang names over ectx_language names. *) Export heap_lang. -(* The following lemma does not seem to be provable using the current axioms -of [ectxi_language]. The current proof requires a case analysis over context -items ([destruct i] on the last line), which in all cases yields a non-value. -To prove this lemma for [ectxi_language] in general, we would require that a -term of the form [fill_item i e] is never a value if [e] is not a value. *) +(* The following lemma is not provable using the axioms of [ectxi_language]. +The proof requires a case analysis over context items ([destruct i] on the +last line), which in all cases yields a non-value. To prove this lemma for +[ectxi_language] in general, we would require that a term of the form +[fill_item i e] is never a value if [e] is not a value. *) Lemma to_val_fill_some K e v : to_val (fill K e) = Some v → K = [] ∧ e = Val v. Proof. intro H. destruct K as [|i K]; first by apply of_to_val in H. exfalso. -- GitLab From f095ba930a75ba55a129f7426bf3055627ae3450 Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Fri, 31 May 2019 18:58:34 +0200 Subject: [PATCH 22/28] Comment fix. --- theories/heap_lang/lang.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theories/heap_lang/lang.v b/theories/heap_lang/lang.v index 40928f21c..cff6a5ef1 100644 --- a/theories/heap_lang/lang.v +++ b/theories/heap_lang/lang.v @@ -664,7 +664,7 @@ Export heap_lang. The proof requires a case analysis over context items ([destruct i] on the last line), which in all cases yields a non-value. To prove this lemma for [ectxi_language] in general, we would require that a term of the form -[fill_item i e] is never a value if [e] is not a value. *) +[fill_item i e] is never a value. *) Lemma to_val_fill_some K e v : to_val (fill K e) = Some v → K = [] ∧ e = Val v. Proof. intro H. destruct K as [|i K]; first by apply of_to_val in H. exfalso. -- GitLab From d450139f451f30cf63c11bb5dbbaec38a76de33b Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Fri, 31 May 2019 20:19:56 +0200 Subject: [PATCH 23/28] Clearer comment + some renaming. --- theories/heap_lang/tactics.v | 68 ++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/theories/heap_lang/tactics.v b/theories/heap_lang/tactics.v index 08a7d464d..6ea6feb75 100644 --- a/theories/heap_lang/tactics.v +++ b/theories/heap_lang/tactics.v @@ -7,47 +7,47 @@ evaluation context [K] and a subexpression [e']. It calls the tactic [tac K e'] for each possible decomposition until [tac] succeeds. *) Ltac reshape_expr e tac := (* Note that the current context is spread into a list of fully-constructed - items [K], and a list of pairs of values [vs] that is only non-empty if - a [ResolveLCtx] item (possibly with several levels)is in the process of - being constructed. The construction is trigerred by calling [go_resolve] - whenever a new, non-[ResolveLCtx] item is constructed. In that case, the - accumulated elements of [vs] (if any) can be used to produce the expected - [ResolveLCtx] context: a sequence of [ResolveLCtx] with elements of [vs] - terminated with the non-[ResolveLCtx] item initially fed to [go_resolve]. *) + items [K], and a list of pairs of values [vs] (prophecy identifier and + resolution value) that is only non-empty if a [ResolveLCtx] item (maybe + having several levels) is in the process of being constructed. Note that + a fully-constructed item is inserted into [K] by calling [add_item], and + that is only the case when a non-[ResolveLCtx] item is built. When [vs] + is non-empty, [add_item] also wraps the item under several [ResolveLCtx] + constructors: one for each pair in [vs]. *) let rec go K vs e := match e with | _ => lazymatch vs with [] => tac K e | _ => fail end - | App ?e (Val ?v) => go_resolve (AppLCtx v) vs K e - | App ?e1 ?e2 => go_resolve (AppRCtx e1) vs K e2 - | UnOp ?op ?e => go_resolve (UnOpCtx op) vs K e - | BinOp ?op ?e (Val ?v) => go_resolve (BinOpLCtx op v) vs K e - | BinOp ?op ?e1 ?e2 => go_resolve (BinOpRCtx op e1) vs K e2 - | If ?e0 ?e1 ?e2 => go_resolve (IfCtx e1 e2) vs K e0 - | Pair ?e (Val ?v) => go_resolve (PairLCtx v) vs K e - | Pair ?e1 ?e2 => go_resolve (PairRCtx e1) vs K e2 - | Fst ?e => go_resolve FstCtx vs K e - | Snd ?e => go_resolve SndCtx vs K e - | InjL ?e => go_resolve InjLCtx vs K e - | InjR ?e => go_resolve InjRCtx vs K e - | Case ?e0 ?e1 ?e2 => go_resolve (CaseCtx e1 e2) vs K e0 - | AllocN ?e (Val ?v) => go_resolve (AllocNLCtx v) vs K e - | AllocN ?e1 ?e2 => go_resolve (AllocNRCtx e1) vs K e2 - | Load ?e => go_resolve LoadCtx vs K e - | Store ?e (Val ?v) => go_resolve (StoreLCtx v) vs K e - | Store ?e1 ?e2 => go_resolve (StoreRCtx e1) vs K e2 - | CAS ?e0 (Val ?v1) (Val ?v2) => go_resolve (CasLCtx v1 v2) vs K e0 - | CAS ?e0 ?e1 (Val ?v2) => go_resolve (CasMCtx e0 v2) vs K e1 - | CAS ?e0 ?e1 ?e2 => go_resolve (CasRCtx e0 e1) vs K e2 - | FAA ?e (Val ?v) => go_resolve (FaaLCtx v) vs K e - | FAA ?e1 ?e2 => go_resolve (FaaRCtx e1) vs K e2 + | App ?e (Val ?v) => add_item (AppLCtx v) vs K e + | App ?e1 ?e2 => add_item (AppRCtx e1) vs K e2 + | UnOp ?op ?e => add_item (UnOpCtx op) vs K e + | BinOp ?op ?e (Val ?v) => add_item (BinOpLCtx op v) vs K e + | BinOp ?op ?e1 ?e2 => add_item (BinOpRCtx op e1) vs K e2 + | If ?e0 ?e1 ?e2 => add_item (IfCtx e1 e2) vs K e0 + | Pair ?e (Val ?v) => add_item (PairLCtx v) vs K e + | Pair ?e1 ?e2 => add_item (PairRCtx e1) vs K e2 + | Fst ?e => add_item FstCtx vs K e + | Snd ?e => add_item SndCtx vs K e + | InjL ?e => add_item InjLCtx vs K e + | InjR ?e => add_item InjRCtx vs K e + | Case ?e0 ?e1 ?e2 => add_item (CaseCtx e1 e2) vs K e0 + | AllocN ?e (Val ?v) => add_item (AllocNLCtx v) vs K e + | AllocN ?e1 ?e2 => add_item (AllocNRCtx e1) vs K e2 + | Load ?e => add_item LoadCtx vs K e + | Store ?e (Val ?v) => add_item (StoreLCtx v) vs K e + | Store ?e1 ?e2 => add_item (StoreRCtx e1) vs K e2 + | CAS ?e0 (Val ?v1) (Val ?v2) => add_item (CasLCtx v1 v2) vs K e0 + | CAS ?e0 ?e1 (Val ?v2) => add_item (CasMCtx e0 v2) vs K e1 + | CAS ?e0 ?e1 ?e2 => add_item (CasRCtx e0 e1) vs K e2 + | FAA ?e (Val ?v) => add_item (FaaLCtx v) vs K e + | FAA ?e1 ?e2 => add_item (FaaRCtx e1) vs K e2 | Resolve ?ex (Val ?v1) (Val ?v2) => go K ((v1,v2) :: vs) ex - | Resolve ?ex ?e1 (Val ?v2) => go_resolve (ResolveMCtx ex v2) vs K e1 - | Resolve ?ex ?e1 ?e2 => go_resolve (ResolveRCtx ex e1) vs K e2 + | Resolve ?ex ?e1 (Val ?v2) => add_item (ResolveMCtx ex v2) vs K e1 + | Resolve ?ex ?e1 ?e2 => add_item (ResolveRCtx ex e1) vs K e2 end - with go_resolve Ki vs K e := + with add_item Ki vs K e := lazymatch vs with | [] => go (Ki :: K) (@nil (val * val)) e - | (?v1,?v2) :: ?vs => go_resolve (ResolveLCtx Ki v1 v2) vs K e + | (?v1,?v2) :: ?vs => add_item (ResolveLCtx Ki v1 v2) vs K e end in go (@nil ectx_item) (@nil (val * val)) e. -- GitLab From d3e5f3c92a4df50e92add1b4775232f922ce8142 Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Mon, 3 Jun 2019 16:57:07 +0200 Subject: [PATCH 24/28] Apply comments by Robbert. --- theories/heap_lang/lang.v | 10 +++++----- theories/heap_lang/lifting.v | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/theories/heap_lang/lang.v b/theories/heap_lang/lang.v index cff6a5ef1..0b59998ff 100644 --- a/theories/heap_lang/lang.v +++ b/theories/heap_lang/lang.v @@ -621,7 +621,7 @@ Proof. destruct 1; naive_solver. Qed. Lemma head_ctx_step_val Ki e σ1 κ e2 σ2 efs : head_step (fill_item Ki e) σ1 κ e2 σ2 efs → is_Some (to_val e). -Proof. revert κ e2. induction Ki; inversion_clear 1; simplify_option_eq; eauto. Qed. +Proof. revert κ e2. induction Ki; inversion_clear 1; simplify_option_eq; eauto. Qed. Lemma fill_item_no_val_inj Ki1 Ki2 e1 e2 : to_val e1 = None → to_val e2 = None → @@ -667,13 +667,13 @@ last line), which in all cases yields a non-value. To prove this lemma for [fill_item i e] is never a value. *) Lemma to_val_fill_some K e v : to_val (fill K e) = Some v → K = [] ∧ e = Val v. Proof. - intro H. destruct K as [|i K]; first by apply of_to_val in H. exfalso. + intro H. destruct K as [|Ki K]; first by apply of_to_val in H. exfalso. assert (to_val e ≠ None) as He. { intro A. by rewrite fill_not_val in H. } assert (∃ w, e = Val w) as [w ->]. { destruct e; try done; eauto. } - assert (to_val (fill (i :: K) (Val w)) = None). - { destruct i; simpl; apply fill_not_val; done. } + assert (to_val (fill (Ki :: K) (Val w)) = None). + { destruct Ki; simpl; apply fill_not_val; done. } by simplify_eq. Qed. @@ -694,7 +694,7 @@ Proof. - rewrite fill_app /= in Hfill. destruct K; (inversion Hfill; subst; clear Hfill; try match goal with | H : Val ?v = fill Ks ?e |- _ => - (assert (to_val (fill Ks e) = Some v) as HEq; first by rewrite -H //); + (assert (to_val (fill Ks e) = Some v) as HEq by rewrite -H //); apply to_val_fill_some in HEq; destruct HEq as [-> ->]; inversion step end). apply (H κs (fill_item K (foldl (flip fill_item) e2' Ks)) σ' efs). diff --git a/theories/heap_lang/lifting.v b/theories/heap_lang/lifting.v index d812fcd81..f5d9bb0a6 100644 --- a/theories/heap_lang/lifting.v +++ b/theories/heap_lang/lifting.v @@ -100,11 +100,11 @@ Proof. [ simpl in H; subst; inversion step | rewrite fill_app in H; simpl in H; destruct K; inversion H ] end). - refine (_ (H σ1 (fill (Ks ++ [K]) e2') _ σ2 efs _)); last first. - econstructor 1 with (K := Ks ++ [K]); try done. simpl. by rewrite fill_app. - destruct s; intro Hs; simpl in *. - + destruct Hs as [v Hs]. apply to_val_fill_some in Hs. by destruct Hs, Ks. - + apply irreducible_resolve. by rewrite fill_app in Hs. + refine (_ (H σ1 (fill (Ks ++ [K]) e2') _ σ2 efs _)). + + destruct s; intro Hs; simpl in *. + * destruct Hs as [v Hs]. apply to_val_fill_some in Hs. by destruct Hs, Ks. + * apply irreducible_resolve. by rewrite fill_app in Hs. + + econstructor 1 with (K := Ks ++ [K]); try done. simpl. by rewrite fill_app. Qed. Instance resolve_proph_atomic s v1 v2 : Atomic s (ResolveProph (Val v1) (Val v2)). @@ -482,9 +482,9 @@ Proof. apply app_inj_2 in H; last done; destruct H as [-> [=-> -> ->]] end. subst. iMod ("WPe" $! (Val w') σ2 efs with "[%]") as "WPe". { eexists [] _ _; try done. } iModIntro. iNext. iMod "WPe" as "[[$ Hκ] WPe]". - iMod (proph_map_resolve_proph p' (w',v') κs with "[$Hκ $Hp]") as (vs') "[% [$ HPost]]". - subst vs. iModIntro. rewrite !wp_unfold /wp_pre /=. - iDestruct "WPe" as "[HΦ $]". iMod "HΦ". iModIntro. iApply "HΦ"; [ done | iFrame ]. + iMod (proph_map_resolve_proph p' (w',v') κs with "[$Hκ $Hp]") as (vs' ->) "[$ HPost]". + iModIntro. rewrite !wp_unfold /wp_pre /=. iDestruct "WPe" as "[HΦ $]". + iMod "HΦ". iModIntro. iApply "HΦ"; [ done | iFrame ]. Qed. Lemma wp_skip s E Φ : ▷ Φ (LitV LitUnit) -∗ WP Skip @ s; E {{ Φ }}. -- GitLab From 827cc03e1fbff903f6816cbcfbcf0b2c871db343 Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Mon, 3 Jun 2019 17:38:52 +0200 Subject: [PATCH 25/28] Avoid long tactic by using assert. --- theories/heap_lang/lifting.v | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/theories/heap_lang/lifting.v b/theories/heap_lang/lifting.v index f5d9bb0a6..a7cee04a4 100644 --- a/theories/heap_lang/lifting.v +++ b/theories/heap_lang/lifting.v @@ -94,12 +94,11 @@ Proof. simpl in *. induction Ks as [|K Ks _] using rev_ind; simpl in Hfill. - subst. inversion_clear step. by apply (H σ1 (Val v) κs σ2 efs), head_prim_step. - rewrite fill_app. rewrite fill_app in Hfill. + assert (∀ v, Val v = fill Ks e1' → False) as fill_absurd. + { intros v Hv. assert (to_val (fill Ks e1') = Some v) as Htv by by rewrite -Hv. + apply to_val_fill_some in Htv. destruct Htv as [-> ->]. inversion step. } destruct K; (inversion Hfill; clear Hfill; subst; try - match goal with | H : Val ?v = fill Ks ?e |- _ => - induction Ks as [|K Ks _] using rev_ind; - [ simpl in H; subst; inversion step - | rewrite fill_app in H; simpl in H; destruct K; inversion H ] - end). + match goal with | H : Val ?v = fill Ks e1' |- _ => by apply fill_absurd in H end). refine (_ (H σ1 (fill (Ks ++ [K]) e2') _ σ2 efs _)). + destruct s; intro Hs; simpl in *. * destruct Hs as [v Hs]. apply to_val_fill_some in Hs. by destruct Hs, Ks. -- GitLab From 78e3c54100d72de75efbfed54159cd47ad13872b Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Mon, 3 Jun 2019 18:13:38 +0200 Subject: [PATCH 26/28] Add a comment. --- theories/heap_lang/lifting.v | 2 ++ 1 file changed, 2 insertions(+) diff --git a/theories/heap_lang/lifting.v b/theories/heap_lang/lifting.v index a7cee04a4..ce71d9fd4 100644 --- a/theories/heap_lang/lifting.v +++ b/theories/heap_lang/lifting.v @@ -467,6 +467,8 @@ Lemma wp_resolve s E e Φ p v vs : WP e @ s; E {{ r, ∀ vs', ⌜vs = (r, v)::vs'⌝ -∗ proph p vs' -∗ Φ r }} -∗ WP Resolve e (Val $ LitV $ LitProphecy p) (Val v) @ s; E {{ Φ }}. Proof. + (* TODO we should try to use a generic lifting lemma (and avoid [wp_unfold]) + here, since this breaks the WP abstraction. *) iIntros (A He) "Hp WPe". rewrite !wp_unfold /wp_pre /= He. simpl in *. iIntros (σ1 κ κs n) "[Hσ Hκ]". destruct (decide (κ = [])) as [->|HNeq]. - iMod ("WPe" $! σ1 [] κs n with "[$Hσ $Hκ]") as "[Hs WPe]". iModIntro. iSplit. -- GitLab From 462d6044e064372dd49aa9b8bf7c177ece8d8963 Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Mon, 3 Jun 2019 20:19:38 +0200 Subject: [PATCH 27/28] Fix indentation. --- tests/heap_lang_proph.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/heap_lang_proph.v b/tests/heap_lang_proph.v index d5e2cbbc5..a68a6ff2e 100644 --- a/tests/heap_lang_proph.v +++ b/tests/heap_lang_proph.v @@ -45,7 +45,7 @@ Section tests. wp_cas_suc. iIntros (ws ->) "Hp". eauto with iFrame. Qed. - Lemma test_resolve2 E (l : loc) (n m : Z) (p : proph_id) (vs : list (val * val)) : + Lemma test_resolve2 E (l : loc) (n m : Z) (p : proph_id) (vs : list (val * val)) : proph p vs -∗ WP Resolve (#n + #m - (#n + #m)) #p #() @ E {{ v, ⌜v = #0⌝ ∗ ∃vs, proph p vs }}%I. Proof. -- GitLab From b38b34344686293815cdf8c6bf3f94bffea8675d Mon Sep 17 00:00:00 2001 From: Rodolphe Lepigre <rodolphe.lepigre@inria.fr> Date: Mon, 3 Jun 2019 23:41:31 +0200 Subject: [PATCH 28/28] More precise comment for [Resolve]. --- theories/heap_lang/lang.v | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/theories/heap_lang/lang.v b/theories/heap_lang/lang.v index 0b59998ff..3fcd37f68 100644 --- a/theories/heap_lang/lang.v +++ b/theories/heap_lang/lang.v @@ -20,9 +20,36 @@ Set Default Proof Using "Type". program diverge unless the variable matches. That, however, requires an erasure proof that this endless loop does not make specifications useless. -If [e] is an expression that executes physically atomically, then so does -[Resolve e p v]. This second expression behaves exactly as [e], except that -it aditionally resolves the prophecy variable [p] to the value [v]. *) +The expression [Resolve e p v] attaches a prophecy resolution (for prophecy +variable [p] to value [v]) to the top-level head-reduction step of [e]. The +prophecy resolution happens simultaneously with the head-step being taken. +Furthermore, it is required that the head-step produces a value (otherwise +the [Resolve] is stuck), and this value is also attached to the resolution. +A prophecy variable is thus resolved to a pair containing (1) the result +value of the wrapped expression (called [e] above), and (2) the value that +was attached by the [Resolve] (called [v] above). This allows, for example, +to distinguish a resolution originating from a successful [CAS] from one +originating from a failing [CAS]. For example: + - [Resolve (CAS #l #n #(n+1)) #p v] will behave as [CAS #l #n #(n+1)], + which means step to a boolean [b] while updating the heap, but in the + meantime the prophecy variable [p] will be resolved to [(#b, v)]. + - [Resolve (! #l) #p v] will behave as [! #l], that is return the value + [w] pointed to by [l] on the heap (assuming it was allocated properly), + but it will additionally resolve [p] to the pair [(w,v)]. + +Note that the sub-expressions of [Resolve e p v] (i.e., [e], [p] and [v]) +are reduced as usual, from right to left. However, the evaluation of [e] +is restricted so that the head-step to which the resolution is attached +cannot be taken by the context. For example: + - [Resolve (CAS #l #n (#n + #1)) #p v] will first be reduced (with by a + context-step) to [Resolve (CAS #l #n #(n+1) #p v], and then behave as + described above. + - However, [Resolve ((λ: "n", CAS #l "n" ("n" + #1)) #n) #p v] is stuck. + Indeed, it can only be evaluated using a head-step (it is a β-redex), + but the process does not yield a value. + +The mechanism described above supports nesting [Resolve] expressions to +attach several prophecy resolutions to a head-redex. *) Delimit Scope expr_scope with E. Delimit Scope val_scope with V. -- GitLab