From c99c5ba5f9ef8af5b102d7ca85d65170215d7846 Mon Sep 17 00:00:00 2001
From: Irene Yoon <euisuny@cis.upenn.edu>
Date: Sun, 10 Dec 2023 18:49:35 -0500
Subject: [PATCH] Existence proofs

---
 theories/vir/contextual_laws.v   |  30 ++-
 theories/vir/examples/examples.v | 250 +++++++++++++++++--
 theories/vir/instr_laws.v        | 396 ++++++++++++++++++++++++++++++-
 theories/vir/logical_relations.v |   1 +
 theories/vir/spec.v              |  27 ++-
 5 files changed, 665 insertions(+), 39 deletions(-)

diff --git a/theories/vir/contextual_laws.v b/theories/vir/contextual_laws.v
index 55ff9de2..f5dfd3cc 100644
--- a/theories/vir/contextual_laws.v
+++ b/theories/vir/contextual_laws.v
@@ -204,17 +204,28 @@ Section contextual_properties.
 
   Definition new_frame args := {| alloca_dom := ∅; local_dom := (list_to_set args) |}.
 
-  Theorem code_to_fn_contextual_args name args c_t c_s i_t i_s C args_t args_s:
+  Definition local_args_own_target args_name args_val i :=
+    ([∗ list] '(l, v) ∈ combine args_name args_val, [ l := v ]t i)%I.
+
+  Definition local_args_own_source args_name args_val i :=
+    ([∗ list] '(l, v) ∈ combine args_name args_val, [ l := v ]s i)%I.
+
+  Theorem code_to_fn_contextual_args
+    name args c_t c_s i_t i_s C args_t args_s:
     NoDup args ->
     length args = length args_t ->
     length args = length args_s ->
     initial_frame_res [i_t] [i_s] C -∗
-    □ (∀ j_t j_s, frame_WF j_t j_s ∗
-          frame_resources_own j_t j_s (new_frame args) (new_frame args) C -∗
+    □ (∀ j_t j_s, (frame_WF j_t j_s ∗
+          frame_resources_own j_t j_s (new_frame args) (new_frame args) C ∗
+        local_args_own_target args args_t j_t ∗
+        local_args_own_source args args_s j_s) -∗
         instr_conv (denote_code c_t) ⪯
         instr_conv (denote_code c_s)
       [{ (x, y), frame_WF j_t j_s ∗
-                   frame_resources_own_exist j_t j_s C }]) -∗
+                  frame_resources_own_exist j_t j_s C ∗
+                  local_args_own_target args args_t j_t ∗
+                  local_args_own_source args args_s j_s }]) -∗
     (<{{ (make_fn name c_t args) (args_t) }}> ) ⪯
     (<{{ (make_fn name c_s args) (args_s) }}> )
     [{ fun x y => initial_frame_res [i_t] [i_s] C }].
@@ -223,7 +234,7 @@ Section contextual_properties.
 
     cbn -[instr_conv denote_code].
     rewrite Hlen_t in Hlen_s.
-    rewrite Hlen_t Hlen_s Nat.eqb_refl; cbn.
+    rewrite Hlen_t Hlen_s Nat.eqb_refl.
     rewrite !bind_ret_l.
 
     Opaque denote_code.
@@ -257,13 +268,15 @@ Section contextual_properties.
               (@Monad.ret (itree L0) (@Monad_itree L0) T)) ?x)
       with (instr_conv x).
     iAssert (frame_resources_own
-               [j_t; i_t] [j_s; i_s] (new_frame args) (new_frame args)
-               C)
+               [j_t; i_t] [j_s; i_s] (new_frame args) (new_frame args) C ∗
+        local_args_own_target args args_t [j_t; i_t] ∗
+        local_args_own_source args args_s [j_s; i_s])%I
       with "[H HC]" as "Hi".
     { rewrite /frame_resources_exist; iFrame.
       iDestruct "H" as "(?&?&?&?&?&?&?&?)"; cbn; iFrame.
       cbn. rewrite !combine_fst; eauto.
       2 : by rewrite Hlen_t Hlen_s. iFrame.
+
       iExists nil, nil; cbn; repeat iSplitL; try done;
         iPureIntro; constructor. }
 
