Module memory_map_refine

Require Export memory_map memory_trees_refine.
Local Open Scope ctype_scope.

Instance cmap_refine `{Env K} :
    Refine K (env K) (mem K) := λ Γ α f Δ1 Δ2 m1 m2,
  (* 1.) *) ✓{Γ,Δ1} m1
  (* 2.) *) ✓{Γ,Δ2} m2
  (* 3.) *) Δ1 ⊑{Γ,α,f} Δ2 ∧
  (* 4.) *) (∀ o1 o2 r w1 μ,
    f !! o1 = Some (o2,r) → cmap_car m1 !! o1 = Some (Obj w1 μ) →
    ∃ w2 w2' τ,
      cmap_car m2 !! o2 = Some (Obj w2 μ) ∧ w2 !!{Γ} r = Some w2' ∧
      w1 ⊑{Γ,α,f@Δ1↦Δ2} w2' : τ ∧ (μ → r = [])).
Instance cmap_refine' `{Env K} : RefineM K (env K) (mem K) := λ Γ α f m1 m2,
  m1 ⊑{Γ,α,f@memenv_of m1memenv_of m2} m2.

Section memory_map.
Context `{EnvSpec K}.
Implicit Types Γ : env K.
Implicit Types m : mem K.
Implicit Types Δ : memenv K.
Implicit Types τ σ : type K.
Implicit Types o : index.
Implicit Types w : mtree K.
Implicit Types rs : ref_seg K.
Implicit Types r : ref K.
Implicit Types a : addr K.
Implicit Types f : meminj K.
Implicit Types g : mtree Kmtree K.
Implicit Types α μ : bool.

Lemma cmap_refine_memenv_refine Γ α f Δ1 Δ2 m1 m2 :
  m1 ⊑{Γ,α,f@Δ1↦Δ2} m2 → Δ1 ⊑{Γ,α,f} Δ2.
Proof. by intros (?&?&?&?). Qed.
Lemma cmap_refine_memenv_refine' Γ α f m1 m2 :
  m1 ⊑{Γ,α,f} m2 → '{m1} ⊑{Γ,α,f} '{m2}.
Proof. by apply cmap_refine_memenv_refine. Qed.
Lemma cmap_refine_injective Γ α f Δ1 Δ2 m1 m2 :
  m1 ⊑{Γ,α,f@Δ1↦Δ2} m2meminj_injective f.
Proof. eauto using cmap_refine_memenv_refine, memenv_refine_injective. Qed.
Lemma cmap_refine_valid_l Γ α f Δ1 Δ2 m1 m2 :
  m1 ⊑{Γ,α,f@Δ1↦Δ2} m2 → ✓{Γ,Δ1} m1.
Proof. by intros (?&?&?&?). Qed.
Lemma cmap_refine_valid_l' Γ α f m1 m2: m1 ⊑{Γ,α,f} m2 → ✓{Γ} m1.
Proof. by apply cmap_refine_valid_l. Qed.
Lemma cmap_refine_valid_r Γ α f Δ1 Δ2 m1 m2 :
  m1 ⊑{Γ,α,f@Δ1↦Δ2} m2 → ✓{Γ,Δ2} m2.
Proof. by intros (?&?&?&?). Qed.
Lemma cmap_refine_valid_r' Γ α f m1 m2: m1 ⊑{Γ,α,f} m2 → ✓{Γ} m2.
Proof. by apply cmap_refine_valid_r. Qed.
Hint Immediate cmap_refine_valid_l cmap_refine_valid_r.
Lemma cmap_refine_id Γ α Δ m : ✓ Γ → ✓{Γ,Δ} mm ⊑{Γ,α@Δ} m.
Proof.
  destruct m as [m]; intros ? Hm.
  do 2 red; split_ands; simpl; auto using memenv_refine_id.
  intros ? o r w μ; rewrite lookup_meminj_id; intros; simplify_equality'.
  destruct (cmap_valid_Obj Γ Δ (CMap m) o w μ) as (τ&?&_&?&_); auto.
  exists w w; eauto 6 using ctree_refine_id, type_of_typed.
Qed.

Lemma cmap_refine_id' Γ α m : ✓ Γ → ✓{Γ} mm ⊑{Γ,α} m.
Proof. by apply cmap_refine_id. Qed.
Lemma cmap_refine_compose Γ α1 α2 f1 f2 Δ1 Δ2 Δ3 m1 m2 m3 :
  ✓ Γ → m1 ⊑{Γ,α1,f1@Δ1↦Δ2} m2m2 ⊑{Γ,α2,f2@Δ2↦Δ3} m3
  m1 ⊑{Γ,α1||α2,f2f1@Δ1↦Δ3} m3.
Proof.
  intros ? (?&?&?&Hm12) (?&Hm3&?&Hm23);
    split; split_ands; eauto 2 using memenv_refine_compose.
  intros o1 o3 r w1 μ.
  rewrite lookup_meminj_compose_Some; intros (o2&r2&r3&?&?&->) Hw1.
  destruct (Hm12 o1 o2 r2 w1 μ) as (w2&w2'&τ2&?&?&?&?); auto.
  destruct (Hm23 o2 o3 r3 w2 μ) as (w3&w3'&τ3&->&?&?&?); auto.
  destruct (ctree_lookup_refine Γ α2 f2 Δ2 Δ3 w2 w3' τ3 r2 w2')
    as (w3''&?&Hw23); auto.
  erewrite ctree_refine_type_of_r in Hw23 by eauto. exists w3 w3'' τ2.
  rewrite ctree_lookup_app; simplify_option_equality.
  naive_solver eauto using ctree_refine_compose.
Qed.

Lemma cmap_refine_compose' Γ α1 α2 f1 f2 m1 m2 m3 :
  ✓ Γ → m1 ⊑{Γ,α1,f1} m2m2 ⊑{Γ,α2,f2} m3m1 ⊑{Γ,α1||α2,f2f1} m3.
Proof. by apply cmap_refine_compose. Qed.
Lemma cmap_refine_inverse' Γ f m1 m2 :
  m1 ⊑{Γ,false,f} m2m2 ⊑{Γ,false,meminj_inverse f} m1.
Proof.
  intros (?&Hm2&?&Hm); split; split_ands; eauto using memenv_refine_inverse.
  intros o2 o1 r w2 μ ??.
  destruct (cmap_valid_Obj Γ '{m2} m2 o2 w2 μ) as (τ&?&?&?&_); auto.
  destruct (lookup_meminj_inverse_1 Γ f '{m1} '{m2} o1 o2 r τ)
    as (?&?&->); auto.
  assert (index_alive' m1 o1) as help; [|unfold index_alive' in help].
  { apply index_alive_spec'; eauto using memenv_refine_alive_r. }
  destruct (index_typed_lookup_cmap m1 o1 τ) as ([|w1 μ']&?&?);
    simplify_map_equality; try done.
  destruct (Hm o1 o2 [] w1 μ') as (?&w1'&τ'&?&?&?&?);
    simplify_type_equality'; auto.
  exists w1 w1 τ'; split_ands; auto using ctree_refine_inverse.
Qed.

Lemma cmap_refine_weaken Γ Γ' α α' f f' Δ1 Δ2 m1 m2 :
  ✓ Γ → m1 ⊑{Γ,α,f@Δ1↦Δ2} m2 → Γ ⊆ Γ' → (α → α') →
  Δ1 ⊑{Γ',α',f'} Δ2 → meminj_extend f f' Δ1 Δ2 →
  m1 ⊑{Γ',α',f'@Δ1↦Δ2} m2.
Proof.
  intros ? (Hm1&?&HΔ&Hm) ?? Hf.
  split; split_ands; eauto using cmap_valid_weaken,
    memenv_valid_weaken, cmap_valid_memenv_valid.
  intros o1 o2 r w1 μ ??.
  destruct (cmap_valid_Obj Γ Δ1 m1 o1 w1 μ) as (τ&?&_); auto.
  destruct (Hm o1 o2 r w1 μ)
    as (w2&w2'&τ'&?&?&?&?); eauto using option_eq_1, meminj_extend_left.
  exists w2 w2' τ'; split_ands;
    eauto using ctree_refine_weaken, ctree_lookup_weaken, option_eq_1_alt.
Qed.

Lemma cmap_lookup_alter_refine Γ Δ g m a w τ :
  ✓ Γ → ✓{Γ,Δ} m → (Γ,Δ) ⊢ a : TType τ →
  m !!{Γ} a = Some w → (Γ,Δ) ⊢ g w : τ → ctree_unshared (g w) →
  ∃ w', cmap_alter Γ g a m !!{Γ} a = Some w' ∧ w' ⊑{Γ,true@Δ} g w : τ.
Proof.
  intros. destruct (decide (addr_is_obj a)).
  { exists (g w). erewrite cmap_lookup_alter by eauto.
    eauto using ctree_refine_id. }
  exists (ctree_lookup_byte_after Γ (addr_type_base a)
    (addr_ref_byte Γ a) (g w)); split; eauto using cmap_lookup_alter_not_obj.
  assert (τ = ucharT) by eauto using addr_not_is_obj_type; subst.
  eauto using ctree_lookup_byte_alter_refine.
Qed.

Lemma cmap_lookup_ref_refine Γ α f Δ1 Δ2 m1 m2 o1 r1 o2 r2 w1 :
  ✓ Γ → m1 ⊑{Γ,α,f@Δ1↦Δ2} m2f !! o1 = Some (o2,r2) →
  m1 !!{Γ} (o1,r1) = Some w1
  ∃ w2, m2 !!{Γ} (o2,r1 ++ r2) = Some w2w1 ⊑{Γ,α,f@Δ1↦Δ2} w2 : type_of w1.
Proof.
  destruct m1 as [m1], m2 as [m2]; simpl; intros ? (Hm1&_&_&Hm) Ha Hw1.
  destruct (m1 !! o1) as [[|w1' μ]|] eqn:?; simplify_equality'.
  destruct (Hm o1 o2 r2 w1' μ) as (w2&w2'&τ2&->&Hr&?&_); auto; csimpl.
  rewrite ctree_lookup_app, Hr; csimpl; eauto using ctree_lookup_refine.
Qed.

Lemma cmap_lookup_refine Γ α f Δ1 Δ2 m1 m2 a1 a2 w1 τ :
  ✓ Γ → m1 ⊑{Γ,α,f@Δ1↦Δ2} m2
  a1 ⊑{Γ,α,f@Δ1↦Δ2} a2 : TType τ → m1 !!{Γ} a1 = Some w1
  ∃ w2, m2 !!{Γ} a2 = Some w2w1 ⊑{Γ,α,f@Δ1↦Δ2} w2 : τ.
Proof.
  intros. assert (type_of w1 = τ) by
    eauto using type_of_correct, cmap_lookup_typed, addr_refine_typed_l.
  unfold lookupE, cmap_lookup in *; case_option_guard; simplify_equality'.
  rewrite option_guard_True by eauto using addr_strict_refine.
  destruct (m1 !!{_} _) as [w1'|] eqn:?; simplify_equality'.
  destruct (addr_ref_refine Γ α f Δ1 Δ2 a1 a2 (TType (type_of w1)))
    as (r&?&_&?); auto.
  destruct (cmap_lookup_ref_refine Γ α f Δ1 Δ2 m1 m2 (addr_index a1)
    (addr_ref Γ a1) (addr_index a2) r w1') as (w2&?&?); auto.
  erewrite cmap_lookup_ref_le by eauto; simpl.
  destruct (decide (addr_is_obj a1)); simplify_equality'.
  { rewrite decide_True by (by erewrite <-addr_is_obj_refine by eauto).
    eauto. }
  case_option_guard; simplify_equality'.
  rewrite decide_False by (by erewrite <-addr_is_obj_refine by eauto).
  rewrite option_guard_True
    by eauto using pbits_refine_unshared, ctree_flatten_refine.
  erewrite <-addr_ref_byte_refine by eauto.
  assert (type_of w1 = ucharT) as ->
    by eauto using addr_not_is_obj_type, addr_refine_typed_l.
  eauto using ctree_lookup_byte_refine.
Qed.

Lemma cmap_alter_ref_refine Γ α f Δ1 Δ2 g1 g2 m1 m2 o1 r1 o2 r2 w1 w2 :
  ✓ Γ → m1 ⊑{Γ,α,f@Δ1↦Δ2} m2f !! o1 = Some (o2,r2) →
  m1 !!{Γ} (o1,r1) = Some w1m2 !!{Γ} (o2,r1 ++ r2) = Some w2
  g1 w1 ⊑{Γ,α,f@Δ1↦Δ2} g2 w2 : type_of w1 → ¬ctree_unmapped (g1 w1) →
  cmap_alter_ref Γ g1 o1 r1 m1
  ⊑{Γ,α,f@Δ1↦Δ2} cmap_alter_ref Γ g2 o2 (r1 ++ r2) m2.
Proof.
  intros ? Hm Hf Hw1 Hw2 Hg ?; split; split_ands; eauto using
    cmap_refine_memenv_refine, cmap_alter_ref_valid, ctree_refine_typed_l.
  { eapply cmap_alter_ref_valid;
      eauto using pbits_refine_mapped, ctree_flatten_refine.
    destruct (cmap_lookup_ref_refine Γ α f Δ1 Δ2 m1 m2 o1 r1 o2 r2 w1)
      as (?&?&?); auto; simplify_equality'.
    erewrite ctree_refine_type_of_r by eauto.
    eauto using ctree_refine_typed_r. }
  destruct m1 as [m1], m2 as [m2]; destruct Hm as (Hm1&_&?&Hm); simpl in *.
  destruct (m1 !! o1) as [[|w1' μ1]|] eqn:?; simplify_equality'.
  destruct (Hm o1 o2 r2 w1' μ1)
    as (w2''&w2'&τ2&?&Hr&?&?); auto; simplify_option_equality.
  rewrite ctree_lookup_app in Hw2; simplify_option_equality.
  intros o3 o4 r4 w3 μ3 ? Hw3.
  destruct (decide (o3 = o1)); simplify_map_equality'.
  { rewrite ctree_alter_app; eauto 10 using ctree_lookup_alter,
      ctree_lookup_le, ref_freeze_le_r, ctree_alter_refine; eauto. }
  destruct (meminj_injective_ne f o1 o2 o3 o4 r2 r4) as [?|[??]];
    eauto using memenv_refine_injective; simplify_map_equality'; [eauto|].
  destruct (Hm o3 o4 r4 w3 μ3)
    as (w4''&w4'&τ4&?&?&?&?); auto; simplify_map_equality'.
  rewrite ctree_alter_app; eauto 10 using ctree_lookup_alter_disjoint.
Qed.

Lemma cmap_alter_refine Γ α f Δ1 Δ2 g1 g2 m1 m2 a1 a2 w1 w2 τ :
  ✓ Γ → m1 ⊑{Γ,α,f@Δ1↦Δ2} m2a1 ⊑{Γ,α,f@Δ1↦Δ2} a2 : TType τ →
  m1 !!{Γ} a1 = Some w1m2 !!{Γ} a2 = Some w2 → ¬ctree_unmapped w1
  g1 w1 ⊑{Γ,α,f@Δ1↦Δ2} g2 w2 : τ → ¬ctree_unmapped (g1 w1) →
  cmap_alter Γ g1 a1 m1 ⊑{Γ,α,f@Δ1↦Δ2} cmap_alter Γ g2 a2 m2.
Proof.
  intros. assert (type_of w1 = τ) by
    eauto using type_of_correct, cmap_lookup_typed, addr_refine_typed_l.
  unfold lookupE, cmap_lookup, cmap_alter in *;
    do 2 case_option_guard; simplify_equality'.
  destruct (m1 !!{_} _) as [w1'|] eqn:?,
    (m2 !!{_} _) as [w2'|] eqn:?; simplify_equality'.
  destruct (addr_ref_refine Γ α f Δ1 Δ2 a1 a2 (TType (type_of w1)))
    as (r&?&_&?); auto.
  erewrite <-(cmap_alter_ref_le _ _ _ _ (addr_ref Γ a2)) by eauto.
  destruct (cmap_lookup_ref_refine Γ α f Δ1 Δ2 m1 m2 (addr_index a1)
    (addr_ref Γ a1) (addr_index a2) r w1') as (w2''&?&?); auto.
  assert (w2'' = w2'); subst.
  { eapply cmap_lookup_ref_freeze_proper; eauto using (ref_freeze_le true). }
  assert (addr_is_obj a1addr_is_obj a2) by eauto using addr_is_obj_refine.
  simplify_option_equality; try tauto; eauto using cmap_alter_ref_refine.
  assert (w1' !!{Γ} addr_ref_byte Γ a2 = Some w1)
    by (by erewrite <-(addr_ref_byte_refine _ _ _ _ _ _ a2) by eauto).
  assert (type_of w1 = ucharT) as ->
    by eauto using addr_not_is_obj_type, addr_refine_typed_l.
  erewrite addr_ref_byte_refine by eauto.
  eapply cmap_alter_ref_refine; eauto 9 using ctree_alter_byte_refine,
    ctree_alter_byte_unmapped, ctree_refine_typed_l.
Qed.

End memory_map.