From fc3ac14835cba3cc39e751b14e08268b2099fd60 Mon Sep 17 00:00:00 2001
From: Robbert Krebbers <mail@robbertkrebbers.nl>
Date: Fri, 21 Oct 2016 21:56:06 +0200
Subject: [PATCH] Move base_logic stuff to its own folder: base_logic.

---
 _CoqProject                                   |   14 +-
 algebra/agree.v                               |    2 +-
 algebra/auth.v                                |    2 +-
 algebra/csum.v                                |    3 +-
 algebra/excl.v                                |    2 +-
 algebra/gmap.v                                |    3 +-
 algebra/iprod.v                               |    4 +-
 algebra/list.v                                |    3 +-
 algebra/upred.v                               | 1599 -----------------
 base_logic/base_logic.v                       |   17 +
 algebra/upred_big_op.v => base_logic/big_op.v |   84 +-
 base_logic/derived.v                          |  751 ++++++++
 {algebra => base_logic}/double_negation.v     |    2 +-
 algebra/upred_hlist.v => base_logic/hlist.v   |    2 +-
 base_logic/primitive.v                        |  592 ++++++
 base_logic/soundness.v                        |   24 +
 .../upred_tactics.v => base_logic/tactics.v   |    3 +-
 base_logic/upred.v                            |  172 ++
 heap_lang/lib/barrier/proof.v                 |    2 +-
 program_logic/adequacy.v                      |    9 +-
 program_logic/auth.v                          |    1 +
 program_logic/boxes.v                         |    3 +-
 program_logic/counter_examples.v              |    4 +-
 program_logic/fancy_updates.v                 |    3 +-
 program_logic/ghost_ownership.v               |    1 +
 program_logic/iris.v                          |    2 +-
 program_logic/lifting.v                       |    2 +-
 program_logic/model.v                         |    2 +-
 program_logic/weakestpre.v                    |    2 +-
 program_logic/wsat.v                          |    3 +-
 proofmode/class_instances.v                   |    3 +-
 proofmode/classes.v                           |    2 +-
 proofmode/coq_tactics.v                       |    4 +-
 proofmode/tactics.v                           |    2 +-
 tests/atomic.v                                |    2 +-
 35 files changed, 1689 insertions(+), 1637 deletions(-)
 delete mode 100644 algebra/upred.v
 create mode 100644 base_logic/base_logic.v
 rename algebra/upred_big_op.v => base_logic/big_op.v (85%)
 create mode 100644 base_logic/derived.v
 rename {algebra => base_logic}/double_negation.v (99%)
 rename algebra/upred_hlist.v => base_logic/hlist.v (96%)
 create mode 100644 base_logic/primitive.v
 create mode 100644 base_logic/soundness.v
 rename algebra/upred_tactics.v => base_logic/tactics.v (98%)
 create mode 100644 base_logic/upred.v

diff --git a/_CoqProject b/_CoqProject
index 5d4efbcb4..54d3925c6 100644
--- a/_CoqProject
+++ b/_CoqProject
@@ -51,10 +51,6 @@ algebra/agree.v
 algebra/dec_agree.v
 algebra/excl.v
 algebra/iprod.v
-algebra/upred.v
-algebra/upred_tactics.v
-algebra/upred_big_op.v
-algebra/upred_hlist.v
 algebra/frac.v
 algebra/csum.v
 algebra/list.v
@@ -62,7 +58,15 @@ algebra/updates.v
 algebra/local_updates.v
 algebra/gset.v
 algebra/coPset.v
-algebra/double_negation.v
+base_logic/upred.v
+base_logic/primitive.v
+base_logic/derived.v
+base_logic/base_logic.v
+base_logic/tactics.v
+base_logic/big_op.v
+base_logic/hlist.v
+base_logic/soundness.v
+base_logic/double_negation.v
 program_logic/model.v
 program_logic/adequacy.v
 program_logic/lifting.v
diff --git a/algebra/agree.v b/algebra/agree.v
index e138d0368..35283796a 100644
--- a/algebra/agree.v
+++ b/algebra/agree.v
@@ -1,5 +1,5 @@
 From iris.algebra Require Export cmra.