@@ -301,7 +314,8 @@ Section contextual_properties.
     setoid_rewrite interp_ret.
     iApply sim_expr_Φ_Proper; last first.
     { iApply (sim_expr_bupd_mono with "[HC Halloc Hdom]"); cycle 1.
-      { iDestruct "Hbij" as (??) "Hbij".
+      { iDestruct "Hbij" as "(Hbij & Hlv_t & Hlv_s)".
+        iDestruct "Hbij" as (??) "Hbij".
         iDestruct "Hbij" as
           "(((Ha_t&Ha_s)&((Hl_t&Hl_s)&(Hs_t&Hs_s)))
             & (HC&H))".
diff --git a/theories/vir/examples/examples.v b/theories/vir/examples/examples.v
index 9da81bec..5bd4d6f7 100644
--- a/theories/vir/examples/examples.v
+++ b/theories/vir/examples/examples.v
@@ -507,27 +507,243 @@ Section examples.
 
 End examples.
 
+(* Existence proofs for function specifications *)
+Section attr_fns.
 
-(** *Exmaple external functions *)
+  Context {Σ : gFunctors} `{!sheapGS Σ, !checkedoutGS Σ, !heapbijGS Σ}.
 
-(* A function that reads from its single argument *)
-Definition reads_only : fn_name := "reads_only".
+  Definition nil_fn_ex_name : fn_name := "nil_fn_ex".
 
-Definition reads_only_args arg : code dtyp :=
-  ((IId (Raw 0), INSTR_Load true (DTYPE_I 32)
-                (DTYPE_I 32, EXP_Ident (ID_Local arg)) None) :: nil).
+  Definition nil_fn_ex : code dtyp := nil.
 
-Definition reads_only_args_fn arg : definition dtyp (cfg dtyp) :=
-  make_fn reads_only (reads_only_args arg) [arg].
+  Definition nil_fn_ex_fn :=
+    make_fn nil_fn_ex_name nil_fn_ex nil.
 
-(* A function that stores to its single argument *)
-Definition argmems_only : fn_name := "argmems_only".
+  (* The empty function satisfies all attributes *)
+  Lemma nil_fn_ex_sat dv C i_t i_s attr:
+    attribute_interp
+      (ExternalCall DTYPE_Void dv nil attr)
+      (ExternalCall DTYPE_Void dv nil attr) C ->
+    initial_frame_res [i_t] [i_s] C -∗
+    (<{{ (make_fn nil_fn_ex_name nil_fn_ex nil) (nil) }}> ) ⪯
+    (<{{ (make_fn nil_fn_ex_name nil_fn_ex nil) (nil) }}> )
+    [{ fun x y =>
+        initial_frame_res [i_t] [i_s] C }].
+  Proof with clean.
+    iIntros (?); simp attribute_interp in H.
+    destruct H as (?&?).
+    destruct x eqn: Hx;
+    iIntros "Hi"; clear H;
+    iApply (code_to_fn_contextual with "Hi");
+    iModIntro; iIntros (??) "(#HWF & Hbij)";
+    cbn; rewrite bind_ret_l;
+    rewrite instr_conv_ret;
+    iApply sim_expr_base;
+      iExists _, _; do 2 (iSplitL ""; first done); iFrame "HWF";
+    iDestruct "Hbij" as "(Hbij & HC)";
+    iExists empty_frame, empty_frame; iFrame.
+  Qed.
 
-Definition argmems_only_args arg : code dtyp :=
-  ((IVoid 2, INSTR_Store true
-                  (DTYPE_I 32, EXP_Integer 2)
-                  (DTYPE_Pointer, EXP_Ident (ID_Local arg))
-                   None) :: nil).
+  (* Readonly *)
+  Definition readonly_ex_name : fn_name := "readonly_ex".
+
+  Definition readonly_ex : code dtyp :=
+    (IId (Raw 1), INSTR_Alloca (DTYPE_I 32) None None) ::
+    (IId (Raw 3), INSTR_Load true (DTYPE_I 32)
+                  (DTYPE_I 32, EXP_Ident (ID_Local (Raw 1))) None) :: nil.
+
+  Definition readonly_ex_fn :=
+    make_fn readonly_ex_name readonly_ex nil.
+
+  Lemma readonly_ex_sat dv C i_t i_s:
+    attribute_interp
+      (ExternalCall DTYPE_Void dv nil [FNATTR_Readonly])
+      (ExternalCall DTYPE_Void dv nil [FNATTR_Readonly]) C ->
+    initial_frame_res [i_t] [i_s] C -∗
+    (<{{ (make_fn readonly_ex_name readonly_ex nil) (nil) }}> ) ⪯
+    (<{{ (make_fn readonly_ex_name readonly_ex nil) (nil) }}> )
+    [{ fun x y =>
+        initial_frame_res [i_t] [i_s] C }].
+  Proof with clean.
+    iIntros (?); simp attribute_interp in H.
+    destruct H as (?&?).
+    destruct x eqn: Hx; cycle 4; destruct H as (?&?);
+      compute in H; try done; cycle 1.
+    { destruct H0 as (?&?&?); by compute in H0. }
+
+    destruct H0.
+    iIntros "Hi"; iApply (code_to_fn_contextual with "Hi").
+    iModIntro; iIntros (??) "(#HWF & Hbij)".
+
+    rewrite /frame_resources_own -frame_resources_eq.
+    iDestruct "Hbij" as "(Hbij & HC)".
+    rewrite /load_readonly_source_code /load_readonly_target_code.
+    to_instr.
+    iDestruct "HC" as "(HC & HA)".
+    iDestruct "Hbij" as "((Hs_t & Ha_t & Hd_t)&(Hs_s & Ha_s & Hd_s))"...
+
+    iApply sim_expr_bind; iApply (sim_expr_bupd_mono with "[HA]");
+      [ | iApply (sim_instr_alloca_checkout with
+              "Ha_t Ha_s Hd_t Hd_s Hs_t Hs_s HC")];
+      [ | by intro | ..]...
+
+    iDestruct "H" as (????)
+        "(Hl_t & Hl_s & Ha_t & Ha_s & Hd_t & Hd_s &
+            H1_t & H1_s & Hs_t & Hs_s & Hb_t & Hb_s & HC & %Hcn)"...
+
+    target:
+      iApply (target_instr_load1 with "Hl_t H1_t Hd_t Hs_t");
+          [ constructor | cbn; set_solver | ].
+    iModIntro. iIntros "H1 H3 Hl_t Hd_t Hs_t"; target_base.
+
+    source:
+      iApply (source_instr_load1 with "Hl_s H1_s Hd_s Hs_s");
+          [ constructor | cbn; set_solver | ].
+    iIntros "H1_s H3_s Hl_s Hd_s Hs_s"; source_base.
+
+    iApply (sim_insert_loc_bij with "Hl_t Hl_s Hb_t Hb_s").
+    { iApply lb_rel_empty_blocks. }
+    iIntros "#Hbij".
+
+    iApply sim_expr_base; frame_res_exists...
+    iDestruct "HA" as (??????) "HA". iFrame.
+    iExists [l_t0], [l_s0].
+    repeat (iSplitL ""; try eauto using NoDup_singleton); cbn; eauto;
+      try (iPureIntro; set_solver).
+  Qed.
+
+  (* Argmemonly, readonly *)
+  Definition argmemonly_readonly_ex_name : fn_name := "argmemonly_readonly_ex".
+
+  Definition argmemonly_readonly_ex : code dtyp :=
+    (IId (Raw 3), INSTR_Load true (DTYPE_I 32)
+                  (DTYPE_I 32, EXP_Ident (ID_Local (Raw 1))) None) :: nil.
+
+  Definition argmemonly_readonly_ex_fn :=
+    make_fn argmemonly_readonly_ex_name argmemonly_readonly_ex nil.
+
+  Lemma argmemonly_readonly_ex_sat dv C i_t i_s l_t l_s:
+    attribute_interp
+      (ExternalCall DTYPE_Void dv [UVALUE_Addr l_t] [FNATTR_Argmemonly; FNATTR_Readonly])
+      (ExternalCall DTYPE_Void dv [UVALUE_Addr l_s] [FNATTR_Argmemonly; FNATTR_Readonly]) C ->
+    l_t ↔h l_s -∗
+    initial_frame_res [i_t] [i_s] C -∗
+    (<{{ (make_fn argmemonly_readonly_ex_name argmemonly_readonly_ex [Raw 1])
+           ([UVALUE_Addr l_t]) }}> ) ⪯
+    (<{{ (make_fn argmemonly_readonly_ex_name argmemonly_readonly_ex [Raw 1])
+           ([UVALUE_Addr l_s]) }}> )
+    [{ fun x y =>
+        initial_frame_res [i_t] [i_s] C }].
+  Proof with clean.
+    iIntros (?); simp attribute_interp in H.
+    destruct H as (?&?).
+    destruct x eqn: Hx; cycle 4; destruct H as (?&?);
+      compute in H; try done;
+      try (destruct H0 as (?&?); by compute in H0).
+    clear H.
+
+    iIntros "#Hl Hi".
+    iApply (code_to_fn_contextual_args with "Hi"); try done.
+    { apply NoDup_singleton. }
+
+    iModIntro; iIntros (??) "(#HWF & Hbij)".
+
+    rewrite /frame_resources_own -frame_resources_eq.
+    rewrite /local_args_own_target /local_args_own_source.
+    iDestruct "Hbij" as "((Hbij & HC) & Hlv_t & Hlv_s)".
+    to_instr.
+    iDestruct "HC" as "(HC & HA)".
+    iDestruct "Hbij" as "((Hs_t & Ha_t & Hd_t)&(Hs_s & Ha_s & Hd_s))"...
+    iDestruct "Hlv_t" as "(Hlv_t & _)"; iDestruct "Hlv_s" as "(Hlv_s & _)".
+
+    specialize (H0 l_t l_s 0%nat eq_refl).
+    destruct H0 as (?&?&?).
+    iApply sim_expr_bind.
+    iApply (sim_expr_bupd_mono with "[Ha_t Ha_s HA]");
+      last (iApply (sim_instr_load_bij_Some with
+                "Hl HC Hd_t Hd_s Hs_t Hs_s Hlv_t Hlv_s");
+        first eauto; try set_solver).
+    2: try done. 2: try constructor.
+
+    cont.
+    iDestruct "H" as "(HC & Hd_t & Hd_s & Hs_t & Hs_s& H1_t & H1_s & H)".
+
+    iApply sim_expr_base; iFrame.
+    iExists tt, tt; do 2 (iSplitL ""; first done).
+    iFrame "HWF".
+    iExists (instr_laws.Frame ∅ {[Raw 3; Raw 1]}),
+      (instr_laws.Frame ∅ {[Raw 3; Raw 1]}); by iFrame.
+  Qed.
+
+  (* Argmemonly *)
+  Definition argmemonly_ex_name : fn_name := "argmemonly_ex".
+
+  Definition argmemonly_ex : code dtyp :=
+    (IVoid 2, INSTR_Store true
+                    (DTYPE_I 32, EXP_Integer 2)
+                    (DTYPE_Pointer, EXP_Ident (ID_Local (Raw 1)))
+                    None) :: nil.
+
+  Definition argmemonly_ex_fn :=
+    make_fn argmemonly_ex_name argmemonly_ex nil.
+
+  Lemma argmemonly_ex_sat dv C i_t i_s l_t l_s:
+    attribute_interp
+      (ExternalCall DTYPE_Void dv [UVALUE_Addr l_t] [FNATTR_Argmemonly])
+      (ExternalCall DTYPE_Void dv [UVALUE_Addr l_s] [FNATTR_Argmemonly]) C ->
+    l_t ↔h l_s -∗
+    initial_frame_res [i_t] [i_s] C -∗
+    (<{{ (make_fn argmemonly_ex_name argmemonly_ex [Raw 1])
+           ([UVALUE_Addr l_t]) }}> ) ⪯
+    (<{{ (make_fn argmemonly_ex_name argmemonly_ex [Raw 1])
+           ([UVALUE_Addr l_s]) }}> )
+    [{ fun x y =>
+        initial_frame_res [i_t] [i_s] C }].
+  Proof with clean.
+    iIntros (?); simp attribute_interp in H.
+    destruct H as (?&?).
+    destruct x eqn: Hx; cycle 4; destruct H as (?&?);
+      compute in H; try done;
+      try (destruct H0 as (?&?); by compute in H0).
+    clear H.
+
+    iIntros "#Hl Hi".
+    iApply (code_to_fn_contextual_args with "Hi"); try done.
+    { apply NoDup_singleton. }
+
+    iModIntro; iIntros (??) "(#HWF & Hbij)".
+
+    rewrite /frame_resources_own -frame_resources_eq.
+    rewrite /local_args_own_target /local_args_own_source.
+    iDestruct "Hbij" as "((Hbij & HC) & Hlv_t & Hlv_s)".
+    to_instr.
+    iDestruct "HC" as "(HC & HA)".
+    iDestruct "Hbij" as "((Hs_t & Ha_t & Hd_t)&(Hs_s & Ha_s & Hd_s))"...
+    iDestruct "Hlv_t" as "(Hlv_t & _)"; iDestruct "Hlv_s" as "(Hlv_s & _)".
+    destruct H0 as (?&?).
+
+    specialize (H0 l_t l_s 0%nat eq_refl).
+    iApply sim_expr_bind.
+    iAssert (dval_rel
+      (DVALUE_I32 (DynamicValues.Int32.repr 2))
+      (DVALUE_I32 (DynamicValues.Int32.repr 2)))%I as "Hdv".
+    { iApply dval_rel_I32. }
+    iApply (sim_expr_bupd_mono with "[Ha_t Ha_s HA]");
+      last (iApply (sim_instr_store_bij1 with
+                "Hl HC Hd_t Hd_s Hs_t Hs_s Hdv Hlv_t Hlv_s");
+        first eauto; try set_solver).
+    2: try done. 2: try constructor.
+    2: iApply target_red_denote_exp_i32.
+    2: iApply source_red_denote_exp_i32.
+
+    cont.
+    iDestruct "H" as "(HC & Hd_t & Hd_s & Hs_t & Hs_s& H1_t & H1_s)".
+
+    iApply sim_expr_base; iFrame.
+    iExists tt, tt; do 2 (iSplitL ""; first done).
+    iFrame "HWF".
+    iExists (instr_laws.Frame ∅ {[Raw 1]}),
+      (instr_laws.Frame ∅ {[Raw 1]}); by iFrame.
+  Qed.
 
-Definition argmems_only_args_fn arg : definition dtyp (cfg dtyp) :=
-  make_fn argmems_only (argmems_only_args arg) [arg].
+End attr_fns.
diff --git a/theories/vir/instr_laws.v b/theories/vir/instr_laws.v
index 2a42f0c9..bcddbeb9 100644
--- a/theories/vir/instr_laws.v
+++ b/theories/vir/instr_laws.v
@@ -610,6 +610,105 @@ Section instruction_laws.
     iApply target_red_tau. by destruct v0.
   Qed.
 
+   Lemma source_instr_load1 l dt du b o L i pid id q Ψ size bytes cid:
+    is_supported dt ->
+    pid ∉ L ->
+    ⊢ l ↦{q}s [ LBlock size bytes cid ] -∗
+      [ id := UVALUE_Addr (l, 0%Z) ]s i -∗
+      ldomain_src i L -∗
+      stack_src i -∗
+      ([ id := UVALUE_Addr (l, 0%Z) ]s i -∗
+        [ pid := (read_in_mem_block bytes 0%Z dt)]s i -∗
+        l ↦{q}s [ LBlock size bytes cid ] -∗
+        ldomain_src i ({[ pid ]} ∪ L) -∗
+        stack_src i -∗
+        source_red (η := vir_handler) (Ret ()) Ψ) -∗
+      source_red (η := vir_handler)
+        (<{ %(IId pid) = (INSTR_Load b dt (du, EXP_Ident (ID_Local id)) o) }>)
+        Ψ.
+  Proof.
+    iIntros (WF Ht) "Hp Hl Hd Hf H".
+
+    cbn. rewrite /instr_conv.
+    iApply source_red_eq_itree.
+    { rewrite interp_bind interp_translate; cbn.
+      rewrite translate_vis interp_vis bind_bind.
+      setoid_rewrite translate_ret.
+      setoid_rewrite interp_ret.
+      setoid_rewrite bind_tau.
+      setoid_rewrite bind_ret_l.
+      rewrite /LU_to_exp; cbn; rewrite /exp_to_instr.
+      simp instrE_conv. reflexivity. }
+
+    iApply source_red_bind.
+    iApply (source_red_mono with "[Hp Hd H] [Hf Hl]");
+      [ | iApply (source_local_read with "Hl Hf"); auto]; cycle 1.
+    { iIntros "Hl Hf".
+      iApply source_red_base.
+      Unshelve.
+      2 : exact (lift_unary_post (fun x => ⌜x = UVALUE_Addr (l, 0%Z)⌝
+       ∗ stack_src i ∗ [id := UVALUE_Addr (l, 0%Z)]s i)%I).
+      iExists _. do 2 (iSplitL ""; [ done | ]). iFrame. }
+
+    iIntros (?) "HP".
+    iDestruct "HP" as (???) "(Hf & Hl)".
+    iApply source_red_eq_itree.
+    { by rewrite H bind_ret_l. }
+
+    iApply source_red_tau.
+
+    rewrite H0; cbn.
+
+    iApply source_red_eq_itree.
+    { setoid_rewrite interp_bind.
+      setoid_rewrite interp_ret.
+      rewrite bind_ret_l. reflexivity. }
+
+    destruct (dvalue_eq_dec (d1:=DVALUE_Addr (l, 0%Z)) (d2:=DVALUE_Poison)) eqn: Heq ; [ done | ].
+    iApply source_red_eq_itree.
+    { rewrite interp_bind.
+
+      cbn.
+      setoid_rewrite interp_vis.
+      setoid_rewrite interp_ret.
+      Unshelve.
+      2 : exact (x <- trigger (Load dt (DVALUE_Addr (l, 0%Z))) ;;
+                 x <- Tau (trigger (LocalWrite pid x)) ;; Tau (Ret x)).
+      rewrite bind_bind.
+      setoid_rewrite bind_tau.
+      setoid_rewrite bind_ret_l.
+      repeat setoid_rewrite bind_vis.
+      repeat setoid_rewrite bind_ret_l.
+      eapply eqit_Vis; intros.
+      apply eqit_Tau.
+      eapply eqit_Vis; intros. reflexivity. }
+
+    iApply source_red_bind.
+
+    change l with ((l, 0%Z).1) at 1.
+    iApply (source_red_load1 with "Hp").
+
+    iIntros "H'".
+    iApply source_red_base.
+
+    iApply source_red_eq_itree.
+    { by rewrite bind_ret_l !bind_tau. }
+
+    iApply source_red_tau; iApply source_red_bind.
+
+    iApply (source_local_write_alloc _ _ _ _ _ Ht with "Hd Hf").
+    iIntros "Hi H_t H_s".
+
+    iApply source_red_base.
+
+    iApply source_red_eq_itree.
+    { by rewrite bind_ret_l. }
+
+    iApply source_red_tau.
+
+    by iSpecialize ("H" with "Hl Hi H' H_t H_s").
+  Qed.
+
   Lemma source_instr_load l dt du b o L i pid v id q Ψ:
     is_supported dt ->
     dvalue_has_dtyp v dt  ->
@@ -1672,6 +1771,122 @@ Section exp_laws.
     Unshelve. all : eauto.
   Qed.
 
+  Lemma sim_instr_alloca_checkout
+    l_t l_s dt t o i_t S_t i_s S_s `{non_void dt} L_t L_s C:
+    l_t ∉ L_t ->
+    l_s ∉ L_s ->
+    ⊢ alloca_tgt i_t S_t -∗
+      alloca_src i_s S_s -∗
+      ldomain_tgt i_t L_t -∗
+      ldomain_src i_s L_s -∗
+      stack_tgt i_t -∗
+      stack_src i_s -∗
+      checkout C -∗
+      <{ %(IId l_t) = (INSTR_Alloca dt t o) }> ⪯
+      <{ %(IId l_s) = (INSTR_Alloca dt t o) }>
+      [{ (v_t, v_s), ∃ l_t0 l_s0,
+          ⌜l_t0 ∉ S_t⌝ ∗
+          ⌜l_s0 ∉ S_s⌝ ∗
+          l_t0 ↦t [make_empty_logical_block dt] ∗
+          l_s0 ↦s [make_empty_logical_block dt] ∗
+          alloca_tgt i_t ({[l_t0]} ∪ S_t) ∗
+          alloca_src i_s ({[l_s0]} ∪ S_s) ∗
+          ldomain_tgt i_t ({[ l_t ]} ∪ L_t) ∗
+          ldomain_src i_s ({[ l_s ]} ∪ L_s) ∗
+          [ l_t := UVALUE_Addr (l_t0, 0%Z) ]t i_t ∗
+          [ l_s := UVALUE_Addr (l_s0, 0%Z) ]s i_s ∗
+          stack_tgt i_t ∗
+          stack_src i_s ∗
+          target_block_size l_t0 (Some (N.to_nat (sizeof_dtyp dt))) ∗
+          source_block_size l_s0 (Some (N.to_nat (sizeof_dtyp dt))) ∗
+          checkout C ∗
+          ⌜C !! (l_t0, l_s0) = None⌝
+      }].
+  Proof.
+    iIntros (Hnt Hns) "Ha_t Ha_s Hd_t Hd_s Hf_t Hf_s HC".
+    setoid_rewrite interp_bind.
+    iApply sim_expr_bind.
+
+    assert (Heq : forall dt,
+        instr_conv (trigger (Alloca dt)) ≅
+          x <- trigger (Alloca dt) ;; Tau (Ret x)).
+    { intros. rewrite /instr_conv.
+      rewrite interp_vis. setoid_rewrite interp_ret.
+
+      rewrite /subevent /resum /ReSum_inr /cat /Cat_IFun /inr_ /Inr_sum1.
+      simp instrE_conv. rewrite bind_trigger.
+      reflexivity. }
+    setoid_rewrite Heq.
+
+    iApply sim_expr_bind.
+
+    iApply (sim_expr_bupd_mono with
+             "[HC Hd_t Hd_s] [Hf_t Hf_s Ha_t Ha_s]");
+      [ | iApply (sim_alloca with "Ha_t Ha_s Hf_t Hf_s") ; eauto ].
+    cbn. iIntros (??) "H".
+    iDestruct "H" as (??????????)
+      "(Ht & Hs & Ha_t & Ha_s & Hf_t & Hf_s & Hb_t & Hb_s)"; subst.
+
+    rewrite H H0 !bind_ret_l; subst.
+    iApply sim_expr_tau.
+    iApply sim_expr_base.
+    rewrite !bind_ret_l.
+
+    iApply sim_update_si.
+    iModIntro; iIntros (??) "SI".
+    iDestruct "SI" as (???) "(Hh_s & Hh_t & H_c & Hbij & %WF_SI & SI)".
+
+    iAssert ((¬ ⌜set_Exists (λ '(b_t', b_s'), l_t0 = b_t') S⌝)%I) as "%Hext_t".
+    { iIntros (([b_t' b_s'] & Hin & <-)).
+      iDestruct "Hbij" as "(Hbij & Hheap)".
+      iPoseProof (big_sepS_elem_of with "Hheap") as "Hr"; first by apply Hin.
+      iDestruct "Hr" as (? v_t' v_s') "(Hr_t & Ha_t' & Ha_s')".
+      by iApply (heap_block_size_excl with "Hb_t Ha_t'"). }
+
+    iPoseProof (lb_rel_empty_blocks dt) as "Hrel".
+
+    destruct_HC "Hh_s".
+    iDestruct (ghost_var_agree with "Hf_s HCF") as %Hd_s; subst.
+    iDestruct (ghost_var_agree with "HC H_c") as %Hc_s; subst.
+    rewrite allocaS_eq.
+    iDestruct (ghost_var_agree with "Ha_s HA") as %Hd_s; subst.
+
+    iDestruct "Hh_t" as (cft hFt)
+        "(Hσ_t&HB_t&HCF_t&HA_t&HL_t&HD_t&HSA_t&HG_t&%Hdup_t&%Hbs_t&%Hwf_t)".
+    iDestruct (ghost_var_agree with "Hf_t HCF_t") as %Hd_t; subst.
+    iDestruct (ghost_var_agree with "Ha_t HA_t") as %Hd_t; subst.
+    iFrame.
+
+    iSplitR "Hd_t Hd_s HC Ha_t Ha_s Ht Hs Hb_t Hb_s Hf_t Hf_s".
+    { iExists _, S, G; iFrame.
+      iSplitR "HB_t HCF_t HA_t HL_t HD_t HSA_t".
+      { iModIntro; iExists _, _; iFrame. done. }
+      iSplitR "".
+      { iModIntro; iExists _, _; iFrame. done. }
+      iModIntro. iPureIntro. set_solver. }
+
+    setoid_rewrite instr_conv_localwrite. cbn.
+
+    iApply sim_expr_vis.
+
+    iApply (sim_expr_bupd_mono with
+             "[HC Ht Hs Ha_t Ha_s Hb_t Hb_s] [Hf_t Hf_s Hd_t Hd_s]");
+      [ | iApply (sim_local_write_alloc with "Hd_t Hd_s Hf_t Hf_s") ; eauto ].
+    cbn.
+    iIntros (??) "H".
+    iDestruct "H" as (????) "(Hp_t & Hp_s & Hf_t & Hf_s)".
+    rewrite H1 H2 !bind_ret_l.
+
+    iApply sim_expr_tau; iApply sim_expr_base.
+    iExists tt, tt; destruct v1, v2.
+    do 2 (iSplitL ""; [ done |]).
+    iExists l_t0, l_s0. base. iFrame.
+    iDestruct "Hf_s" as "(?&?&?)"; iFrame.
+    iPureIntro. clear -WF_SI Hext_t.
+    apply not_elem_of_dom_1.
+    set_solver.
+  Qed.
+
   Lemma source_instr_bij_load {R} l dt b du o L i pid id Ψ l_t C (e_t : _ R) (k : _ R):
     pid ∉ L ->
     ⊢ l_t ↔h l -∗
@@ -1917,9 +2132,9 @@ Section more_properties.
           (λ '(t, op), translate exp_to_instr (denote_exp (Some t) op)) p_s)
       [{ (args_t, args_s),
           ([∗ list] x;y ∈ args_t; args_s, uval_rel x y) ∗
-          ⌜∀ (l_t0 l_s0 : loc) (n : nat),
+          ⌜∀ l_t0 l_s0 (n : nat),
             nth_error (zip args_t args_s) n =
-              Some (# l_t0 ̂, # l_s0 ̂) → C !! (l_t0, l_s0) = None⌝
+              Some (UVALUE_Addr l_t0, UVALUE_Addr l_s0 ) → C !! (l_t0.1, l_s0.1) = None⌝
             ∗ Q ∗
           ldomain_tgt i_t L_t ∗ ldomain_src i_s L_s ∗
           stack_tgt i_t ∗ stack_src i_s }]) -∗
@@ -2031,9 +2246,10 @@ Section more_properties.
           (λ '(t, op), translate exp_to_instr (denote_exp (Some t) op)) p_s)
       [{ (args_t, args_s),
           ([∗ list] x;y ∈ args_t; args_s, uval_rel x y) ∗
-          ⌜∀ (l_t0 l_s0 : loc) (n : nat),
+          ⌜∀ l_t0 l_s0 (n : nat),
             nth_error (zip args_t args_s) n =
-              Some (# l_t0 ̂, # l_s0 ̂) → C !! (l_t0, l_s0) = None⌝
+              Some (UVALUE_Addr l_t0, UVALUE_Addr l_s0) →
+            C !! (l_t0.1, l_s0.1) = None⌝
             ∗ Q ∗
           ldomain_tgt i_t L_t ∗ ldomain_src i_s L_s ∗
           stack_tgt i_t ∗ stack_src i_s }]) -∗
@@ -2320,4 +2536,176 @@ Section more_properties.
     by iSpecialize ("H" with "Hl Hi H' H_t H_s").
   Qed.
 
+  Lemma sim_instr_load_bij_Some
+    l_t l_s dt o i_t i_s `{non_void dt} L_t L_s C id_t id_s b du l_t0 l_s0 q:
+    l_t0 ∉ L_t ->
+    l_s0 ∉ L_s ->
+    dtyp_WF dt ->
+    (q < 1)%Qp ->
+    C !! (l_t.1, l_s.1) = Some q ->
+    ⊢ l_t ↔h l_s -∗
+      checkout C -∗
+      ldomain_tgt i_t L_t -∗
+      ldomain_src i_s L_s -∗
+      stack_tgt i_t -∗
+      stack_src i_s -∗
+      [ id_t := UVALUE_Addr l_t ]t i_t -∗
+      [ id_s := UVALUE_Addr l_s ]s i_s -∗
+      <{ %(IId l_t0) =
+          (INSTR_Load b dt (du, EXP_Ident (ID_Local id_t)) o) }> ⪯
+      <{ %(IId l_s0) =
+          (INSTR_Load b dt (du, EXP_Ident (ID_Local id_s)) o)}>
+      [{ (v_t, v_s),
+          checkout C ∗
+          ldomain_tgt i_t ({[ l_t0 ]} ∪ L_t) ∗
+          ldomain_src i_s ({[ l_s0 ]} ∪ L_s) ∗
+          stack_tgt i_t ∗
+          stack_src i_s ∗
+          [ id_t := UVALUE_Addr l_t ]t i_t ∗
+          [ id_s := UVALUE_Addr l_s ]s i_s ∗
+          ∃ v_t v_s,
+          [ l_t0 := v_t ]t i_t ∗ [ l_s0 := v_s ]s i_s ∗
+          uval_rel v_t v_s
+      }].
+  Proof.
+    iIntros (Ht Hs WF Hq Hc) "#Hl HC Hd_t Hd_s Hf_t Hf_s Hid_t Hid_s".
+    setoid_rewrite interp_bind.
+    iApply sim_expr_bind; iApply exp_conv_to_instr.
+
+    iApply (sim_expr_bupd_mono with "[HC Hd_t Hd_s]");
+      [ | iApply (sim_local_read_exp_conv with "Hf_t Hf_s Hid_t Hid_s")].
+
+    cont.
+    iDestruct "H" as (??) "(Hf_t & Hf_s & Hid_t & Hid_s)"; subst.
+    cbn. rewrite !bind_ret_l.
+    destruct (dvalue_eq_dec
+                (d1:=DVALUE_Addr l_t)
+                (d2:=DVALUE_Poison)) eqn: Heq ; [ done | ]; clear Heq.
+    destruct (dvalue_eq_dec
+                (d1:=DVALUE_Addr l_s)
+                (d2:=DVALUE_Poison)) eqn: Heq ; [ done | ]; clear Heq.
+    rewrite !interp_bind !interp_vis !bind_bind; iApply sim_expr_bind.
+
+    iApply (sim_expr_bupd_mono with "[Hd_t Hd_s Hf_t Hf_s Hid_t Hid_s]");
+      last iApply (bij_laws.sim_bij_load_Some with "Hl HC"); eauto.
+
+    cont.
+
+    rewrite !bind_tau !interp_ret !bind_ret_l.
+    iApply sim_expr_tau.
+    setoid_rewrite instr_conv_localwrite.
+
+    iApply sim_expr_vis.
+
+    iApply (sim_expr_bupd_mono with "[Hid_t Hid_s H]"); last
+      iApply (sim_local_write_alloc _ _ _ _ _ _ _ _ Ht Hs with
+              "Hd_t Hd_s Hf_t Hf_s").
+    iDestruct "H" as "(#Hv & HC)".
+
+    cont.
+    iApply sim_expr_tau; iApply sim_expr_base; iFrame.
+    iDestruct "H" as "(Hid_t & Hid_s & Hd_t & Hd_s & Hs_t & Hs_s)".
+    iExists _, _; iFrame; try done.
+    do 2 (iSplitL ""; [ done | ]). iExists _, _; by iFrame.
+  Qed.
+
+  Lemma sim_instr_store_bij1 vt vs
+    l_t l_s dt o i_t i_s `{non_void dt} L_t L_s C id_t id_s
+    b v_t v_s val_t val_s:
+    dtyp_WF dt ->
+    dvalue_has_dtyp_fun v_t dt ->
+    dvalue_has_dtyp_fun v_s dt ->
+    C !! (l_t.1, l_s.1) = None ->
+    ⊢ l_t ↔h l_s -∗
+      checkout C -∗
+      ldomain_tgt i_t L_t -∗
+      ldomain_src i_s L_s -∗
+      stack_tgt i_t -∗
+      stack_src i_s -∗
+      dval_rel v_t v_s -∗
+      [ id_t := UVALUE_Addr l_t ]t i_t -∗
+      [ id_s := UVALUE_Addr l_s ]s i_s -∗
+      target_red (η := vir_handler)
+        (exp_conv (denote_exp (Some dt) val_t))
+        (lift_unary_post
+           (fun x =>
+              ⌜is_concrete x⌝ ∗ ⌜dvalue_to_uvalue v_t = x⌝ ∗
+                ⌜dvalue_has_dtyp_fun v_t dt⌝)) -∗
+      source_red (η := vir_handler)
+        (exp_conv (denote_exp (Some dt) val_s))
+        (lift_unary_post
+           (fun x =>
+              ⌜is_concrete x⌝ ∗ ⌜dvalue_to_uvalue v_s = x⌝ ∗
+                ⌜dvalue_has_dtyp_fun v_s dt⌝)) -∗
+      <{ %(IVoid vt) =
+          (INSTR_Store b (dt, val_t)
+                (DTYPE_Pointer, EXP_Ident (ID_Local id_t)) o) }> ⪯
+      <{ %(IVoid vs) =
+          (INSTR_Store b (dt, val_s)
+                (DTYPE_Pointer, EXP_Ident (ID_Local id_s)) o) }>
+      [{ (x_t, x_s),
+          checkout C ∗
+          ldomain_tgt i_t L_t ∗
+          ldomain_src i_s L_s ∗
+          stack_tgt i_t ∗
+          stack_src i_s ∗
+          [ id_t := UVALUE_Addr l_t ]t i_t ∗
+          [ id_s := UVALUE_Addr l_s ]s i_s }].
+  Proof.
+    iIntros (WF Htyp_t Htyp_s H)
+      "#Hl HC Hd_t Hd_s Hf_t Hf_s #Hdv Hid_t Hid_s Hdt Hds".
+
+    setoid_rewrite interp_bind.
+    iApply sim_expr_bind; iApply exp_conv_to_instr.
+    iApply source_red_sim_expr.
+    iApply (source_red_mono with "[HC Hd_t Hd_s Hf_t Hf_s Hid_t Hid_s Hdt]");
+      last iApply "Hds".
+    iIntros (?) "H".
+    iDestruct "H" as (????) "%Hv"; subst.
+    rewrite H0; clear H0.
+
+    iApply target_red_sim_expr.
+    iApply (target_red_mono with "[HC Hd_t Hd_s Hf_t Hf_s Hid_t Hid_s]");
+            last iApply "Hdt".
+    iIntros (?) "H".
+    iDestruct "H" as (????) "%Hv'"; subst.
+    rewrite H0; clear H0.
+    iApply sim_expr_base.
+    rewrite !bind_ret_l. cbn.
+    rewrite /concretize_or_pick !is_concrete_dvalue_to_uvalue.
+    rewrite !uvalue_to_dvalue_of_dvalue_to_uvalue !interp_bind.
+    rewrite /lift_err !interp_ret !bind_ret_l.
+    destruct (dvalue_has_dtyp_fun v_t dt) eqn: Hv_t; try inversion Hv'.
+    destruct (dvalue_has_dtyp_fun v_s dt) eqn: Hv_s; try inversion Hv.
+    rewrite !interp_bind.
+
+    iApply sim_expr_bind; iApply exp_conv_to_instr.
+
+    iApply (sim_expr_bupd_mono with "[HC Hd_t Hd_s]");
+      [ | iApply (sim_local_read_exp_conv with "Hf_t Hf_s Hid_t Hid_s")].
+
+    cont.
+    iDestruct "H" as (??) "(Hf_t & Hf_s & Hid_t & Hid_s)"; subst.
+    cbn. rewrite !bind_ret_l.
+    destruct (dvalue_eq_dec
+                (d1:=DVALUE_Addr l_t)
+                (d2:=DVALUE_Poison)) eqn: Heq ; [ done | ]; clear Heq.
+    destruct (dvalue_eq_dec
+                (d1:=DVALUE_Addr l_s)
+                (d2:=DVALUE_Poison)) eqn: Heq ; [ done | ]; clear Heq.
+    rewrite !interp_vis; iApply sim_expr_bind.
+
+    iApply (sim_expr_bupd_mono with "[Hd_t Hd_s Hf_t Hf_s Hid_t Hid_s]");
+      last iApply (bij_laws.sim_bij_store1 with "Hdv Hl HC");
+      eauto.
+    2,3 : by eapply dvalue_has_dtyp_fun_sound.
+
+    cont.
+
+    rewrite !interp_ret; iApply sim_expr_tau.
+      iApply sim_expr_base; iFrame.
+
+    iExists _, _; iFrame; try done.
+  Qed.
+
 End more_properties.
diff --git a/theories/vir/logical_relations.v b/theories/vir/logical_relations.v
index 6741e666..96c4277d 100644
--- a/theories/vir/logical_relations.v
+++ b/theories/vir/logical_relations.v
@@ -1107,4 +1107,5 @@ Section logical_relations_properties.
     Unshelve. all : set_solver.
   Qed.
 
+
 End logical_relations_properties.
diff --git a/theories/vir/spec.v b/theories/vir/spec.v
index eca19d65..7fa5eb64 100644
--- a/theories/vir/spec.v
+++ b/theories/vir/spec.v
@@ -34,7 +34,7 @@ Definition HasAttr : fn_attr -> list fn_attr -> bool :=
     | nil => false
     | l => 
       foldl (fun p b => 
-        p && (Coqlib.proj_sumbool (decide (b = attr)))) true l
+        p || (Coqlib.proj_sumbool (decide (b = attr)))) false l
     end.
 
 Definition HaveAttr : fn_attr -> list fn_attr -> list fn_attr -> bool :=
@@ -79,21 +79,28 @@ Section spec.
        ∃ (c : attr_case),
          match c with
          | ARG_READ => have FNATTR_Argmemonly && have FNATTR_Readonly /\
-                      (∀ (l_t l_s : Z) n,
-                              nth_error (zip args_t args_s) n = Some (# l_t̂, # l_ŝ) ->
-                              ∃ q, C !! (l_t, l_s) = Some q ∧ Qp.lt q 1)
+              (∀ l_t l_s n,
+                  nth_error (zip args_t args_s) n =
+                    Some (UVALUE_Addr l_t, UVALUE_Addr l_s) ->
+                      ∃ q, C !! (l_t.1, l_s.1) = Some q ∧ Qp.lt q 1)
          | WRITEONLY => have FNATTR_Writeonly /\ C = ∅
          | NOFREE => have FNATTR_Nofree /\ C = ∅
          | ARGMONLY => have FNATTR_Argmemonly /\ not (have FNATTR_Readonly) /\
-                      (∀ (l_t l_s : loc) n,
-                        nth_error (zip args_t args_s) n = Some (#l_t̂, #l_ŝ) ->
-                        C !! (l_t, l_s) = None)
+                      (∀ l_t l_s n,
+                        nth_error (zip args_t args_s) n =
+                          Some (UVALUE_Addr l_t, UVALUE_Addr l_s) ->
+                        C !! (l_t.1, l_s.1) = None)
          | READONLY => have FNATTR_Readonly /\ not (have FNATTR_Argmemonly) /\
                         (∀ (l_t l_s : loc) q, C !! (l_t, l_s) = Some q -> Qp.lt q 1)
          | INACC_OR_ARGMONLY => have FNATTR_Inaccessiblemem_or_argmemonly /\
-                                 (∀ (l_t l_s : loc) n,
-                                    nth_error (zip args_t args_s) n = Some (#l_t̂, # l_ŝ) ->
-                                    C !! (l_t, l_s) = None)
+                      (∀ l_t l_s n,
+                        nth_error (zip args_t args_s) n =
+                          Some (UVALUE_Addr l_t, UVALUE_Addr l_s) ->
+                        C !! (l_t.1, l_s.1) = None) /\
+                      (∀ (l_t l_s : Z * Z),
+                          (l_t.1, l_s.1) ∈ dom C ->
+                          (UVALUE_Addr l_t, UVALUE_Addr l_s) ∉ (zip args_t args_s) ->
+                          C !! (l_t.1, l_s.1) = Some 1%Qp)
          | OTHER =>
              not (have FNATTR_Argmemonly) /\
              not (have FNATTR_Readonly) /\
-- 
GitLab