-From iris.algebra Require Import upred.
+From iris.base_logic Require Import base_logic.
 Local Hint Extern 10 (_ ≤ _) => omega.
 
 Record agree (A : Type) : Type := Agree {
diff --git a/algebra/auth.v b/algebra/auth.v
index 94b0cabf3..c9ba5b776 100644
--- a/algebra/auth.v
+++ b/algebra/auth.v
@@ -1,5 +1,5 @@
 From iris.algebra Require Export excl local_updates.
-From iris.algebra Require Import upred updates.
+From iris.base_logic Require Import base_logic.
 From iris.proofmode Require Import class_instances.
 Local Arguments valid _ _ !_ /.
 Local Arguments validN _ _ _ !_ /.
diff --git a/algebra/csum.v b/algebra/csum.v
index 27066a1d8..954fdabf5 100644
--- a/algebra/csum.v
+++ b/algebra/csum.v
@@ -1,5 +1,6 @@
 From iris.algebra Require Export cmra.
-From iris.algebra Require Import upred updates local_updates.
+From iris.base_logic Require Import base_logic.
+From iris.algebra Require Import local_updates.
 Local Arguments pcore _ _ !_ /.
 Local Arguments cmra_pcore _ !_ /.
 Local Arguments validN _ _ _ !_ /.
diff --git a/algebra/excl.v b/algebra/excl.v
index bd1bc8612..4c0200eaa 100644
--- a/algebra/excl.v
+++ b/algebra/excl.v
@@ -1,5 +1,5 @@
 From iris.algebra Require Export cmra.
-From iris.algebra Require Import upred.
+From iris.base_logic Require Import base_logic.
 Local Arguments validN _ _ _ !_ /.
 Local Arguments valid _ _  !_ /.
 
diff --git a/algebra/gmap.v b/algebra/gmap.v
index 42f430f56..5af9911a0 100644
--- a/algebra/gmap.v
+++ b/algebra/gmap.v
@@ -1,6 +1,7 @@
 From iris.algebra Require Export cmra.
 From iris.prelude Require Export gmap.
-From iris.algebra Require Import upred updates local_updates.
+From iris.algebra Require Import updates local_updates.
+From iris.base_logic Require Import base_logic.
 
 Section cofe.
 Context `{Countable K} {A : cofeT}.
diff --git a/algebra/iprod.v b/algebra/iprod.v
index d2870d53f..317484fbe 100644
--- a/algebra/iprod.v
+++ b/algebra/iprod.v
@@ -1,5 +1,5 @@
-From iris.algebra Require Export cmra updates.
-From iris.algebra Require Import upred.
+From iris.algebra Require Export cmra.
+From iris.base_logic Require Import base_logic.
 From iris.prelude Require Import finite.
 
 (** * Indexed product *)
diff --git a/algebra/list.v b/algebra/list.v
index c9bd4bfcf..5d67d4f74 100644
--- a/algebra/list.v
+++ b/algebra/list.v
@@ -1,6 +1,7 @@
 From iris.algebra Require Export cmra.
 From iris.prelude Require Export list.
-From iris.algebra Require Import upred updates local_updates.
+From iris.base_logic Require Import base_logic.
+From iris.algebra Require Import updates local_updates.
 
 Section cofe.
 Context {A : cofeT}.
diff --git a/algebra/upred.v b/algebra/upred.v
deleted file mode 100644
index c4b6e5da4..000000000
--- a/algebra/upred.v
+++ /dev/null
@@ -1,1599 +0,0 @@
-From iris.algebra Require Export cmra updates.
-Local Hint Extern 1 (_ ≼ _) => etrans; [eassumption|].
-Local Hint Extern 1 (_ ≼ _) => etrans; [|eassumption].
-Local Hint Extern 10 (_ ≤ _) => omega.
-
-Record uPred (M : ucmraT) : Type := IProp {
-  uPred_holds :> nat → M → Prop;
-  uPred_mono n x1 x2 : uPred_holds n x1 → x1 ≼{n} x2 → uPred_holds n x2;
-  uPred_closed n1 n2 x : uPred_holds n1 x → n2 ≤ n1 → ✓{n2} x → uPred_holds n2 x
-}.
-Arguments uPred_holds {_} _ _ _ : simpl never.
-Add Printing Constructor uPred.
-Instance: Params (@uPred_holds) 3.
-
-Delimit Scope uPred_scope with I.
-Bind Scope uPred_scope with uPred.
-Arguments uPred_holds {_} _%I _ _.
-
-Section cofe.
-  Context {M : ucmraT}.
-
-  Inductive uPred_equiv' (P Q : uPred M) : Prop :=
-    { uPred_in_equiv : ∀ n x, ✓{n} x → P n x ↔ Q n x }.
-  Instance uPred_equiv : Equiv (uPred M) := uPred_equiv'.
-  Inductive uPred_dist' (n : nat) (P Q : uPred M) : Prop :=
-    { uPred_in_dist : ∀ n' x, n' ≤ n → ✓{n'} x → P n' x ↔ Q n' x }.
-  Instance uPred_dist : Dist (uPred M) := uPred_dist'.
-  Program Instance uPred_compl : Compl (uPred M) := λ c,
-    {| uPred_holds n x := c n n x |}.
-  Next Obligation. naive_solver eauto using uPred_mono. Qed.
-  Next Obligation.
-    intros c n1 n2 x ???; simpl in *.
-    apply (chain_cauchy c n2 n1); eauto using uPred_closed.
-  Qed.
-  Definition uPred_cofe_mixin : CofeMixin (uPred M).
-  Proof.
-    split.
-    - intros P Q; split.
-      + by intros HPQ n; split=> i x ??; apply HPQ.
-      + intros HPQ; split=> n x ?; apply HPQ with n; auto.
-    - intros n; split.
-      + by intros P; split=> x i.
-      + by intros P Q HPQ; split=> x i ??; symmetry; apply HPQ.
-      + intros P Q Q' HP HQ; split=> i x ??.
-        by trans (Q i x);[apply HP|apply HQ].
-    - intros n P Q HPQ; split=> i x ??; apply HPQ; auto.
-    - intros n c; split=>i x ??; symmetry; apply (chain_cauchy c i n); auto.
-  Qed.
-  Canonical Structure uPredC : cofeT := CofeT (uPred M) uPred_cofe_mixin.
-End cofe.
-Arguments uPredC : clear implicits.
-
-Instance uPred_ne {M} (P : uPred M) n : Proper (dist n ==> iff) (P n).
-Proof.
-  intros x1 x2 Hx; split=> ?; eapply uPred_mono; eauto; by rewrite Hx.
-Qed.
-Instance uPred_proper {M} (P : uPred M) n : Proper ((≡) ==> iff) (P n).
-Proof. by intros x1 x2 Hx; apply uPred_ne, equiv_dist. Qed.
-
-Lemma uPred_holds_ne {M} (P Q : uPred M) n1 n2 x :
-  P ≡{n2}≡ Q → n2 ≤ n1 → ✓{n2} x → Q n1 x → P n2 x.
-Proof.
-  intros [Hne] ???. eapply Hne; try done.
-  eapply uPred_closed; eauto using cmra_validN_le.
-Qed.
-
-(** functor *)
-Program Definition uPred_map {M1 M2 : ucmraT} (f : M2 -n> M1)
-  `{!CMRAMonotone f} (P : uPred M1) :
-  uPred M2 := {| uPred_holds n x := P n (f x) |}.
-Next Obligation. naive_solver eauto using uPred_mono, cmra_monotoneN. Qed.
-Next Obligation. naive_solver eauto using uPred_closed, cmra_monotone_validN. Qed.
-
-Instance uPred_map_ne {M1 M2 : ucmraT} (f : M2 -n> M1)
-  `{!CMRAMonotone f} n : Proper (dist n ==> dist n) (uPred_map f).
-Proof.
-  intros x1 x2 Hx; split=> n' y ??.
-  split; apply Hx; auto using cmra_monotone_validN.
-Qed.
-Lemma uPred_map_id {M : ucmraT} (P : uPred M): uPred_map cid P ≡ P.
-Proof. by split=> n x ?. Qed.
-Lemma uPred_map_compose {M1 M2 M3 : ucmraT} (f : M1 -n> M2) (g : M2 -n> M3)
-    `{!CMRAMonotone f, !CMRAMonotone g} (P : uPred M3):
-  uPred_map (g ◎ f) P ≡ uPred_map f (uPred_map g P).
-Proof. by split=> n x Hx. Qed.
-Lemma uPred_map_ext {M1 M2 : ucmraT} (f g : M1 -n> M2)
-      `{!CMRAMonotone f} `{!CMRAMonotone g}:
-  (∀ x, f x ≡ g x) → ∀ x, uPred_map f x ≡ uPred_map g x.
-Proof. intros Hf P; split=> n x Hx /=; by rewrite /uPred_holds /= Hf. Qed.
-Definition uPredC_map {M1 M2 : ucmraT} (f : M2 -n> M1) `{!CMRAMonotone f} :
-  uPredC M1 -n> uPredC M2 := CofeMor (uPred_map f : uPredC M1 → uPredC M2).
-Lemma uPredC_map_ne {M1 M2 : ucmraT} (f g : M2 -n> M1)
-    `{!CMRAMonotone f, !CMRAMonotone g} n :
-  f ≡{n}≡ g → uPredC_map f ≡{n}≡ uPredC_map g.
-Proof.
-  by intros Hfg P; split=> n' y ??;
-    rewrite /uPred_holds /= (dist_le _ _ _ _(Hfg y)); last lia.
-Qed.
-
-Program Definition uPredCF (F : urFunctor) : cFunctor := {|
-  cFunctor_car A B := uPredC (urFunctor_car F B A);
-  cFunctor_map A1 A2 B1 B2 fg := uPredC_map (urFunctor_map F (fg.2, fg.1))
-|}.
-Next Obligation.
-  intros F A1 A2 B1 B2 n P Q HPQ.
-  apply uPredC_map_ne, urFunctor_ne; split; by apply HPQ.
-Qed.
-Next Obligation.
-  intros F A B P; simpl. rewrite -{2}(uPred_map_id P).
-  apply uPred_map_ext=>y. by rewrite urFunctor_id.
-Qed.
-Next Obligation.
-  intros F A1 A2 A3 B1 B2 B3 f g f' g' P; simpl. rewrite -uPred_map_compose.
-  apply uPred_map_ext=>y; apply urFunctor_compose.
-Qed.
-
-Instance uPredCF_contractive F :
-  urFunctorContractive F → cFunctorContractive (uPredCF F).
-Proof.
-  intros ? A1 A2 B1 B2 n P Q HPQ.
-  apply uPredC_map_ne, urFunctor_contractive=> i ?; split; by apply HPQ.
-Qed.
-
-(** logical entailement *)
-Inductive uPred_entails {M} (P Q : uPred M) : Prop :=
-  { uPred_in_entails : ∀ n x, ✓{n} x → P n x → Q n x }.
-Hint Extern 0 (uPred_entails _ _) => reflexivity.
-Instance uPred_entails_rewrite_relation M : RewriteRelation (@uPred_entails M).
-
-Hint Resolve uPred_mono uPred_closed : uPred_def.
-
-(** logical connectives *)
-Program Definition uPred_pure_def {M} (φ : Prop) : uPred M :=
-  {| uPred_holds n x := φ |}.
-Solve Obligations with done.
-Definition uPred_pure_aux : { x | x = @uPred_pure_def }. by eexists. Qed.
-Definition uPred_pure {M} := proj1_sig uPred_pure_aux M.
-Definition uPred_pure_eq :
-  @uPred_pure = @uPred_pure_def := proj2_sig uPred_pure_aux.
-
-Instance uPred_inhabited M : Inhabited (uPred M) := populate (uPred_pure True).
-
-Program Definition uPred_and_def {M} (P Q : uPred M) : uPred M :=
-  {| uPred_holds n x := P n x ∧ Q n x |}.
-Solve Obligations with naive_solver eauto 2 with uPred_def.
-Definition uPred_and_aux : { x | x = @uPred_and_def }. by eexists. Qed.
-Definition uPred_and {M} := proj1_sig uPred_and_aux M.
-Definition uPred_and_eq: @uPred_and = @uPred_and_def := proj2_sig uPred_and_aux.
-
-Program Definition uPred_or_def {M} (P Q : uPred M) : uPred M :=
-  {| uPred_holds n x := P n x ∨ Q n x |}.
-Solve Obligations with naive_solver eauto 2 with uPred_def.
-Definition uPred_or_aux : { x | x = @uPred_or_def }. by eexists. Qed.
-Definition uPred_or {M} := proj1_sig uPred_or_aux M.
-Definition uPred_or_eq: @uPred_or = @uPred_or_def := proj2_sig uPred_or_aux.
-
-Program Definition uPred_impl_def {M} (P Q : uPred M) : uPred M :=
-  {| uPred_holds n x := ∀ n' x',
-       x ≼ x' → n' ≤ n → ✓{n'} x' → P n' x' → Q n' x' |}.
-Next Obligation.
-  intros M P Q n1 x1 x1' HPQ [x2 Hx1'] n2 x3 [x4 Hx3] ?; simpl in *.
-  rewrite Hx3 (dist_le _ _ _ _ Hx1'); auto. intros ??.
-  eapply HPQ; auto. exists (x2 â‹… x4); by rewrite assoc.
-Qed.
-Next Obligation. intros M P Q [|n1] [|n2] x; auto with lia. Qed.
-Definition uPred_impl_aux : { x | x = @uPred_impl_def }. by eexists. Qed.
-Definition uPred_impl {M} := proj1_sig uPred_impl_aux M.
-Definition uPred_impl_eq :
-  @uPred_impl = @uPred_impl_def := proj2_sig uPred_impl_aux.
-
-Program Definition uPred_forall_def {M A} (Ψ : A → uPred M) : uPred M :=
-  {| uPred_holds n x := ∀ a, Ψ a n x |}.
-Solve Obligations with naive_solver eauto 2 with uPred_def.
-Definition uPred_forall_aux : { x | x = @uPred_forall_def }. by eexists. Qed.
-Definition uPred_forall {M A} := proj1_sig uPred_forall_aux M A.
-Definition uPred_forall_eq :
-  @uPred_forall = @uPred_forall_def := proj2_sig uPred_forall_aux.
-
-Program Definition uPred_exist_def {M A} (Ψ : A → uPred M) : uPred M :=
-  {| uPred_holds n x := ∃ a, Ψ a n x |}.
-Solve Obligations with naive_solver eauto 2 with uPred_def.
-Definition uPred_exist_aux : { x | x = @uPred_exist_def }. by eexists. Qed.
-Definition uPred_exist {M A} := proj1_sig uPred_exist_aux M A.
-Definition uPred_exist_eq: @uPred_exist = @uPred_exist_def := proj2_sig uPred_exist_aux.
-
-Program Definition uPred_eq_def {M} {A : cofeT} (a1 a2 : A) : uPred M :=
-  {| uPred_holds n x := a1 ≡{n}≡ a2 |}.
-Solve Obligations with naive_solver eauto 2 using (dist_le (A:=A)).
-Definition uPred_eq_aux : { x | x = @uPred_eq_def }. by eexists. Qed.
-Definition uPred_eq {M A} := proj1_sig uPred_eq_aux M A.
-Definition uPred_eq_eq: @uPred_eq = @uPred_eq_def := proj2_sig uPred_eq_aux.
-
-Program Definition uPred_sep_def {M} (P Q : uPred M) : uPred M :=
-  {| uPred_holds n x := ∃ x1 x2, x ≡{n}≡ x1 ⋅ x2 ∧ P n x1 ∧ Q n x2 |}.
-Next Obligation.
-  intros M P Q n x y (x1&x2&Hx&?&?) [z Hy].
-  exists x1, (x2 â‹… z); split_and?; eauto using uPred_mono, cmra_includedN_l.
-  by rewrite Hy Hx assoc.
-Qed.
-Next Obligation.
-  intros M P Q n1 n2 x (x1&x2&Hx&?&?) ?; rewrite {1}(dist_le _ _ _ _ Hx) // =>?.
-  exists x1, x2; cofe_subst; split_and!;
-    eauto using dist_le, uPred_closed, cmra_validN_op_l, cmra_validN_op_r.
-Qed.
-Definition uPred_sep_aux : { x | x = @uPred_sep_def }. by eexists. Qed.
-Definition uPred_sep {M} := proj1_sig uPred_sep_aux M.
-Definition uPred_sep_eq: @uPred_sep = @uPred_sep_def := proj2_sig uPred_sep_aux.
-
-Program Definition uPred_wand_def {M} (P Q : uPred M) : uPred M :=
-  {| uPred_holds n x := ∀ n' x',
-       n' ≤ n → ✓{n'} (x ⋅ x') → P n' x' → Q n' (x ⋅ x') |}.
-Next Obligation.
-  intros M P Q n x1 x1' HPQ ? n3 x3 ???; simpl in *.
-  apply uPred_mono with (x1 â‹… x3);
-    eauto using cmra_validN_includedN, cmra_monoN_r, cmra_includedN_le.
-Qed.
-Next Obligation. naive_solver. Qed.
-Definition uPred_wand_aux : { x | x = @uPred_wand_def }. by eexists. Qed.
-Definition uPred_wand {M} := proj1_sig uPred_wand_aux M.
-Definition uPred_wand_eq :
-  @uPred_wand = @uPred_wand_def := proj2_sig uPred_wand_aux.
-
-Program Definition uPred_always_def {M} (P : uPred M) : uPred M :=
-  {| uPred_holds n x := P n (core x) |}.
-Next Obligation.
-  intros M; naive_solver eauto using uPred_mono, @cmra_core_monoN.
-Qed.
-Next Obligation. naive_solver eauto using uPred_closed, @cmra_core_validN. Qed.
-Definition uPred_always_aux : { x | x = @uPred_always_def }. by eexists. Qed.
-Definition uPred_always {M} := proj1_sig uPred_always_aux M.
-Definition uPred_always_eq :
-  @uPred_always = @uPred_always_def := proj2_sig uPred_always_aux.
-
-Program Definition uPred_later_def {M} (P : uPred M) : uPred M :=
-  {| uPred_holds n x := match n return _ with 0 => True | S n' => P n' x end |}.
-Next Obligation.
-  intros M P [|n] x1 x2; eauto using uPred_mono, cmra_includedN_S.
-Qed.
-Next Obligation.
-  intros M P [|n1] [|n2] x; eauto using uPred_closed, cmra_validN_S with lia.
-Qed.
-Definition uPred_later_aux : { x | x = @uPred_later_def }. by eexists. Qed.
-Definition uPred_later {M} := proj1_sig uPred_later_aux M.
-Definition uPred_later_eq :
-  @uPred_later = @uPred_later_def := proj2_sig uPred_later_aux.
-
-Program Definition uPred_ownM_def {M : ucmraT} (a : M) : uPred M :=
-  {| uPred_holds n x := a ≼{n} x |}.
-Next Obligation.
-  intros M a n x1 x [a' Hx1] [x2 ->].
-  exists (a' â‹… x2). by rewrite (assoc op) Hx1.
-Qed.
-Next Obligation. naive_solver eauto using cmra_includedN_le. Qed.
-Definition uPred_ownM_aux : { x | x = @uPred_ownM_def }. by eexists. Qed.
-Definition uPred_ownM {M} := proj1_sig uPred_ownM_aux M.
-Definition uPred_ownM_eq :
-  @uPred_ownM = @uPred_ownM_def := proj2_sig uPred_ownM_aux.
-
-Program Definition uPred_cmra_valid_def {M} {A : cmraT} (a : A) : uPred M :=
-  {| uPred_holds n x := ✓{n} a |}.
-Solve Obligations with naive_solver eauto 2 using cmra_validN_le.
-Definition uPred_cmra_valid_aux : { x | x = @uPred_cmra_valid_def }. by eexists. Qed.
-Definition uPred_cmra_valid {M A} := proj1_sig uPred_cmra_valid_aux M A.
-Definition uPred_cmra_valid_eq :
-  @uPred_cmra_valid = @uPred_cmra_valid_def := proj2_sig uPred_cmra_valid_aux.
-
-Program Definition uPred_bupd_def {M} (Q : uPred M) : uPred M :=
-  {| uPred_holds n x := ∀ k yf,
-      k ≤ n → ✓{k} (x ⋅ yf) → ∃ x', ✓{k} (x' ⋅ yf) ∧ Q k x' |}.
-Next Obligation.
-  intros M Q n x1 x2 HQ [x3 Hx] k yf Hk.
-  rewrite (dist_le _ _ _ _ Hx); last lia. intros Hxy.
-  destruct (HQ k (x3 â‹… yf)) as (x'&?&?); [auto|by rewrite assoc|].
-  exists (x' â‹… x3); split; first by rewrite -assoc.
-  apply uPred_mono with x'; eauto using cmra_includedN_l.
-Qed.
-Next Obligation. naive_solver. Qed.
-Definition uPred_bupd_aux : { x | x = @uPred_bupd_def }. by eexists. Qed.
-Definition uPred_bupd {M} := proj1_sig uPred_bupd_aux M.
-Definition uPred_bupd_eq : @uPred_bupd = @uPred_bupd_def := proj2_sig uPred_bupd_aux.
-
-Notation "P ⊢ Q" := (uPred_entails P%I Q%I)
-  (at level 99, Q at level 200, right associativity) : C_scope.
-Notation "(⊢)" := uPred_entails (only parsing) : C_scope.
-Notation "P ⊣⊢ Q" := (equiv (A:=uPred _) P%I Q%I)
-  (at level 95, no associativity) : C_scope.
-Notation "(⊣⊢)" := (equiv (A:=uPred _)) (only parsing) : C_scope.
-Notation "■ φ" := (uPred_pure φ%C%type)
-  (at level 20, right associativity) : uPred_scope.
-Notation "x = y" := (uPred_pure (x%C%type = y%C%type)) : uPred_scope.
-Notation "x ⊥ y" := (uPred_pure (x%C%type ⊥ y%C%type)) : uPred_scope.
-Notation "'False'" := (uPred_pure False) : uPred_scope.
-Notation "'True'" := (uPred_pure True) : uPred_scope.
-Infix "∧" := uPred_and : uPred_scope.
-Notation "(∧)" := uPred_and (only parsing) : uPred_scope.
-Infix "∨" := uPred_or : uPred_scope.
-Notation "(∨)" := uPred_or (only parsing) : uPred_scope.
-Infix "→" := uPred_impl : uPred_scope.
-Infix "★" := uPred_sep (at level 80, right associativity) : uPred_scope.
-Notation "(★)" := uPred_sep (only parsing) : uPred_scope.
-Notation "P -★ Q" := (uPred_wand P Q)
-  (at level 99, Q at level 200, right associativity) : uPred_scope.
-Notation "∀ x .. y , P" :=
-  (uPred_forall (λ x, .. (uPred_forall (λ y, P)) ..)%I) : uPred_scope.
-Notation "∃ x .. y , P" :=
-  (uPred_exist (λ x, .. (uPred_exist (λ y, P)) ..)%I) : uPred_scope.
-Notation "â–¡ P" := (uPred_always P)
-  (at level 20, right associativity) : uPred_scope.
-Notation "â–· P" := (uPred_later P)
-  (at level 20, right associativity) : uPred_scope.
-Infix "≡" := uPred_eq : uPred_scope.
-Notation "✓ x" := (uPred_cmra_valid x) (at level 20) : uPred_scope.
-Notation "|==> Q" := (uPred_bupd Q)
-  (at level 99, Q at level 200, format "|==>  Q") : uPred_scope.
-Notation "P ==★ Q" := (P ⊢ |==> Q)
-  (at level 99, Q at level 200, only parsing) : C_scope.
-Notation "P ==★ Q" := (P -★ |==> Q)%I
-  (at level 99, Q at level 200, format "P  ==★  Q") : uPred_scope.
-
-Definition uPred_iff {M} (P Q : uPred M) : uPred M := ((P → Q) ∧ (Q → P))%I.
-Instance: Params (@uPred_iff) 1.
-Infix "↔" := uPred_iff : uPred_scope.
-
-Definition uPred_always_if {M} (p : bool) (P : uPred M) : uPred M :=
-  (if p then â–¡ P else P)%I.
-Instance: Params (@uPred_always_if) 2.
-Arguments uPred_always_if _ !_ _/.
-Notation "â–¡? p P" := (uPred_always_if p P)
-  (at level 20, p at level 0, P at level 20, format "â–¡? p  P").
-
-Definition uPred_except_last {M} (P : uPred M) : uPred M := ▷ False ∨ P.
-Notation "â—‡ P" := (uPred_except_last P)
-  (at level 20, right associativity) : uPred_scope.
-Instance: Params (@uPred_except_last) 1.
-Typeclasses Opaque uPred_except_last.
-
-Class TimelessP {M} (P : uPred M) := timelessP : ▷ P ⊢ ◇ P.
-Arguments timelessP {_} _ {_}.
-
-Class PersistentP {M} (P : uPred M) := persistentP : P ⊢ □ P.
-Arguments persistentP {_} _ {_}.
-
-Module uPred.
-Definition unseal :=
-  (uPred_pure_eq, uPred_and_eq, uPred_or_eq, uPred_impl_eq, uPred_forall_eq,
-  uPred_exist_eq, uPred_eq_eq, uPred_sep_eq, uPred_wand_eq, uPred_always_eq,
-  uPred_later_eq, uPred_ownM_eq, uPred_cmra_valid_eq, uPred_bupd_eq).
-Ltac unseal := rewrite !unseal /=.
-
-Section uPred_logic.
-Context {M : ucmraT}.
-Implicit Types φ : Prop.
-Implicit Types P Q : uPred M.
-Implicit Types A : Type.
-Notation "P ⊢ Q" := (@uPred_entails M P%I Q%I). (* Force implicit argument M *)
-Notation "P ⊣⊢ Q" := (equiv (A:=uPred M) P%I Q%I). (* Force implicit argument M *)
-Arguments uPred_holds {_} !_ _ _ /.
-Hint Immediate uPred_in_entails.
-
-Global Instance: PreOrder (@uPred_entails M).
-Proof.
-  split.
-  - by intros P; split=> x i.
-  - by intros P Q Q' HP HQ; split=> x i ??; apply HQ, HP.
-Qed.
-Global Instance: AntiSymm (⊣⊢) (@uPred_entails M).
-Proof. intros P Q HPQ HQP; split=> x n; by split; [apply HPQ|apply HQP]. Qed.
-
-Lemma equiv_spec P Q : (P ⊣⊢ Q) ↔ (P ⊢ Q) ∧ (Q ⊢ P).
-Proof.
-  split; [|by intros [??]; apply (anti_symm (⊢))].
-  intros HPQ; split; split=> x i; apply HPQ.
-Qed.
-Lemma equiv_entails P Q : (P ⊣⊢ Q) → (P ⊢ Q).
-Proof. apply equiv_spec. Qed.
-Lemma equiv_entails_sym P Q : (Q ⊣⊢ P) → (P ⊢ Q).
-Proof. apply equiv_spec. Qed.
-Global Instance entails_proper :
-  Proper ((⊣⊢) ==> (⊣⊢) ==> iff) ((⊢) : relation (uPred M)).
-Proof.
-  move => P1 P2 /equiv_spec [HP1 HP2] Q1 Q2 /equiv_spec [HQ1 HQ2]; split; intros.
-  - by trans P1; [|trans Q1].
-  - by trans P2; [|trans Q2].
-Qed.
-Lemma entails_equiv_l (P Q R : uPred M) : (P ⊣⊢ Q) → (Q ⊢ R) → (P ⊢ R).
-Proof. by intros ->. Qed.
-Lemma entails_equiv_r (P Q R : uPred M) : (P ⊢ Q) → (Q ⊣⊢ R) → (P ⊢ R).
-Proof. by intros ? <-. Qed.
-
-(** Non-expansiveness and setoid morphisms *)
-Global Instance pure_proper : Proper (iff ==> (⊣⊢)) (@uPred_pure M).
-Proof. intros φ1 φ2 Hφ. by unseal; split=> -[|n] ?; try apply Hφ. Qed.
-Global Instance and_ne n : Proper (dist n ==> dist n ==> dist n) (@uPred_and M).
-Proof.
-  intros P P' HP Q Q' HQ; unseal; split=> x n' ??.
-  split; (intros [??]; split; [by apply HP|by apply HQ]).
-Qed.
-Global Instance and_proper :
-  Proper ((⊣⊢) ==> (⊣⊢) ==> (⊣⊢)) (@uPred_and M) := ne_proper_2 _.
-Global Instance or_ne n : Proper (dist n ==> dist n ==> dist n) (@uPred_or M).
-Proof.
-  intros P P' HP Q Q' HQ; split=> x n' ??.
-  unseal; split; (intros [?|?]; [left; by apply HP|right; by apply HQ]).
-Qed.
-Global Instance or_proper :
-  Proper ((⊣⊢) ==> (⊣⊢) ==> (⊣⊢)) (@uPred_or M) := ne_proper_2 _.
-Global Instance impl_ne n :
-  Proper (dist n ==> dist n ==> dist n) (@uPred_impl M).
-Proof.
-  intros P P' HP Q Q' HQ; split=> x n' ??.
-  unseal; split; intros HPQ x' n'' ????; apply HQ, HPQ, HP; auto.
-Qed.
-Global Instance impl_proper :
-  Proper ((⊣⊢) ==> (⊣⊢) ==> (⊣⊢)) (@uPred_impl M) := ne_proper_2 _.
-Global Instance sep_ne n : Proper (dist n ==> dist n ==> dist n) (@uPred_sep M).
-Proof.
-  intros P P' HP Q Q' HQ; split=> n' x ??.
-  unseal; split; intros (x1&x2&?&?&?); cofe_subst x;
-    exists x1, x2; split_and!; try (apply HP || apply HQ);
-    eauto using cmra_validN_op_l, cmra_validN_op_r.
-Qed.
-Global Instance sep_proper :
-  Proper ((⊣⊢) ==> (⊣⊢) ==> (⊣⊢)) (@uPred_sep M) := ne_proper_2 _.
-Global Instance wand_ne n :
-  Proper (dist n ==> dist n ==> dist n) (@uPred_wand M).
-Proof.
-  intros P P' HP Q Q' HQ; split=> n' x ??; unseal; split; intros HPQ x' n'' ???;
-    apply HQ, HPQ, HP; eauto using cmra_validN_op_r.
-Qed.
-Global Instance wand_proper :
-  Proper ((⊣⊢) ==> (⊣⊢) ==> (⊣⊢)) (@uPred_wand M) := ne_proper_2 _.
-Global Instance eq_ne (A : cofeT) n :
-  Proper (dist n ==> dist n ==> dist n) (@uPred_eq M A).
-Proof.
-  intros x x' Hx y y' Hy; split=> n' z; unseal; split; intros; simpl in *.
-  - by rewrite -(dist_le _ _ _ _ Hx) -?(dist_le _ _ _ _ Hy); auto.
-  - by rewrite (dist_le _ _ _ _ Hx) ?(dist_le _ _ _ _ Hy); auto.
-Qed.
-Global Instance eq_proper (A : cofeT) :
-  Proper ((≡) ==> (≡) ==> (⊣⊢)) (@uPred_eq M A) := ne_proper_2 _.
-Global Instance forall_ne A n :
-  Proper (pointwise_relation _ (dist n) ==> dist n) (@uPred_forall M A).
-Proof.
-  by intros Ψ1 Ψ2 HΨ; unseal; split=> n' x; split; intros HP a; apply HΨ.
-Qed.
-Global Instance forall_proper A :
-  Proper (pointwise_relation _ (⊣⊢) ==> (⊣⊢)) (@uPred_forall M A).
-Proof.
-  by intros Ψ1 Ψ2 HΨ; unseal; split=> n' x; split; intros HP a; apply HΨ.
-Qed.
-Global Instance exist_ne A n :
-  Proper (pointwise_relation _ (dist n) ==> dist n) (@uPred_exist M A).
-Proof.
-  intros Ψ1 Ψ2 HΨ.
-  unseal; split=> n' x ??; split; intros [a ?]; exists a; by apply HΨ.
-Qed.
-Global Instance exist_proper A :
-  Proper (pointwise_relation _ (⊣⊢) ==> (⊣⊢)) (@uPred_exist M A).
-Proof.
-  intros Ψ1 Ψ2 HΨ.
-  unseal; split=> n' x ?; split; intros [a ?]; exists a; by apply HΨ.
-Qed.
-Global Instance later_contractive : Contractive (@uPred_later M).
-Proof.
-  intros n P Q HPQ; unseal; split=> -[|n'] x ??; simpl; [done|].
-  apply (HPQ n'); eauto using cmra_validN_S.
-Qed.
-Global Instance later_proper' :
-  Proper ((⊣⊢) ==> (⊣⊢)) (@uPred_later M) := ne_proper _.
-Global Instance always_ne n : Proper (dist n ==> dist n) (@uPred_always M).
-Proof.
-  intros P1 P2 HP.
-  unseal; split=> n' x; split; apply HP; eauto using @cmra_core_validN.
-Qed.
-Global Instance always_proper :
-  Proper ((⊣⊢) ==> (⊣⊢)) (@uPred_always M) := ne_proper _.
-Global Instance ownM_ne n : Proper (dist n ==> dist n) (@uPred_ownM M).
-Proof.
-  intros a b Ha.
-  unseal; split=> n' x ? /=. by rewrite (dist_le _ _ _ _ Ha); last lia.
-Qed.
-Global Instance ownM_proper: Proper ((≡) ==> (⊣⊢)) (@uPred_ownM M) := ne_proper _.
-Global Instance cmra_valid_ne {A : cmraT} n :
-Proper (dist n ==> dist n) (@uPred_cmra_valid M A).
-Proof.
-  intros a b Ha; unseal; split=> n' x ? /=.
-  by rewrite (dist_le _ _ _ _ Ha); last lia.
-Qed.
-Global Instance cmra_valid_proper {A : cmraT} :
-  Proper ((≡) ==> (⊣⊢)) (@uPred_cmra_valid M A) := ne_proper _.
-Global Instance bupd_ne n : Proper (dist n ==> dist n) (@uPred_bupd M).
-Proof.
-  intros P Q HPQ.
-  unseal; split=> n' x; split; intros HP k yf ??;
-    destruct (HP k yf) as (x'&?&?); auto;
-    exists x'; split; auto; apply HPQ; eauto using cmra_validN_op_l.
-Qed.
-Global Instance bupd_proper : Proper ((≡) ==> (≡)) (@uPred_bupd M) := ne_proper _.
-
-(** Introduction and elimination rules *)
-Lemma pure_intro φ P : φ → P ⊢ ■ φ.
-Proof. by intros ?; unseal; split. Qed.
-Lemma pure_elim φ Q R : (Q ⊢ ■ φ) → (φ → Q ⊢ R) → Q ⊢ R.
-Proof.
-  unseal; intros HQP HQR; split=> n x ??; apply HQR; first eapply HQP; eauto.
-Qed.
-Lemma pure_forall_2 {A} (φ : A → Prop) : (∀ x : A, ■ φ x) ⊢ ■ (∀ x : A, φ x).
-Proof. by unseal. Qed.
-
-Lemma and_elim_l P Q : P ∧ Q ⊢ P.
-Proof. by unseal; split=> n x ? [??]. Qed.
-Lemma and_elim_r P Q : P ∧ Q ⊢ Q.
-Proof. by unseal; split=> n x ? [??]. Qed.
-Lemma and_intro P Q R : (P ⊢ Q) → (P ⊢ R) → P ⊢ Q ∧ R.
-Proof. intros HQ HR; unseal; split=> n x ??; by split; [apply HQ|apply HR]. Qed.
-
-Lemma or_intro_l P Q : P ⊢ P ∨ Q.
-Proof. unseal; split=> n x ??; left; auto. Qed.
-Lemma or_intro_r P Q : Q ⊢ P ∨ Q.
-Proof. unseal; split=> n x ??; right; auto. Qed.
-Lemma or_elim P Q R : (P ⊢ R) → (Q ⊢ R) → P ∨ Q ⊢ R.
-Proof. intros HP HQ; unseal; split=> n x ? [?|?]. by apply HP. by apply HQ. Qed.
-
-Lemma impl_intro_r P Q R : (P ∧ Q ⊢ R) → P ⊢ Q → R.
-Proof.
-  unseal; intros HQ; split=> n x ?? n' x' ????. apply HQ;
-    naive_solver eauto using uPred_mono, uPred_closed, cmra_included_includedN.
-Qed.
-Lemma impl_elim P Q R : (P ⊢ Q → R) → (P ⊢ Q) → P ⊢ R.
-Proof. by unseal; intros HP HP'; split=> n x ??; apply HP with n x, HP'. Qed.
-
-Lemma forall_intro {A} P (Ψ : A → uPred M): (∀ a, P ⊢ Ψ a) → P ⊢ ∀ a, Ψ a.
-Proof. unseal; intros HPΨ; split=> n x ?? a; by apply HPΨ. Qed.
-Lemma forall_elim {A} {Ψ : A → uPred M} a : (∀ a, Ψ a) ⊢ Ψ a.
-Proof. unseal; split=> n x ? HP; apply HP. Qed.
-
-Lemma exist_intro {A} {Ψ : A → uPred M} a : Ψ a ⊢ ∃ a, Ψ a.
-Proof. unseal; split=> n x ??; by exists a. Qed.
-Lemma exist_elim {A} (Φ : A → uPred M) Q : (∀ a, Φ a ⊢ Q) → (∃ a, Φ a) ⊢ Q.
-Proof. unseal; intros HΦΨ; split=> n x ? [a ?]; by apply HΦΨ with a. Qed.
-
-Lemma eq_refl {A : cofeT} (a : A) : True ⊢ a ≡ a.
-Proof. unseal; by split=> n x ??; simpl. Qed.
-Lemma eq_rewrite {A : cofeT} a b (Ψ : A → uPred M) P
-  {HΨ : ∀ n, Proper (dist n ==> dist n) Ψ} : (P ⊢ a ≡ b) → (P ⊢ Ψ a) → P ⊢ Ψ b.
-Proof.
-  unseal; intros Hab Ha; split=> n x ??. apply HΨ with n a; auto.
-  - by symmetry; apply Hab with x.
-  - by apply Ha.
-Qed.
-Lemma eq_equiv {A : cofeT} (a b : A) : (True ⊢ a ≡ b) → a ≡ b.
-Proof.
-  unseal=> Hab; apply equiv_dist; intros n; apply Hab with ∅; last done.
-  apply cmra_valid_validN, ucmra_unit_valid.
-Qed.
-Lemma eq_rewrite_contractive {A : cofeT} a b (Ψ : A → uPred M) P
-  {HΨ : Contractive Ψ} : (P ⊢ ▷ (a ≡ b)) → (P ⊢ Ψ a) → P ⊢ Ψ b.
-Proof.
-  unseal; intros Hab Ha; split=> n x ??. apply HΨ with n a; auto.
-  - destruct n; intros m ?; first omega. apply (dist_le n); last omega.
-    symmetry. by destruct Hab as [Hab]; eapply (Hab (S n)).
-  - by apply Ha.
-Qed.
-
-(* Derived logical stuff *)
-Lemma False_elim P : False ⊢ P.
-Proof. by apply (pure_elim False). Qed.
-Lemma True_intro P : P ⊢ True.
-Proof. by apply pure_intro. Qed.
-
-Lemma and_elim_l' P Q R : (P ⊢ R) → P ∧ Q ⊢ R.
-Proof. by rewrite and_elim_l. Qed.
-Lemma and_elim_r' P Q R : (Q ⊢ R) → P ∧ Q ⊢ R.
-Proof. by rewrite and_elim_r. Qed.
-Lemma or_intro_l' P Q R : (P ⊢ Q) → P ⊢ Q ∨ R.
-Proof. intros ->; apply or_intro_l. Qed.
-Lemma or_intro_r' P Q R : (P ⊢ R) → P ⊢ Q ∨ R.
-Proof. intros ->; apply or_intro_r. Qed.
-Lemma exist_intro' {A} P (Ψ : A → uPred M) a : (P ⊢ Ψ a) → P ⊢ ∃ a, Ψ a.
-Proof. intros ->; apply exist_intro. Qed.
-Lemma forall_elim' {A} P (Ψ : A → uPred M) : (P ⊢ ∀ a, Ψ a) → ∀ a, P ⊢ Ψ a.
-Proof. move=> HP a. by rewrite HP forall_elim. Qed.
-
-Hint Resolve pure_intro.
-Hint Resolve or_elim or_intro_l' or_intro_r'.
-Hint Resolve and_intro and_elim_l' and_elim_r'.
-Hint Immediate True_intro False_elim.
-
-Lemma impl_intro_l P Q R : (Q ∧ P ⊢ R) → P ⊢ Q → R.
-Proof. intros HR; apply impl_intro_r; rewrite -HR; auto. Qed.
-Lemma impl_elim_l P Q : (P → Q) ∧ P ⊢ Q.
-Proof. apply impl_elim with P; auto. Qed.
-Lemma impl_elim_r P Q : P ∧ (P → Q) ⊢ Q.
-Proof. apply impl_elim with P; auto. Qed.
-Lemma impl_elim_l' P Q R : (P ⊢ Q → R) → P ∧ Q ⊢ R.
-Proof. intros; apply impl_elim with Q; auto. Qed.
-Lemma impl_elim_r' P Q R : (Q ⊢ P → R) → P ∧ Q ⊢ R.
-Proof. intros; apply impl_elim with P; auto. Qed.
-Lemma impl_entails P Q : (True ⊢ P → Q) → P ⊢ Q.
-Proof. intros HPQ; apply impl_elim with P; rewrite -?HPQ; auto. Qed.
-Lemma entails_impl P Q : (P ⊢ Q) → True ⊢ P → Q.
-Proof. auto using impl_intro_l. Qed.
-
-Lemma and_mono P P' Q Q' : (P ⊢ Q) → (P' ⊢ Q') → P ∧ P' ⊢ Q ∧ Q'.
-Proof. auto. Qed.
-Lemma and_mono_l P P' Q : (P ⊢ Q) → P ∧ P' ⊢ Q ∧ P'.
-Proof. by intros; apply and_mono. Qed.
-Lemma and_mono_r P P' Q' : (P' ⊢ Q') → P ∧ P' ⊢ P ∧ Q'.
-Proof. by apply and_mono. Qed.
-
-Lemma or_mono P P' Q Q' : (P ⊢ Q) → (P' ⊢ Q') → P ∨ P' ⊢ Q ∨ Q'.
-Proof. auto. Qed.
-Lemma or_mono_l P P' Q : (P ⊢ Q) → P ∨ P' ⊢ Q ∨ P'.
-Proof. by intros; apply or_mono. Qed.
-Lemma or_mono_r P P' Q' : (P' ⊢ Q') → P ∨ P' ⊢ P ∨ Q'.
-Proof. by apply or_mono. Qed.
-
-Lemma impl_mono P P' Q Q' : (Q ⊢ P) → (P' ⊢ Q') → (P → P') ⊢ Q → Q'.
-Proof.
-  intros HP HQ'; apply impl_intro_l; rewrite -HQ'.
-  apply impl_elim with P; eauto.
-Qed.
-Lemma forall_mono {A} (Φ Ψ : A → uPred M) :
-  (∀ a, Φ a ⊢ Ψ a) → (∀ a, Φ a) ⊢ ∀ a, Ψ a.
-Proof.
-  intros HP. apply forall_intro=> a; rewrite -(HP a); apply forall_elim.
-Qed.
-Lemma exist_mono {A} (Φ Ψ : A → uPred M) :
-  (∀ a, Φ a ⊢ Ψ a) → (∃ a, Φ a) ⊢ ∃ a, Ψ a.
-Proof. intros HΦ. apply exist_elim=> a; rewrite (HΦ a); apply exist_intro. Qed.
-
-Global Instance and_mono' : Proper ((⊢) ==> (⊢) ==> (⊢)) (@uPred_and M).
-Proof. by intros P P' HP Q Q' HQ; apply and_mono. Qed.
-Global Instance and_flip_mono' :
-  Proper (flip (⊢) ==> flip (⊢) ==> flip (⊢)) (@uPred_and M).
-Proof. by intros P P' HP Q Q' HQ; apply and_mono. Qed.
-Global Instance or_mono' : Proper ((⊢) ==> (⊢) ==> (⊢)) (@uPred_or M).
-Proof. by intros P P' HP Q Q' HQ; apply or_mono. Qed.
-Global Instance or_flip_mono' :
-  Proper (flip (⊢) ==> flip (⊢) ==> flip (⊢)) (@uPred_or M).
-Proof. by intros P P' HP Q Q' HQ; apply or_mono. Qed.
-Global Instance impl_mono' :
-  Proper (flip (⊢) ==> (⊢) ==> (⊢)) (@uPred_impl M).
-Proof. by intros P P' HP Q Q' HQ; apply impl_mono. Qed.
-Global Instance forall_mono' A :
-  Proper (pointwise_relation _ (⊢) ==> (⊢)) (@uPred_forall M A).
-Proof. intros P1 P2; apply forall_mono. Qed.
-Global Instance exist_mono' A :
-  Proper (pointwise_relation _ (⊢) ==> (⊢)) (@uPred_exist M A).
-Proof. intros P1 P2; apply exist_mono. Qed.
-
-Global Instance and_idem : IdemP (⊣⊢) (@uPred_and M).
-Proof. intros P; apply (anti_symm (⊢)); auto. Qed.
-Global Instance or_idem : IdemP (⊣⊢) (@uPred_or M).
-Proof. intros P; apply (anti_symm (⊢)); auto. Qed.
-Global Instance and_comm : Comm (⊣⊢) (@uPred_and M).
-Proof. intros P Q; apply (anti_symm (⊢)); auto. Qed.
-Global Instance True_and : LeftId (⊣⊢) True%I (@uPred_and M).
-Proof. intros P; apply (anti_symm (⊢)); auto. Qed.
-Global Instance and_True : RightId (⊣⊢) True%I (@uPred_and M).
-Proof. intros P; apply (anti_symm (⊢)); auto. Qed.
-Global Instance False_and : LeftAbsorb (⊣⊢) False%I (@uPred_and M).
-Proof. intros P; apply (anti_symm (⊢)); auto. Qed.
-Global Instance and_False : RightAbsorb (⊣⊢) False%I (@uPred_and M).
-Proof. intros P; apply (anti_symm (⊢)); auto. Qed.
-Global Instance True_or : LeftAbsorb (⊣⊢) True%I (@uPred_or M).
-Proof. intros P; apply (anti_symm (⊢)); auto. Qed.
-Global Instance or_True : RightAbsorb (⊣⊢) True%I (@uPred_or M).
-Proof. intros P; apply (anti_symm (⊢)); auto. Qed.
-Global Instance False_or : LeftId (⊣⊢) False%I (@uPred_or M).
-Proof. intros P; apply (anti_symm (⊢)); auto. Qed.
-Global Instance or_False : RightId (⊣⊢) False%I (@uPred_or M).
-Proof. intros P; apply (anti_symm (⊢)); auto. Qed.
-Global Instance and_assoc : Assoc (⊣⊢) (@uPred_and M).
-Proof. intros P Q R; apply (anti_symm (⊢)); auto. Qed.
-Global Instance or_comm : Comm (⊣⊢) (@uPred_or M).
-Proof. intros P Q; apply (anti_symm (⊢)); auto. Qed.
-Global Instance or_assoc : Assoc (⊣⊢) (@uPred_or M).
-Proof. intros P Q R; apply (anti_symm (⊢)); auto. Qed.
-Global Instance True_impl : LeftId (⊣⊢) True%I (@uPred_impl M).
-Proof.
-  intros P; apply (anti_symm (⊢)).
-  - by rewrite -(left_id True%I uPred_and (_ → _)%I) impl_elim_r.
-  - by apply impl_intro_l; rewrite left_id.
-Qed.
-
-Lemma exists_impl_forall {A} P (Ψ : A → uPred M) :
-  ((∃ x : A, Ψ x) → P) ⊣⊢ ∀ x : A, Ψ x → P.
-Proof.
-  apply equiv_spec; split.
-  - apply forall_intro=>x. by rewrite -exist_intro.
-  - apply impl_intro_r, impl_elim_r', exist_elim=>x.
-    apply impl_intro_r. by rewrite (forall_elim x) impl_elim_r.
-Qed.
-
-Lemma or_and_l P Q R : P ∨ Q ∧ R ⊣⊢ (P ∨ Q) ∧ (P ∨ R).
-Proof.
-  apply (anti_symm (⊢)); first auto.
-  do 2 (apply impl_elim_l', or_elim; apply impl_intro_l); auto.
-Qed.
-Lemma or_and_r P Q R : P ∧ Q ∨ R ⊣⊢ (P ∨ R) ∧ (Q ∨ R).
-Proof. by rewrite -!(comm _ R) or_and_l. Qed.
-Lemma and_or_l P Q R : P ∧ (Q ∨ R) ⊣⊢ P ∧ Q ∨ P ∧ R.
-Proof.
-  apply (anti_symm (⊢)); last auto.
-  apply impl_elim_r', or_elim; apply impl_intro_l; auto.
-Qed.
-Lemma and_or_r P Q R : (P ∨ Q) ∧ R ⊣⊢ P ∧ R ∨ Q ∧ R.
-Proof. by rewrite -!(comm _ R) and_or_l. Qed.
-Lemma and_exist_l {A} P (Ψ : A → uPred M) : P ∧ (∃ a, Ψ a) ⊣⊢ ∃ a, P ∧ Ψ a.
-Proof.
-  apply (anti_symm (⊢)).
-  - apply impl_elim_r'. apply exist_elim=>a. apply impl_intro_l.
-    by rewrite -(exist_intro a).
-  - apply exist_elim=>a. apply and_intro; first by rewrite and_elim_l.
-    by rewrite -(exist_intro a) and_elim_r.
-Qed.
-Lemma and_exist_r {A} P (Φ: A → uPred M) : (∃ a, Φ a) ∧ P ⊣⊢ ∃ a, Φ a ∧ P.
-Proof.
-  rewrite -(comm _ P) and_exist_l. apply exist_proper=>a. by rewrite comm.
-Qed.
-
-Lemma pure_mono φ1 φ2 : (φ1 → φ2) → ■ φ1 ⊢ ■ φ2.
-Proof. intros; apply pure_elim with φ1; eauto. Qed.
-Global Instance pure_mono' : Proper (impl ==> (⊢)) (@uPred_pure M).
-Proof. intros φ1 φ2; apply pure_mono. Qed.
-Lemma pure_iff φ1 φ2 : (φ1 ↔ φ2) → ■ φ1 ⊣⊢ ■ φ2.
-Proof. intros [??]; apply (anti_symm _); auto using pure_mono. Qed.
-Lemma pure_intro_l φ Q R : φ → (■ φ ∧ Q ⊢ R) → Q ⊢ R.
-Proof. intros ? <-; auto using pure_intro. Qed.
-Lemma pure_intro_r φ Q R : φ → (Q ∧ ■ φ ⊢ R) → Q ⊢ R.
-Proof. intros ? <-; auto. Qed.
-Lemma pure_intro_impl φ Q R : φ → (Q ⊢ ■ φ → R) → Q ⊢ R.
-Proof. intros ? ->. eauto using pure_intro_l, impl_elim_r. Qed.
-Lemma pure_elim_l φ Q R : (φ → Q ⊢ R) → ■ φ ∧ Q ⊢ R.
-Proof. intros; apply pure_elim with φ; eauto. Qed.
-Lemma pure_elim_r φ Q R : (φ → Q ⊢ R) → Q ∧ ■ φ ⊢ R.
-Proof. intros; apply pure_elim with φ; eauto. Qed.
-Lemma pure_equiv (φ : Prop) : φ → ■ φ ⊣⊢ True.
-Proof. intros; apply (anti_symm _); auto. Qed.
-
-Lemma pure_and φ1 φ2 : ■ (φ1 ∧ φ2) ⊣⊢ ■ φ1 ∧ ■ φ2.
-Proof.
-  apply (anti_symm _).
-  - eapply pure_elim=> // -[??]; auto.
-  - eapply (pure_elim φ1); [auto|]=> ?. eapply (pure_elim φ2); auto.
-Qed.
-Lemma pure_or φ1 φ2 : ■ (φ1 ∨ φ2) ⊣⊢ ■ φ1 ∨ ■ φ2.
-Proof.
-  apply (anti_symm _).
-  - eapply pure_elim=> // -[?|?]; auto.
-  - apply or_elim; eapply pure_elim; eauto.
-Qed.
-Lemma pure_impl φ1 φ2 : ■ (φ1 → φ2) ⊣⊢ (■ φ1 → ■ φ2).
-Proof.
-  apply (anti_symm _).
-  - apply impl_intro_l. rewrite -pure_and. apply pure_mono. naive_solver.
-  - rewrite -pure_forall_2. apply forall_intro=> ?.
-    by rewrite -(left_id True uPred_and (_→_))%I (pure_equiv φ1) // impl_elim_r.
-Qed.
-Lemma pure_forall {A} (φ : A → Prop) : ■ (∀ x, φ x) ⊣⊢ ∀ x, ■ φ x.
-Proof.
-  apply (anti_symm _); auto using pure_forall_2.
-  apply forall_intro=> x. eauto using pure_mono.
-Qed.
-Lemma pure_exist {A} (φ : A → Prop) : ■ (∃ x, φ x) ⊣⊢ ∃ x, ■ φ x.
-Proof.
-  apply (anti_symm _).
-  - eapply pure_elim=> // -[x ?]. rewrite -(exist_intro x); auto.
-  - apply exist_elim=> x. eauto using pure_mono.
-Qed.
-
-Lemma eq_refl' {A : cofeT} (a : A) P : P ⊢ a ≡ a.
-Proof. rewrite (True_intro P). apply eq_refl. Qed.
-Hint Resolve eq_refl'.
-Lemma equiv_eq {A : cofeT} P (a b : A) : a ≡ b → P ⊢ a ≡ b.
-Proof. by intros ->. Qed.
-Lemma eq_sym {A : cofeT} (a b : A) : a ≡ b ⊢ b ≡ a.
-Proof. apply (eq_rewrite a b (λ b, b ≡ a)%I); auto. solve_proper. Qed.
-
-Lemma pure_alt φ : ■ φ ⊣⊢ ∃ _ : φ, True.
-Proof.
-  apply (anti_symm _).
-  - eapply pure_elim; eauto=> H. rewrite -(exist_intro H); auto.
-  - by apply exist_elim, pure_intro.
-Qed.
-Lemma and_alt P Q : P ∧ Q ⊣⊢ ∀ b : bool, if b then P else Q.
-Proof.
-  apply (anti_symm _); first apply forall_intro=> -[]; auto.
-  apply and_intro. by rewrite (forall_elim true). by rewrite (forall_elim false).
-Qed.
-Lemma or_alt P Q : P ∨ Q ⊣⊢ ∃ b : bool, if b then P else Q.
-Proof.
-  apply (anti_symm _); last apply exist_elim=> -[]; auto.
-  apply or_elim. by rewrite -(exist_intro true). by rewrite -(exist_intro false).
-Qed.
-
-Global Instance iff_ne n : Proper (dist n ==> dist n ==> dist n) (@uPred_iff M).
-Proof. unfold uPred_iff; solve_proper. Qed.
-Global Instance iff_proper :
-  Proper ((⊣⊢) ==> (⊣⊢) ==> (⊣⊢)) (@uPred_iff M) := ne_proper_2 _.
-
-Lemma iff_refl Q P : Q ⊢ P ↔ P.
-Proof. rewrite /uPred_iff; apply and_intro; apply impl_intro_l; auto. Qed.
-Lemma iff_equiv P Q : (True ⊢ P ↔ Q) → (P ⊣⊢ Q).
-Proof.
-  intros HPQ; apply (anti_symm (⊢));
-    apply impl_entails; rewrite HPQ /uPred_iff; auto.
-Qed.
-Lemma equiv_iff P Q : (P ⊣⊢ Q) → True ⊢ P ↔ Q.
-Proof. intros ->; apply iff_refl. Qed.
-Lemma eq_iff P Q : P ≡ Q ⊢ P ↔ Q.
-Proof.
-  apply (eq_rewrite P Q (λ Q, P ↔ Q))%I; first solve_proper; auto using iff_refl.
-Qed.
-
-(* BI connectives *)
-Lemma sep_mono P P' Q Q' : (P ⊢ Q) → (P' ⊢ Q') → P ★ P' ⊢ Q ★ Q'.
-Proof.
-  intros HQ HQ'; unseal.
-  split; intros n' x ? (x1&x2&?&?&?); exists x1,x2; cofe_subst x;
-    eauto 7 using cmra_validN_op_l, cmra_validN_op_r, uPred_in_entails.
-Qed.
-Lemma True_sep_1 P : P ⊢ True ★ P.
-Proof.
-  unseal; split; intros n x ??. exists (core x), x. by rewrite cmra_core_l.
-Qed.
-Lemma True_sep_2 P : True ★ P ⊢ P.
-Proof.
-  unseal; split; intros n x ? (x1&x2&?&_&?); cofe_subst;
-    eauto using uPred_mono, cmra_includedN_r.
-Qed.
-Lemma sep_comm' P Q : P ★ Q ⊢ Q ★ P.
-Proof.
-  unseal; split; intros n x ? (x1&x2&?&?&?); exists x2, x1; by rewrite (comm op).
-Qed.
-Lemma sep_assoc' P Q R : (P ★ Q) ★ R ⊢ P ★ (Q ★ R).
-Proof.
-  unseal; split; intros n x ? (x1&x2&Hx&(y1&y2&Hy&?&?)&?).
-  exists y1, (y2 â‹… x2); split_and?; auto.
-  + by rewrite (assoc op) -Hy -Hx.
-  + by exists y2, x2.
-Qed.
-Lemma wand_intro_r P Q R : (P ★ Q ⊢ R) → P ⊢ Q -★ R.
-Proof.
-  unseal=> HPQR; split=> n x ?? n' x' ???; apply HPQR; auto.
-  exists x, x'; split_and?; auto.
-  eapply uPred_closed with n; eauto using cmra_validN_op_l.
-Qed.
-Lemma wand_elim_l' P Q R : (P ⊢ Q -★ R) → P ★ Q ⊢ R.
-Proof.
-  unseal =>HPQR. split; intros n x ? (?&?&?&?&?). cofe_subst.
-  eapply HPQR; eauto using cmra_validN_op_l.
-Qed.
-
-(* Derived BI Stuff *)
-Hint Resolve sep_mono.
-Lemma sep_mono_l P P' Q : (P ⊢ Q) → P ★ P' ⊢ Q ★ P'.
-Proof. by intros; apply sep_mono. Qed.
-Lemma sep_mono_r P P' Q' : (P' ⊢ Q') → P ★ P' ⊢ P ★ Q'.
-Proof. by apply sep_mono. Qed.
-Global Instance sep_mono' : Proper ((⊢) ==> (⊢) ==> (⊢)) (@uPred_sep M).
-Proof. by intros P P' HP Q Q' HQ; apply sep_mono. Qed.
-Global Instance sep_flip_mono' :
-  Proper (flip (⊢) ==> flip (⊢) ==> flip (⊢)) (@uPred_sep M).
-Proof. by intros P P' HP Q Q' HQ; apply sep_mono. Qed.
-Lemma wand_mono P P' Q Q' : (Q ⊢ P) → (P' ⊢ Q') → (P -★ P') ⊢ Q -★ Q'.
-Proof.
-  intros HP HQ; apply wand_intro_r. rewrite HP -HQ. by apply wand_elim_l'.
-Qed.
-Global Instance wand_mono' : Proper (flip (⊢) ==> (⊢) ==> (⊢)) (@uPred_wand M).
-Proof. by intros P P' HP Q Q' HQ; apply wand_mono. Qed.
-
-Global Instance sep_comm : Comm (⊣⊢) (@uPred_sep M).
-Proof. intros P Q; apply (anti_symm _); auto using sep_comm'. Qed.
-Global Instance sep_assoc : Assoc (⊣⊢) (@uPred_sep M).
-Proof.
-  intros P Q R; apply (anti_symm _); auto using sep_assoc'.
-  by rewrite !(comm _ P) !(comm _ _ R) sep_assoc'.
-Qed.
-Global Instance True_sep : LeftId (⊣⊢) True%I (@uPred_sep M).
-Proof. intros P; apply (anti_symm _); auto using True_sep_1, True_sep_2. Qed.
-Global Instance sep_True : RightId (⊣⊢) True%I (@uPred_sep M).
-Proof. by intros P; rewrite comm left_id. Qed.
-Lemma sep_elim_l P Q : P ★ Q ⊢ P.
-Proof. by rewrite (True_intro Q) right_id. Qed.
-Lemma sep_elim_r P Q : P ★ Q ⊢ Q.
-Proof. by rewrite (comm (★))%I; apply sep_elim_l. Qed.
-Lemma sep_elim_l' P Q R : (P ⊢ R) → P ★ Q ⊢ R.
-Proof. intros ->; apply sep_elim_l. Qed.
-Lemma sep_elim_r' P Q R : (Q ⊢ R) → P ★ Q ⊢ R.
-Proof. intros ->; apply sep_elim_r. Qed.
-Hint Resolve sep_elim_l' sep_elim_r'.
-Lemma sep_intro_True_l P Q R : (True ⊢ P) → (R ⊢ Q) → R ⊢ P ★ Q.
-Proof. by intros; rewrite -(left_id True%I uPred_sep R); apply sep_mono. Qed.
-Lemma sep_intro_True_r P Q R : (R ⊢ P) → (True ⊢ Q) → R ⊢ P ★ Q.
-Proof. by intros; rewrite -(right_id True%I uPred_sep R); apply sep_mono. Qed.
-Lemma sep_elim_True_l P Q R : (True ⊢ P) → (P ★ R ⊢ Q) → R ⊢ Q.
-Proof. by intros HP; rewrite -HP left_id. Qed.
-Lemma sep_elim_True_r P Q R : (True ⊢ P) → (R ★ P ⊢ Q) → R ⊢ Q.
-Proof. by intros HP; rewrite -HP right_id. Qed.
-Lemma wand_intro_l P Q R : (Q ★ P ⊢ R) → P ⊢ Q -★ R.
-Proof. rewrite comm; apply wand_intro_r. Qed.
-Lemma wand_elim_l P Q : (P -★ Q) ★ P ⊢ Q.
-Proof. by apply wand_elim_l'. Qed.
-Lemma wand_elim_r P Q : P ★ (P -★ Q) ⊢ Q.
-Proof. rewrite (comm _ P); apply wand_elim_l. Qed.
-Lemma wand_elim_r' P Q R : (Q ⊢ P -★ R) → P ★ Q ⊢ R.
-Proof. intros ->; apply wand_elim_r. Qed.
-Lemma wand_apply_l P Q Q' R R' : (P ⊢ Q' -★ R') → (R' ⊢ R) → (Q ⊢ Q') → P ★ Q ⊢ R.
-Proof. intros -> -> <-; apply wand_elim_l. Qed.
-Lemma wand_apply_r P Q Q' R R' : (P ⊢ Q' -★ R') → (R' ⊢ R) → (Q ⊢ Q') → Q ★ P ⊢ R.
-Proof. intros -> -> <-; apply wand_elim_r. Qed.
-Lemma wand_apply_l' P Q Q' R : (P ⊢ Q' -★ R) → (Q ⊢ Q') → P ★ Q ⊢ R.
-Proof. intros -> <-; apply wand_elim_l. Qed.
-Lemma wand_apply_r' P Q Q' R : (P ⊢ Q' -★ R) → (Q ⊢ Q') → Q ★ P ⊢ R.
-Proof. intros -> <-; apply wand_elim_r. Qed.
-Lemma wand_frame_l P Q R : (Q -★ R) ⊢ P ★ Q -★ P ★ R.
-Proof. apply wand_intro_l. rewrite -assoc. apply sep_mono_r, wand_elim_r. Qed.
-Lemma wand_frame_r P Q R : (Q -★ R) ⊢ Q ★ P -★ R ★ P.
-Proof.
-  apply wand_intro_l. rewrite ![(_ ★ P)%I]comm -assoc.
-  apply sep_mono_r, wand_elim_r.
-Qed.
-Lemma wand_diag P : (P -★ P) ⊣⊢ True.
-Proof. apply (anti_symm _); auto. apply wand_intro_l; by rewrite right_id. Qed.
-Lemma wand_True P : (True -★ P) ⊣⊢ P.
-Proof.
-  apply (anti_symm _); last by auto using wand_intro_l.
-  eapply sep_elim_True_l; first reflexivity. by rewrite wand_elim_r.
-Qed.
-Lemma wand_entails P Q : (True ⊢ P -★ Q) → P ⊢ Q.
-Proof.
-  intros HPQ. eapply sep_elim_True_r; first exact: HPQ. by rewrite wand_elim_r.
-Qed.
-Lemma entails_wand P Q : (P ⊢ Q) → True ⊢ P -★ Q.
-Proof. auto using wand_intro_l. Qed.
-Lemma wand_curry P Q R : (P -★ Q -★ R) ⊣⊢ (P ★ Q -★ R).
-Proof.
-  apply (anti_symm _).
-  - apply wand_intro_l. by rewrite (comm _ P) -assoc !wand_elim_r.
-  - do 2 apply wand_intro_l. by rewrite assoc (comm _ Q) wand_elim_r.
-Qed.
-
-Lemma sep_and P Q : (P ★ Q) ⊢ (P ∧ Q).
-Proof. auto. Qed.
-Lemma impl_wand P Q : (P → Q) ⊢ P -★ Q.
-Proof. apply wand_intro_r, impl_elim with P; auto. Qed.
-Lemma pure_elim_sep_l φ Q R : (φ → Q ⊢ R) → ■ φ ★ Q ⊢ R.
-Proof. intros; apply pure_elim with φ; eauto. Qed.
-Lemma pure_elim_sep_r φ Q R : (φ → Q ⊢ R) → Q ★ ■ φ ⊢ R.
-Proof. intros; apply pure_elim with φ; eauto. Qed.
-
-Global Instance sep_False : LeftAbsorb (⊣⊢) False%I (@uPred_sep M).
-Proof. intros P; apply (anti_symm _); auto. Qed.
-Global Instance False_sep : RightAbsorb (⊣⊢) False%I (@uPred_sep M).
-Proof. intros P; apply (anti_symm _); auto. Qed.
-
-Lemma sep_and_l P Q R : P ★ (Q ∧ R) ⊢ (P ★ Q) ∧ (P ★ R).
-Proof. auto. Qed.
-Lemma sep_and_r P Q R : (P ∧ Q) ★ R ⊢ (P ★ R) ∧ (Q ★ R).
-Proof. auto. Qed.
-Lemma sep_or_l P Q R : P ★ (Q ∨ R) ⊣⊢ (P ★ Q) ∨ (P ★ R).
-Proof.
-  apply (anti_symm (⊢)); last by eauto 8.
-  apply wand_elim_r', or_elim; apply wand_intro_l; auto.
-Qed.
-Lemma sep_or_r P Q R : (P ∨ Q) ★ R ⊣⊢ (P ★ R) ∨ (Q ★ R).
-Proof. by rewrite -!(comm _ R) sep_or_l. Qed.
-Lemma sep_exist_l {A} P (Ψ : A → uPred M) : P ★ (∃ a, Ψ a) ⊣⊢ ∃ a, P ★ Ψ a.
-Proof.
-  intros; apply (anti_symm (⊢)).
-  - apply wand_elim_r', exist_elim=>a. apply wand_intro_l.
-    by rewrite -(exist_intro a).
-  - apply exist_elim=> a; apply sep_mono; auto using exist_intro.
-Qed.
-Lemma sep_exist_r {A} (Φ: A → uPred M) Q: (∃ a, Φ a) ★ Q ⊣⊢ ∃ a, Φ a ★ Q.
-Proof. setoid_rewrite (comm _ _ Q); apply sep_exist_l. Qed.
-Lemma sep_forall_l {A} P (Ψ : A → uPred M) : P ★ (∀ a, Ψ a) ⊢ ∀ a, P ★ Ψ a.
-Proof. by apply forall_intro=> a; rewrite forall_elim. Qed.
-Lemma sep_forall_r {A} (Φ : A → uPred M) Q : (∀ a, Φ a) ★ Q ⊢ ∀ a, Φ a ★ Q.
-Proof. by apply forall_intro=> a; rewrite forall_elim. Qed.
-
-(* Always *)
-Lemma always_mono P Q : (P ⊢ Q) → □ P ⊢ □ Q.
-Proof. intros HP; unseal; split=> n x ? /=. by apply HP, cmra_core_validN. Qed.
-Lemma always_elim P : □ P ⊢ P.
-Proof.
-  unseal; split=> n x ? /=.
-  eauto using uPred_mono, @cmra_included_core, cmra_included_includedN.
-Qed.
-Lemma always_idemp P : □ P ⊢ □ □ P.
-Proof. unseal; split=> n x ?? /=. by rewrite cmra_core_idemp. Qed.
-
-Lemma always_pure_2 φ : ■ φ ⊢ □ ■ φ.
-Proof. by unseal. Qed.
-Lemma always_forall_2 {A} (Ψ : A → uPred M) : (∀ a, □ Ψ a) ⊢ (□ ∀ a, Ψ a).
-Proof. by unseal. Qed.
-Lemma always_exist_1 {A} (Ψ : A → uPred M) : (□ ∃ a, Ψ a) ⊢ (∃ a, □ Ψ a).
-Proof. by unseal. Qed.
-
-Lemma always_and_sep_1 P Q : □ (P ∧ Q) ⊢ □ (P ★ Q).
-Proof.
-  unseal; split=> n x ? [??].
-  exists (core x), (core x); rewrite -cmra_core_dup; auto.
-Qed.
-Lemma always_and_sep_l_1 P Q : □ P ∧ Q ⊢ □ P ★ Q.
-Proof.
-  unseal; split=> n x ? [??]; exists (core x), x; simpl in *.
-  by rewrite cmra_core_l cmra_core_idemp.
-Qed.
-
-(* Always derived *)
-Hint Resolve always_mono always_elim.
-Global Instance always_mono' : Proper ((⊢) ==> (⊢)) (@uPred_always M).
-Proof. intros P Q; apply always_mono. Qed.
-Global Instance always_flip_mono' :
-  Proper (flip (⊢) ==> flip (⊢)) (@uPred_always M).
-Proof. intros P Q; apply always_mono. Qed.
-
-Lemma always_intro' P Q : (□ P ⊢ Q) → □ P ⊢ □ Q.
-Proof. intros <-. apply always_idemp. Qed.
-
-Lemma always_pure φ : □ ■ φ ⊣⊢ ■ φ.
-Proof. apply (anti_symm _); auto using always_pure_2. Qed.
-Lemma always_forall {A} (Ψ : A → uPred M) : (□ ∀ a, Ψ a) ⊣⊢ (∀ a, □ Ψ a).
-Proof.
-  apply (anti_symm _); auto using always_forall_2.
-  apply forall_intro=> x. by rewrite (forall_elim x).
-Qed.
-Lemma always_exist {A} (Ψ : A → uPred M) : (□ ∃ a, Ψ a) ⊣⊢ (∃ a, □ Ψ a).
-Proof.
-  apply (anti_symm _); auto using always_exist_1.
-  apply exist_elim=> x. by rewrite (exist_intro x).
-Qed.
-Lemma always_and P Q : □ (P ∧ Q) ⊣⊢ □ P ∧ □ Q.
-Proof. rewrite !and_alt always_forall. by apply forall_proper=> -[]. Qed.
-Lemma always_or P Q : □ (P ∨ Q) ⊣⊢ □ P ∨ □ Q.
-Proof. rewrite !or_alt always_exist. by apply exist_proper=> -[]. Qed.
-Lemma always_impl P Q : □ (P → Q) ⊢ □ P → □ Q.
-Proof.
-  apply impl_intro_l; rewrite -always_and.
-  apply always_mono, impl_elim with P; auto.
-Qed.
-Lemma always_eq {A:cofeT} (a b : A) : □ (a ≡ b) ⊣⊢ a ≡ b.
-Proof.
-  apply (anti_symm (⊢)); auto using always_elim.
-  apply (eq_rewrite a b (λ b, □ (a ≡ b))%I); auto.
-  { intros n; solve_proper. }
-  rewrite -(eq_refl a) always_pure; auto.
-Qed.
-
-Lemma always_and_sep P Q : □ (P ∧ Q) ⊣⊢ □ (P ★ Q).
-Proof. apply (anti_symm (⊢)); auto using always_and_sep_1. Qed.
-Lemma always_and_sep_l' P Q : □ P ∧ Q ⊣⊢ □ P ★ Q.
-Proof. apply (anti_symm (⊢)); auto using always_and_sep_l_1. Qed.
-Lemma always_and_sep_r' P Q : P ∧ □ Q ⊣⊢ P ★ □ Q.
-Proof. by rewrite !(comm _ P) always_and_sep_l'. Qed.
-Lemma always_sep P Q : □ (P ★ Q) ⊣⊢ □ P ★ □ Q.
-Proof. by rewrite -always_and_sep -always_and_sep_l' always_and. Qed.
-Lemma always_sep_dup' P : □ P ⊣⊢ □ P ★ □ P.
-Proof. by rewrite -always_sep -always_and_sep (idemp _). Qed.
-
-Lemma always_wand P Q : □ (P -★ Q) ⊢ □ P -★ □ Q.
-Proof. by apply wand_intro_r; rewrite -always_sep wand_elim_l. Qed.
-Lemma always_wand_impl P Q : □ (P -★ Q) ⊣⊢ □ (P → Q).
-Proof.
-  apply (anti_symm (⊢)); [|by rewrite -impl_wand].
-  apply always_intro', impl_intro_r.
-  by rewrite always_and_sep_l' always_elim wand_elim_l.
-Qed.
-Lemma always_entails_l' P Q : (P ⊢ □ Q) → P ⊢ □ Q ★ P.
-Proof. intros; rewrite -always_and_sep_l'; auto. Qed.
-Lemma always_entails_r' P Q : (P ⊢ □ Q) → P ⊢ P ★ □ Q.
-Proof. intros; rewrite -always_and_sep_r'; auto. Qed.
-
-(* Later *)
-Lemma later_mono P Q : (P ⊢ Q) → ▷ P ⊢ ▷ Q.
-Proof.
-  unseal=> HP; split=>-[|n] x ??; [done|apply HP; eauto using cmra_validN_S].
-Qed.
-Lemma löb P : (▷ P → P) ⊢ P.
-Proof.
-  unseal; split=> n x ? HP; induction n as [|n IH]; [by apply HP|].
-  apply HP, IH, uPred_closed with (S n); eauto using cmra_validN_S.
-Qed.
-Lemma later_forall_2 {A} (Φ : A → uPred M) : (∀ a, ▷ Φ a) ⊢ ▷ ∀ a, Φ a.
-Proof. unseal; by split=> -[|n] x. Qed.
-Lemma later_exist_false {A} (Φ : A → uPred M) :
-  (▷ ∃ a, Φ a) ⊢ ▷ False ∨ (∃ a, ▷ Φ a).
-Proof. unseal; split=> -[|[|n]] x /=; eauto. Qed.
-Lemma later_sep P Q : ▷ (P ★ Q) ⊣⊢ ▷ P ★ ▷ Q.
-Proof.
-  unseal; split=> n x ?; split.
-  - destruct n as [|n]; simpl.
-    { by exists x, (core x); rewrite cmra_core_r. }
-    intros (x1&x2&Hx&?&?); destruct (cmra_extend n x x1 x2)
-      as (y1&y2&Hx'&Hy1&Hy2); eauto using cmra_validN_S; simpl in *.
-    exists y1, y2; split; [by rewrite Hx'|by rewrite Hy1 Hy2].
-  - destruct n as [|n]; simpl; [done|intros (x1&x2&Hx&?&?)].
-    exists x1, x2; eauto using dist_S.
-Qed.
-Lemma later_false_excluded_middle P : ▷ P ⊢ ▷ False ∨ (▷ False → P).
-Proof.
-  unseal; split=> -[|n] x ? /= HP; [by left|right].
-  intros [|n'] x' ????; [|done].
-  eauto using uPred_closed, uPred_mono, cmra_included_includedN.
-Qed.
-
-Lemma always_later P : □ ▷ P ⊣⊢ ▷ □ P.
-Proof. by unseal. Qed.
-
-
-(* Later derived *)
-Lemma later_proper P Q : (P ⊣⊢ Q) → ▷ P ⊣⊢ ▷ Q.
-Proof. by intros ->. Qed.
-Hint Resolve later_mono later_proper.
-Global Instance later_mono' : Proper ((⊢) ==> (⊢)) (@uPred_later M).
-Proof. intros P Q; apply later_mono. Qed.
-Global Instance later_flip_mono' :
-  Proper (flip (⊢) ==> flip (⊢)) (@uPred_later M).
-Proof. intros P Q; apply later_mono. Qed.
-
-Lemma later_intro P : P ⊢ ▷ P.
-Proof.
-  rewrite -(and_elim_l (▷ P) P) -(löb (▷ P ∧ P)).
-  apply impl_intro_l. by rewrite {1}(and_elim_r (â–· P)).
-Qed.
-
-Lemma later_True : ▷ True ⊣⊢ True.
-Proof. apply (anti_symm (⊢)); auto using later_intro. Qed.
-Lemma later_forall {A} (Φ : A → uPred M) : (▷ ∀ a, Φ a) ⊣⊢ (∀ a, ▷ Φ a).
-Proof.
-  apply (anti_symm _); auto using later_forall_2.
-  apply forall_intro=> x. by rewrite (forall_elim x).
-Qed.
-Lemma later_exist `{Inhabited A} (Φ : A → uPred M) :
-  ▷ (∃ a, Φ a) ⊣⊢ (∃ a, ▷ Φ a).
-Proof.
-  apply: anti_symm; [|apply exist_elim; eauto using exist_intro].
-  rewrite later_exist_false. apply or_elim; last done.
-  rewrite -(exist_intro inhabitant); auto.
-Qed.
-Lemma later_and P Q : ▷ (P ∧ Q) ⊣⊢ ▷ P ∧ ▷ Q.
-Proof. rewrite !and_alt later_forall. by apply forall_proper=> -[]. Qed.
-Lemma later_or P Q : ▷ (P ∨ Q) ⊣⊢ ▷ P ∨ ▷ Q.
-Proof. rewrite !or_alt later_exist. by apply exist_proper=> -[]. Qed.
-Lemma later_impl P Q : ▷ (P → Q) ⊢ ▷ P → ▷ Q.
-Proof. apply impl_intro_l; rewrite -later_and; eauto using impl_elim. Qed.
-Lemma later_wand P Q : ▷ (P -★ Q) ⊢ ▷ P -★ ▷ Q.
-Proof. apply wand_intro_r; rewrite -later_sep; eauto using wand_elim_l. Qed.
-Lemma later_iff P Q : ▷ (P ↔ Q) ⊢ ▷ P ↔ ▷ Q.
-Proof. by rewrite /uPred_iff later_and !later_impl. Qed.
-
-
-(* Conditional always *)
-Global Instance always_if_ne n p : Proper (dist n ==> dist n) (@uPred_always_if M p).
-Proof. solve_proper. Qed.
-Global Instance always_if_proper p : Proper ((⊣⊢) ==> (⊣⊢)) (@uPred_always_if M p).
-Proof. solve_proper. Qed.
-Global Instance always_if_mono p : Proper ((⊢) ==> (⊢)) (@uPred_always_if M p).
-Proof. solve_proper. Qed.
-
-Lemma always_if_elim p P : □?p P ⊢ P.
-Proof. destruct p; simpl; auto using always_elim. Qed.
-Lemma always_elim_if p P : □ P ⊢ □?p P.
-Proof. destruct p; simpl; auto using always_elim. Qed.
-
-Lemma always_if_pure p φ : □?p ■ φ ⊣⊢ ■ φ.
-Proof. destruct p; simpl; auto using always_pure. Qed.
-Lemma always_if_and p P Q : □?p (P ∧ Q) ⊣⊢ □?p P ∧ □?p Q.
-Proof. destruct p; simpl; auto using always_and. Qed.
-Lemma always_if_or p P Q : □?p (P ∨ Q) ⊣⊢ □?p P ∨ □?p Q.
-Proof. destruct p; simpl; auto using always_or. Qed.
-Lemma always_if_exist {A} p (Ψ : A → uPred M) : (□?p ∃ a, Ψ a) ⊣⊢ ∃ a, □?p Ψ a.
-Proof. destruct p; simpl; auto using always_exist. Qed.
-Lemma always_if_sep p P Q : □?p (P ★ Q) ⊣⊢ □?p P ★ □?p Q.
-Proof. destruct p; simpl; auto using always_sep. Qed.
-Lemma always_if_later p P : □?p ▷ P ⊣⊢ ▷ □?p P.
-Proof. destruct p; simpl; auto using always_later. Qed.
-
-
-(* True now *)
-Global Instance except_last_ne n : Proper (dist n ==> dist n) (@uPred_except_last M).
-Proof. solve_proper. Qed.
-Global Instance except_last_proper : Proper ((⊣⊢) ==> (⊣⊢)) (@uPred_except_last M).
-Proof. solve_proper. Qed.
-Global Instance except_last_mono' : Proper ((⊢) ==> (⊢)) (@uPred_except_last M).
-Proof. solve_proper. Qed.
-Global Instance except_last_flip_mono' :
-  Proper (flip (⊢) ==> flip (⊢)) (@uPred_except_last M).
-Proof. solve_proper. Qed.
-
-Lemma except_last_intro P : P ⊢ ◇ P.
-Proof. rewrite /uPred_except_last; auto. Qed.
-Lemma except_last_mono P Q : (P ⊢ Q) → ◇ P ⊢ ◇ Q.
-Proof. by intros ->. Qed.
-Lemma except_last_idemp P : ◇ ◇ P ⊢ ◇ P.
-Proof. rewrite /uPred_except_last; auto. Qed.
-
-Lemma except_last_True : ◇ True ⊣⊢ True.
-Proof. rewrite /uPred_except_last. apply (anti_symm _); auto. Qed.
-Lemma except_last_or P Q : ◇ (P ∨ Q) ⊣⊢ ◇ P ∨ ◇ Q.
-Proof. rewrite /uPred_except_last. apply (anti_symm _); auto. Qed.
-Lemma except_last_and P Q : ◇ (P ∧ Q) ⊣⊢ ◇ P ∧ ◇ Q.
-Proof. by rewrite /uPred_except_last or_and_l. Qed.
-Lemma except_last_sep P Q : ◇ (P ★ Q) ⊣⊢ ◇ P ★ ◇ Q.
-Proof.
-  rewrite /uPred_except_last. apply (anti_symm _).
-  - apply or_elim; last by auto.
-    by rewrite -!or_intro_l -always_pure -always_later -always_sep_dup'.
-  - rewrite sep_or_r sep_elim_l sep_or_l; auto.
-Qed.
-Lemma except_last_forall {A} (Φ : A → uPred M) : ◇ (∀ a, Φ a) ⊢ ∀ a, ◇ Φ a.
-Proof. apply forall_intro=> a. by rewrite (forall_elim a). Qed.
-Lemma except_last_exist {A} (Φ : A → uPred M) : (∃ a, ◇ Φ a) ⊢ ◇ ∃ a, Φ a.
-Proof. apply exist_elim=> a. by rewrite (exist_intro a). Qed.
-Lemma except_last_later P : ◇ ▷ P ⊢ ▷ P.
-Proof. by rewrite /uPred_except_last -later_or False_or. Qed.
-Lemma except_last_always P : ◇ □ P ⊣⊢ □ ◇ P.
-Proof. by rewrite /uPred_except_last always_or always_later always_pure. Qed.
-Lemma except_last_always_if p P : ◇ □?p P ⊣⊢ □?p ◇ P.
-Proof. destruct p; simpl; auto using except_last_always. Qed.
-Lemma except_last_frame_l P Q : P ★ ◇ Q ⊢ ◇ (P ★ Q).
-Proof. by rewrite {1}(except_last_intro P) except_last_sep. Qed.
-Lemma except_last_frame_r P Q : ◇ P ★ Q ⊢ ◇ (P ★ Q).
-Proof. by rewrite {1}(except_last_intro Q) except_last_sep. Qed.
-
-(* Own *)
-Lemma ownM_op (a1 a2 : M) :
-  uPred_ownM (a1 ⋅ a2) ⊣⊢ uPred_ownM a1 ★ uPred_ownM a2.
-Proof.
-  unseal; split=> n x ?; split.
-  - intros [z ?]; exists a1, (a2 â‹… z); split; [by rewrite (assoc op)|].
-    split. by exists (core a1); rewrite cmra_core_r. by exists z.
-  - intros (y1&y2&Hx&[z1 Hy1]&[z2 Hy2]); exists (z1 â‹… z2).
-    by rewrite (assoc op _ z1) -(comm op z1) (assoc op z1)
-      -(assoc op _ a2) (comm op z1) -Hy1 -Hy2.
-Qed.
-Lemma always_ownM_core (a : M) : uPred_ownM a ⊢ □ uPred_ownM (core a).
-Proof.
-  split=> n x /=; unseal; intros Hx. simpl. by apply cmra_core_monoN.
-Qed.
-Lemma ownM_empty : True ⊢ uPred_ownM ∅.
-Proof. unseal; split=> n x ??; by  exists x; rewrite left_id. Qed.
-Lemma later_ownM a : ▷ uPred_ownM a ⊢ ∃ b, uPred_ownM b ∧ ▷ (a ≡ b).
-Proof.
-  unseal; split=> -[|n] x /= ? Hax; first by eauto using ucmra_unit_leastN.
-  destruct Hax as [y ?].
-  destruct (cmra_extend n x a y) as (a'&y'&Hx&?&?); auto using cmra_validN_S.
-  exists a'. rewrite Hx. eauto using cmra_includedN_l.
-Qed.
-
-(* Valid *)
-Lemma ownM_valid (a : M) : uPred_ownM a ⊢ ✓ a.
-Proof.
-  unseal; split=> n x Hv [a' ?]; cofe_subst; eauto using cmra_validN_op_l.
-Qed.
-Lemma cmra_valid_intro {A : cmraT} (a : A) : ✓ a → True ⊢ ✓ a.
-Proof. unseal=> ?; split=> n x ? _ /=; by apply cmra_valid_validN. Qed.
-Lemma cmra_valid_elim {A : cmraT} (a : A) : ¬ ✓{0} a → ✓ a ⊢ False.
-Proof. unseal=> Ha; split=> n x ??; apply Ha, cmra_validN_le with n; auto. Qed.
-Lemma always_cmra_valid_1 {A : cmraT} (a : A) : ✓ a ⊢ □ ✓ a.
-Proof. by unseal. Qed.
-Lemma cmra_valid_weaken {A : cmraT} (a b : A) : ✓ (a ⋅ b) ⊢ ✓ a.
-Proof. unseal; split=> n x _; apply cmra_validN_op_l. Qed.
-
-(* Own and valid derived *)
-Lemma always_ownM (a : M) : Persistent a → □ uPred_ownM a ⊣⊢ uPred_ownM a.
-Proof.
-  intros; apply (anti_symm _); first by apply:always_elim.
-  by rewrite {1}always_ownM_core persistent_core.
-Qed.
-Lemma ownM_invalid (a : M) : ¬ ✓{0} a → uPred_ownM a ⊢ False.
-Proof. by intros; rewrite ownM_valid cmra_valid_elim. Qed.
-Global Instance ownM_mono : Proper (flip (≼) ==> (⊢)) (@uPred_ownM M).
-Proof. intros a b [b' ->]. rewrite ownM_op. eauto. Qed.
-Lemma ownM_empty' : uPred_ownM ∅ ⊣⊢ True.
-Proof. apply (anti_symm _); auto using ownM_empty. Qed.
-Lemma always_cmra_valid {A : cmraT} (a : A) : □ ✓ a ⊣⊢ ✓ a.
-  intros; apply (anti_symm _); first by apply:always_elim.
-  apply:always_cmra_valid_1.
-Qed.
-
-(* Basic update modality *)
-Lemma bupd_intro P : P ==★ P.
-Proof.
-  unseal. split=> n x ? HP k yf ?; exists x; split; first done.
-  apply uPred_closed with n; eauto using cmra_validN_op_l.
-Qed.
-Lemma bupd_mono P Q : (P ⊢ Q) → (|==> P) ==★ Q.
-Proof.
-  unseal. intros HPQ; split=> n x ? HP k yf ??.
-  destruct (HP k yf) as (x'&?&?); eauto.
-  exists x'; split; eauto using uPred_in_entails, cmra_validN_op_l.
-Qed.
-Lemma bupd_trans P : (|==> |==> P) ==★ P.
-Proof. unseal; split; naive_solver. Qed.
-Lemma bupd_frame_r P R : (|==> P) ★ R ==★ P ★ R.
-Proof.
-  unseal; split; intros n x ? (x1&x2&Hx&HP&?) k yf ??.
-  destruct (HP k (x2 â‹… yf)) as (x'&?&?); eauto.
-  { by rewrite assoc -(dist_le _ _ _ _ Hx); last lia. }
-  exists (x' â‹… x2); split; first by rewrite -assoc.
-  exists x', x2; split_and?; auto.
-  apply uPred_closed with n; eauto 3 using cmra_validN_op_l, cmra_validN_op_r.
-Qed.
-Lemma bupd_ownM_updateP x (Φ : M → Prop) :
-  x ~~>: Φ → uPred_ownM x ==★ ∃ y, ■ Φ y ∧ uPred_ownM y.
-Proof.
-  unseal=> Hup; split=> n x2 ? [x3 Hx] k yf ??.
-  destruct (Hup k (Some (x3 â‹… yf))) as (y&?&?); simpl in *.
-  { rewrite /= assoc -(dist_le _ _ _ _ Hx); auto. }
-  exists (y â‹… x3); split; first by rewrite -assoc.
-  exists y; eauto using cmra_includedN_l.
-Qed.
-
-(** * Derived rules *)
-Global Instance bupd_mono' : Proper ((⊢) ==> (⊢)) (@uPred_bupd M).
-Proof. intros P Q; apply bupd_mono. Qed.
-Global Instance bupd_flip_mono' : Proper (flip (⊢) ==> flip (⊢)) (@uPred_bupd M).
-Proof. intros P Q; apply bupd_mono. Qed.
-Lemma bupd_frame_l R Q : (R ★ |==> Q) ==★ R ★ Q.
-Proof. rewrite !(comm _ R); apply bupd_frame_r. Qed.
-Lemma bupd_wand_l P Q : (P -★ Q) ★ (|==> P) ==★ Q.
-Proof. by rewrite bupd_frame_l wand_elim_l. Qed.
-Lemma bupd_wand_r P Q : (|==> P) ★ (P -★ Q) ==★ Q.
-Proof. by rewrite bupd_frame_r wand_elim_r. Qed.
-Lemma bupd_sep P Q : (|==> P) ★ (|==> Q) ==★ P ★ Q.
-Proof. by rewrite bupd_frame_r bupd_frame_l bupd_trans. Qed.
-Lemma bupd_ownM_update x y : x ~~> y → uPred_ownM x ⊢ |==> uPred_ownM y.
-Proof.
-  intros; rewrite (bupd_ownM_updateP _ (y =)); last by apply cmra_update_updateP.
-  by apply bupd_mono, exist_elim=> y'; apply pure_elim_l=> ->.
-Qed.
-Lemma except_last_bupd P : ◇ (|==> P) ⊢ (|==> ◇ P).
-Proof.
-  rewrite /uPred_except_last. apply or_elim; auto using bupd_mono.
-  by rewrite -bupd_intro -or_intro_l.
-Qed.
-
-(* Products *)
-Lemma prod_equivI {A B : cofeT} (x y : A * B) : x ≡ y ⊣⊢ x.1 ≡ y.1 ∧ x.2 ≡ y.2.
-Proof. by unseal. Qed.
-Lemma prod_validI {A B : cmraT} (x : A * B) : ✓ x ⊣⊢ ✓ x.1 ∧ ✓ x.2.
-Proof. by unseal. Qed.
-
-(* Later *)
-Lemma later_equivI {A : cofeT} (x y : A) : Next x ≡ Next y ⊣⊢ ▷ (x ≡ y).
-Proof. by unseal. Qed.
-
-(* Discrete *)
-Lemma discrete_valid {A : cmraT} `{!CMRADiscrete A} (a : A) : ✓ a ⊣⊢ ■ ✓ a.
-Proof. unseal; split=> n x _. by rewrite /= -cmra_discrete_valid_iff. Qed.
-Lemma timeless_eq {A : cofeT} (a b : A) : Timeless a → a ≡ b ⊣⊢ ■ (a ≡ b).
-Proof.
-  unseal=> ?. apply (anti_symm (⊢)); split=> n x ?; by apply (timeless_iff n).
-Qed.
-
-(* Option *)
-Lemma option_equivI {A : cofeT} (mx my : option A) :
-  mx ≡ my ⊣⊢ match mx, my with
-             | Some x, Some y => x ≡ y | None, None => True | _, _ => False
-             end.
-Proof.
-  uPred.unseal. do 2 split. by destruct 1. by destruct mx, my; try constructor.
-Qed.
-Lemma option_validI {A : cmraT} (mx : option A) :
-  ✓ mx ⊣⊢ match mx with Some x => ✓ x | None => True end.
-Proof. uPred.unseal. by destruct mx. Qed.
-
-(* Functions *)
-Lemma cofe_funC_equivI {A B} (f g : A -c> B) : f ≡ g ⊣⊢ ∀ x, f x ≡ g x.
-Proof. by uPred.unseal. Qed.
-Lemma cofe_moreC_equivI {A B : cofeT} (f g : A -n> B) : f ≡ g ⊣⊢ ∀ x, f x ≡ g x.
-Proof. by uPred.unseal. Qed.
-
-(* Timeless instances *)
-Global Instance pure_timeless φ : TimelessP (■ φ : uPred M)%I.
-Proof.
-  rewrite /TimelessP pure_alt later_exist_false. by setoid_rewrite later_True.
-Qed.
-Global Instance valid_timeless {A : cmraT} `{CMRADiscrete A} (a : A) :
-  TimelessP (✓ a : uPred M)%I.
-Proof. rewrite /TimelessP !discrete_valid. apply (timelessP _). Qed.
-Global Instance and_timeless P Q: TimelessP P → TimelessP Q → TimelessP (P ∧ Q).
-Proof. intros; rewrite /TimelessP except_last_and later_and; auto. Qed.
-Global Instance or_timeless P Q : TimelessP P → TimelessP Q → TimelessP (P ∨ Q).
-Proof. intros; rewrite /TimelessP except_last_or later_or; auto. Qed.
-Global Instance impl_timeless P Q : TimelessP Q → TimelessP (P → Q).
-Proof.
-  rewrite /TimelessP=> HQ. rewrite later_false_excluded_middle.
-  apply or_mono, impl_intro_l; first done.
-  rewrite -{2}(löb Q); apply impl_intro_l.
-  rewrite HQ /uPred_except_last !and_or_r. apply or_elim; last auto.
-  by rewrite assoc (comm _ _ P) -assoc !impl_elim_r.
-Qed.
-Global Instance sep_timeless P Q: TimelessP P → TimelessP Q → TimelessP (P ★ Q).
-Proof. intros; rewrite /TimelessP except_last_sep later_sep; auto. Qed.
-Global Instance wand_timeless P Q : TimelessP Q → TimelessP (P -★ Q).
-Proof.
-  rewrite /TimelessP=> HQ. rewrite later_false_excluded_middle.
-  apply or_mono, wand_intro_l; first done.
-  rewrite -{2}(löb Q); apply impl_intro_l.
-  rewrite HQ /uPred_except_last !and_or_r. apply or_elim; last auto.
-  rewrite -(always_pure) -always_later always_and_sep_l'.
-  by rewrite assoc (comm _ _ P) -assoc -always_and_sep_l' impl_elim_r wand_elim_r.
-Qed.
-Global Instance forall_timeless {A} (Ψ : A → uPred M) :
-  (∀ x, TimelessP (Ψ x)) → TimelessP (∀ x, Ψ x).
-Proof.
-  rewrite /TimelessP=> HQ. rewrite later_false_excluded_middle.
-  apply or_mono; first done. apply forall_intro=> x.
-  rewrite -(löb (Ψ x)); apply impl_intro_l.
-  rewrite HQ /uPred_except_last !and_or_r. apply or_elim; last auto.
-  by rewrite impl_elim_r (forall_elim x).
-Qed.
-Global Instance exist_timeless {A} (Ψ : A → uPred M) :
-  (∀ x, TimelessP (Ψ x)) → TimelessP (∃ x, Ψ x).
-Proof.
-  rewrite /TimelessP=> ?. rewrite later_exist_false. apply or_elim.
-  - rewrite /uPred_except_last; auto.
-  - apply exist_elim=> x. rewrite -(exist_intro x); auto.
-Qed.
-Global Instance always_timeless P : TimelessP P → TimelessP (□ P).
-Proof. intros; rewrite /TimelessP except_last_always -always_later; auto. Qed.
-Global Instance always_if_timeless p P : TimelessP P → TimelessP (□?p P).
-Proof. destruct p; apply _. Qed.
-Global Instance eq_timeless {A : cofeT} (a b : A) :
-  Timeless a → TimelessP (a ≡ b : uPred M)%I.
-Proof. intros. rewrite /TimelessP !timeless_eq. apply (timelessP _). Qed.
-Global Instance ownM_timeless (a : M) : Timeless a → TimelessP (uPred_ownM a).
-Proof.
-  intros ?. rewrite /TimelessP later_ownM. apply exist_elim=> b.
-  rewrite (timelessP (a≡b)) (except_last_intro (uPred_ownM b)) -except_last_and.
-  apply except_last_mono. rewrite eq_sym.
-  apply (eq_rewrite b a (uPred_ownM)); first apply _; auto.
-Qed.
-
-(* Persistence *)
-Global Instance pure_persistent φ : PersistentP (■ φ : uPred M)%I.
-Proof. by rewrite /PersistentP always_pure. Qed.
-Global Instance always_persistent P : PersistentP (â–¡ P).
-Proof. by intros; apply always_intro'. Qed.
-Global Instance and_persistent P Q :
-  PersistentP P → PersistentP Q → PersistentP (P ∧ Q).
-Proof. by intros; rewrite /PersistentP always_and; apply and_mono. Qed.
-Global Instance or_persistent P Q :
-  PersistentP P → PersistentP Q → PersistentP (P ∨ Q).
-Proof. by intros; rewrite /PersistentP always_or; apply or_mono. Qed.
-Global Instance sep_persistent P Q :
-  PersistentP P → PersistentP Q → PersistentP (P ★ Q).
-Proof. by intros; rewrite /PersistentP always_sep; apply sep_mono. Qed.
-Global Instance forall_persistent {A} (Ψ : A → uPred M) :
-  (∀ x, PersistentP (Ψ x)) → PersistentP (∀ x, Ψ x).
-Proof. by intros; rewrite /PersistentP always_forall; apply forall_mono. Qed.
-Global Instance exist_persistent {A} (Ψ : A → uPred M) :
-  (∀ x, PersistentP (Ψ x)) → PersistentP (∃ x, Ψ x).
-Proof. by intros; rewrite /PersistentP always_exist; apply exist_mono. Qed.
-Global Instance eq_persistent {A : cofeT} (a b : A) :
-  PersistentP (a ≡ b : uPred M)%I.
-Proof. by intros; rewrite /PersistentP always_eq. Qed.
-Global Instance cmra_valid_persistent {A : cmraT} (a : A) :
-  PersistentP (✓ a : uPred M)%I.
-Proof. by intros; rewrite /PersistentP always_cmra_valid. Qed.
-Global Instance later_persistent P : PersistentP P → PersistentP (▷ P).
-Proof. by intros; rewrite /PersistentP always_later; apply later_mono. Qed.
-Global Instance ownM_persistent : Persistent a → PersistentP (@uPred_ownM M a).
-Proof. intros. by rewrite /PersistentP always_ownM. Qed.
-Global Instance from_option_persistent {A} P (Ψ : A → uPred M) (mx : option A) :
-  (∀ x, PersistentP (Ψ x)) → PersistentP P → PersistentP (from_option Ψ P mx).
-Proof. destruct mx; apply _. Qed.
-
-(* Derived lemmas for persistence *)
-Lemma always_always P `{!PersistentP P} : □ P ⊣⊢ P.
-Proof. apply (anti_symm (⊢)); auto using always_elim. Qed.
-Lemma always_if_always p P `{!PersistentP P} : □?p P ⊣⊢ P.
-Proof. destruct p; simpl; auto using always_always. Qed.
-Lemma always_intro P Q `{!PersistentP P} : (P ⊢ Q) → P ⊢ □ Q.
-Proof. rewrite -(always_always P); apply always_intro'. Qed.
-Lemma always_and_sep_l P Q `{!PersistentP P} : P ∧ Q ⊣⊢ P ★ Q.
-Proof. by rewrite -(always_always P) always_and_sep_l'. Qed.
-Lemma always_and_sep_r P Q `{!PersistentP Q} : P ∧ Q ⊣⊢ P ★ Q.
-Proof. by rewrite -(always_always Q) always_and_sep_r'. Qed.
-Lemma always_sep_dup P `{!PersistentP P} : P ⊣⊢ P ★ P.
-Proof. by rewrite -(always_always P) -always_sep_dup'. Qed.
-Lemma always_entails_l P Q `{!PersistentP Q} : (P ⊢ Q) → P ⊢ Q ★ P.
-Proof. by rewrite -(always_always Q); apply always_entails_l'. Qed.
-Lemma always_entails_r P Q `{!PersistentP Q} : (P ⊢ Q) → P ⊢ P ★ Q.
-Proof. by rewrite -(always_always Q); apply always_entails_r'. Qed.
-
-(** Consistency and adequancy statements *)
-Lemma adequacy φ n : (True ⊢ Nat.iter n (λ P, |==> ▷ P) (■ φ)) → φ.
-Proof.
-  cut (∀ x, ✓{n} x → Nat.iter n (λ P, |==> ▷ P)%I (■ φ)%I n x → φ).
-  { intros help H. eapply (help ∅); eauto using ucmra_unit_validN.
-    eapply H; try unseal; eauto using ucmra_unit_validN. }
-  unseal. induction n as [|n IH]=> x Hx Hupd; auto.
-  destruct (Hupd (S n) ∅) as (x'&?&?); rewrite ?right_id; auto.
-  eapply IH with x'; eauto using cmra_validN_S, cmra_validN_op_l.
-Qed.
-
-Corollary consistency_modal n : ¬ (True ⊢ Nat.iter n (λ P, |==> ▷ P) False).
-Proof. exact (adequacy False n). Qed.
-
-Corollary consistency : ¬ (True ⊢ False).
-Proof. exact (consistency_modal 0). Qed.
-End uPred_logic.
-
-(* Hint DB for the logic *)
-Hint Resolve pure_intro.
-Hint Resolve or_elim or_intro_l' or_intro_r' : I.
-Hint Resolve and_intro and_elim_l' and_elim_r' : I.
-Hint Resolve always_mono : I.
-Hint Resolve sep_elim_l' sep_elim_r' sep_mono : I.
-Hint Immediate True_intro False_elim : I.
-Hint Immediate iff_refl eq_refl' : I.
-End uPred.
-
-Import uPred.
-
-(* CMRA structure on uPred *)
-Section cmra.
-  Context {M : ucmraT}.
-
-  Instance uPred_valid : Valid (uPred M) := λ P, ∀ n x, ✓{n} x → P n x.
-  Instance uPred_validN : ValidN (uPred M) := λ n P,
-    ∀ n' x, n' ≤ n → ✓{n'} x → P n' x.
-  Instance uPred_op : Op (uPred M) := uPred_sep.
-  Instance uPred_pcore : PCore (uPred M) := λ _, Some True%I.
-
-  Instance uPred_validN_ne n : Proper (dist n ==> iff) (uPred_validN n).
-  Proof. intros P Q HPQ; split=> H n' x ??; by apply HPQ, H. Qed.
-
-  Lemma uPred_validN_alt n (P : uPred M) : ✓{n} P → P ≡{n}≡ True%I.
-  Proof.
-    unseal=> HP; split=> n' x ??; split; [done|].
-    intros _. by apply HP.
-  Qed.
-
-  Lemma uPred_cmra_validN_op_l n P Q : ✓{n} (P ★ Q)%I → ✓{n} P.
-  Proof.
-    unseal. intros HPQ n' x ??.
-    destruct (HPQ n' x) as (x1&x2&->&?&?); auto.
-    eapply uPred_mono with x1; eauto using cmra_includedN_l.
-  Qed.
-
-  Lemma uPred_included P Q : P ≼ Q → Q ⊢ P.
-  Proof. intros [P' ->]. apply sep_elim_l. Qed.
-
-  Definition uPred_cmra_mixin : CMRAMixin (uPred M).
-  Proof.
-    apply cmra_total_mixin; try apply _ || by eauto.
-    - intros n P Q ??. by cofe_subst.
-    - intros P; split.
-      + intros HP n n' x ?. apply HP.
-      + intros HP n x. by apply (HP n).
-    - intros n P HP n' x ?. apply HP; auto.
-    - intros P. by rewrite left_id.
-    - intros P Q _. exists True%I. by rewrite left_id.
-    - intros n P Q. apply uPred_cmra_validN_op_l.
-    - intros n P Q1 Q2 HP HPQ. exists True%I, P; split_and!.
-      + by rewrite left_id.
-      + move: HP; by rewrite HPQ=> /uPred_cmra_validN_op_l /uPred_validN_alt.
-      + move: HP; rewrite HPQ=> /uPred_cmra_validN_op_l /uPred_validN_alt=> ->.
-        by rewrite left_id.
-  Qed.
-
-  Canonical Structure uPredR :=
-    CMRAT (uPred M) uPred_cofe_mixin uPred_cmra_mixin.
-
-  Instance uPred_empty : Empty (uPred M) := True%I.
-
-  Definition uPred_ucmra_mixin : UCMRAMixin (uPred M).
-  Proof.
-    split; last done.
-    - by rewrite /empty /uPred_empty uPred_pure_eq.
-    - intros P. by rewrite left_id.
-  Qed.
-
-  Canonical Structure uPredUR :=
-    UCMRAT (uPred M) uPred_cofe_mixin uPred_cmra_mixin uPred_ucmra_mixin.
-
-  Global Instance uPred_always_homomorphism : UCMRAHomomorphism uPred_always.
-  Proof. split; [split|]. apply _. apply always_sep. apply always_pure. Qed.
-  Global Instance uPred_always_if_homomorphism b :
-    UCMRAHomomorphism (uPred_always_if b).
-  Proof. split; [split|]. apply _. apply always_if_sep. apply always_if_pure. Qed.
-  Global Instance uPred_later_homomorphism : UCMRAHomomorphism uPred_later.
-  Proof. split; [split|]. apply _. apply later_sep. apply later_True. Qed.
-  Global Instance uPred_except_last_homomorphism :
-    CMRAHomomorphism uPred_except_last.
-  Proof. split. apply _. apply except_last_sep. Qed.
-  Global Instance uPred_ownM_homomorphism : UCMRAHomomorphism uPred_ownM.
-  Proof. split; [split|]. apply _. apply ownM_op. apply ownM_empty'. Qed.
-End cmra.
-
-Arguments uPredR : clear implicits.
-Arguments uPredUR : clear implicits.
diff --git a/base_logic/base_logic.v b/base_logic/base_logic.v
new file mode 100644
index 000000000..31e643b15
--- /dev/null
+++ b/base_logic/base_logic.v
@@ -0,0 +1,17 @@
+From iris.base_logic Require Export derived.
+
+Module uPred.
+  Include uPred_entails.
+  Include uPred_primitive.
+  Include uPred_derived.
+End uPred.
+
+(* Hint DB for the logic *)
+Import uPred.
+Hint Resolve pure_intro.
+Hint Resolve or_elim or_intro_l' or_intro_r' : I.
+Hint Resolve and_intro and_elim_l' and_elim_r' : I.
+Hint Resolve always_mono : I.
+Hint Resolve sep_elim_l' sep_elim_r' sep_mono : I.
+Hint Immediate True_intro False_elim : I.
+Hint Immediate iff_refl eq_refl' : I.
diff --git a/algebra/upred_big_op.v b/base_logic/big_op.v
similarity index 85%
rename from algebra/upred_big_op.v
rename to base_logic/big_op.v
index 9f2dded3d..214c9e69e 100644
--- a/algebra/upred_big_op.v
+++ b/base_logic/big_op.v
@@ -1,7 +1,89 @@
-From iris.algebra Require Export upred list cmra_big_op.
+From iris.algebra Require Export list cmra_big_op.
+From iris.base_logic Require Export base_logic.
 From iris.prelude Require Import gmap fin_collections functions.
 Import uPred.
 
+(* We make use of the bigops on CMRAs, so we first define a (somewhat ad-hoc)
+CMRA structure on uPred. *)
+Section cmra.
+  Context {M : ucmraT}.
+
+  Instance uPred_valid : Valid (uPred M) := λ P, ∀ n x, ✓{n} x → P n x.
+  Instance uPred_validN : ValidN (uPred M) := λ n P,
+    ∀ n' x, n' ≤ n → ✓{n'} x → P n' x.
+  Instance uPred_op : Op (uPred M) := uPred_sep.
+  Instance uPred_pcore : PCore (uPred M) := λ _, Some True%I.
+
+  Instance uPred_validN_ne n : Proper (dist n ==> iff) (uPred_validN n).
+  Proof. intros P Q HPQ; split=> H n' x ??; by apply HPQ, H. Qed.
+
+  Lemma uPred_validN_alt n (P : uPred M) : ✓{n} P → P ≡{n}≡ True%I.
+  Proof.
+    unseal=> HP; split=> n' x ??; split; [done|].
+    intros _. by apply HP.
+  Qed.
+
+  Lemma uPred_cmra_validN_op_l n P Q : ✓{n} (P ★ Q)%I → ✓{n} P.
+  Proof.
+    unseal. intros HPQ n' x ??.
+    destruct (HPQ n' x) as (x1&x2&->&?&?); auto.
+    eapply uPred_mono with x1; eauto using cmra_includedN_l.
+  Qed.
+
+  Lemma uPred_included P Q : P ≼ Q → Q ⊢ P.
+  Proof. intros [P' ->]. apply sep_elim_l. Qed.
+
+  Definition uPred_cmra_mixin : CMRAMixin (uPred M).
+  Proof.
+    apply cmra_total_mixin; try apply _ || by eauto.
+    - intros n P Q ??. by cofe_subst.
+    - intros P; split.
+      + intros HP n n' x ?. apply HP.
+      + intros HP n x. by apply (HP n).
+    - intros n P HP n' x ?. apply HP; auto.
+    - intros P. by rewrite left_id.
+    - intros P Q _. exists True%I. by rewrite left_id.
+    - intros n P Q. apply uPred_cmra_validN_op_l.
+    - intros n P Q1 Q2 HP HPQ. exists True%I, P; split_and!.
+      + by rewrite left_id.
+      + move: HP; by rewrite HPQ=> /uPred_cmra_validN_op_l /uPred_validN_alt.
+      + move: HP; rewrite HPQ=> /uPred_cmra_validN_op_l /uPred_validN_alt=> ->.
+        by rewrite left_id.
+  Qed.
+
+  Canonical Structure uPredR :=
+    CMRAT (uPred M) uPred_cofe_mixin uPred_cmra_mixin.
+
+  Instance uPred_empty : Empty (uPred M) := True%I.
+
+  Definition uPred_ucmra_mixin : UCMRAMixin (uPred M).
+  Proof.
+    split; last done.
+    - by rewrite /empty /uPred_empty uPred_pure_eq.
+    - intros P. by rewrite left_id.
+  Qed.
+
+  Canonical Structure uPredUR :=
+    UCMRAT (uPred M) uPred_cofe_mixin uPred_cmra_mixin uPred_ucmra_mixin.
+
+  Global Instance uPred_always_homomorphism : UCMRAHomomorphism uPred_always.
+  Proof. split; [split|]. apply _. apply always_sep. apply always_pure. Qed.
+  Global Instance uPred_always_if_homomorphism b :
+    UCMRAHomomorphism (uPred_always_if b).
+  Proof. split; [split|]. apply _. apply always_if_sep. apply always_if_pure. Qed.
+  Global Instance uPred_later_homomorphism : UCMRAHomomorphism uPred_later.
+  Proof. split; [split|]. apply _. apply later_sep. apply later_True. Qed.
+  Global Instance uPred_except_0_homomorphism :
+    CMRAHomomorphism uPred_except_0.
+  Proof. split. apply _. apply except_0_sep. Qed.
+  Global Instance uPred_ownM_homomorphism : UCMRAHomomorphism uPred_ownM.
+  Proof. split; [split|]. apply _. apply ownM_op. apply ownM_empty'. Qed.
+End cmra.
+
+Arguments uPredR : clear implicits.
+Arguments uPredUR : clear implicits.
+
+(* Notations *)
 Notation "'[★]' Ps" := (big_op (M:=uPredUR _) Ps) (at level 20) : uPred_scope.
 
 Notation "'[★' 'list' ] k ↦ x ∈ l , P" := (big_opL (M:=uPredUR _) l (λ k x, P))
diff --git a/base_logic/derived.v b/base_logic/derived.v
new file mode 100644
index 000000000..7cb853696
--- /dev/null
+++ b/base_logic/derived.v
@@ -0,0 +1,751 @@
+From iris.base_logic Require Export primitive.
+Import uPred_entails uPred_primitive.
+
+Definition uPred_iff {M} (P Q : uPred M) : uPred M := ((P → Q) ∧ (Q → P))%I.
+Instance: Params (@uPred_iff) 1.
+Infix "↔" := uPred_iff : uPred_scope.
+
+Definition uPred_always_if {M} (p : bool) (P : uPred M) : uPred M :=
+  (if p then â–¡ P else P)%I.
+Instance: Params (@uPred_always_if) 2.
+Arguments uPred_always_if _ !_ _/.
+Notation "â–¡? p P" := (uPred_always_if p P)
+  (at level 20, p at level 0, P at level 20, format "â–¡? p  P").
+
+Definition uPred_except_last {M} (P : uPred M) : uPred M := ▷ False ∨ P.
+Notation "â—‡ P" := (uPred_except_last P)
+  (at level 20, right associativity) : uPred_scope.
+Instance: Params (@uPred_except_last) 1.
+Typeclasses Opaque uPred_except_last.
+
+Class TimelessP {M} (P : uPred M) := timelessP : ▷ P ⊢ ◇ P.
+Arguments timelessP {_} _ {_}.
+
+Class PersistentP {M} (P : uPred M) := persistentP : P ⊢ □ P.
+Arguments persistentP {_} _ {_}.
+
+Module uPred_derived.
+Section derived.
+Context {M : ucmraT}.
+Implicit Types φ : Prop.
+Implicit Types P Q : uPred M.
+Implicit Types A : Type.
+Notation "P ⊢ Q" := (@uPred_entails M P%I Q%I). (* Force implicit argument M *)
+Notation "P ⊣⊢ Q" := (equiv (A:=uPred M) P%I Q%I). (* Force implicit argument M *)
+
+(* Derived logical stuff *)
+Lemma False_elim P : False ⊢ P.
+Proof. by apply (pure_elim False). Qed.
+Lemma True_intro P : P ⊢ True.
+Proof. by apply pure_intro. Qed.
+
+Lemma and_elim_l' P Q R : (P ⊢ R) → P ∧ Q ⊢ R.
+Proof. by rewrite and_elim_l. Qed.
+Lemma and_elim_r' P Q R : (Q ⊢ R) → P ∧ Q ⊢ R.
+Proof. by rewrite and_elim_r. Qed.
+Lemma or_intro_l' P Q R : (P ⊢ Q) → P ⊢ Q ∨ R.
+Proof. intros ->; apply or_intro_l. Qed.
+Lemma or_intro_r' P Q R : (P ⊢ R) → P ⊢ Q ∨ R.
+Proof. intros ->; apply or_intro_r. Qed.
+Lemma exist_intro' {A} P (Ψ : A → uPred M) a : (P ⊢ Ψ a) → P ⊢ ∃ a, Ψ a.
+Proof. intros ->; apply exist_intro. Qed.
+Lemma forall_elim' {A} P (Ψ : A → uPred M) : (P ⊢ ∀ a, Ψ a) → ∀ a, P ⊢ Ψ a.
+Proof. move=> HP a. by rewrite HP forall_elim. Qed.
+
+Hint Resolve pure_intro.
+Hint Resolve or_elim or_intro_l' or_intro_r'.
+Hint Resolve and_intro and_elim_l' and_elim_r'.
+Hint Immediate True_intro False_elim.
+
+Lemma impl_intro_l P Q R : (Q ∧ P ⊢ R) → P ⊢ Q → R.
+Proof. intros HR; apply impl_intro_r; rewrite -HR; auto. Qed.
+Lemma impl_elim_l P Q : (P → Q) ∧ P ⊢ Q.
+Proof. apply impl_elim with P; auto. Qed.
+Lemma impl_elim_r P Q : P ∧ (P → Q) ⊢ Q.
+Proof. apply impl_elim with P; auto. Qed.
+Lemma impl_elim_l' P Q R : (P ⊢ Q → R) → P ∧ Q ⊢ R.
+Proof. intros; apply impl_elim with Q; auto. Qed.
+Lemma impl_elim_r' P Q R : (Q ⊢ P → R) → P ∧ Q ⊢ R.
+Proof. intros; apply impl_elim with P; auto. Qed.
+Lemma impl_entails P Q : (True ⊢ P → Q) → P ⊢ Q.
+Proof. intros HPQ; apply impl_elim with P; rewrite -?HPQ; auto. Qed.
+Lemma entails_impl P Q : (P ⊢ Q) → True ⊢ P → Q.
+Proof. auto using impl_intro_l. Qed.
+
+Lemma and_mono P P' Q Q' : (P ⊢ Q) → (P' ⊢ Q') → P ∧ P' ⊢ Q ∧ Q'.
+Proof. auto. Qed.
+Lemma and_mono_l P P' Q : (P ⊢ Q) → P ∧ P' ⊢ Q ∧ P'.
+Proof. by intros; apply and_mono. Qed.
+Lemma and_mono_r P P' Q' : (P' ⊢ Q') → P ∧ P' ⊢ P ∧ Q'.
+Proof. by apply and_mono. Qed.
+
+Lemma or_mono P P' Q Q' : (P ⊢ Q) → (P' ⊢ Q') → P ∨ P' ⊢ Q ∨ Q'.
+Proof. auto. Qed.
+Lemma or_mono_l P P' Q : (P ⊢ Q) → P ∨ P' ⊢ Q ∨ P'.
+Proof. by intros; apply or_mono. Qed.
+Lemma or_mono_r P P' Q' : (P' ⊢ Q') → P ∨ P' ⊢ P ∨ Q'.
+Proof. by apply or_mono. Qed.
+
+Lemma impl_mono P P' Q Q' : (Q ⊢ P) → (P' ⊢ Q') → (P → P') ⊢ Q → Q'.
+Proof.
+  intros HP HQ'; apply impl_intro_l; rewrite -HQ'.
+  apply impl_elim with P; eauto.
+Qed.
+Lemma forall_mono {A} (Φ Ψ : A → uPred M) :
+  (∀ a, Φ a ⊢ Ψ a) → (∀ a, Φ a) ⊢ ∀ a, Ψ a.
+Proof.
+  intros HP. apply forall_intro=> a; rewrite -(HP a); apply forall_elim.
+Qed.
+Lemma exist_mono {A} (Φ Ψ : A → uPred M) :
+  (∀ a, Φ a ⊢ Ψ a) → (∃ a, Φ a) ⊢ ∃ a, Ψ a.
+Proof. intros HΦ. apply exist_elim=> a; rewrite (HΦ a); apply exist_intro. Qed.
+
+Global Instance and_mono' : Proper ((⊢) ==> (⊢) ==> (⊢)) (@uPred_and M).
+Proof. by intros P P' HP Q Q' HQ; apply and_mono. Qed.
+Global Instance and_flip_mono' :
+  Proper (flip (⊢) ==> flip (⊢) ==> flip (⊢)) (@uPred_and M).
+Proof. by intros P P' HP Q Q' HQ; apply and_mono. Qed.
+Global Instance or_mono' : Proper ((⊢) ==> (⊢) ==> (⊢)) (@uPred_or M).
+Proof. by intros P P' HP Q Q' HQ; apply or_mono. Qed.
+Global Instance or_flip_mono' :
+  Proper (flip (⊢) ==> flip (⊢) ==> flip (⊢)) (@uPred_or M).
+Proof. by intros P P' HP Q Q' HQ; apply or_mono. Qed.
+Global Instance impl_mono' :
+  Proper (flip (⊢) ==> (⊢) ==> (⊢)) (@uPred_impl M).
+Proof. by intros P P' HP Q Q' HQ; apply impl_mono. Qed.
+Global Instance forall_mono' A :
+  Proper (pointwise_relation _ (⊢) ==> (⊢)) (@uPred_forall M A).
+Proof. intros P1 P2; apply forall_mono. Qed.
+Global Instance exist_mono' A :
+  Proper (pointwise_relation _ (⊢) ==> (⊢)) (@uPred_exist M A).
+Proof. intros P1 P2; apply exist_mono. Qed.
+
+Global Instance and_idem : IdemP (⊣⊢) (@uPred_and M).
+Proof. intros P; apply (anti_symm (⊢)); auto. Qed.
+Global Instance or_idem : IdemP (⊣⊢) (@uPred_or M).
+Proof. intros P; apply (anti_symm (⊢)); auto. Qed.
+Global Instance and_comm : Comm (⊣⊢) (@uPred_and M).
+Proof. intros P Q; apply (anti_symm (⊢)); auto. Qed.
+Global Instance True_and : LeftId (⊣⊢) True%I (@uPred_and M).
+Proof. intros P; apply (anti_symm (⊢)); auto. Qed.
+Global Instance and_True : RightId (⊣⊢) True%I (@uPred_and M).
+Proof. intros P; apply (anti_symm (⊢)); auto. Qed.
+Global Instance False_and : LeftAbsorb (⊣⊢) False%I (@uPred_and M).
+Proof. intros P; apply (anti_symm (⊢)); auto. Qed.
+Global Instance and_False : RightAbsorb (⊣⊢) False%I (@uPred_and M).
+Proof. intros P; apply (anti_symm (⊢)); auto. Qed.
+Global Instance True_or : LeftAbsorb (⊣⊢) True%I (@uPred_or M).
+Proof. intros P; apply (anti_symm (⊢)); auto. Qed.
+Global Instance or_True : RightAbsorb (⊣⊢) True%I (@uPred_or M).
+Proof. intros P; apply (anti_symm (⊢)); auto. Qed.
+Global Instance False_or : LeftId (⊣⊢) False%I (@uPred_or M).
+Proof. intros P; apply (anti_symm (⊢)); auto. Qed.
+Global Instance or_False : RightId (⊣⊢) False%I (@uPred_or M).
+Proof. intros P; apply (anti_symm (⊢)); auto. Qed.
+Global Instance and_assoc : Assoc (⊣⊢) (@uPred_and M).
+Proof. intros P Q R; apply (anti_symm (⊢)); auto. Qed.
+Global Instance or_comm : Comm (⊣⊢) (@uPred_or M).
+Proof. intros P Q; apply (anti_symm (⊢)); auto. Qed.
+Global Instance or_assoc : Assoc (⊣⊢) (@uPred_or M).
+Proof. intros P Q R; apply (anti_symm (⊢)); auto. Qed.
+Global Instance True_impl : LeftId (⊣⊢) True%I (@uPred_impl M).
+Proof.
+  intros P; apply (anti_symm (⊢)).
+  - by rewrite -(left_id True%I uPred_and (_ → _)%I) impl_elim_r.
+  - by apply impl_intro_l; rewrite left_id.
+Qed.
+
+Lemma exists_impl_forall {A} P (Ψ : A → uPred M) :
+  ((∃ x : A, Ψ x) → P) ⊣⊢ ∀ x : A, Ψ x → P.
+Proof.
+  apply equiv_spec; split.
+  - apply forall_intro=>x. by rewrite -exist_intro.
+  - apply impl_intro_r, impl_elim_r', exist_elim=>x.
+    apply impl_intro_r. by rewrite (forall_elim x) impl_elim_r.
+Qed.
+
+Lemma or_and_l P Q R : P ∨ Q ∧ R ⊣⊢ (P ∨ Q) ∧ (P ∨ R).
+Proof.
+  apply (anti_symm (⊢)); first auto.
+  do 2 (apply impl_elim_l', or_elim; apply impl_intro_l); auto.
+Qed.
+Lemma or_and_r P Q R : P ∧ Q ∨ R ⊣⊢ (P ∨ R) ∧ (Q ∨ R).
+Proof. by rewrite -!(comm _ R) or_and_l. Qed.
+Lemma and_or_l P Q R : P ∧ (Q ∨ R) ⊣⊢ P ∧ Q ∨ P ∧ R.
+Proof.
+  apply (anti_symm (⊢)); last auto.
+  apply impl_elim_r', or_elim; apply impl_intro_l; auto.
+Qed.
+Lemma and_or_r P Q R : (P ∨ Q) ∧ R ⊣⊢ P ∧ R ∨ Q ∧ R.
+Proof. by rewrite -!(comm _ R) and_or_l. Qed.
+Lemma and_exist_l {A} P (Ψ : A → uPred M) : P ∧ (∃ a, Ψ a) ⊣⊢ ∃ a, P ∧ Ψ a.
+Proof.
+  apply (anti_symm (⊢)).
+  - apply impl_elim_r'. apply exist_elim=>a. apply impl_intro_l.
+    by rewrite -(exist_intro a).
+  - apply exist_elim=>a. apply and_intro; first by rewrite and_elim_l.
+    by rewrite -(exist_intro a) and_elim_r.
+Qed.
+Lemma and_exist_r {A} P (Φ: A → uPred M) : (∃ a, Φ a) ∧ P ⊣⊢ ∃ a, Φ a ∧ P.
+Proof.
+  rewrite -(comm _ P) and_exist_l. apply exist_proper=>a. by rewrite comm.
+Qed.
+
+Lemma pure_mono φ1 φ2 : (φ1 → φ2) → ■ φ1 ⊢ ■ φ2.
+Proof. intros; apply pure_elim with φ1; eauto. Qed.
+Global Instance pure_mono' : Proper (impl ==> (⊢)) (@uPred_pure M).
+Proof. intros φ1 φ2; apply pure_mono. Qed.
+Lemma pure_iff φ1 φ2 : (φ1 ↔ φ2) → ■ φ1 ⊣⊢ ■ φ2.
+Proof. intros [??]; apply (anti_symm _); auto using pure_mono. Qed.
+Lemma pure_intro_l φ Q R : φ → (■ φ ∧ Q ⊢ R) → Q ⊢ R.
+Proof. intros ? <-; auto using pure_intro. Qed.
+Lemma pure_intro_r φ Q R : φ → (Q ∧ ■ φ ⊢ R) → Q ⊢ R.
+Proof. intros ? <-; auto. Qed.
+Lemma pure_intro_impl φ Q R : φ → (Q ⊢ ■ φ → R) → Q ⊢ R.
+Proof. intros ? ->. eauto using pure_intro_l, impl_elim_r. Qed.
+Lemma pure_elim_l φ Q R : (φ → Q ⊢ R) → ■ φ ∧ Q ⊢ R.
+Proof. intros; apply pure_elim with φ; eauto. Qed.
+Lemma pure_elim_r φ Q R : (φ → Q ⊢ R) → Q ∧ ■ φ ⊢ R.
+Proof. intros; apply pure_elim with φ; eauto. Qed.
+Lemma pure_equiv (φ : Prop) : φ → ■ φ ⊣⊢ True.
+Proof. intros; apply (anti_symm _); auto. Qed.
+
+Lemma pure_and φ1 φ2 : ■ (φ1 ∧ φ2) ⊣⊢ ■ φ1 ∧ ■ φ2.
+Proof.
+  apply (anti_symm _).
+  - eapply pure_elim=> // -[??]; auto.
+  - eapply (pure_elim φ1); [auto|]=> ?. eapply (pure_elim φ2); auto.
+Qed.
+Lemma pure_or φ1 φ2 : ■ (φ1 ∨ φ2) ⊣⊢ ■ φ1 ∨ ■ φ2.
+Proof.
+  apply (anti_symm _).
+  - eapply pure_elim=> // -[?|?]; auto.
+  - apply or_elim; eapply pure_elim; eauto.
+Qed.
+Lemma pure_impl φ1 φ2 : ■ (φ1 → φ2) ⊣⊢ (■ φ1 → ■ φ2).
+Proof.
+  apply (anti_symm _).
+  - apply impl_intro_l. rewrite -pure_and. apply pure_mono. naive_solver.
+  - rewrite -pure_forall_2. apply forall_intro=> ?.
+    by rewrite -(left_id True uPred_and (_→_))%I (pure_equiv φ1) // impl_elim_r.
+Qed.
+Lemma pure_forall {A} (φ : A → Prop) : ■ (∀ x, φ x) ⊣⊢ ∀ x, ■ φ x.
+Proof.
+  apply (anti_symm _); auto using pure_forall_2.
+  apply forall_intro=> x. eauto using pure_mono.
+Qed.
+Lemma pure_exist {A} (φ : A → Prop) : ■ (∃ x, φ x) ⊣⊢ ∃ x, ■ φ x.
+Proof.
+  apply (anti_symm _).
+  - eapply pure_elim=> // -[x ?]. rewrite -(exist_intro x); auto.
+  - apply exist_elim=> x. eauto using pure_mono.
+Qed.
+
+Lemma eq_refl' {A : cofeT} (a : A) P : P ⊢ a ≡ a.
+Proof. rewrite (True_intro P). apply eq_refl. Qed.
+Hint Resolve eq_refl'.
+Lemma equiv_eq {A : cofeT} P (a b : A) : a ≡ b → P ⊢ a ≡ b.
+Proof. by intros ->. Qed.
+Lemma eq_sym {A : cofeT} (a b : A) : a ≡ b ⊢ b ≡ a.
+Proof. apply (eq_rewrite a b (λ b, b ≡ a)%I); auto. solve_proper. Qed.
+
+Lemma pure_alt φ : ■ φ ⊣⊢ ∃ _ : φ, True.
+Proof.
+  apply (anti_symm _).
+  - eapply pure_elim; eauto=> H. rewrite -(exist_intro H); auto.
+  - by apply exist_elim, pure_intro.
+Qed.
+Lemma and_alt P Q : P ∧ Q ⊣⊢ ∀ b : bool, if b then P else Q.
+Proof.
+  apply (anti_symm _); first apply forall_intro=> -[]; auto.
+  apply and_intro. by rewrite (forall_elim true). by rewrite (forall_elim false).
+Qed.
+Lemma or_alt P Q : P ∨ Q ⊣⊢ ∃ b : bool, if b then P else Q.
+Proof.
+  apply (anti_symm _); last apply exist_elim=> -[]; auto.
+  apply or_elim. by rewrite -(exist_intro true). by rewrite -(exist_intro false).
+Qed.
+
+Global Instance iff_ne n : Proper (dist n ==> dist n ==> dist n) (@uPred_iff M).
+Proof. unfold uPred_iff; solve_proper. Qed.
+Global Instance iff_proper :
+  Proper ((⊣⊢) ==> (⊣⊢) ==> (⊣⊢)) (@uPred_iff M) := ne_proper_2 _.
+
+Lemma iff_refl Q P : Q ⊢ P ↔ P.
+Proof. rewrite /uPred_iff; apply and_intro; apply impl_intro_l; auto. Qed.
+Lemma iff_equiv P Q : (True ⊢ P ↔ Q) → (P ⊣⊢ Q).
+Proof.
+  intros HPQ; apply (anti_symm (⊢));
+    apply impl_entails; rewrite HPQ /uPred_iff; auto.
+Qed.
+Lemma equiv_iff P Q : (P ⊣⊢ Q) → True ⊢ P ↔ Q.
+Proof. intros ->; apply iff_refl. Qed.
+Lemma eq_iff P Q : P ≡ Q ⊢ P ↔ Q.
+Proof.
+  apply (eq_rewrite P Q (λ Q, P ↔ Q))%I; first solve_proper; auto using iff_refl.
+Qed.
+
+(* Derived BI Stuff *)
+Hint Resolve sep_mono.
+Lemma sep_mono_l P P' Q : (P ⊢ Q) → P ★ P' ⊢ Q ★ P'.
+Proof. by intros; apply sep_mono. Qed.
+Lemma sep_mono_r P P' Q' : (P' ⊢ Q') → P ★ P' ⊢ P ★ Q'.
+Proof. by apply sep_mono. Qed.
+Global Instance sep_mono' : Proper ((⊢) ==> (⊢) ==> (⊢)) (@uPred_sep M).
+Proof. by intros P P' HP Q Q' HQ; apply sep_mono. Qed.
+Global Instance sep_flip_mono' :
+  Proper (flip (⊢) ==> flip (⊢) ==> flip (⊢)) (@uPred_sep M).
+Proof. by intros P P' HP Q Q' HQ; apply sep_mono. Qed.
+Lemma wand_mono P P' Q Q' : (Q ⊢ P) → (P' ⊢ Q') → (P -★ P') ⊢ Q -★ Q'.
+Proof.
+  intros HP HQ; apply wand_intro_r. rewrite HP -HQ. by apply wand_elim_l'.
+Qed.
+Global Instance wand_mono' : Proper (flip (⊢) ==> (⊢) ==> (⊢)) (@uPred_wand M).
+Proof. by intros P P' HP Q Q' HQ; apply wand_mono. Qed.
+
+Global Instance sep_comm : Comm (⊣⊢) (@uPred_sep M).
+Proof. intros P Q; apply (anti_symm _); auto using sep_comm'. Qed.
+Global Instance sep_assoc : Assoc (⊣⊢) (@uPred_sep M).
+Proof.
+  intros P Q R; apply (anti_symm _); auto using sep_assoc'.
+  by rewrite !(comm _ P) !(comm _ _ R) sep_assoc'.
+Qed.
+Global Instance True_sep : LeftId (⊣⊢) True%I (@uPred_sep M).
+Proof. intros P; apply (anti_symm _); auto using True_sep_1, True_sep_2. Qed.
+Global Instance sep_True : RightId (⊣⊢) True%I (@uPred_sep M).
+Proof. by intros P; rewrite comm left_id. Qed.
+Lemma sep_elim_l P Q : P ★ Q ⊢ P.
+Proof. by rewrite (True_intro Q) right_id. Qed.
+Lemma sep_elim_r P Q : P ★ Q ⊢ Q.
+Proof. by rewrite (comm (★))%I; apply sep_elim_l. Qed.
+Lemma sep_elim_l' P Q R : (P ⊢ R) → P ★ Q ⊢ R.
+Proof. intros ->; apply sep_elim_l. Qed.
+Lemma sep_elim_r' P Q R : (Q ⊢ R) → P ★ Q ⊢ R.
+Proof. intros ->; apply sep_elim_r. Qed.
+Hint Resolve sep_elim_l' sep_elim_r'.
+Lemma sep_intro_True_l P Q R : (True ⊢ P) → (R ⊢ Q) → R ⊢ P ★ Q.
+Proof. by intros; rewrite -(left_id True%I uPred_sep R); apply sep_mono. Qed.
+Lemma sep_intro_True_r P Q R : (R ⊢ P) → (True ⊢ Q) → R ⊢ P ★ Q.
+Proof. by intros; rewrite -(right_id True%I uPred_sep R); apply sep_mono. Qed.
+Lemma sep_elim_True_l P Q R : (True ⊢ P) → (P ★ R ⊢ Q) → R ⊢ Q.
+Proof. by intros HP; rewrite -HP left_id. Qed.
+Lemma sep_elim_True_r P Q R : (True ⊢ P) → (R ★ P ⊢ Q) → R ⊢ Q.
+Proof. by intros HP; rewrite -HP right_id. Qed.
+Lemma wand_intro_l P Q R : (Q ★ P ⊢ R) → P ⊢ Q -★ R.
+Proof. rewrite comm; apply wand_intro_r. Qed.
+Lemma wand_elim_l P Q : (P -★ Q) ★ P ⊢ Q.
+Proof. by apply wand_elim_l'. Qed.
+Lemma wand_elim_r P Q : P ★ (P -★ Q) ⊢ Q.
+Proof. rewrite (comm _ P); apply wand_elim_l. Qed.
+Lemma wand_elim_r' P Q R : (Q ⊢ P -★ R) → P ★ Q ⊢ R.
+Proof. intros ->; apply wand_elim_r. Qed.
+Lemma wand_apply_l P Q Q' R R' : (P ⊢ Q' -★ R') → (R' ⊢ R) → (Q ⊢ Q') → P ★ Q ⊢ R.
+Proof. intros -> -> <-; apply wand_elim_l. Qed.
+Lemma wand_apply_r P Q Q' R R' : (P ⊢ Q' -★ R') → (R' ⊢ R) → (Q ⊢ Q') → Q ★ P ⊢ R.
+Proof. intros -> -> <-; apply wand_elim_r. Qed.
+Lemma wand_apply_l' P Q Q' R : (P ⊢ Q' -★ R) → (Q ⊢ Q') → P ★ Q ⊢ R.
+Proof. intros -> <-; apply wand_elim_l. Qed.
+Lemma wand_apply_r' P Q Q' R : (P ⊢ Q' -★ R) → (Q ⊢ Q') → Q ★ P ⊢ R.
+Proof. intros -> <-; apply wand_elim_r. Qed.
+Lemma wand_frame_l P Q R : (Q -★ R) ⊢ P ★ Q -★ P ★ R.
+Proof. apply wand_intro_l. rewrite -assoc. apply sep_mono_r, wand_elim_r. Qed.
+Lemma wand_frame_r P Q R : (Q -★ R) ⊢ Q ★ P -★ R ★ P.
+Proof.
+  apply wand_intro_l. rewrite ![(_ ★ P)%I]comm -assoc.
+  apply sep_mono_r, wand_elim_r.
+Qed.
+Lemma wand_diag P : (P -★ P) ⊣⊢ True.
+Proof. apply (anti_symm _); auto. apply wand_intro_l; by rewrite right_id. Qed.
+Lemma wand_True P : (True -★ P) ⊣⊢ P.
+Proof.
+  apply (anti_symm _); last by auto using wand_intro_l.
+  eapply sep_elim_True_l; first reflexivity. by rewrite wand_elim_r.
+Qed.
+Lemma wand_entails P Q : (True ⊢ P -★ Q) → P ⊢ Q.
+Proof.
+  intros HPQ. eapply sep_elim_True_r; first exact: HPQ. by rewrite wand_elim_r.
+Qed.
+Lemma entails_wand P Q : (P ⊢ Q) → True ⊢ P -★ Q.
+Proof. auto using wand_intro_l. Qed.
+Lemma wand_curry P Q R : (P -★ Q -★ R) ⊣⊢ (P ★ Q -★ R).
+Proof.
+  apply (anti_symm _).
+  - apply wand_intro_l. by rewrite (comm _ P) -assoc !wand_elim_r.
+  - do 2 apply wand_intro_l. by rewrite assoc (comm _ Q) wand_elim_r.
+Qed.
+
+Lemma sep_and P Q : (P ★ Q) ⊢ (P ∧ Q).
+Proof. auto. Qed.
+Lemma impl_wand P Q : (P → Q) ⊢ P -★ Q.
+Proof. apply wand_intro_r, impl_elim with P; auto. Qed.
+Lemma pure_elim_sep_l φ Q R : (φ → Q ⊢ R) → ■ φ ★ Q ⊢ R.
+Proof. intros; apply pure_elim with φ; eauto. Qed.
+Lemma pure_elim_sep_r φ Q R : (φ → Q ⊢ R) → Q ★ ■ φ ⊢ R.
+Proof. intros; apply pure_elim with φ; eauto. Qed.
+
+Global Instance sep_False : LeftAbsorb (⊣⊢) False%I (@uPred_sep M).
+Proof. intros P; apply (anti_symm _); auto. Qed.
+Global Instance False_sep : RightAbsorb (⊣⊢) False%I (@uPred_sep M).
+Proof. intros P; apply (anti_symm _); auto. Qed.
+
+Lemma sep_and_l P Q R : P ★ (Q ∧ R) ⊢ (P ★ Q) ∧ (P ★ R).
+Proof. auto. Qed.
+Lemma sep_and_r P Q R : (P ∧ Q) ★ R ⊢ (P ★ R) ∧ (Q ★ R).
+Proof. auto. Qed.
+Lemma sep_or_l P Q R : P ★ (Q ∨ R) ⊣⊢ (P ★ Q) ∨ (P ★ R).
+Proof.
+  apply (anti_symm (⊢)); last by eauto 8.
+  apply wand_elim_r', or_elim; apply wand_intro_l; auto.
+Qed.
+Lemma sep_or_r P Q R : (P ∨ Q) ★ R ⊣⊢ (P ★ R) ∨ (Q ★ R).
+Proof. by rewrite -!(comm _ R) sep_or_l. Qed.
+Lemma sep_exist_l {A} P (Ψ : A → uPred M) : P ★ (∃ a, Ψ a) ⊣⊢ ∃ a, P ★ Ψ a.
+Proof.
+  intros; apply (anti_symm (⊢)).
+  - apply wand_elim_r', exist_elim=>a. apply wand_intro_l.
+    by rewrite -(exist_intro a).
+  - apply exist_elim=> a; apply sep_mono; auto using exist_intro.
+Qed.
+Lemma sep_exist_r {A} (Φ: A → uPred M) Q: (∃ a, Φ a) ★ Q ⊣⊢ ∃ a, Φ a ★ Q.
+Proof. setoid_rewrite (comm _ _ Q); apply sep_exist_l. Qed.
+Lemma sep_forall_l {A} P (Ψ : A → uPred M) : P ★ (∀ a, Ψ a) ⊢ ∀ a, P ★ Ψ a.
+Proof. by apply forall_intro=> a; rewrite forall_elim. Qed.
+Lemma sep_forall_r {A} (Φ : A → uPred M) Q : (∀ a, Φ a) ★ Q ⊢ ∀ a, Φ a ★ Q.
+Proof. by apply forall_intro=> a; rewrite forall_elim. Qed.
+
+(* Always derived *)
+Hint Resolve always_mono always_elim.
+Global Instance always_mono' : Proper ((⊢) ==> (⊢)) (@uPred_always M).
+Proof. intros P Q; apply always_mono. Qed.
+Global Instance always_flip_mono' :
+  Proper (flip (⊢) ==> flip (⊢)) (@uPred_always M).
+Proof. intros P Q; apply always_mono. Qed.
+
+Lemma always_intro' P Q : (□ P ⊢ Q) → □ P ⊢ □ Q.
+Proof. intros <-. apply always_idemp. Qed.
+
+Lemma always_pure φ : □ ■ φ ⊣⊢ ■ φ.
+Proof. apply (anti_symm _); auto using always_pure_2. Qed.
+Lemma always_forall {A} (Ψ : A → uPred M) : (□ ∀ a, Ψ a) ⊣⊢ (∀ a, □ Ψ a).
+Proof.
+  apply (anti_symm _); auto using always_forall_2.
+  apply forall_intro=> x. by rewrite (forall_elim x).
+Qed.
+Lemma always_exist {A} (Ψ : A → uPred M) : (□ ∃ a, Ψ a) ⊣⊢ (∃ a, □ Ψ a).
+Proof.
+  apply (anti_symm _); auto using always_exist_1.
+  apply exist_elim=> x. by rewrite (exist_intro x).
+Qed.
+Lemma always_and P Q : □ (P ∧ Q) ⊣⊢ □ P ∧ □ Q.
+Proof. rewrite !and_alt always_forall. by apply forall_proper=> -[]. Qed.
+Lemma always_or P Q : □ (P ∨ Q) ⊣⊢ □ P ∨ □ Q.
+Proof. rewrite !or_alt always_exist. by apply exist_proper=> -[]. Qed.
+Lemma always_impl P Q : □ (P → Q) ⊢ □ P → □ Q.
+Proof.
+  apply impl_intro_l; rewrite -always_and.
+  apply always_mono, impl_elim with P; auto.
+Qed.
+Lemma always_eq {A:cofeT} (a b : A) : □ (a ≡ b) ⊣⊢ a ≡ b.
+Proof.
+  apply (anti_symm (⊢)); auto using always_elim.
+  apply (eq_rewrite a b (λ b, □ (a ≡ b))%I); auto.
+  { intros n; solve_proper. }
+  rewrite -(eq_refl a) always_pure; auto.
+Qed.
+
+Lemma always_and_sep P Q : □ (P ∧ Q) ⊣⊢ □ (P ★ Q).
+Proof. apply (anti_symm (⊢)); auto using always_and_sep_1. Qed.
+Lemma always_and_sep_l' P Q : □ P ∧ Q ⊣⊢ □ P ★ Q.
+Proof. apply (anti_symm (⊢)); auto using always_and_sep_l_1. Qed.
+Lemma always_and_sep_r' P Q : P ∧ □ Q ⊣⊢ P ★ □ Q.
+Proof. by rewrite !(comm _ P) always_and_sep_l'. Qed.
+Lemma always_sep P Q : □ (P ★ Q) ⊣⊢ □ P ★ □ Q.
+Proof. by rewrite -always_and_sep -always_and_sep_l' always_and. Qed.
+Lemma always_sep_dup' P : □ P ⊣⊢ □ P ★ □ P.
+Proof. by rewrite -always_sep -always_and_sep (idemp _). Qed.
+
+Lemma always_wand P Q : □ (P -★ Q) ⊢ □ P -★ □ Q.
+Proof. by apply wand_intro_r; rewrite -always_sep wand_elim_l. Qed.
+Lemma always_wand_impl P Q : □ (P -★ Q) ⊣⊢ □ (P → Q).
+Proof.
+  apply (anti_symm (⊢)); [|by rewrite -impl_wand].
+  apply always_intro', impl_intro_r.
+  by rewrite always_and_sep_l' always_elim wand_elim_l.
+Qed.
+Lemma always_entails_l' P Q : (P ⊢ □ Q) → P ⊢ □ Q ★ P.
+Proof. intros; rewrite -always_and_sep_l'; auto. Qed.
+Lemma always_entails_r' P Q : (P ⊢ □ Q) → P ⊢ P ★ □ Q.
+Proof. intros; rewrite -always_and_sep_r'; auto. Qed.
+
+(* Later derived *)
+Lemma later_proper P Q : (P ⊣⊢ Q) → ▷ P ⊣⊢ ▷ Q.
+Proof. by intros ->. Qed.
+Hint Resolve later_mono later_proper.
+Global Instance later_mono' : Proper ((⊢) ==> (⊢)) (@uPred_later M).
+Proof. intros P Q; apply later_mono. Qed.
+Global Instance later_flip_mono' :
+  Proper (flip (⊢) ==> flip (⊢)) (@uPred_later M).
+Proof. intros P Q; apply later_mono. Qed.
+
+Lemma later_intro P : P ⊢ ▷ P.
+Proof.
+  rewrite -(and_elim_l (▷ P) P) -(löb (▷ P ∧ P)).
+  apply impl_intro_l. by rewrite {1}(and_elim_r (â–· P)).
+Qed.
+
+Lemma later_True : ▷ True ⊣⊢ True.
+Proof. apply (anti_symm (⊢)); auto using later_intro. Qed.
+Lemma later_forall {A} (Φ : A → uPred M) : (▷ ∀ a, Φ a) ⊣⊢ (∀ a, ▷ Φ a).
+Proof.
+  apply (anti_symm _); auto using later_forall_2.
+  apply forall_intro=> x. by rewrite (forall_elim x).
+Qed.
+Lemma later_exist `{Inhabited A} (Φ : A → uPred M) :
+  ▷ (∃ a, Φ a) ⊣⊢ (∃ a, ▷ Φ a).
+Proof.
+  apply: anti_symm; [|apply exist_elim; eauto using exist_intro].
+  rewrite later_exist_false. apply or_elim; last done.
+  rewrite -(exist_intro inhabitant); auto.
+Qed.
+Lemma later_and P Q : ▷ (P ∧ Q) ⊣⊢ ▷ P ∧ ▷ Q.
+Proof. rewrite !and_alt later_forall. by apply forall_proper=> -[]. Qed.
+Lemma later_or P Q : ▷ (P ∨ Q) ⊣⊢ ▷ P ∨ ▷ Q.
+Proof. rewrite !or_alt later_exist. by apply exist_proper=> -[]. Qed.
+Lemma later_impl P Q : ▷ (P → Q) ⊢ ▷ P → ▷ Q.
+Proof. apply impl_intro_l; rewrite -later_and; eauto using impl_elim. Qed.
+Lemma later_wand P Q : ▷ (P -★ Q) ⊢ ▷ P -★ ▷ Q.
+Proof. apply wand_intro_r; rewrite -later_sep; eauto using wand_elim_l. Qed.
+Lemma later_iff P Q : ▷ (P ↔ Q) ⊢ ▷ P ↔ ▷ Q.
+Proof. by rewrite /uPred_iff later_and !later_impl. Qed.
+
+
+(* Conditional always *)
+Global Instance always_if_ne n p : Proper (dist n ==> dist n) (@uPred_always_if M p).
+Proof. solve_proper. Qed.
+Global Instance always_if_proper p : Proper ((⊣⊢) ==> (⊣⊢)) (@uPred_always_if M p).
+Proof. solve_proper. Qed.
+Global Instance always_if_mono p : Proper ((⊢) ==> (⊢)) (@uPred_always_if M p).
+Proof. solve_proper. Qed.
+
+Lemma always_if_elim p P : □?p P ⊢ P.
+Proof. destruct p; simpl; auto using always_elim. Qed.
+Lemma always_elim_if p P : □ P ⊢ □?p P.
+Proof. destruct p; simpl; auto using always_elim. Qed.
+
+Lemma always_if_pure p φ : □?p ■ φ ⊣⊢ ■ φ.
+Proof. destruct p; simpl; auto using always_pure. Qed.
+Lemma always_if_and p P Q : □?p (P ∧ Q) ⊣⊢ □?p P ∧ □?p Q.
+Proof. destruct p; simpl; auto using always_and. Qed.
+Lemma always_if_or p P Q : □?p (P ∨ Q) ⊣⊢ □?p P ∨ □?p Q.
+Proof. destruct p; simpl; auto using always_or. Qed.
+Lemma always_if_exist {A} p (Ψ : A → uPred M) : (□?p ∃ a, Ψ a) ⊣⊢ ∃ a, □?p Ψ a.
+Proof. destruct p; simpl; auto using always_exist. Qed.
+Lemma always_if_sep p P Q : □?p (P ★ Q) ⊣⊢ □?p P ★ □?p Q.
+Proof. destruct p; simpl; auto using always_sep. Qed.
+Lemma always_if_later p P : □?p ▷ P ⊣⊢ ▷ □?p P.
+Proof. destruct p; simpl; auto using always_later. Qed.
+
+
+(* True now *)
+Global Instance except_last_ne n : Proper (dist n ==> dist n) (@uPred_except_last M).
+Proof. solve_proper. Qed.
+Global Instance except_last_proper : Proper ((⊣⊢) ==> (⊣⊢)) (@uPred_except_last M).
+Proof. solve_proper. Qed.
+Global Instance except_last_mono' : Proper ((⊢) ==> (⊢)) (@uPred_except_last M).
+Proof. solve_proper. Qed.
+Global Instance except_last_flip_mono' :
+  Proper (flip (⊢) ==> flip (⊢)) (@uPred_except_last M).
+Proof. solve_proper. Qed.
+
+Lemma except_last_intro P : P ⊢ ◇ P.
+Proof. rewrite /uPred_except_last; auto. Qed.
+Lemma except_last_mono P Q : (P ⊢ Q) → ◇ P ⊢ ◇ Q.
+Proof. by intros ->. Qed.
+Lemma except_last_idemp P : ◇ ◇ P ⊢ ◇ P.
+Proof. rewrite /uPred_except_last; auto. Qed.
+
+Lemma except_last_True : ◇ True ⊣⊢ True.
+Proof. rewrite /uPred_except_last. apply (anti_symm _); auto. Qed.
+Lemma except_last_or P Q : ◇ (P ∨ Q) ⊣⊢ ◇ P ∨ ◇ Q.
+Proof. rewrite /uPred_except_last. apply (anti_symm _); auto. Qed.
+Lemma except_last_and P Q : ◇ (P ∧ Q) ⊣⊢ ◇ P ∧ ◇ Q.
+Proof. by rewrite /uPred_except_last or_and_l. Qed.
+Lemma except_last_sep P Q : ◇ (P ★ Q) ⊣⊢ ◇ P ★ ◇ Q.
+Proof.
+  rewrite /uPred_except_last. apply (anti_symm _).
+  - apply or_elim; last by auto.
+    by rewrite -!or_intro_l -always_pure -always_later -always_sep_dup'.
+  - rewrite sep_or_r sep_elim_l sep_or_l; auto.
+Qed.
+Lemma except_last_forall {A} (Φ : A → uPred M) : ◇ (∀ a, Φ a) ⊢ ∀ a, ◇ Φ a.
+Proof. apply forall_intro=> a. by rewrite (forall_elim a). Qed.
+Lemma except_last_exist {A} (Φ : A → uPred M) : (∃ a, ◇ Φ a) ⊢ ◇ ∃ a, Φ a.
+Proof. apply exist_elim=> a. by rewrite (exist_intro a). Qed.
+Lemma except_last_later P : ◇ ▷ P ⊢ ▷ P.
+Proof. by rewrite /uPred_except_last -later_or False_or. Qed.
+Lemma except_last_always P : ◇ □ P ⊣⊢ □ ◇ P.
+Proof. by rewrite /uPred_except_last always_or always_later always_pure. Qed.
+Lemma except_last_always_if p P : ◇ □?p P ⊣⊢ □?p ◇ P.
+Proof. destruct p; simpl; auto using except_last_always. Qed.
+Lemma except_last_frame_l P Q : P ★ ◇ Q ⊢ ◇ (P ★ Q).
+Proof. by rewrite {1}(except_last_intro P) except_last_sep. Qed.
+Lemma except_last_frame_r P Q : ◇ P ★ Q ⊢ ◇ (P ★ Q).
+Proof. by rewrite {1}(except_last_intro Q) except_last_sep. Qed.
+
+(* Own and valid derived *)
+Lemma always_ownM (a : M) : Persistent a → □ uPred_ownM a ⊣⊢ uPred_ownM a.
+Proof.
+  intros; apply (anti_symm _); first by apply:always_elim.
+  by rewrite {1}always_ownM_core persistent_core.
+Qed.
+Lemma ownM_invalid (a : M) : ¬ ✓{0} a → uPred_ownM a ⊢ False.
+Proof. by intros; rewrite ownM_valid cmra_valid_elim. Qed.
+Global Instance ownM_mono : Proper (flip (≼) ==> (⊢)) (@uPred_ownM M).
+Proof. intros a b [b' ->]. rewrite ownM_op. eauto. Qed.
+Lemma ownM_empty' : uPred_ownM ∅ ⊣⊢ True.
+Proof. apply (anti_symm _); auto using ownM_empty. Qed.
+Lemma always_cmra_valid {A : cmraT} (a : A) : □ ✓ a ⊣⊢ ✓ a.
+Proof.
+  intros; apply (anti_symm _); first by apply:always_elim.
+  apply:always_cmra_valid_1.
+Qed.
+
+(** * Derived rules *)
+Global Instance bupd_mono' : Proper ((⊢) ==> (⊢)) (@uPred_bupd M).
+Proof. intros P Q; apply bupd_mono. Qed.
+Global Instance bupd_flip_mono' : Proper (flip (⊢) ==> flip (⊢)) (@uPred_bupd M).
+Proof. intros P Q; apply bupd_mono. Qed.
+Lemma bupd_frame_l R Q : (R ★ |==> Q) ==★ R ★ Q.
+Proof. rewrite !(comm _ R); apply bupd_frame_r. Qed.
+Lemma bupd_wand_l P Q : (P -★ Q) ★ (|==> P) ==★ Q.
+Proof. by rewrite bupd_frame_l wand_elim_l. Qed.
+Lemma bupd_wand_r P Q : (|==> P) ★ (P -★ Q) ==★ Q.
+Proof. by rewrite bupd_frame_r wand_elim_r. Qed.
+Lemma bupd_sep P Q : (|==> P) ★ (|==> Q) ==★ P ★ Q.
+Proof. by rewrite bupd_frame_r bupd_frame_l bupd_trans. Qed.
+Lemma bupd_ownM_update x y : x ~~> y → uPred_ownM x ⊢ |==> uPred_ownM y.
+Proof.
+  intros; rewrite (bupd_ownM_updateP _ (y =)); last by apply cmra_update_updateP.
+  by apply bupd_mono, exist_elim=> y'; apply pure_elim_l=> ->.
+Qed.
+Lemma except_last_bupd P : ◇ (|==> P) ⊢ (|==> ◇ P).
+Proof.
+  rewrite /uPred_except_last. apply or_elim; auto using bupd_mono.
+  by rewrite -bupd_intro -or_intro_l.
+Qed.
+
+(* Timeless instances *)
+Global Instance pure_timeless φ : TimelessP (■ φ : uPred M)%I.
+Proof.
+  rewrite /TimelessP pure_alt later_exist_false. by setoid_rewrite later_True.
+Qed.
+Global Instance valid_timeless {A : cmraT} `{CMRADiscrete A} (a : A) :
+  TimelessP (✓ a : uPred M)%I.
+Proof. rewrite /TimelessP !discrete_valid. apply (timelessP _). Qed.
+Global Instance and_timeless P Q: TimelessP P → TimelessP Q → TimelessP (P ∧ Q).
+Proof. intros; rewrite /TimelessP except_last_and later_and; auto. Qed.
+Global Instance or_timeless P Q : TimelessP P → TimelessP Q → TimelessP (P ∨ Q).
+Proof. intros; rewrite /TimelessP except_last_or later_or; auto. Qed.
+Global Instance impl_timeless P Q : TimelessP Q → TimelessP (P → Q).
+Proof.
+  rewrite /TimelessP=> HQ. rewrite later_false_excluded_middle.
+  apply or_mono, impl_intro_l; first done.
+  rewrite -{2}(löb Q); apply impl_intro_l.
+  rewrite HQ /uPred_except_last !and_or_r. apply or_elim; last auto.
+  by rewrite assoc (comm _ _ P) -assoc !impl_elim_r.
+Qed.
+Global Instance sep_timeless P Q: TimelessP P → TimelessP Q → TimelessP (P ★ Q).
+Proof. intros; rewrite /TimelessP except_last_sep later_sep; auto. Qed.
+Global Instance wand_timeless P Q : TimelessP Q → TimelessP (P -★ Q).
+Proof.
+  rewrite /TimelessP=> HQ. rewrite later_false_excluded_middle.
+  apply or_mono, wand_intro_l; first done.
+  rewrite -{2}(löb Q); apply impl_intro_l.
+  rewrite HQ /uPred_except_last !and_or_r. apply or_elim; last auto.
+  rewrite -(always_pure) -always_later always_and_sep_l'.
+  by rewrite assoc (comm _ _ P) -assoc -always_and_sep_l' impl_elim_r wand_elim_r.
+Qed.
+Global Instance forall_timeless {A} (Ψ : A → uPred M) :
+  (∀ x, TimelessP (Ψ x)) → TimelessP (∀ x, Ψ x).
+Proof.
+  rewrite /TimelessP=> HQ. rewrite later_false_excluded_middle.
+  apply or_mono; first done. apply forall_intro=> x.
+  rewrite -(löb (Ψ x)); apply impl_intro_l.
+  rewrite HQ /uPred_except_last !and_or_r. apply or_elim; last auto.
+  by rewrite impl_elim_r (forall_elim x).
+Qed.
+Global Instance exist_timeless {A} (Ψ : A → uPred M) :
+  (∀ x, TimelessP (Ψ x)) → TimelessP (∃ x, Ψ x).
+Proof.
+  rewrite /TimelessP=> ?. rewrite later_exist_false. apply or_elim.
+  - rewrite /uPred_except_last; auto.
+  - apply exist_elim=> x. rewrite -(exist_intro x); auto.
+Qed.
+Global Instance always_timeless P : TimelessP P → TimelessP (□ P).
+Proof. intros; rewrite /TimelessP except_last_always -always_later; auto. Qed.
+Global Instance always_if_timeless p P : TimelessP P → TimelessP (□?p P).
+Proof. destruct p; apply _. Qed.
+Global Instance eq_timeless {A : cofeT} (a b : A) :
+  Timeless a → TimelessP (a ≡ b : uPred M)%I.
+Proof. intros. rewrite /TimelessP !timeless_eq. apply (timelessP _). Qed.
+Global Instance ownM_timeless (a : M) : Timeless a → TimelessP (uPred_ownM a).
+Proof.
+  intros ?. rewrite /TimelessP later_ownM. apply exist_elim=> b.
+  rewrite (timelessP (a≡b)) (except_last_intro (uPred_ownM b)) -except_last_and.
+  apply except_last_mono. rewrite eq_sym.
+  apply (eq_rewrite b a (uPred_ownM)); first apply _; auto.
+Qed.
+
+(* Persistence *)
+Global Instance pure_persistent φ : PersistentP (■ φ : uPred M)%I.
+Proof. by rewrite /PersistentP always_pure. Qed.
+Global Instance always_persistent P : PersistentP (â–¡ P).
+Proof. by intros; apply always_intro'. Qed.
+Global Instance and_persistent P Q :
+  PersistentP P → PersistentP Q → PersistentP (P ∧ Q).
+Proof. by intros; rewrite /PersistentP always_and; apply and_mono. Qed.
+Global Instance or_persistent P Q :
+  PersistentP P → PersistentP Q → PersistentP (P ∨ Q).
+Proof. by intros; rewrite /PersistentP always_or; apply or_mono. Qed.
+Global Instance sep_persistent P Q :
+  PersistentP P → PersistentP Q → PersistentP (P ★ Q).
+Proof. by intros; rewrite /PersistentP always_sep; apply sep_mono. Qed.
+Global Instance forall_persistent {A} (Ψ : A → uPred M) :
+  (∀ x, PersistentP (Ψ x)) → PersistentP (∀ x, Ψ x).
+Proof. by intros; rewrite /PersistentP always_forall; apply forall_mono. Qed.
+Global Instance exist_persistent {A} (Ψ : A → uPred M) :
+  (∀ x, PersistentP (Ψ x)) → PersistentP (∃ x, Ψ x).
+Proof. by intros; rewrite /PersistentP always_exist; apply exist_mono. Qed.
+Global Instance eq_persistent {A : cofeT} (a b : A) :
+  PersistentP (a ≡ b : uPred M)%I.
+Proof. by intros; rewrite /PersistentP always_eq. Qed.
+Global Instance cmra_valid_persistent {A : cmraT} (a : A) :
+  PersistentP (✓ a : uPred M)%I.
+Proof. by intros; rewrite /PersistentP always_cmra_valid. Qed.
+Global Instance later_persistent P : PersistentP P → PersistentP (▷ P).
+Proof. by intros; rewrite /PersistentP always_later; apply later_mono. Qed.
+Global Instance ownM_persistent : Persistent a → PersistentP (@uPred_ownM M a).
+Proof. intros. by rewrite /PersistentP always_ownM. Qed.
+Global Instance from_option_persistent {A} P (Ψ : A → uPred M) (mx : option A) :
+  (∀ x, PersistentP (Ψ x)) → PersistentP P → PersistentP (from_option Ψ P mx).
+Proof. destruct mx; apply _. Qed.
+
+(* Derived lemmas for persistence *)
+Lemma always_always P `{!PersistentP P} : □ P ⊣⊢ P.
+Proof. apply (anti_symm (⊢)); auto using always_elim. Qed.
+Lemma always_if_always p P `{!PersistentP P} : □?p P ⊣⊢ P.
+Proof. destruct p; simpl; auto using always_always. Qed.
+Lemma always_intro P Q `{!PersistentP P} : (P ⊢ Q) → P ⊢ □ Q.
+Proof. rewrite -(always_always P); apply always_intro'. Qed.
+Lemma always_and_sep_l P Q `{!PersistentP P} : P ∧ Q ⊣⊢ P ★ Q.
+Proof. by rewrite -(always_always P) always_and_sep_l'. Qed.
+Lemma always_and_sep_r P Q `{!PersistentP Q} : P ∧ Q ⊣⊢ P ★ Q.
+Proof. by rewrite -(always_always Q) always_and_sep_r'. Qed.
+Lemma always_sep_dup P `{!PersistentP P} : P ⊣⊢ P ★ P.
+Proof. by rewrite -(always_always P) -always_sep_dup'. Qed.
+Lemma always_entails_l P Q `{!PersistentP Q} : (P ⊢ Q) → P ⊢ Q ★ P.
+Proof. by rewrite -(always_always Q); apply always_entails_l'. Qed.
+Lemma always_entails_r P Q `{!PersistentP Q} : (P ⊢ Q) → P ⊢ P ★ Q.
+Proof. by rewrite -(always_always Q); apply always_entails_r'. Qed.
+End derived.
+End uPred_derived.
diff --git a/algebra/double_negation.v b/base_logic/double_negation.v
similarity index 99%
rename from algebra/double_negation.v
rename to base_logic/double_negation.v
index 875045d22..123d5b831 100644
--- a/algebra/double_negation.v
+++ b/base_logic/double_negation.v
@@ -1,4 +1,4 @@
-From iris.algebra Require Import upred.
+From iris.base_logic Require Import base_logic.
 Import upred.
 
 (* In this file we show that the bupd can be thought of a kind of
diff --git a/algebra/upred_hlist.v b/base_logic/hlist.v
similarity index 96%
rename from algebra/upred_hlist.v
rename to base_logic/hlist.v
index 82d0e55aa..e70bd6eac 100644
--- a/algebra/upred_hlist.v
+++ b/base_logic/hlist.v
@@ -1,5 +1,5 @@
 From iris.prelude Require Export hlist.
-From iris.algebra Require Export upred.
+From iris.base_logic Require Export base_logic.
 Import uPred.
 
 Fixpoint uPred_hexist {M As} : himpl As (uPred M) → uPred M :=
diff --git a/base_logic/primitive.v b/base_logic/primitive.v
new file mode 100644
index 000000000..5c8f15f1a
--- /dev/null
+++ b/base_logic/primitive.v
@@ -0,0 +1,592 @@
+From iris.base_logic Require Export upred.
+From iris.algebra Require Export updates.
+Local Hint Extern 1 (_ ≼ _) => etrans; [eassumption|].
+Local Hint Extern 1 (_ ≼ _) => etrans; [|eassumption].
+Local Hint Extern 10 (_ ≤ _) => omega.
+
+(** logical connectives *)
+Program Definition uPred_pure_def {M} (φ : Prop) : uPred M :=
+  {| uPred_holds n x := φ |}.
+Solve Obligations with done.
+Definition uPred_pure_aux : { x | x = @uPred_pure_def }. by eexists. Qed.
+Definition uPred_pure {M} := proj1_sig uPred_pure_aux M.
+Definition uPred_pure_eq :
+  @uPred_pure = @uPred_pure_def := proj2_sig uPred_pure_aux.
+
+Instance uPred_inhabited M : Inhabited (uPred M) := populate (uPred_pure True).
+
+Program Definition uPred_and_def {M} (P Q : uPred M) : uPred M :=
+  {| uPred_holds n x := P n x ∧ Q n x |}.
+Solve Obligations with naive_solver eauto 2 with uPred_def.
+Definition uPred_and_aux : { x | x = @uPred_and_def }. by eexists. Qed.
+Definition uPred_and {M} := proj1_sig uPred_and_aux M.
+Definition uPred_and_eq: @uPred_and = @uPred_and_def := proj2_sig uPred_and_aux.
+
+Program Definition uPred_or_def {M} (P Q : uPred M) : uPred M :=
+  {| uPred_holds n x := P n x ∨ Q n x |}.
+Solve Obligations with naive_solver eauto 2 with uPred_def.
+Definition uPred_or_aux : { x | x = @uPred_or_def }. by eexists. Qed.
+Definition uPred_or {M} := proj1_sig uPred_or_aux M.
+Definition uPred_or_eq: @uPred_or = @uPred_or_def := proj2_sig uPred_or_aux.
+
+Program Definition uPred_impl_def {M} (P Q : uPred M) : uPred M :=
+  {| uPred_holds n x := ∀ n' x',
+       x ≼ x' → n' ≤ n → ✓{n'} x' → P n' x' → Q n' x' |}.
+Next Obligation.
+  intros M P Q n1 x1 x1' HPQ [x2 Hx1'] n2 x3 [x4 Hx3] ?; simpl in *.
+  rewrite Hx3 (dist_le _ _ _ _ Hx1'); auto. intros ??.
+  eapply HPQ; auto. exists (x2 â‹… x4); by rewrite assoc.
+Qed.
+Next Obligation. intros M P Q [|n1] [|n2] x; auto with lia. Qed.
+Definition uPred_impl_aux : { x | x = @uPred_impl_def }. by eexists. Qed.
+Definition uPred_impl {M} := proj1_sig uPred_impl_aux M.
+Definition uPred_impl_eq :
+  @uPred_impl = @uPred_impl_def := proj2_sig uPred_impl_aux.
+
+Program Definition uPred_forall_def {M A} (Ψ : A → uPred M) : uPred M :=
+  {| uPred_holds n x := ∀ a, Ψ a n x |}.
+Solve Obligations with naive_solver eauto 2 with uPred_def.
+Definition uPred_forall_aux : { x | x = @uPred_forall_def }. by eexists. Qed.
+Definition uPred_forall {M A} := proj1_sig uPred_forall_aux M A.
+Definition uPred_forall_eq :
+  @uPred_forall = @uPred_forall_def := proj2_sig uPred_forall_aux.
+
+Program Definition uPred_exist_def {M A} (Ψ : A → uPred M) : uPred M :=
+  {| uPred_holds n x := ∃ a, Ψ a n x |}.
+Solve Obligations with naive_solver eauto 2 with uPred_def.
+Definition uPred_exist_aux : { x | x = @uPred_exist_def }. by eexists. Qed.
+Definition uPred_exist {M A} := proj1_sig uPred_exist_aux M A.
+Definition uPred_exist_eq: @uPred_exist = @uPred_exist_def := proj2_sig uPred_exist_aux.
+
+Program Definition uPred_eq_def {M} {A : cofeT} (a1 a2 : A) : uPred M :=
+  {| uPred_holds n x := a1 ≡{n}≡ a2 |}.
+Solve Obligations with naive_solver eauto 2 using (dist_le (A:=A)).
+Definition uPred_eq_aux : { x | x = @uPred_eq_def }. by eexists. Qed.
+Definition uPred_eq {M A} := proj1_sig uPred_eq_aux M A.
+Definition uPred_eq_eq: @uPred_eq = @uPred_eq_def := proj2_sig uPred_eq_aux.
+
+Program Definition uPred_sep_def {M} (P Q : uPred M) : uPred M :=
+  {| uPred_holds n x := ∃ x1 x2, x ≡{n}≡ x1 ⋅ x2 ∧ P n x1 ∧ Q n x2 |}.
+Next Obligation.
+  intros M P Q n x y (x1&x2&Hx&?&?) [z Hy].
+  exists x1, (x2 â‹… z); split_and?; eauto using uPred_mono, cmra_includedN_l.
+  by rewrite Hy Hx assoc.
+Qed.
+Next Obligation.
+  intros M P Q n1 n2 x (x1&x2&Hx&?&?) ?; rewrite {1}(dist_le _ _ _ _ Hx) // =>?.
+  exists x1, x2; cofe_subst; split_and!;
+    eauto using dist_le, uPred_closed, cmra_validN_op_l, cmra_validN_op_r.
+Qed.
+Definition uPred_sep_aux : { x | x = @uPred_sep_def }. by eexists. Qed.
+Definition uPred_sep {M} := proj1_sig uPred_sep_aux M.
+Definition uPred_sep_eq: @uPred_sep = @uPred_sep_def := proj2_sig uPred_sep_aux.
+
+Program Definition uPred_wand_def {M} (P Q : uPred M) : uPred M :=
+  {| uPred_holds n x := ∀ n' x',
+       n' ≤ n → ✓{n'} (x ⋅ x') → P n' x' → Q n' (x ⋅ x') |}.
+Next Obligation.
+  intros M P Q n x1 x1' HPQ ? n3 x3 ???; simpl in *.
+  apply uPred_mono with (x1 â‹… x3);
+    eauto using cmra_validN_includedN, cmra_monoN_r, cmra_includedN_le.
+Qed.
+Next Obligation. naive_solver. Qed.
+Definition uPred_wand_aux : { x | x = @uPred_wand_def }. by eexists. Qed.
+Definition uPred_wand {M} := proj1_sig uPred_wand_aux M.
+Definition uPred_wand_eq :
+  @uPred_wand = @uPred_wand_def := proj2_sig uPred_wand_aux.
+
+Program Definition uPred_always_def {M} (P : uPred M) : uPred M :=
+  {| uPred_holds n x := P n (core x) |}.
+Next Obligation.
+  intros M; naive_solver eauto using uPred_mono, @cmra_core_monoN.
+Qed.
+Next Obligation. naive_solver eauto using uPred_closed, @cmra_core_validN. Qed.
+Definition uPred_always_aux : { x | x = @uPred_always_def }. by eexists. Qed.
+Definition uPred_always {M} := proj1_sig uPred_always_aux M.
+Definition uPred_always_eq :
+  @uPred_always = @uPred_always_def := proj2_sig uPred_always_aux.
+
+Program Definition uPred_later_def {M} (P : uPred M) : uPred M :=
+  {| uPred_holds n x := match n return _ with 0 => True | S n' => P n' x end |}.
+Next Obligation.
+  intros M P [|n] x1 x2; eauto using uPred_mono, cmra_includedN_S.
+Qed.
+Next Obligation.
+  intros M P [|n1] [|n2] x; eauto using uPred_closed, cmra_validN_S with lia.
+Qed.
+Definition uPred_later_aux : { x | x = @uPred_later_def }. by eexists. Qed.
+Definition uPred_later {M} := proj1_sig uPred_later_aux M.
+Definition uPred_later_eq :
+  @uPred_later = @uPred_later_def := proj2_sig uPred_later_aux.
+
+Program Definition uPred_ownM_def {M : ucmraT} (a : M) : uPred M :=
+  {| uPred_holds n x := a ≼{n} x |}.
+Next Obligation.
+  intros M a n x1 x [a' Hx1] [x2 ->].
+  exists (a' â‹… x2). by rewrite (assoc op) Hx1.
+Qed.
+Next Obligation. naive_solver eauto using cmra_includedN_le. Qed.
+Definition uPred_ownM_aux : { x | x = @uPred_ownM_def }. by eexists. Qed.
+Definition uPred_ownM {M} := proj1_sig uPred_ownM_aux M.
+Definition uPred_ownM_eq :
+  @uPred_ownM = @uPred_ownM_def := proj2_sig uPred_ownM_aux.
+
+Program Definition uPred_cmra_valid_def {M} {A : cmraT} (a : A) : uPred M :=
+  {| uPred_holds n x := ✓{n} a |}.
+Solve Obligations with naive_solver eauto 2 using cmra_validN_le.
+Definition uPred_cmra_valid_aux : { x | x = @uPred_cmra_valid_def }. by eexists. Qed.
+Definition uPred_cmra_valid {M A} := proj1_sig uPred_cmra_valid_aux M A.
+Definition uPred_cmra_valid_eq :
+  @uPred_cmra_valid = @uPred_cmra_valid_def := proj2_sig uPred_cmra_valid_aux.
+
+Program Definition uPred_bupd_def {M} (Q : uPred M) : uPred M :=
+  {| uPred_holds n x := ∀ k yf,
+      k ≤ n → ✓{k} (x ⋅ yf) → ∃ x', ✓{k} (x' ⋅ yf) ∧ Q k x' |}.
+Next Obligation.
+  intros M Q n x1 x2 HQ [x3 Hx] k yf Hk.
+  rewrite (dist_le _ _ _ _ Hx); last lia. intros Hxy.
+  destruct (HQ k (x3 â‹… yf)) as (x'&?&?); [auto|by rewrite assoc|].
+  exists (x' â‹… x3); split; first by rewrite -assoc.
+  apply uPred_mono with x'; eauto using cmra_includedN_l.
+Qed.
+Next Obligation. naive_solver. Qed.
+Definition uPred_bupd_aux : { x | x = @uPred_bupd_def }. by eexists. Qed.
+Definition uPred_bupd {M} := proj1_sig uPred_bupd_aux M.
+Definition uPred_bupd_eq : @uPred_bupd = @uPred_bupd_def := proj2_sig uPred_bupd_aux.
+
+Notation "■ φ" := (uPred_pure φ%C%type)
+  (at level 20, right associativity) : uPred_scope.
+Notation "x = y" := (uPred_pure (x%C%type = y%C%type)) : uPred_scope.
+Notation "x ⊥ y" := (uPred_pure (x%C%type ⊥ y%C%type)) : uPred_scope.
+Notation "'False'" := (uPred_pure False) : uPred_scope.
+Notation "'True'" := (uPred_pure True) : uPred_scope.
+Infix "∧" := uPred_and : uPred_scope.
+Notation "(∧)" := uPred_and (only parsing) : uPred_scope.
+Infix "∨" := uPred_or : uPred_scope.
+Notation "(∨)" := uPred_or (only parsing) : uPred_scope.
+Infix "→" := uPred_impl : uPred_scope.
+Infix "★" := uPred_sep (at level 80, right associativity) : uPred_scope.
+Notation "(★)" := uPred_sep (only parsing) : uPred_scope.
+Notation "P -★ Q" := (uPred_wand P Q)
+  (at level 99, Q at level 200, right associativity) : uPred_scope.
+Notation "∀ x .. y , P" :=
+  (uPred_forall (λ x, .. (uPred_forall (λ y, P)) ..)%I) : uPred_scope.
+Notation "∃ x .. y , P" :=
+  (uPred_exist (λ x, .. (uPred_exist (λ y, P)) ..)%I) : uPred_scope.
+Notation "â–¡ P" := (uPred_always P)
+  (at level 20, right associativity) : uPred_scope.
+Notation "â–· P" := (uPred_later P)
+  (at level 20, right associativity) : uPred_scope.
+Infix "≡" := uPred_eq : uPred_scope.
+Notation "✓ x" := (uPred_cmra_valid x) (at level 20) : uPred_scope.
+Notation "|==> Q" := (uPred_bupd Q)
+  (at level 99, Q at level 200, format "|==>  Q") : uPred_scope.
+Notation "P ==★ Q" := (P ⊢ |==> Q)
+  (at level 99, Q at level 200, only parsing) : C_scope.
+Notation "P ==★ Q" := (P -★ |==> Q)%I
+  (at level 99, Q at level 200, format "P  ==★  Q") : uPred_scope.
+
+Module uPred_primitive.
+Definition unseal :=
+  (uPred_pure_eq, uPred_and_eq, uPred_or_eq, uPred_impl_eq, uPred_forall_eq,
+  uPred_exist_eq, uPred_eq_eq, uPred_sep_eq, uPred_wand_eq, uPred_always_eq,
+  uPred_later_eq, uPred_ownM_eq, uPred_cmra_valid_eq, uPred_bupd_eq).
+Ltac unseal := rewrite !unseal /=.
+
+Section primitive.
+Context {M : ucmraT}.
+Implicit Types φ : Prop.
+Implicit Types P Q : uPred M.
+Implicit Types A : Type.
+Notation "P ⊢ Q" := (@uPred_entails M P%I Q%I). (* Force implicit argument M *)
+Notation "P ⊣⊢ Q" := (equiv (A:=uPred M) P%I Q%I). (* Force implicit argument M *)
+Arguments uPred_holds {_} !_ _ _ /.
+Hint Immediate uPred_in_entails.
+
+(** Non-expansiveness and setoid morphisms *)
+Global Instance pure_proper : Proper (iff ==> (⊣⊢)) (@uPred_pure M).
+Proof. intros φ1 φ2 Hφ. by unseal; split=> -[|n] ?; try apply Hφ. Qed.
+Global Instance and_ne n : Proper (dist n ==> dist n ==> dist n) (@uPred_and M).
+Proof.
+  intros P P' HP Q Q' HQ; unseal; split=> x n' ??.
+  split; (intros [??]; split; [by apply HP|by apply HQ]).
+Qed.
+Global Instance and_proper :
+  Proper ((⊣⊢) ==> (⊣⊢) ==> (⊣⊢)) (@uPred_and M) := ne_proper_2 _.
+Global Instance or_ne n : Proper (dist n ==> dist n ==> dist n) (@uPred_or M).
+Proof.
+  intros P P' HP Q Q' HQ; split=> x n' ??.
+  unseal; split; (intros [?|?]; [left; by apply HP|right; by apply HQ]).
+Qed.
+Global Instance or_proper :
+  Proper ((⊣⊢) ==> (⊣⊢) ==> (⊣⊢)) (@uPred_or M) := ne_proper_2 _.
+Global Instance impl_ne n :
+  Proper (dist n ==> dist n ==> dist n) (@uPred_impl M).
+Proof.
+  intros P P' HP Q Q' HQ; split=> x n' ??.
+  unseal; split; intros HPQ x' n'' ????; apply HQ, HPQ, HP; auto.
+Qed.
+Global Instance impl_proper :
+  Proper ((⊣⊢) ==> (⊣⊢) ==> (⊣⊢)) (@uPred_impl M) := ne_proper_2 _.
+Global Instance sep_ne n : Proper (dist n ==> dist n ==> dist n) (@uPred_sep M).
+Proof.
+  intros P P' HP Q Q' HQ; split=> n' x ??.
+  unseal; split; intros (x1&x2&?&?&?); cofe_subst x;
+    exists x1, x2; split_and!; try (apply HP || apply HQ);
+    eauto using cmra_validN_op_l, cmra_validN_op_r.
+Qed.
+Global Instance sep_proper :
+  Proper ((⊣⊢) ==> (⊣⊢) ==> (⊣⊢)) (@uPred_sep M) := ne_proper_2 _.
+Global Instance wand_ne n :
+  Proper (dist n ==> dist n ==> dist n) (@uPred_wand M).
+Proof.
+  intros P P' HP Q Q' HQ; split=> n' x ??; unseal; split; intros HPQ x' n'' ???;
+    apply HQ, HPQ, HP; eauto using cmra_validN_op_r.
+Qed.
+Global Instance wand_proper :
+  Proper ((⊣⊢) ==> (⊣⊢) ==> (⊣⊢)) (@uPred_wand M) := ne_proper_2 _.
+Global Instance eq_ne (A : cofeT) n :
+  Proper (dist n ==> dist n ==> dist n) (@uPred_eq M A).
+Proof.
+  intros x x' Hx y y' Hy; split=> n' z; unseal; split; intros; simpl in *.
+  - by rewrite -(dist_le _ _ _ _ Hx) -?(dist_le _ _ _ _ Hy); auto.
+  - by rewrite (dist_le _ _ _ _ Hx) ?(dist_le _ _ _ _ Hy); auto.
+Qed.
+Global Instance eq_proper (A : cofeT) :
+  Proper ((≡) ==> (≡) ==> (⊣⊢)) (@uPred_eq M A) := ne_proper_2 _.
+Global Instance forall_ne A n :
+  Proper (pointwise_relation _ (dist n) ==> dist n) (@uPred_forall M A).
+Proof.
+  by intros Ψ1 Ψ2 HΨ; unseal; split=> n' x; split; intros HP a; apply HΨ.
+Qed.
+Global Instance forall_proper A :
+  Proper (pointwise_relation _ (⊣⊢) ==> (⊣⊢)) (@uPred_forall M A).
+Proof.
+  by intros Ψ1 Ψ2 HΨ; unseal; split=> n' x; split; intros HP a; apply HΨ.
+Qed.
+Global Instance exist_ne A n :
+  Proper (pointwise_relation _ (dist n) ==> dist n) (@uPred_exist M A).
+Proof.
+  intros Ψ1 Ψ2 HΨ.
+  unseal; split=> n' x ??; split; intros [a ?]; exists a; by apply HΨ.
+Qed.
+Global Instance exist_proper A :
+  Proper (pointwise_relation _ (⊣⊢) ==> (⊣⊢)) (@uPred_exist M A).
+Proof.
+  intros Ψ1 Ψ2 HΨ.
+  unseal; split=> n' x ?; split; intros [a ?]; exists a; by apply HΨ.
+Qed.
+Global Instance later_contractive : Contractive (@uPred_later M).
+Proof.
+  intros n P Q HPQ; unseal; split=> -[|n'] x ??; simpl; [done|].
+  apply (HPQ n'); eauto using cmra_validN_S.
+Qed.
+Global Instance later_proper' :
+  Proper ((⊣⊢) ==> (⊣⊢)) (@uPred_later M) := ne_proper _.
+Global Instance always_ne n : Proper (dist n ==> dist n) (@uPred_always M).
+Proof.
+  intros P1 P2 HP.
+  unseal; split=> n' x; split; apply HP; eauto using @cmra_core_validN.
+Qed.
+Global Instance always_proper :
+  Proper ((⊣⊢) ==> (⊣⊢)) (@uPred_always M) := ne_proper _.
+Global Instance ownM_ne n : Proper (dist n ==> dist n) (@uPred_ownM M).
+Proof.
+  intros a b Ha.
+  unseal; split=> n' x ? /=. by rewrite (dist_le _ _ _ _ Ha); last lia.
+Qed.
+Global Instance ownM_proper: Proper ((≡) ==> (⊣⊢)) (@uPred_ownM M) := ne_proper _.
+Global Instance cmra_valid_ne {A : cmraT} n :
+Proper (dist n ==> dist n) (@uPred_cmra_valid M A).
+Proof.
+  intros a b Ha; unseal; split=> n' x ? /=.
+  by rewrite (dist_le _ _ _ _ Ha); last lia.
+Qed.
+Global Instance cmra_valid_proper {A : cmraT} :
+  Proper ((≡) ==> (⊣⊢)) (@uPred_cmra_valid M A) := ne_proper _.
+Global Instance bupd_ne n : Proper (dist n ==> dist n) (@uPred_bupd M).
+Proof.
+  intros P Q HPQ.
+  unseal; split=> n' x; split; intros HP k yf ??;
+    destruct (HP k yf) as (x'&?&?); auto;
+    exists x'; split; auto; apply HPQ; eauto using cmra_validN_op_l.
+Qed.
+Global Instance bupd_proper : Proper ((≡) ==> (≡)) (@uPred_bupd M) := ne_proper _.
+
+(** Introduction and elimination rules *)
+Lemma pure_intro φ P : φ → P ⊢ ■ φ.
+Proof. by intros ?; unseal; split. Qed.
+Lemma pure_elim φ Q R : (Q ⊢ ■ φ) → (φ → Q ⊢ R) → Q ⊢ R.
+Proof.
+  unseal; intros HQP HQR; split=> n x ??; apply HQR; first eapply HQP; eauto.
+Qed.
+Lemma pure_forall_2 {A} (φ : A → Prop) : (∀ x : A, ■ φ x) ⊢ ■ (∀ x : A, φ x).
+Proof. by unseal. Qed.
+
+Lemma and_elim_l P Q : P ∧ Q ⊢ P.
+Proof. by unseal; split=> n x ? [??]. Qed.
+Lemma and_elim_r P Q : P ∧ Q ⊢ Q.
+Proof. by unseal; split=> n x ? [??]. Qed.
+Lemma and_intro P Q R : (P ⊢ Q) → (P ⊢ R) → P ⊢ Q ∧ R.
+Proof. intros HQ HR; unseal; split=> n x ??; by split; [apply HQ|apply HR]. Qed.
+
+Lemma or_intro_l P Q : P ⊢ P ∨ Q.
+Proof. unseal; split=> n x ??; left; auto. Qed.
+Lemma or_intro_r P Q : Q ⊢ P ∨ Q.
+Proof. unseal; split=> n x ??; right; auto. Qed.
+Lemma or_elim P Q R : (P ⊢ R) → (Q ⊢ R) → P ∨ Q ⊢ R.
+Proof. intros HP HQ; unseal; split=> n x ? [?|?]. by apply HP. by apply HQ. Qed.
+
+Lemma impl_intro_r P Q R : (P ∧ Q ⊢ R) → P ⊢ Q → R.
+Proof.
+  unseal; intros HQ; split=> n x ?? n' x' ????. apply HQ;
+    naive_solver eauto using uPred_mono, uPred_closed, cmra_included_includedN.
+Qed.
+Lemma impl_elim P Q R : (P ⊢ Q → R) → (P ⊢ Q) → P ⊢ R.
+Proof. by unseal; intros HP HP'; split=> n x ??; apply HP with n x, HP'. Qed.
+
+Lemma forall_intro {A} P (Ψ : A → uPred M): (∀ a, P ⊢ Ψ a) → P ⊢ ∀ a, Ψ a.
+Proof. unseal; intros HPΨ; split=> n x ?? a; by apply HPΨ. Qed.
+Lemma forall_elim {A} {Ψ : A → uPred M} a : (∀ a, Ψ a) ⊢ Ψ a.
+Proof. unseal; split=> n x ? HP; apply HP. Qed.
+
+Lemma exist_intro {A} {Ψ : A → uPred M} a : Ψ a ⊢ ∃ a, Ψ a.
+Proof. unseal; split=> n x ??; by exists a. Qed.
+Lemma exist_elim {A} (Φ : A → uPred M) Q : (∀ a, Φ a ⊢ Q) → (∃ a, Φ a) ⊢ Q.
+Proof. unseal; intros HΦΨ; split=> n x ? [a ?]; by apply HΦΨ with a. Qed.
+
+Lemma eq_refl {A : cofeT} (a : A) : True ⊢ a ≡ a.
+Proof. unseal; by split=> n x ??; simpl. Qed.
+Lemma eq_rewrite {A : cofeT} a b (Ψ : A → uPred M) P
+  {HΨ : ∀ n, Proper (dist n ==> dist n) Ψ} : (P ⊢ a ≡ b) → (P ⊢ Ψ a) → P ⊢ Ψ b.
+Proof.
+  unseal; intros Hab Ha; split=> n x ??. apply HΨ with n a; auto.
+  - by symmetry; apply Hab with x.
+  - by apply Ha.
+Qed.
+Lemma eq_equiv {A : cofeT} (a b : A) : (True ⊢ a ≡ b) → a ≡ b.
+Proof.
+  unseal=> Hab; apply equiv_dist; intros n; apply Hab with ∅; last done.
+  apply cmra_valid_validN, ucmra_unit_valid.
+Qed.
+Lemma eq_rewrite_contractive {A : cofeT} a b (Ψ : A → uPred M) P
+  {HΨ : Contractive Ψ} : (P ⊢ ▷ (a ≡ b)) → (P ⊢ Ψ a) → P ⊢ Ψ b.
+Proof.
+  unseal; intros Hab Ha; split=> n x ??. apply HΨ with n a; auto.
+  - destruct n; intros m ?; first omega. apply (dist_le n); last omega.
+    symmetry. by destruct Hab as [Hab]; eapply (Hab (S n)).
+  - by apply Ha.
+Qed.
+
+(* BI connectives *)
+Lemma sep_mono P P' Q Q' : (P ⊢ Q) → (P' ⊢ Q') → P ★ P' ⊢ Q ★ Q'.
+Proof.
+  intros HQ HQ'; unseal.
+  split; intros n' x ? (x1&x2&?&?&?); exists x1,x2; cofe_subst x;
+    eauto 7 using cmra_validN_op_l, cmra_validN_op_r, uPred_in_entails.
+Qed.
+Lemma True_sep_1 P : P ⊢ True ★ P.
+Proof.
+  unseal; split; intros n x ??. exists (core x), x. by rewrite cmra_core_l.
+Qed.
+Lemma True_sep_2 P : True ★ P ⊢ P.
+Proof.
+  unseal; split; intros n x ? (x1&x2&?&_&?); cofe_subst;
+    eauto using uPred_mono, cmra_includedN_r.
+Qed.
+Lemma sep_comm' P Q : P ★ Q ⊢ Q ★ P.
+Proof.
+  unseal; split; intros n x ? (x1&x2&?&?&?); exists x2, x1; by rewrite (comm op).
+Qed.
+Lemma sep_assoc' P Q R : (P ★ Q) ★ R ⊢ P ★ (Q ★ R).
+Proof.
+  unseal; split; intros n x ? (x1&x2&Hx&(y1&y2&Hy&?&?)&?).
+  exists y1, (y2 â‹… x2); split_and?; auto.
+  + by rewrite (assoc op) -Hy -Hx.
+  + by exists y2, x2.
+Qed.
+Lemma wand_intro_r P Q R : (P ★ Q ⊢ R) → P ⊢ Q -★ R.
+Proof.
+  unseal=> HPQR; split=> n x ?? n' x' ???; apply HPQR; auto.
+  exists x, x'; split_and?; auto.
+  eapply uPred_closed with n; eauto using cmra_validN_op_l.
+Qed.
+Lemma wand_elim_l' P Q R : (P ⊢ Q -★ R) → P ★ Q ⊢ R.
+Proof.
+  unseal =>HPQR. split; intros n x ? (?&?&?&?&?). cofe_subst.
+  eapply HPQR; eauto using cmra_validN_op_l.
+Qed.
+
+(* Always *)
+Lemma always_mono P Q : (P ⊢ Q) → □ P ⊢ □ Q.
+Proof. intros HP; unseal; split=> n x ? /=. by apply HP, cmra_core_validN. Qed.
+Lemma always_elim P : □ P ⊢ P.
+Proof.
+  unseal; split=> n x ? /=.
+  eauto using uPred_mono, @cmra_included_core, cmra_included_includedN.
+Qed.
+Lemma always_idemp P : □ P ⊢ □ □ P.
+Proof. unseal; split=> n x ?? /=. by rewrite cmra_core_idemp. Qed.
+
+Lemma always_pure_2 φ : ■ φ ⊢ □ ■ φ.
+Proof. by unseal. Qed.
+Lemma always_forall_2 {A} (Ψ : A → uPred M) : (∀ a, □ Ψ a) ⊢ (□ ∀ a, Ψ a).
+Proof. by unseal. Qed.
+Lemma always_exist_1 {A} (Ψ : A → uPred M) : (□ ∃ a, Ψ a) ⊢ (∃ a, □ Ψ a).
+Proof. by unseal. Qed.
+
+Lemma always_and_sep_1 P Q : □ (P ∧ Q) ⊢ □ (P ★ Q).
+Proof.
+  unseal; split=> n x ? [??].
+  exists (core x), (core x); rewrite -cmra_core_dup; auto.
+Qed.
+Lemma always_and_sep_l_1 P Q : □ P ∧ Q ⊢ □ P ★ Q.
+Proof.
+  unseal; split=> n x ? [??]; exists (core x), x; simpl in *.
+  by rewrite cmra_core_l cmra_core_idemp.
+Qed.
+
+(* Later *)
+Lemma later_mono P Q : (P ⊢ Q) → ▷ P ⊢ ▷ Q.
+Proof.
+  unseal=> HP; split=>-[|n] x ??; [done|apply HP; eauto using cmra_validN_S].
+Qed.
+Lemma löb P : (▷ P → P) ⊢ P.
+Proof.
+  unseal; split=> n x ? HP; induction n as [|n IH]; [by apply HP|].
+  apply HP, IH, uPred_closed with (S n); eauto using cmra_validN_S.
+Qed.
+Lemma later_forall_2 {A} (Φ : A → uPred M) : (∀ a, ▷ Φ a) ⊢ ▷ ∀ a, Φ a.
+Proof. unseal; by split=> -[|n] x. Qed.
+Lemma later_exist_false {A} (Φ : A → uPred M) :
+  (▷ ∃ a, Φ a) ⊢ ▷ False ∨ (∃ a, ▷ Φ a).
+Proof. unseal; split=> -[|[|n]] x /=; eauto. Qed.
+Lemma later_sep P Q : ▷ (P ★ Q) ⊣⊢ ▷ P ★ ▷ Q.
+Proof.
+  unseal; split=> n x ?; split.
+  - destruct n as [|n]; simpl.
+    { by exists x, (core x); rewrite cmra_core_r. }
+    intros (x1&x2&Hx&?&?); destruct (cmra_extend n x x1 x2)
+      as (y1&y2&Hx'&Hy1&Hy2); eauto using cmra_validN_S; simpl in *.
+    exists y1, y2; split; [by rewrite Hx'|by rewrite Hy1 Hy2].
+  - destruct n as [|n]; simpl; [done|intros (x1&x2&Hx&?&?)].
+    exists x1, x2; eauto using dist_S.
+Qed.
+Lemma later_false_excluded_middle P : ▷ P ⊢ ▷ False ∨ (▷ False → P).
+Proof.
+  unseal; split=> -[|n] x ? /= HP; [by left|right].
+  intros [|n'] x' ????; [|done].
+  eauto using uPred_closed, uPred_mono, cmra_included_includedN.
+Qed.
+Lemma always_later P : □ ▷ P ⊣⊢ ▷ □ P.
+Proof. by unseal. Qed.
+
+(* Own *)
+Lemma ownM_op (a1 a2 : M) :
+  uPred_ownM (a1 ⋅ a2) ⊣⊢ uPred_ownM a1 ★ uPred_ownM a2.
+Proof.
+  unseal; split=> n x ?; split.
+  - intros [z ?]; exists a1, (a2 â‹… z); split; [by rewrite (assoc op)|].
+    split. by exists (core a1); rewrite cmra_core_r. by exists z.
+  - intros (y1&y2&Hx&[z1 Hy1]&[z2 Hy2]); exists (z1 â‹… z2).
+    by rewrite (assoc op _ z1) -(comm op z1) (assoc op z1)
+      -(assoc op _ a2) (comm op z1) -Hy1 -Hy2.
+Qed.
+Lemma always_ownM_core (a : M) : uPred_ownM a ⊢ □ uPred_ownM (core a).
+Proof.
+  split=> n x /=; unseal; intros Hx. simpl. by apply cmra_core_monoN.
+Qed.
+Lemma ownM_empty : True ⊢ uPred_ownM ∅.
+Proof. unseal; split=> n x ??; by  exists x; rewrite left_id. Qed.
+Lemma later_ownM a : ▷ uPred_ownM a ⊢ ∃ b, uPred_ownM b ∧ ▷ (a ≡ b).
+Proof.
+  unseal; split=> -[|n] x /= ? Hax; first by eauto using ucmra_unit_leastN.
+  destruct Hax as [y ?].
+  destruct (cmra_extend n x a y) as (a'&y'&Hx&?&?); auto using cmra_validN_S.
+  exists a'. rewrite Hx. eauto using cmra_includedN_l.
+Qed.
+
+(* Valid *)
+Lemma ownM_valid (a : M) : uPred_ownM a ⊢ ✓ a.
+Proof.
+  unseal; split=> n x Hv [a' ?]; cofe_subst; eauto using cmra_validN_op_l.
+Qed.
+Lemma cmra_valid_intro {A : cmraT} (a : A) : ✓ a → True ⊢ ✓ a.
+Proof. unseal=> ?; split=> n x ? _ /=; by apply cmra_valid_validN. Qed.
+Lemma cmra_valid_elim {A : cmraT} (a : A) : ¬ ✓{0} a → ✓ a ⊢ False.
+Proof. unseal=> Ha; split=> n x ??; apply Ha, cmra_validN_le with n; auto. Qed.
+Lemma always_cmra_valid_1 {A : cmraT} (a : A) : ✓ a ⊢ □ ✓ a.
+Proof. by unseal. Qed.
+Lemma cmra_valid_weaken {A : cmraT} (a b : A) : ✓ (a ⋅ b) ⊢ ✓ a.
+Proof. unseal; split=> n x _; apply cmra_validN_op_l. Qed.
+
+(* Basic update modality *)
+Lemma bupd_intro P : P ==★ P.
+Proof.
+  unseal. split=> n x ? HP k yf ?; exists x; split; first done.
+  apply uPred_closed with n; eauto using cmra_validN_op_l.
+Qed.
+Lemma bupd_mono P Q : (P ⊢ Q) → (|==> P) ==★ Q.
+Proof.
+  unseal. intros HPQ; split=> n x ? HP k yf ??.
+  destruct (HP k yf) as (x'&?&?); eauto.
+  exists x'; split; eauto using uPred_in_entails, cmra_validN_op_l.
+Qed.
+Lemma bupd_trans P : (|==> |==> P) ==★ P.
+Proof. unseal; split; naive_solver. Qed.
+Lemma bupd_frame_r P R : (|==> P) ★ R ==★ P ★ R.
+Proof.
+  unseal; split; intros n x ? (x1&x2&Hx&HP&?) k yf ??.
+  destruct (HP k (x2 â‹… yf)) as (x'&?&?); eauto.
+  { by rewrite assoc -(dist_le _ _ _ _ Hx); last lia. }
+  exists (x' â‹… x2); split; first by rewrite -assoc.
+  exists x', x2; split_and?; auto.
+  apply uPred_closed with n; eauto 3 using cmra_validN_op_l, cmra_validN_op_r.
+Qed.
+Lemma bupd_ownM_updateP x (Φ : M → Prop) :
+  x ~~>: Φ → uPred_ownM x ==★ ∃ y, ■ Φ y ∧ uPred_ownM y.
+Proof.
+  unseal=> Hup; split=> n x2 ? [x3 Hx] k yf ??.
+  destruct (Hup k (Some (x3 â‹… yf))) as (y&?&?); simpl in *.
+  { rewrite /= assoc -(dist_le _ _ _ _ Hx); auto. }
+  exists (y â‹… x3); split; first by rewrite -assoc.
+  exists y; eauto using cmra_includedN_l.
+Qed.
+
+(* Products *)
+Lemma prod_equivI {A B : cofeT} (x y : A * B) : x ≡ y ⊣⊢ x.1 ≡ y.1 ∧ x.2 ≡ y.2.
+Proof. by unseal. Qed.
+Lemma prod_validI {A B : cmraT} (x : A * B) : ✓ x ⊣⊢ ✓ x.1 ∧ ✓ x.2.
+Proof. by unseal. Qed.
+
+(* Later *)
+Lemma later_equivI {A : cofeT} (x y : A) : Next x ≡ Next y ⊣⊢ ▷ (x ≡ y).
+Proof. by unseal. Qed.
+
+(* Discrete *)
+Lemma discrete_valid {A : cmraT} `{!CMRADiscrete A} (a : A) : ✓ a ⊣⊢ ■ ✓ a.
+Proof. unseal; split=> n x _. by rewrite /= -cmra_discrete_valid_iff. Qed.
+Lemma timeless_eq {A : cofeT} (a b : A) : Timeless a → a ≡ b ⊣⊢ ■ (a ≡ b).
+Proof.
+  unseal=> ?. apply (anti_symm (⊢)); split=> n x ?; by apply (timeless_iff n).
+Qed.
+
+(* Option *)
+Lemma option_equivI {A : cofeT} (mx my : option A) :
+  mx ≡ my ⊣⊢ match mx, my with
+             | Some x, Some y => x ≡ y | None, None => True | _, _ => False
+             end.
+Proof.
+  unseal. do 2 split. by destruct 1. by destruct mx, my; try constructor.
+Qed.
+Lemma option_validI {A : cmraT} (mx : option A) :
+  ✓ mx ⊣⊢ match mx with Some x => ✓ x | None => True end.
+Proof. unseal. by destruct mx. Qed.
+
+(* Functions *)
+Lemma cofe_funC_equivI {A B} (f g : A -c> B) : f ≡ g ⊣⊢ ∀ x, f x ≡ g x.
+Proof. by unseal. Qed.
+Lemma cofe_moreC_equivI {A B : cofeT} (f g : A -n> B) : f ≡ g ⊣⊢ ∀ x, f x ≡ g x.
+Proof. by unseal. Qed.
+End primitive.
+End uPred_primitive.
diff --git a/base_logic/soundness.v b/base_logic/soundness.v
new file mode 100644
index 000000000..4f3c5f793
--- /dev/null
+++ b/base_logic/soundness.v
@@ -0,0 +1,24 @@
+From iris.base_logic Require Export primitive.
+Import uPred_entails uPred_primitive.
+
+Section adequacy.
+Context {M : ucmraT}.
+
+(** Consistency and adequancy statements *)
+Lemma soundness φ n : (True ⊢ Nat.iter n (λ P, |==> ▷ P) (@uPred_pure M φ)) → φ.
+Proof.
+  cut (∀ x, ✓{n} x → Nat.iter n (λ P, |==> ▷ P)%I (@uPred_pure M φ) n x → φ).
+  { intros help H. eapply (help ∅); eauto using ucmra_unit_validN.
+    eapply H; try unseal; by eauto using ucmra_unit_validN. }
+  unseal. induction n as [|n IH]=> x Hx Hupd; auto.
+  destruct (Hupd (S n) ∅) as (x'&?&?); rewrite ?right_id; auto.
+  eapply IH with x'; eauto using cmra_validN_S, cmra_validN_op_l.
+Qed.
+
+Corollary consistency_modal n :
+  ¬ (True ⊢ Nat.iter n (λ P, |==> ▷ P) (False : uPred M)).
+Proof. exact (soundness False n). Qed.
+
+Corollary consistency : ¬ (True ⊢ False : uPred M).
+Proof. exact (consistency_modal 0). Qed.
+End adequacy.
diff --git a/algebra/upred_tactics.v b/base_logic/tactics.v
similarity index 98%
rename from algebra/upred_tactics.v
rename to base_logic/tactics.v
index 8ccf0c127..750dd0f83 100644
--- a/algebra/upred_tactics.v
+++ b/base_logic/tactics.v
@@ -1,6 +1,5 @@
 From iris.prelude Require Import gmap.
-From iris.algebra Require Export upred.
-From iris.algebra Require Export upred_big_op.
+From iris.base_logic Require Export base_logic big_op.
 Import uPred.
 
 Module uPred_reflection. Section uPred_reflection.
diff --git a/base_logic/upred.v b/base_logic/upred.v
new file mode 100644
index 000000000..710effb26
--- /dev/null
+++ b/base_logic/upred.v
@@ -0,0 +1,172 @@
+From iris.algebra Require Export cmra.
+
+Record uPred (M : ucmraT) : Type := IProp {
+  uPred_holds :> nat → M → Prop;
+  uPred_mono n x1 x2 : uPred_holds n x1 → x1 ≼{n} x2 → uPred_holds n x2;
+  uPred_closed n1 n2 x : uPred_holds n1 x → n2 ≤ n1 → ✓{n2} x → uPred_holds n2 x
+}.
+Arguments uPred_holds {_} _ _ _ : simpl never.
+Add Printing Constructor uPred.
+Instance: Params (@uPred_holds) 3.
+
+Delimit Scope uPred_scope with I.
+Bind Scope uPred_scope with uPred.
+Arguments uPred_holds {_} _%I _ _.
+
+Section cofe.
+  Context {M : ucmraT}.
+
+  Inductive uPred_equiv' (P Q : uPred M) : Prop :=
+    { uPred_in_equiv : ∀ n x, ✓{n} x → P n x ↔ Q n x }.
+  Instance uPred_equiv : Equiv (uPred M) := uPred_equiv'.
+  Inductive uPred_dist' (n : nat) (P Q : uPred M) : Prop :=
+    { uPred_in_dist : ∀ n' x, n' ≤ n → ✓{n'} x → P n' x ↔ Q n' x }.
+  Instance uPred_dist : Dist (uPred M) := uPred_dist'.
+  Program Instance uPred_compl : Compl (uPred M) := λ c,
+    {| uPred_holds n x := c n n x |}.
+  Next Obligation. naive_solver eauto using uPred_mono. Qed.
+  Next Obligation.
+    intros c n1 n2 x ???; simpl in *.
+    apply (chain_cauchy c n2 n1); eauto using uPred_closed.
+  Qed.
+  Definition uPred_cofe_mixin : CofeMixin (uPred M).
+  Proof.
+    split.
+    - intros P Q; split.
+      + by intros HPQ n; split=> i x ??; apply HPQ.
+      + intros HPQ; split=> n x ?; apply HPQ with n; auto.
+    - intros n; split.
+      + by intros P; split=> x i.
+      + by intros P Q HPQ; split=> x i ??; symmetry; apply HPQ.
+      + intros P Q Q' HP HQ; split=> i x ??.
+        by trans (Q i x);[apply HP|apply HQ].
+    - intros n P Q HPQ; split=> i x ??; apply HPQ; auto.
+    - intros n c; split=>i x ??; symmetry; apply (chain_cauchy c i n); auto.
+  Qed.
+  Canonical Structure uPredC : cofeT := CofeT (uPred M) uPred_cofe_mixin.
+End cofe.
+Arguments uPredC : clear implicits.
+
+Instance uPred_ne {M} (P : uPred M) n : Proper (dist n ==> iff) (P n).
+Proof.
+  intros x1 x2 Hx; split=> ?; eapply uPred_mono; eauto; by rewrite Hx.
+Qed.
+Instance uPred_proper {M} (P : uPred M) n : Proper ((≡) ==> iff) (P n).
+Proof. by intros x1 x2 Hx; apply uPred_ne, equiv_dist. Qed.
+
+Lemma uPred_holds_ne {M} (P Q : uPred M) n1 n2 x :
+  P ≡{n2}≡ Q → n2 ≤ n1 → ✓{n2} x → Q n1 x → P n2 x.
+Proof.
+  intros [Hne] ???. eapply Hne; try done.
+  eapply uPred_closed; eauto using cmra_validN_le.
+Qed.
+
+(** functor *)
+Program Definition uPred_map {M1 M2 : ucmraT} (f : M2 -n> M1)
+  `{!CMRAMonotone f} (P : uPred M1) :
+  uPred M2 := {| uPred_holds n x := P n (f x) |}.
+Next Obligation. naive_solver eauto using uPred_mono, cmra_monotoneN. Qed.
+Next Obligation. naive_solver eauto using uPred_closed, cmra_monotone_validN. Qed.
+
+Instance uPred_map_ne {M1 M2 : ucmraT} (f : M2 -n> M1)
+  `{!CMRAMonotone f} n : Proper (dist n ==> dist n) (uPred_map f).
+Proof.
+  intros x1 x2 Hx; split=> n' y ??.
+  split; apply Hx; auto using cmra_monotone_validN.
+Qed.
+Lemma uPred_map_id {M : ucmraT} (P : uPred M): uPred_map cid P ≡ P.
+Proof. by split=> n x ?. Qed.
+Lemma uPred_map_compose {M1 M2 M3 : ucmraT} (f : M1 -n> M2) (g : M2 -n> M3)
+    `{!CMRAMonotone f, !CMRAMonotone g} (P : uPred M3):
+  uPred_map (g ◎ f) P ≡ uPred_map f (uPred_map g P).
+Proof. by split=> n x Hx. Qed.
+Lemma uPred_map_ext {M1 M2 : ucmraT} (f g : M1 -n> M2)
+      `{!CMRAMonotone f} `{!CMRAMonotone g}:
+  (∀ x, f x ≡ g x) → ∀ x, uPred_map f x ≡ uPred_map g x.
+Proof. intros Hf P; split=> n x Hx /=; by rewrite /uPred_holds /= Hf. Qed.
+Definition uPredC_map {M1 M2 : ucmraT} (f : M2 -n> M1) `{!CMRAMonotone f} :
+  uPredC M1 -n> uPredC M2 := CofeMor (uPred_map f : uPredC M1 → uPredC M2).
+Lemma uPredC_map_ne {M1 M2 : ucmraT} (f g : M2 -n> M1)
+    `{!CMRAMonotone f, !CMRAMonotone g} n :
+  f ≡{n}≡ g → uPredC_map f ≡{n}≡ uPredC_map g.
+Proof.
+  by intros Hfg P; split=> n' y ??;
+    rewrite /uPred_holds /= (dist_le _ _ _ _(Hfg y)); last lia.
+Qed.
+
+Program Definition uPredCF (F : urFunctor) : cFunctor := {|
+  cFunctor_car A B := uPredC (urFunctor_car F B A);
+  cFunctor_map A1 A2 B1 B2 fg := uPredC_map (urFunctor_map F (fg.2, fg.1))
+|}.
+Next Obligation.
+  intros F A1 A2 B1 B2 n P Q HPQ.
+  apply uPredC_map_ne, urFunctor_ne; split; by apply HPQ.
+Qed.
+Next Obligation.
+  intros F A B P; simpl. rewrite -{2}(uPred_map_id P).
+  apply uPred_map_ext=>y. by rewrite urFunctor_id.
+Qed.
+Next Obligation.
+  intros F A1 A2 A3 B1 B2 B3 f g f' g' P; simpl. rewrite -uPred_map_compose.
+  apply uPred_map_ext=>y; apply urFunctor_compose.
+Qed.
+
+Instance uPredCF_contractive F :
+  urFunctorContractive F → cFunctorContractive (uPredCF F).
+Proof.
+  intros ? A1 A2 B1 B2 n P Q HPQ.
+  apply uPredC_map_ne, urFunctor_contractive=> i ?; split; by apply HPQ.
+Qed.
+
+(** logical entailement *)
+Inductive uPred_entails {M} (P Q : uPred M) : Prop :=
+  { uPred_in_entails : ∀ n x, ✓{n} x → P n x → Q n x }.
+Hint Extern 0 (uPred_entails _ _) => reflexivity.
+Instance uPred_entails_rewrite_relation M : RewriteRelation (@uPred_entails M).
+
+Hint Resolve uPred_mono uPred_closed : uPred_def.
+
+(** Notations *)
+Notation "P ⊢ Q" := (uPred_entails P%I Q%I)
+  (at level 99, Q at level 200, right associativity) : C_scope.
+Notation "(⊢)" := uPred_entails (only parsing) : C_scope.
+Notation "P ⊣⊢ Q" := (equiv (A:=uPred _) P%I Q%I)
+  (at level 95, no associativity) : C_scope.
+Notation "(⊣⊢)" := (equiv (A:=uPred _)) (only parsing) : C_scope.
+
+Module uPred_entails.
+Section entails.
+Context {M : ucmraT}.
+Implicit Types P Q : uPred M.
+
+Global Instance: PreOrder (@uPred_entails M).
+Proof.
+  split.
+  - by intros P; split=> x i.
+  - by intros P Q Q' HP HQ; split=> x i ??; apply HQ, HP.
+Qed.
+Global Instance: AntiSymm (⊣⊢) (@uPred_entails M).
+Proof. intros P Q HPQ HQP; split=> x n; by split; [apply HPQ|apply HQP]. Qed.
+
+Lemma equiv_spec P Q : (P ⊣⊢ Q) ↔ (P ⊢ Q) ∧ (Q ⊢ P).
+Proof.
+  split; [|by intros [??]; apply (anti_symm (⊢))].
+  intros HPQ; split; split=> x i; apply HPQ.
+Qed.
+Lemma equiv_entails P Q : (P ⊣⊢ Q) → (P ⊢ Q).
+Proof. apply equiv_spec. Qed.
+Lemma equiv_entails_sym P Q : (Q ⊣⊢ P) → (P ⊢ Q).
+Proof. apply equiv_spec. Qed.
+Global Instance entails_proper :
+  Proper ((⊣⊢) ==> (⊣⊢) ==> iff) ((⊢) : relation (uPred M)).
+Proof.
+  move => P1 P2 /equiv_spec [HP1 HP2] Q1 Q2 /equiv_spec [HQ1 HQ2]; split; intros.
+  - by trans P1; [|trans Q1].
+  - by trans P2; [|trans Q2].
+Qed.
+Lemma entails_equiv_l (P Q R : uPred M) : (P ⊣⊢ Q) → (Q ⊢ R) → (P ⊢ R).
+Proof. by intros ->. Qed.
+Lemma entails_equiv_r (P Q R : uPred M) : (P ⊢ Q) → (Q ⊣⊢ R) → (P ⊢ R).
+Proof. by intros ? <-. Qed.
+End entails.
+End uPred_entails.
diff --git a/heap_lang/lib/barrier/proof.v b/heap_lang/lib/barrier/proof.v
index be6417d58..a9b9db7fb 100644
--- a/heap_lang/lib/barrier/proof.v
+++ b/heap_lang/lib/barrier/proof.v
@@ -2,7 +2,7 @@ From iris.program_logic Require Export weakestpre.
 From iris.heap_lang Require Export lang.
 From iris.heap_lang.lib.barrier Require Export barrier.
 From iris.prelude Require Import functions.
-From iris.algebra Require Import upred_big_op.
+From iris.base_logic Require Import big_op.
 From iris.program_logic Require Import saved_prop sts.
 From iris.heap_lang Require Import proofmode.
 From iris.heap_lang.lib.barrier Require Import protocol.
diff --git a/program_logic/adequacy.v b/program_logic/adequacy.v
index a140c5b5b..de9d3c55b 100644
--- a/program_logic/adequacy.v
+++ b/program_logic/adequacy.v
@@ -1,5 +1,6 @@
 From iris.program_logic Require Export weakestpre.
-From iris.algebra Require Import gmap auth agree gset coPset upred_big_op.
+From iris.algebra Require Import gmap auth agree gset coPset.
+From iris.base_logic Require Import big_op soundness.
 From iris.program_logic Require Import wsat.
 From iris.proofmode Require Import tactics.
 Import uPred.
@@ -144,12 +145,12 @@ Theorem wp_adequacy Σ `{irisPreG Λ Σ} e σ φ :
 Proof.
   intros Hwp; split.
   - intros t2 σ2 v2 [n ?]%rtc_nsteps.
-    eapply (adequacy (M:=iResUR Σ) _ (S (S (S n)))); iIntros "".
+    eapply (soundness (M:=iResUR Σ) _ (S (S (S n)))); iIntros "".
     rewrite Nat_iter_S. iUpd (iris_alloc σ) as (?) "(?&?&?&Hσ)".
     iUpdIntro. iNext. iApply wptp_result; eauto.
     iFrame. iSplitL. by iApply Hwp. by iApply big_sepL_nil.
   - intros t2 σ2 e2 [n ?]%rtc_nsteps ?.
-    eapply (adequacy (M:=iResUR Σ) _ (S (S (S n)))); iIntros "".
+    eapply (soundness (M:=iResUR Σ) _ (S (S (S n)))); iIntros "".
     rewrite Nat_iter_S. iUpd (iris_alloc σ) as (?) "(Hw & HE & Hσ & Hσf)".
     iUpdIntro. iNext. iApply wptp_safe; eauto.
     iFrame "Hw HE Hσ". iSplitL. by iApply Hwp. by iApply big_sepL_nil.
@@ -162,7 +163,7 @@ Theorem wp_invariance Σ `{irisPreG Λ Σ} e σ1 t2 σ2 I φ Φ :
   φ σ2.
 Proof.
   intros Hwp HI [n ?]%rtc_nsteps.
-  eapply (adequacy (M:=iResUR Σ) _ (S (S (S n)))); iIntros "".
+  eapply (soundness (M:=iResUR Σ) _ (S (S (S n)))); iIntros "".
   rewrite Nat_iter_S. iUpd (iris_alloc σ1) as (?) "(Hw & HE & ? & Hσ)".
   rewrite fupd_eq in Hwp.
   iUpd (Hwp _ with "Hσ [Hw HE]") as ">(? & ? & ? & ?)"; first by iFrame.
diff --git a/program_logic/auth.v b/program_logic/auth.v
index d089851c4..28d2f6c83 100644
--- a/program_logic/auth.v
+++ b/program_logic/auth.v
@@ -1,6 +1,7 @@
 From iris.program_logic Require Export invariants.
 From iris.algebra Require Export auth.
 From iris.algebra Require Import gmap.
+From iris.base_logic Require Import big_op.
 From iris.proofmode Require Import tactics.
 Import uPred.
 
diff --git a/program_logic/boxes.v b/program_logic/boxes.v
index bfb964e97..afba03c55 100644
--- a/program_logic/boxes.v
+++ b/program_logic/boxes.v
@@ -1,5 +1,6 @@
 From iris.program_logic Require Export invariants.
-From iris.algebra Require Import auth gmap agree upred_big_op.
+From iris.algebra Require Import auth gmap agree.
+From iris.base_logic Require Import big_op.
 From iris.proofmode Require Import tactics.
 Import uPred.
 
diff --git a/program_logic/counter_examples.v b/program_logic/counter_examples.v
index 7b1d8a00b..ec7d171e5 100644
--- a/program_logic/counter_examples.v
+++ b/program_logic/counter_examples.v
@@ -1,4 +1,4 @@
-From iris.algebra Require Import upred.
+From iris.base_logic Require Import base_logic soundness.
 From iris.proofmode Require Import tactics.
 
 (** This proves that we need the â–· in a "Saved Proposition" construction with
@@ -39,7 +39,7 @@ Module savedprop. Section savedprop.
 
   Lemma contradiction : False.
   Proof.
-    apply (@uPred.adequacy M False 1); simpl.
+    apply (@soundness M False 1); simpl.
     iIntros "". iUpd A_alloc as (i) "#H".
     iPoseProof (saved_NA with "H") as "HN".
     iUpdIntro. iNext.
diff --git a/program_logic/fancy_updates.v b/program_logic/fancy_updates.v
index f1c5ec814..7d5a78443 100644
--- a/program_logic/fancy_updates.v
+++ b/program_logic/fancy_updates.v
@@ -1,6 +1,7 @@
 From iris.program_logic Require Export iris.
 From iris.program_logic Require Import wsat.
-From iris.algebra Require Import upred_big_op gmap.
+From iris.algebra Require Import gmap.
+From iris.base_logic Require Import big_op.
 From iris.proofmode Require Import tactics classes.
 Import uPred.
 
diff --git a/program_logic/ghost_ownership.v b/program_logic/ghost_ownership.v
index 826dd1234..a69bd62bd 100644
--- a/program_logic/ghost_ownership.v
+++ b/program_logic/ghost_ownership.v
@@ -1,5 +1,6 @@
 From iris.program_logic Require Export model.
 From iris.algebra Require Import iprod gmap.
+From iris.base_logic Require Import big_op.
 From iris.proofmode Require Import classes.
 Import uPred.
 
diff --git a/program_logic/iris.v b/program_logic/iris.v
index 8269a5982..17d827315 100644
--- a/program_logic/iris.v
+++ b/program_logic/iris.v
@@ -1,6 +1,6 @@
 From iris.program_logic Require Export ghost_ownership language.
 From iris.prelude Require Export coPset.
-From iris.algebra Require Import gmap auth agree gset coPset upred_big_op.
+From iris.algebra Require Import gmap auth agree gset coPset.
 
 Class irisPreG (Λ : language) (Σ : gFunctors) : Set := IrisPreG {
   state_inG :> inG Σ (authR (optionUR (exclR (stateC Λ))));
diff --git a/program_logic/lifting.v b/program_logic/lifting.v
index 9cf5f0ae6..410250333 100644
--- a/program_logic/lifting.v
+++ b/program_logic/lifting.v
@@ -1,6 +1,6 @@
 From iris.program_logic Require Export weakestpre.
 From iris.program_logic Require Import wsat.
-From iris.algebra Require Export upred_big_op.
+From iris.base_logic Require Export big_op.
 From iris.proofmode Require Import tactics.
 
 Section lifting.
diff --git a/program_logic/model.v b/program_logic/model.v
index f0199b825..62c7ceb05 100644
--- a/program_logic/model.v
+++ b/program_logic/model.v
@@ -1,4 +1,4 @@
-From iris.algebra Require Export upred.
+From iris.base_logic Require Export base_logic.
 From iris.algebra Require Import iprod gmap.
 From iris.algebra Require cofe_solver.
 
diff --git a/program_logic/weakestpre.v b/program_logic/weakestpre.v
index 582174638..e38b71ea6 100644
--- a/program_logic/weakestpre.v
+++ b/program_logic/weakestpre.v
@@ -1,6 +1,6 @@
 From iris.program_logic Require Export fancy_updates.
 From iris.program_logic Require Import wsat.
-From iris.algebra Require Import upred_big_op.
+From iris.base_logic Require Import big_op.
 From iris.prelude Require Export coPset.
 From iris.proofmode Require Import tactics classes.
 Import uPred.
diff --git a/program_logic/wsat.v b/program_logic/wsat.v
index f4d33686a..3315aa668 100644
--- a/program_logic/wsat.v
+++ b/program_logic/wsat.v
@@ -1,5 +1,6 @@
 From iris.program_logic Require Export iris.
-From iris.algebra Require Import gmap auth agree gset coPset upred_big_op.
+From iris.algebra Require Import gmap auth agree gset coPset.
+From iris.base_logic Require Import big_op.
 From iris.proofmode Require Import tactics.
 
 Definition invariant_unfold {Σ} (P : iProp Σ) : agree (later (iPreProp Σ)) :=
diff --git a/proofmode/class_instances.v b/proofmode/class_instances.v
index 31c2b0471..7dc421a0e 100644
--- a/proofmode/class_instances.v
+++ b/proofmode/class_instances.v
@@ -1,5 +1,6 @@
 From iris.proofmode Require Export classes.
-From iris.algebra Require Import upred_big_op gmap.
+From iris.algebra Require Import gmap.
+From iris.base_logic Require Import big_op.
 Import uPred.
 
 Section classes.
diff --git a/proofmode/classes.v b/proofmode/classes.v
index 3cc3e6995..3c3316bf2 100644
--- a/proofmode/classes.v
+++ b/proofmode/classes.v
@@ -1,4 +1,4 @@
-From iris.algebra Require Export upred.
+From iris.base_logic Require Export base_logic.
 Import uPred.
 
 Section classes.
diff --git a/proofmode/coq_tactics.v b/proofmode/coq_tactics.v
index ffe86380c..30a1dfd38 100644
--- a/proofmode/coq_tactics.v
+++ b/proofmode/coq_tactics.v
@@ -1,5 +1,5 @@
-From iris.algebra Require Export upred.
-From iris.algebra Require Import upred_big_op upred_tactics.
+From iris.base_logic Require Export base_logic.
+From iris.base_logic Require Import big_op tactics.
 From iris.proofmode Require Export environments classes.
 From iris.prelude Require Import stringmap hlist.
 Import uPred.
diff --git a/proofmode/tactics.v b/proofmode/tactics.v
index f2a640bb1..06b6e95e9 100644
--- a/proofmode/tactics.v
+++ b/proofmode/tactics.v
@@ -1,6 +1,6 @@
 From iris.proofmode Require Import coq_tactics.
 From iris.proofmode Require Import intro_patterns spec_patterns sel_patterns.
-From iris.algebra Require Export upred.
+From iris.base_logic Require Export base_logic.
 From iris.proofmode Require Export classes notation.
 From iris.proofmode Require Import class_instances.
 From iris.prelude Require Import stringmap hlist.
diff --git a/tests/atomic.v b/tests/atomic.v
index 251f033f7..151517dbb 100644
--- a/tests/atomic.v
+++ b/tests/atomic.v
@@ -1,5 +1,5 @@
 From iris.program_logic Require Export hoare weakestpre.
-From iris.algebra Require Import upred_big_op.
+From iris.base_logic Require Import big_op.
 From iris.prelude Require Export coPset.
 From iris.proofmode Require Import tactics.
 Import uPred.
-- 
GitLab