cap_machine.rules.rules_Subseg

From iris.base_logic Require Export invariants gen_heap.
From iris.program_logic Require Export weakestpre ectx_lifting.
From iris.proofmode Require Import proofmode.
From iris.algebra Require Import frac.
From cap_machine Require Export rules_base.

Section cap_lang_rules.
  Context `{memG Σ, regG Σ}.
  Context `{MachineParameters}.
  Implicit Types P Q : iProp Σ.
  Implicit Types σ : ExecConf.
  Implicit Types r : RegName.
  Implicit Types v : cap_lang.val.
  Implicit Types w : Word.
  Implicit Types reg : gmap RegName Word.
  Implicit Types ms : gmap Addr Word.

  Inductive Subseg_failure (regs: Reg) (dst: RegName) (src1 src2: Z + RegName) : Reg Prop :=
  | Subseg_fail_allowed w :
      regs !! dst = Some w
      is_mutable_range w = false
      Subseg_failure regs dst src1 src2 regs
  | Subseg_fail_src1_nonaddr p b e a:
      regs !! dst = Some (WCap p b e a)
      addr_of_argument regs src1 = None
      Subseg_failure regs dst src1 src2 regs
  | Subseg_fail_src2_nonaddr p b e a:
      regs !! dst = Some (WCap p b e a)
      addr_of_argument regs src2 = None
      Subseg_failure regs dst src1 src2 regs
  | Subseg_fail_src1_nonotype p b e a:
      regs !! dst = Some (WSealRange p b e a)
      otype_of_argument regs src1 = None
      Subseg_failure regs dst src1 src2 regs
  | Subseg_fail_src2_nonotype p b e a:
      regs !! dst = Some (WSealRange p b e a)
      otype_of_argument regs src2 = None
      Subseg_failure regs dst src1 src2 regs
  | Subseg_fail_not_iswithin_cap p b e a a1 a2 :
      regs !! dst = Some (WCap p b e a)
      addr_of_argument regs src1 = Some a1
      addr_of_argument regs src2 = Some a2
      isWithin a1 a2 b e = false
      Subseg_failure regs dst src1 src2 regs
  | Subseg_fail_incrPC_cap p b e a a1 a2 :
      regs !! dst = Some (WCap p b e a)
      p <> E
      addr_of_argument regs src1 = Some a1
      addr_of_argument regs src2 = Some a2
      isWithin a1 a2 b e = true
      incrementPC (<[ dst := WCap p a1 a2 a ]> regs) = None
      Subseg_failure regs dst src1 src2 regs
  | Subseg_fail_not_iswithin_sr p b e a a1 a2 :
      regs !! dst = Some (WSealRange p b e a)
      otype_of_argument regs src1 = Some a1
      otype_of_argument regs src2 = Some a2
      isWithin a1 a2 b e = false
      Subseg_failure regs dst src1 src2 regs
  | Subseg_fail_incrPC_sr p b e a a1 a2 :
      regs !! dst = Some (WSealRange p b e a)
      otype_of_argument regs src1 = Some a1
      otype_of_argument regs src2 = Some a2
      isWithin a1 a2 b e = true
      incrementPC (<[ dst := WSealRange p a1 a2 a ]> regs) = None
      Subseg_failure regs dst src1 src2 regs.

  Inductive Subseg_spec (regs: Reg) (dst: RegName) (src1 src2: Z + RegName) (regs': Reg): cap_lang.val -> Prop :=
  | Subseg_spec_success_cap p b e a a1 a2:
      regs !! dst = Some (WCap p b e a) ->
      p <> E ->
      addr_of_argument regs src1 = Some a1 ->
      addr_of_argument regs src2 = Some a2 ->
      isWithin a1 a2 b e = true ->
      incrementPC (<[ dst := WCap p a1 a2 a ]> regs) = Some regs' ->
      Subseg_spec regs dst src1 src2 regs' NextIV
  | Subseg_spec_success_sr p b e a a1 a2:
      regs !! dst = Some (WSealRange p b e a) ->
      otype_of_argument regs src1 = Some a1 ->
      otype_of_argument regs src2 = Some a2 ->
      isWithin a1 a2 b e = true ->
      incrementPC (<[ dst := WSealRange p a1 a2 a ]> regs) = Some regs' ->
      Subseg_spec regs dst src1 src2 regs' NextIV
  | Subseg_spec_failure :
      Subseg_failure regs dst src1 src2 regs'
      Subseg_spec regs dst src1 src2 regs' FailedV.

  Lemma wp_Subseg Ep pc_p pc_b pc_e pc_a w dst src1 src2 regs :
    decodeInstrW w = Subseg dst src1 src2 ->
    isCorrectPC (WCap pc_p pc_b pc_e pc_a)
    regs !! PC = Some (WCap pc_p pc_b pc_e pc_a)
    regs_of (Subseg dst src1 src2) dom regs

    {{{ pc_a ↦ₐ w
         [∗ map] ky regs, k ↦ᵣ y }}}
      Instr Executable @ Ep
    {{{ regs' retv, RET retv;
         Subseg_spec regs dst src1 src2 regs' retv
        pc_a ↦ₐ w
        [∗ map] ky regs', k ↦ᵣ y }}}.
  Proof.
    iIntros (Hinstr Hvpc HPC Dregs φ) "(>Hpc_a & >Hmap) Hφ".
    iApply wp_lift_atomic_base_step_no_fork; auto.
    iIntros (σ1 ns l1 l2 nt) "Hσ1 /=". destruct σ1; simpl.
    iDestruct "Hσ1" as "[Hr Hm]".
    iDestruct (gen_heap_valid_inclSepM with "Hr Hmap") as %Hregs.
    have ? := lookup_weaken _ _ _ _ HPC Hregs.
    iDestruct (@gen_heap_valid with "Hm Hpc_a") as %Hpc_a; auto.
    iModIntro. iSplitR. by iPureIntro; apply normal_always_base_reducible.
    iNext. iIntros (e2 σ2 efs Hpstep).
    apply prim_step_exec_inv in Hpstep as (-> & -> & (c & -> & Hstep)).
    iIntros "_".
    iSplitR; auto. eapply step_exec_inv in Hstep; eauto.

    specialize (indom_regs_incl _ _ _ Dregs Hregs) as Hri.
    unfold regs_of in Hri, Dregs.
    destruct (Hri dst) as [wdst [H'dst Hdst]]. by set_solver+.

    rewrite /exec /= Hdst /= in Hstep.

    destruct (is_mutable_range wdst) eqn:Hwdst.
     2: { (* Failure: wdst is not of the right type *)
       unfold is_mutable_range in Hwdst.
       assert (c = Failed σ2 = (r, m)) as (-> & ->).
       { destruct wdst as [ | [p b e a | ] | ]; try by inversion Hwdst.
         all: try by simplify_pair_eq.
         destruct p; try congruence.
         repeat destruct (addr_of_argument r _); cbn in Hstep; simplify_pair_eq; auto. }
       iFailWP "Hφ" Subseg_fail_allowed. }

    (* Now the proof splits depending on the type of value in wdst *)
    destruct wdst as [ | [p b e a | p b e a] | ].
    1,4: inversion Hwdst.

    (* First, the case where r1v is a capability *)
    + destruct (perm_eq_dec p E); [ subst p |].
       { rewrite /is_mutable_range in Hwdst; congruence. }

      destruct (addr_of_argument regs src1) as [a1|] eqn:Ha1;
        pose proof Ha1 as H'a1; cycle 1.
      { destruct src1 as [| r1] eqn:?; cbn in Ha1, Hstep.
        { rewrite Ha1 /= in Hstep.
          assert (c = Failed σ2 = (r, m)) as (-> & ->).
          { repeat case_match; inv Hstep; auto. }
          iFailWP "Hφ" Subseg_fail_src1_nonaddr. }
        subst src1. destruct (Hri r1) as [r1v [Hr'1 Hr1]].
          by unfold regs_of_argument; set_solver+.
          rewrite /addr_of_argument /= Hr'1 in Ha1.
          assert (c = Failed σ2 = (r, m)) as (-> & ->).
          { destruct r1v ; simplify_pair_eq.
            all: unfold addr_of_argument, z_of_argument at 2 in Hstep.
            all: rewrite /= Hr1 ?Ha1 /= in Hstep.
            all: inv Hstep; auto.
          }
          repeat case_match; try congruence.
          all: iFailWP "Hφ" Subseg_fail_src1_nonaddr. }
      apply (addr_of_arg_mono _ r) in Ha1; auto. rewrite Ha1 /= in Hstep.

      destruct (addr_of_argument regs src2) as [a2|] eqn:Ha2;
        pose proof Ha2 as H'a2; cycle 1.
      { destruct src2 as [| r2] eqn:?; cbn in Ha2, Hstep.
        { rewrite Ha2 /= in Hstep.
          assert (c = Failed σ2 = (r, m)) as (-> & ->).
          { repeat case_match; inv Hstep; auto. }
          iFailWP "Hφ" Subseg_fail_src2_nonaddr. }
        subst src2. destruct (Hri r2) as [r2v [Hr'2 Hr2]].
          by unfold regs_of_argument; set_solver+.
          rewrite /addr_of_argument /= Hr'2 in Ha2.
          assert (c = Failed σ2 = (r, m)) as (-> & ->).
          { destruct r2v ; simplify_pair_eq.
            all: unfold addr_of_argument, z_of_argument in Hstep.
            all: rewrite /= Hr2 ?Ha2 /= in Hstep.
            all: inv Hstep; auto.
          }
          repeat case_match; try congruence.
          all: iFailWP "Hφ" Subseg_fail_src2_nonaddr. }
      apply (addr_of_arg_mono _ r) in Ha2; auto. rewrite Ha2 /= in Hstep.
      rewrite /update_reg /= in Hstep.

      destruct (isWithin a1 a2 b e) eqn:Hiw; cycle 1.
      { destruct p; try congruence; inv Hstep ; iFailWP "Hφ" Subseg_fail_not_iswithin_cap. }

      destruct (incrementPC (<[ dst := (WCap p a1 a2 a) ]> regs)) eqn:Hregs';
        pose proof Hregs' as H'regs'; cycle 1.
      { assert (incrementPC (<[ dst := (WCap p a1 a2 a) ]> r) = None) as HH.
        { eapply incrementPC_overflow_mono; first eapply Hregs'.
            by rewrite lookup_insert_is_Some'; eauto.
              by apply insert_mono; eauto. }
        apply (incrementPC_fail_updatePC _ m) in HH. rewrite HH in Hstep.
        assert (c = Failed σ2 = (r, m)) as (-> & ->)
            by (destruct p; inversion Hstep; auto).
        iFailWP "Hφ" Subseg_fail_incrPC_cap. }

      eapply (incrementPC_success_updatePC _ m) in Hregs'
        as (p' & g' & b' & e' & a'' & a_pc' & HPC'' & HuPC & ->).
      eapply updatePC_success_incl with (m':=m) in HuPC. 2: by eapply insert_mono; eauto. rewrite HuPC in Hstep.
      eassert ((c, σ2) = (NextI, _)) as HH.
      { destruct p; cbn in Hstep; eauto. congruence. }
      simplify_pair_eq. iFrame.
      iMod ((gen_heap_update_inSepM _ _ dst) with "Hr Hmap") as "[Hr Hmap]"; eauto.
      iMod ((gen_heap_update_inSepM _ _ PC) with "Hr Hmap") as "[Hr Hmap]"; eauto.
      iFrame. iApply "Hφ". iFrame. iPureIntro. econstructor; eauto.
     (* Now, the case where wsrc is a capability *)
    + destruct (otype_of_argument regs src1) as [a1|] eqn:Ha1;
        pose proof Ha1 as H'a1; cycle 1.
      { destruct src1 as [| r1] eqn:?; cbn in Ha1, Hstep.
        { rewrite Ha1 /= in Hstep.
          assert (c = Failed σ2 = (r, m)) as (-> & ->).
          { repeat case_match; inv Hstep; auto. }
          iFailWP "Hφ" Subseg_fail_src1_nonotype. }
        subst src1. destruct (Hri r1) as [r1v [Hr'1 Hr1]].
          by unfold regs_of_argument; set_solver+.
          rewrite /otype_of_argument /= Hr'1 in Ha1.
          assert (c = Failed σ2 = (r, m)) as (-> & ->).
          { destruct r1v ; simplify_pair_eq.
            all: unfold otype_of_argument, z_of_argument at 2 in Hstep.
            all: rewrite /= Hr1 ?Ha1 /= in Hstep.
            all: inv Hstep; auto.
          }
          repeat case_match; try congruence.
          all: iFailWP "Hφ" Subseg_fail_src1_nonotype. }
      apply (otype_of_arg_mono _ r) in Ha1; auto. rewrite Ha1 /= in Hstep.

      destruct (otype_of_argument regs src2) as [a2|] eqn:Ha2;
        pose proof Ha2 as H'a2; cycle 1.
      { destruct src2 as [| r2] eqn:?; cbn in Ha2, Hstep.
        { rewrite Ha2 /= in Hstep.
          assert (c = Failed σ2 = (r, m)) as (-> & ->).
          { repeat case_match; inv Hstep; auto. }
          iFailWP "Hφ" Subseg_fail_src2_nonotype. }
        subst src2. destruct (Hri r2) as [r2v [Hr'2 Hr2]].
          by unfold regs_of_argument; set_solver+.
          rewrite /otype_of_argument /= Hr'2 in Ha2.
          assert (c = Failed σ2 = (r, m)) as (-> & ->).
          { destruct r2v ; simplify_pair_eq.
            all: unfold otype_of_argument, z_of_argument in Hstep.
            all: rewrite /= Hr2 ?Ha2 /= in Hstep.
            all: inv Hstep; auto.
          }
          repeat case_match; try congruence.
          all: iFailWP "Hφ" Subseg_fail_src2_nonotype. }
      apply (otype_of_arg_mono _ r) in Ha2; auto. rewrite Ha2 /= in Hstep.
      rewrite /update_reg /= in Hstep.

      destruct (isWithin a1 a2 b e) eqn:Hiw; cycle 1.
      { destruct p; try congruence; inv Hstep ; iFailWP "Hφ" Subseg_fail_not_iswithin_sr. }

      destruct (incrementPC (<[ dst := (WSealRange p a1 a2 a) ]> regs)) eqn:Hregs';
        pose proof Hregs' as H'regs'; cycle 1.
      { assert (incrementPC (<[ dst := (WSealRange p a1 a2 a) ]> r) = None) as HH.
        { eapply incrementPC_overflow_mono; first eapply Hregs'.
            by rewrite lookup_insert_is_Some'; eauto.
              by apply insert_mono; eauto. }
        apply (incrementPC_fail_updatePC _ m) in HH. rewrite HH in Hstep.
        assert (c = Failed σ2 = (r, m)) as (-> & ->)
            by (destruct p; inversion Hstep; auto).
        iFailWP "Hφ" Subseg_fail_incrPC_sr. }

      eapply (incrementPC_success_updatePC _ m) in Hregs'
        as (p' & g' & b' & e' & a'' & a_pc' & HPC'' & HuPC & ->).
      eapply updatePC_success_incl with (m':=m) in HuPC. 2: by eapply insert_mono; eauto. rewrite HuPC in Hstep.
      eassert ((c, σ2) = (NextI, _)) as HH.
      { destruct p; cbn in Hstep; eauto. }
      simplify_pair_eq. iFrame.
      iMod ((gen_heap_update_inSepM _ _ dst) with "Hr Hmap") as "[Hr Hmap]"; eauto.
      iMod ((gen_heap_update_inSepM _ _ PC) with "Hr Hmap") as "[Hr Hmap]"; eauto.
      iFrame. iApply "Hφ". iFrame. iPureIntro. econstructor 2; eauto.
  Unshelve. Fail idtac. Admitted.

  Lemma wp_subseg_success E pc_p pc_b pc_e pc_a w dst r1 r2 p b e a n1 n2 a1 a2 pc_a' :
    decodeInstrW w = Subseg dst (inr r1) (inr r2)
    isCorrectPC (WCap pc_p pc_b pc_e pc_a)
    z_to_addr n1 = Some a1 z_to_addr n2 = Some a2
    p machine_base.E
    isWithin a1 a2 b e = true
    (pc_a + 1)%a = Some pc_a'

    {{{ PC ↦ᵣ WCap pc_p pc_b pc_e pc_a
         pc_a ↦ₐ w
         dst ↦ᵣ WCap p b e a
         r1 ↦ᵣ WInt n1
         r2 ↦ᵣ WInt n2 }}}
      Instr Executable @ E
      {{{ RET NextIV;
          PC ↦ᵣ WCap pc_p pc_b pc_e pc_a'
           pc_a ↦ₐ w
           r1 ↦ᵣ WInt n1
           r2 ↦ᵣ WInt n2
           dst ↦ᵣ WCap p a1 a2 a
      }}}.
  Proof.
    iIntros (Hinstr Hvpc Hn1 Hn2 Hpne Hwb Hpc_a' ϕ) "(>HPC & >Hpc_a & >Hdst & >Hr1 & >Hr2) Hφ".
    iDestruct (map_of_regs_4 with "HPC Hr1 Hr2 Hdst") as "[Hmap (%&%&%&%&%&%)]".
    iApply (wp_Subseg with "[$Hmap Hpc_a]"); eauto; simplify_map_eq; eauto.
    by unfold regs_of; rewrite !dom_insert; set_solver+.
    iNext. iIntros (regs' retv) "(#Hspec & Hpc_a & Hmap)". iDestruct "Hspec" as %Hspec.

    destruct Hspec as [| | * Hfail].
    { (* Success *)
      iApply "Hφ". iFrame. incrementPC_inv; simplify_map_eq.
      unfold addr_of_argument, z_of_argument in *. simplify_map_eq.
      rewrite (insert_commute _ PC dst) // insert_insert (insert_commute _ r2 dst) //
              (insert_commute _ r1 dst) // (insert_commute _ PC dst) // insert_insert.
      iDestruct (regs_of_map_4 with "Hmap") as "(?&?&?&?)"; eauto; iFrame. }
     { (* Success with WSealRange (contradiction) *)
       simplify_map_eq. }
    { (* Failure (contradiction) *)
      destruct Hfail; try incrementPC_inv; unfold addr_of_argument, z_of_argument in *.
      all: simplify_map_eq; eauto; try congruence.
      destruct p; congruence. }
    Unshelve. all: auto.
  Unshelve. Fail idtac. Admitted.

  Lemma wp_subseg_success_same E pc_p pc_b pc_e pc_a w dst r1 p b e a n1 a1 pc_a' :
    decodeInstrW w = Subseg dst (inr r1) (inr r1)
    isCorrectPC (WCap pc_p pc_b pc_e pc_a)
    z_to_addr n1 = Some a1
    p machine_base.E
    isWithin a1 a1 b e = true
    (pc_a + 1)%a = Some pc_a'

    {{{ PC ↦ᵣ WCap pc_p pc_b pc_e pc_a
         pc_a ↦ₐ w
         dst ↦ᵣ WCap p b e a
         r1 ↦ᵣ WInt n1 }}}
      Instr Executable @ E
      {{{ RET NextIV;
          PC ↦ᵣ WCap pc_p pc_b pc_e pc_a'
           pc_a ↦ₐ w
           r1 ↦ᵣ WInt n1
           dst ↦ᵣ WCap p a1 a1 a
      }}}.
  Proof.
    iIntros (Hinstr Hvpc Hn1 Hpne Hwb Hpc_a' ϕ) "(>HPC & >Hpc_a & >Hdst & >Hr1) Hφ".
    iDestruct (map_of_regs_3 with "HPC Hr1 Hdst") as "[Hmap (%&%&%)]".
    iApply (wp_Subseg with "[$Hmap Hpc_a]"); eauto; simplify_map_eq; eauto.
    by unfold regs_of; rewrite !dom_insert; set_solver+.
    iNext. iIntros (regs' retv) "(#Hspec & Hpc_a & Hmap)". iDestruct "Hspec" as %Hspec.

    destruct Hspec as [| | * Hfail].
    { (* Success *)
      iApply "Hφ". iFrame. incrementPC_inv; simplify_map_eq.
      unfold addr_of_argument, z_of_argument in *. simplify_map_eq.
      rewrite (insert_commute _ PC dst) // insert_insert (insert_commute _ r1 dst) //
              (insert_commute _ PC dst) // insert_insert.
      iDestruct (regs_of_map_3 with "Hmap") as "(?&?&?)"; eauto; iFrame. }
    { (* Success with WSealRange (contradiction) *)
      simplify_map_eq. }
    { (* Failure (contradiction) *)
      destruct Hfail; try incrementPC_inv; unfold addr_of_argument, z_of_argument in *.
      all: simplify_map_eq; eauto; try congruence.
      destruct p; congruence. }
    Unshelve. all: auto.
  Unshelve. Fail idtac. Admitted.

  Lemma wp_subseg_success_l E pc_p pc_b pc_e pc_a w dst r2 p b e a n1 n2 a1 a2 pc_a' :
    decodeInstrW w = Subseg dst (inl n1) (inr r2)
    isCorrectPC (WCap pc_p pc_b pc_e pc_a)
    z_to_addr n1 = Some a1 z_to_addr n2 = Some a2
    p machine_base.E
    isWithin a1 a2 b e = true
    (pc_a + 1)%a = Some pc_a'

    {{{ PC ↦ᵣ WCap pc_p pc_b pc_e pc_a
         pc_a ↦ₐ w
         dst ↦ᵣ WCap p b e a
         r2 ↦ᵣ WInt n2 }}}
      Instr Executable @ E
      {{{ RET NextIV;
          PC ↦ᵣ WCap pc_p pc_b pc_e pc_a'
           pc_a ↦ₐ w
           r2 ↦ᵣ WInt n2
           dst ↦ᵣ WCap p a1 a2 a
      }}}.
  Proof.
    iIntros (Hinstr Hvpc Hn1 Hn2 Hpne Hwb Hpc_a' ϕ) "(>HPC & >Hpc_a & >Hdst & >Hr2) Hφ".
    iDestruct (map_of_regs_3 with "HPC Hr2 Hdst") as "[Hmap (%&%&%)]".
    iApply (wp_Subseg with "[$Hmap Hpc_a]"); eauto; simplify_map_eq; eauto.
    by unfold regs_of; rewrite !dom_insert; set_solver+.
    iNext. iIntros (regs' retv) "(#Hspec & Hpc_a & Hmap)". iDestruct "Hspec" as %Hspec.

    destruct Hspec as [| | * Hfail].
    { (* Success *)
      iApply "Hφ". iFrame. incrementPC_inv; simplify_map_eq.
      unfold addr_of_argument, z_of_argument in *. simplify_map_eq.
      rewrite (insert_commute _ PC dst) // insert_insert (insert_commute _ r2 dst) //
              (insert_commute _ PC dst) // insert_insert.
      iDestruct (regs_of_map_3 with "Hmap") as "(?&?&?)"; eauto; iFrame. }
    { (* Success with WSealRange (contradiction) *)
      simplify_map_eq. }
    { (* Failure (contradiction) *)
      destruct Hfail; try incrementPC_inv; unfold addr_of_argument, z_of_argument in *.
      all: simplify_map_eq; eauto; try congruence.
      destruct p; congruence. }
    Unshelve. all: auto.
  Unshelve. Fail idtac. Admitted.

  Lemma wp_subseg_success_r E pc_p pc_b pc_e pc_a w dst r1 p b e a n1 n2 a1 a2 pc_a' :
    decodeInstrW w = Subseg dst (inr r1) (inl n2)
    isCorrectPC (WCap pc_p pc_b pc_e pc_a)
    z_to_addr n1 = Some a1 z_to_addr n2 = Some a2
    p machine_base.E
    isWithin a1 a2 b e = true
    (pc_a + 1)%a = Some pc_a'

    {{{ PC ↦ᵣ WCap pc_p pc_b pc_e pc_a
         pc_a ↦ₐ w
         dst ↦ᵣ WCap p b e a
         r1 ↦ᵣ WInt n1 }}}
      Instr Executable @ E
      {{{ RET NextIV;
          PC ↦ᵣ WCap pc_p pc_b pc_e pc_a'
           pc_a ↦ₐ w
           r1 ↦ᵣ WInt n1
           dst ↦ᵣ WCap p a1 a2 a
      }}}.
  Proof.
    iIntros (Hinstr Hvpc Hn1 Hn2 Hpne Hwb Hpc_a' ϕ) "(>HPC & >Hpc_a & >Hdst & >Hr1) Hφ".
    iDestruct (map_of_regs_3 with "HPC Hr1 Hdst") as "[Hmap (%&%&%)]".
    iApply (wp_Subseg with "[$Hmap Hpc_a]"); eauto; simplify_map_eq; eauto.
    by unfold regs_of; rewrite !dom_insert; set_solver+.
    iNext. iIntros (regs' retv) "(#Hspec & Hpc_a & Hmap)". iDestruct "Hspec" as %Hspec.

    destruct Hspec as [| | * Hfail].
    { (* Success *)
      iApply "Hφ". iFrame. incrementPC_inv; simplify_map_eq.
      unfold addr_of_argument, z_of_argument in *. simplify_map_eq.
      rewrite (insert_commute _ PC dst) // insert_insert (insert_commute _ r1 dst) //
              (insert_commute _ PC dst) // insert_insert.
      iDestruct (regs_of_map_3 with "Hmap") as "(?&?&?)"; eauto; iFrame. }
    { (* Success with WSealRange (contradiction) *)
      simplify_map_eq. }
    { (* Failure (contradiction) *)
      destruct Hfail; try incrementPC_inv; unfold addr_of_argument, z_of_argument in *.
      all: simplify_map_eq; eauto; try congruence.
      destruct p; congruence. }
    Unshelve. all: auto.
  Unshelve. Fail idtac. Admitted.

  Lemma wp_subseg_success_lr E pc_p pc_b pc_e pc_a w dst p b e a n1 n2 a1 a2 pc_a' :
    decodeInstrW w = Subseg dst (inl n1) (inl n2)
    isCorrectPC (WCap pc_p pc_b pc_e pc_a)
    z_to_addr n1 = Some a1 z_to_addr n2 = Some a2
    p machine_base.E
    isWithin a1 a2 b e = true
    (pc_a + 1)%a = Some pc_a'

    {{{ PC ↦ᵣ WCap pc_p pc_b pc_e pc_a
         pc_a ↦ₐ w
         dst ↦ᵣ WCap p b e a }}}
      Instr Executable @ E
      {{{ RET NextIV;
          PC ↦ᵣ WCap pc_p pc_b pc_e pc_a'
           pc_a ↦ₐ w
           dst ↦ᵣ WCap p a1 a2 a
      }}}.
  Proof.
    iIntros (Hinstr Hvpc Hn1 Hn2 Hpne Hwb Hpc_a' ϕ) "(>HPC & >Hpc_a & >Hdst) Hφ".
    iDestruct (map_of_regs_2 with "HPC Hdst") as "[Hmap %]".
    iApply (wp_Subseg with "[$Hmap Hpc_a]"); eauto; simplify_map_eq; eauto.
    by unfold regs_of; rewrite !dom_insert; set_solver+.
    iNext. iIntros (regs' retv) "(#Hspec & Hpc_a & Hmap)". iDestruct "Hspec" as %Hspec.

    destruct Hspec as [| | * Hfail].
    { (* Success *)
      iApply "Hφ". iFrame. incrementPC_inv; simplify_map_eq.
      unfold addr_of_argument, z_of_argument in *. simplify_map_eq.
      rewrite (insert_commute _ PC dst) // insert_insert insert_commute // insert_insert.
      iDestruct (regs_of_map_2 with "Hmap") as "(?&?)"; eauto; iFrame. }
    { (* Success with WSealRange (contradiction) *)
      simplify_map_eq. }
    { (* Failure (contradiction) *)
      destruct Hfail; try incrementPC_inv; unfold addr_of_argument, z_of_argument in *.
      all: simplify_map_eq; eauto; try congruence.
      destruct p; congruence. }
    Unshelve. all: auto.
  Unshelve. Fail idtac. Admitted.

  Lemma wp_subseg_fail_lr E pc_p pc_b pc_e pc_a w dst p b e a n1 n2 a1 a2 :
    decodeInstrW w = Subseg dst (inl n1) (inl n2)
    isCorrectPC (WCap pc_p pc_b pc_e pc_a)
    z_to_addr n1 = Some a1 z_to_addr n2 = Some a2
    ¬ (p machine_base.E isWithin a1 a2 b e = true)
    {{{ PC ↦ᵣ WCap pc_p pc_b pc_e pc_a
           pc_a ↦ₐ w
           dst ↦ᵣ WCap p b e a }}}
      Instr Executable @ E
      {{{ RET FailedV;
           PC ↦ᵣ WCap pc_p pc_b pc_e pc_a
             pc_a ↦ₐ w
             dst ↦ᵣ WCap p b e a }}}.
  Proof.
    iIntros (? ? ? ? Hncond ?) "(>HPC & >Hpc_a & >Hdst) Hφ".
    iDestruct (map_of_regs_2 with "HPC Hdst") as "[Hmap %]".
    iApply (wp_Subseg with "[$Hmap Hpc_a]"); eauto; simplify_map_eq; eauto.
    by unfold regs_of; rewrite !dom_insert; set_solver+.
    iNext. iIntros (regs' retv) "(#Hspec & Hpc_a & Hmap)". iDestruct "Hspec" as %Hspec.
    destruct Hspec as [| | * Hfail].
    { (* Success (contradiction) *)
      exfalso. apply Hncond. simplify_map_eq. split; first done.
      repeat match goal with H : _ |- _ =>
                               apply addr_of_argument_Some_inv in H as (?&?&[?|(?&?&?)]) end; by simplify_eq. }
    { (* Success with WSealRange (contradiction) *)
      simplify_map_eq. }
    { (* Failure *)
      destruct Hfail; cbn in *; simplify_map_eq.
      all: iApply "Hφ"; iDestruct (regs_of_map_2 with "Hmap") as "(?&?)"; eauto; iFrame. }
  Unshelve. Fail idtac. Admitted.

  Lemma wp_subseg_success_pc E pc_p pc_b pc_e pc_a w r1 r2 n1 n2 a1 a2 pc_a' :
    decodeInstrW w = Subseg PC (inr r1) (inr r2)
    isCorrectPC (WCap pc_p pc_b pc_e pc_a)
    z_to_addr n1 = Some a1 z_to_addr n2 = Some a2
    pc_p machine_base.E
    isWithin a1 a2 pc_b pc_e = true
    (pc_a + 1)%a = Some pc_a'

    {{{ PC ↦ᵣ WCap pc_p pc_b pc_e pc_a
         pc_a ↦ₐ w
         r1 ↦ᵣ WInt n1
         r2 ↦ᵣ WInt n2 }}}
      Instr Executable @ E
      {{{ RET NextIV;
          PC ↦ᵣ WCap pc_p a1 a2 pc_a'
           pc_a ↦ₐ w
           r1 ↦ᵣ WInt n1
           r2 ↦ᵣ WInt n2
      }}}.
  Proof.
    iIntros (Hinstr Hvpc Hn1 Hn2 Hpne Hwb Hpc_a' ϕ) "(>HPC & >Hpc_a & >Hr1 & >Hr2) Hφ".
    iDestruct (map_of_regs_3 with "HPC Hr1 Hr2") as "[Hmap (%&%&%)]".
    iApply (wp_Subseg with "[$Hmap Hpc_a]"); eauto; simplify_map_eq; eauto.
    by unfold regs_of; rewrite !dom_insert; set_solver+.
    iNext. iIntros (regs' retv) "(#Hspec & Hpc_a & Hmap)". iDestruct "Hspec" as %Hspec.

    destruct Hspec as [| | * Hfail].
    { (* Success *)
      iApply "Hφ". iFrame. incrementPC_inv; simplify_map_eq.
      unfold addr_of_argument, z_of_argument in *. simplify_map_eq.
      rewrite !insert_insert.
      iDestruct (regs_of_map_3 with "Hmap") as "(?&?&?)"; eauto; iFrame. }
    { (* Success with WSealRange (contradiction) *)
      simplify_map_eq. }
    { (* Failure (contradiction) *)
      destruct Hfail; try incrementPC_inv; unfold addr_of_argument, z_of_argument in *.
      all: simplify_map_eq; eauto; try congruence.
      destruct pc_p; congruence. congruence. }
    Unshelve. all: auto.
  Unshelve. Fail idtac. Admitted.

  Lemma wp_subseg_success_pc_same E pc_p pc_b pc_e pc_a w r1 n1 a1 pc_a' :
    decodeInstrW w = Subseg PC (inr r1) (inr r1)
    isCorrectPC (WCap pc_p pc_b pc_e pc_a)
    z_to_addr n1 = Some a1
    pc_p machine_base.E
    isWithin a1 a1 pc_b pc_e = true
    (pc_a + 1)%a = Some pc_a'

    {{{ PC ↦ᵣ WCap pc_p pc_b pc_e pc_a
         pc_a ↦ₐ w
         r1 ↦ᵣ WInt n1 }}}
      Instr Executable @ E
      {{{ RET NextIV;
          PC ↦ᵣ WCap pc_p a1 a1 pc_a'
           pc_a ↦ₐ w
           r1 ↦ᵣ WInt n1
      }}}.
  Proof.
    iIntros (Hinstr Hvpc Hn1 Hpne Hwb Hpc_a' ϕ) "(>HPC & >Hpc_a & >Hr1) Hφ".
    iDestruct (map_of_regs_2 with "HPC Hr1") as "[Hmap %]".
    iApply (wp_Subseg with "[$Hmap Hpc_a]"); eauto; simplify_map_eq; eauto.
    by unfold regs_of; rewrite !dom_insert; set_solver+.
    iNext. iIntros (regs' retv) "(#Hspec & Hpc_a & Hmap)". iDestruct "Hspec" as %Hspec.

    destruct Hspec as [| | * Hfail].
    { (* Success *)
      iApply "Hφ". iFrame. incrementPC_inv; simplify_map_eq.
      unfold addr_of_argument, z_of_argument in *. simplify_map_eq.
      rewrite (insert_commute _ PC r1) // insert_insert insert_commute // insert_insert.
      iDestruct (regs_of_map_2 with "Hmap") as "(?&?)"; eauto; iFrame. }
    { (* Success with WSealRange (contradiction) *)
      simplify_map_eq. }
    { (* Failure (contradiction) *)
      destruct Hfail; try incrementPC_inv; unfold addr_of_argument, z_of_argument in *.
      all: simplify_map_eq; eauto; try congruence.
      destruct pc_p; congruence. congruence. }
    Unshelve. all: auto.
  Unshelve. Fail idtac. Admitted.

  Lemma wp_subseg_success_pc_l E pc_p pc_b pc_e pc_a w r2 n1 n2 a1 a2 pc_a' :
    decodeInstrW w = Subseg PC (inl n1) (inr r2)
    isCorrectPC (WCap pc_p pc_b pc_e pc_a)
    z_to_addr n1 = Some a1 z_to_addr n2 = Some a2
    pc_p machine_base.E
    isWithin a1 a2 pc_b pc_e = true
    (pc_a + 1)%a = Some pc_a'

    {{{ PC ↦ᵣ WCap pc_p pc_b pc_e pc_a
         pc_a ↦ₐ w
         r2 ↦ᵣ WInt n2 }}}
      Instr Executable @ E
      {{{ RET NextIV;
          PC ↦ᵣ WCap pc_p a1 a2 pc_a'
           pc_a ↦ₐ w
           r2 ↦ᵣ WInt n2
      }}}.
  Proof.
    iIntros (Hinstr Hvpc Hn1 Hn2 Hpne Hwb Hpc_a' ϕ) "(>HPC & >Hpc_a & >Hr2) Hφ".
    iDestruct (map_of_regs_2 with "HPC Hr2") as "[Hmap %]".
    iApply (wp_Subseg with "[$Hmap Hpc_a]"); eauto; simplify_map_eq; eauto.
    by unfold regs_of; rewrite !dom_insert; set_solver+.
    iNext. iIntros (regs' retv) "(#Hspec & Hpc_a & Hmap)". iDestruct "Hspec" as %Hspec.

    destruct Hspec as [| | * Hfail].
    { (* Success *)
      iApply "Hφ". iFrame. incrementPC_inv; simplify_map_eq.
      unfold addr_of_argument, z_of_argument in *. simplify_map_eq.
      rewrite (insert_commute _ PC r2) // insert_insert insert_commute // insert_insert.
      iDestruct (regs_of_map_2 with "Hmap") as "(?&?)"; eauto; iFrame. }
    { (* Success with WSealRange (contradiction) *)
      simplify_map_eq. }
    { (* Failure (contradiction) *)
      destruct Hfail; try incrementPC_inv; unfold addr_of_argument, z_of_argument in *.
      all: simplify_map_eq; eauto; try congruence.
      destruct pc_p; congruence. congruence. }
    Unshelve. all: auto.
  Unshelve. Fail idtac. Admitted.

  Lemma wp_subseg_success_pc_r E pc_p pc_b pc_e pc_a w r1 n1 n2 a1 a2 pc_a' :
    decodeInstrW w = Subseg PC (inr r1) (inl n2)
    isCorrectPC (WCap pc_p pc_b pc_e pc_a)
    z_to_addr n1 = Some a1 z_to_addr n2 = Some a2
    pc_p machine_base.E
    isWithin a1 a2 pc_b pc_e = true
    (pc_a + 1)%a = Some pc_a'

    {{{ PC ↦ᵣ WCap pc_p pc_b pc_e pc_a
         pc_a ↦ₐ w
         r1 ↦ᵣ WInt n1 }}}
      Instr Executable @ E
      {{{ RET NextIV;
          PC ↦ᵣ WCap pc_p a1 a2 pc_a'
           pc_a ↦ₐ w
           r1 ↦ᵣ WInt n1
      }}}.
  Proof.
    iIntros (Hinstr Hvpc Hn1 Hn2 Hpne Hwb Hpc_a' ϕ) "(>HPC & >Hpc_a & >Hr1) Hφ".
    iDestruct (map_of_regs_2 with "HPC Hr1") as "[Hmap %]".
    iApply (wp_Subseg with "[$Hmap Hpc_a]"); eauto; simplify_map_eq; eauto.
    by unfold regs_of; rewrite !dom_insert; set_solver+.
    iNext. iIntros (regs' retv) "(#Hspec & Hpc_a & Hmap)". iDestruct "Hspec" as %Hspec.

    destruct Hspec as [| | * Hfail].
    { (* Success *)
      iApply "Hφ". iFrame. incrementPC_inv; simplify_map_eq.
      unfold addr_of_argument, z_of_argument in *. simplify_map_eq.
      rewrite (insert_commute _ PC r1) // insert_insert insert_commute // insert_insert.
      iDestruct (regs_of_map_2 with "Hmap") as "(?&?)"; eauto; iFrame. }
    { (* Success with WSealRange (contradiction) *)
      simplify_map_eq. }
    { (* Failure (contradiction) *)
      destruct Hfail; try incrementPC_inv; unfold addr_of_argument, z_of_argument in *.
      all: simplify_map_eq; eauto; try congruence.
      destruct pc_p; congruence. congruence. }
    Unshelve. all: auto.
  Unshelve. Fail idtac. Admitted.

  Lemma wp_subseg_success_pc_lr E pc_p pc_b pc_e pc_a w n1 n2 a1 a2 pc_a' :
    decodeInstrW w = Subseg PC (inl n1) (inl n2)
    isCorrectPC (WCap pc_p pc_b pc_e pc_a)
    z_to_addr n1 = Some a1 z_to_addr n2 = Some a2
    pc_p machine_base.E
    isWithin a1 a2 pc_b pc_e = true
    (pc_a + 1)%a = Some pc_a'

    {{{ PC ↦ᵣ WCap pc_p pc_b pc_e pc_a
         pc_a ↦ₐ w }}}
      Instr Executable @ E
      {{{ RET NextIV;
          PC ↦ᵣ WCap pc_p a1 a2 pc_a'
           pc_a ↦ₐ w
      }}}.
  Proof.
    iIntros (Hinstr Hvpc Hn1 Hn2 Hpne Hwb Hpc_a' ϕ) "(>HPC & >Hpc_a) Hφ".
    iDestruct (map_of_regs_1 with "HPC") as "Hmap".
    iApply (wp_Subseg with "[$Hmap Hpc_a]"); eauto; simplify_map_eq; eauto.
    iNext. iIntros (regs' retv) "(#Hspec & Hpc_a & Hmap)". iDestruct "Hspec" as %Hspec.

    destruct Hspec as [| | * Hfail].
    { (* Success *)
      iApply "Hφ". iFrame. incrementPC_inv; simplify_map_eq.
      unfold addr_of_argument, z_of_argument in *. simplify_map_eq.
      rewrite !insert_insert.
      iDestruct (regs_of_map_1 with "Hmap") as "?"; eauto; iFrame. }
    { (* Success with WSealRange (contradiction) *)
      simplify_map_eq. }
    { (* Failure (contradiction) *)
      destruct Hfail; try incrementPC_inv; unfold addr_of_argument, z_of_argument in *.
      all: simplify_map_eq; eauto; try congruence.
      destruct pc_p; congruence. congruence. }
    Unshelve. all: auto.
  Unshelve. Fail idtac. Admitted.

   (* Similar rules in case we have a SealRange instead of a capability, where some cases are impossible, because a SealRange is not a valid PC *)

  Lemma wp_subseg_success_sr E pc_p pc_b pc_e pc_a w dst r1 r2 p b e a n1 n2 a1 a2 pc_a' :
    decodeInstrW w = Subseg dst (inr r1) (inr r2)
    isCorrectPC (WCap pc_p pc_b pc_e pc_a)
    z_to_otype n1 = Some a1 z_to_otype n2 = Some a2
    isWithin a1 a2 b e = true
    (pc_a + 1)%a = Some pc_a'

    {{{ PC ↦ᵣ WCap pc_p pc_b pc_e pc_a
         pc_a ↦ₐ w
         dst ↦ᵣ WSealRange p b e a
         r1 ↦ᵣ WInt n1
         r2 ↦ᵣ WInt n2 }}}
      Instr Executable @ E
      {{{ RET NextIV;
          PC ↦ᵣ WCap pc_p pc_b pc_e pc_a'
           pc_a ↦ₐ w
           r1 ↦ᵣ WInt n1
           r2 ↦ᵣ WInt n2
           dst ↦ᵣ WSealRange p a1 a2 a
      }}}.
  Proof.
    iIntros (Hinstr Hvpc Hn1 Hn2 Hwb Hpc_a' ϕ) "(>HPC & >Hpc_a & >Hdst & >Hr1 & >Hr2) Hφ".
    iDestruct (map_of_regs_4 with "HPC Hr1 Hr2 Hdst") as "[Hmap (%&%&%&%&%&%)]".
    iApply (wp_Subseg with "[$Hmap Hpc_a]"); eauto; simplify_map_eq; eauto.
    by unfold regs_of; rewrite !dom_insert; set_solver+.
    iNext. iIntros (regs' retv) "(#Hspec & Hpc_a & Hmap)". iDestruct "Hspec" as %Hspec.

    destruct Hspec as [| | * Hfail].
    { (* Success with WCap (contradiction) *)
       simplify_map_eq. }
    { (* Success *)
      iApply "Hφ". iFrame. incrementPC_inv; simplify_map_eq.
      unfold otype_of_argument, z_of_argument in *. simplify_map_eq.
      rewrite (insert_commute _ PC dst) // insert_insert (insert_commute _ r2 dst) //
              (insert_commute _ r1 dst) // (insert_commute _ PC dst) // insert_insert.
      iDestruct (regs_of_map_4 with "Hmap") as "(?&?&?&?)"; eauto; iFrame. }
    { (* Failure (contradiction) *)
      destruct Hfail; try incrementPC_inv; unfold otype_of_argument, z_of_argument in *.
      all: simplify_map_eq; eauto; congruence. }
    Unshelve. all: auto.
  Unshelve. Fail idtac. Admitted.

  Lemma wp_subseg_success_same_sr E pc_p pc_b pc_e pc_a w dst r1 p b e a n1 a1 pc_a' :
    decodeInstrW w = Subseg dst (inr r1) (inr r1)
    isCorrectPC (WCap pc_p pc_b pc_e pc_a)
    z_to_otype n1 = Some a1
    isWithin a1 a1 b e = true
    (pc_a + 1)%a = Some pc_a'

    {{{ PC ↦ᵣ WCap pc_p pc_b pc_e pc_a
         pc_a ↦ₐ w
         dst ↦ᵣ WSealRange p b e a
         r1 ↦ᵣ WInt n1 }}}
      Instr Executable @ E
      {{{ RET NextIV;
          PC ↦ᵣ WCap pc_p pc_b pc_e pc_a'
           pc_a ↦ₐ w
           r1 ↦ᵣ WInt n1
           dst ↦ᵣ WSealRange p a1 a1 a
      }}}.
  Proof.
    iIntros (Hinstr Hvpc Hn1 Hwb Hpc_a' ϕ) "(>HPC & >Hpc_a & >Hdst & >Hr1) Hφ".
    iDestruct (map_of_regs_3 with "HPC Hr1 Hdst") as "[Hmap (%&%&%)]".
    iApply (wp_Subseg with "[$Hmap Hpc_a]"); eauto; simplify_map_eq; eauto.
    by unfold regs_of; rewrite !dom_insert; set_solver+.
    iNext. iIntros (regs' retv) "(#Hspec & Hpc_a & Hmap)". iDestruct "Hspec" as %Hspec.

    destruct Hspec as [| | * Hfail].
    { (* Success with WSealRange (contradiction) *)
      simplify_map_eq. }
    { (* Success *)
      iApply "Hφ". iFrame. incrementPC_inv; simplify_map_eq.
      unfold otype_of_argument, z_of_argument in *. simplify_map_eq.
      rewrite (insert_commute _ PC dst) // insert_insert (insert_commute _ r1 dst) //
              (insert_commute _ PC dst) // insert_insert.
      iDestruct (regs_of_map_3 with "Hmap") as "(?&?&?)"; eauto; iFrame. }
    { (* Failure (contradiction) *)
      destruct Hfail; try incrementPC_inv; unfold otype_of_argument, z_of_argument in *.
      all: simplify_map_eq; eauto; congruence. }
    Unshelve. all: auto.
  Unshelve. Fail idtac. Admitted.

  Lemma wp_subseg_success_l_sr E pc_p pc_b pc_e pc_a w dst r2 p b e a n1 n2 a1 a2 pc_a' :
    decodeInstrW w = Subseg dst (inl n1) (inr r2)
    isCorrectPC (WCap pc_p pc_b pc_e pc_a)
    z_to_otype n1 = Some a1 z_to_otype n2 = Some a2
    isWithin a1 a2 b e = true
    (pc_a + 1)%a = Some pc_a'

    {{{ PC ↦ᵣ WCap pc_p pc_b pc_e pc_a
         pc_a ↦ₐ w
         dst ↦ᵣ WSealRange p b e a
         r2 ↦ᵣ WInt n2 }}}
      Instr Executable @ E
      {{{ RET NextIV;
          PC ↦ᵣ WCap pc_p pc_b pc_e pc_a'
           pc_a ↦ₐ w
           r2 ↦ᵣ WInt n2
           dst ↦ᵣ WSealRange p a1 a2 a
      }}}.
  Proof.
    iIntros (Hinstr Hvpc Hn1 Hn2 Hwb Hpc_a' ϕ) "(>HPC & >Hpc_a & >Hdst & >Hr2) Hφ".
    iDestruct (map_of_regs_3 with "HPC Hr2 Hdst") as "[Hmap (%&%&%)]".
    iApply (wp_Subseg with "[$Hmap Hpc_a]"); eauto; simplify_map_eq; eauto.
    by unfold regs_of; rewrite !dom_insert; set_solver+.
    iNext. iIntros (regs' retv) "(#Hspec & Hpc_a & Hmap)". iDestruct "Hspec" as %Hspec.

    destruct Hspec as [| | * Hfail].
    { (* Success with WSealRange (contradiction) *)
      simplify_map_eq. }
    { (* Success *)
      iApply "Hφ". iFrame. incrementPC_inv; simplify_map_eq.
      unfold otype_of_argument, z_of_argument in *. simplify_map_eq.
      rewrite (insert_commute _ PC dst) // insert_insert (insert_commute _ r2 dst) //
              (insert_commute _ PC dst) // insert_insert.
      iDestruct (regs_of_map_3 with "Hmap") as "(?&?&?)"; eauto; iFrame. }
    { (* Failure (contradiction) *)
      destruct Hfail; try incrementPC_inv; unfold otype_of_argument, z_of_argument in *.
      all: simplify_map_eq; eauto; congruence. }
    Unshelve. all: auto.
  Unshelve. Fail idtac. Admitted.

  Lemma wp_subseg_success_r_sr E pc_p pc_b pc_e pc_a w dst r1 p b e a n1 n2 a1 a2 pc_a' :
    decodeInstrW w = Subseg dst (inr r1) (inl n2)
    isCorrectPC (WCap pc_p pc_b pc_e pc_a)
    z_to_otype n1 = Some a1 z_to_otype n2 = Some a2
    isWithin a1 a2 b e = true
    (pc_a + 1)%a = Some pc_a'

    {{{ PC ↦ᵣ WCap pc_p pc_b pc_e pc_a
         pc_a ↦ₐ w
         dst ↦ᵣ WSealRange p b e a
         r1 ↦ᵣ WInt n1 }}}
      Instr Executable @ E
      {{{ RET NextIV;
          PC ↦ᵣ WCap pc_p pc_b pc_e pc_a'
           pc_a ↦ₐ w
           r1 ↦ᵣ WInt n1
           dst ↦ᵣ WSealRange p a1 a2 a
      }}}.
  Proof.
    iIntros (Hinstr Hvpc Hn1 Hn2 Hwb Hpc_a' ϕ) "(>HPC & >Hpc_a & >Hdst & >Hr1) Hφ".
    iDestruct (map_of_regs_3 with "HPC Hr1 Hdst") as "[Hmap (%&%&%)]".
    iApply (wp_Subseg with "[$Hmap Hpc_a]"); eauto; simplify_map_eq; eauto.
    by unfold regs_of; rewrite !dom_insert; set_solver+.
    iNext. iIntros (regs' retv) "(#Hspec & Hpc_a & Hmap)". iDestruct "Hspec" as %Hspec.

    destruct Hspec as [| | * Hfail].
    { (* Success with WSealRange (contradiction) *)
      simplify_map_eq. }
    { (* Success *)
      iApply "Hφ". iFrame. incrementPC_inv; simplify_map_eq.
      unfold otype_of_argument, z_of_argument in *. simplify_map_eq.
      rewrite (insert_commute _ PC dst) // insert_insert (insert_commute _ r1 dst) //
              (insert_commute _ PC dst) // insert_insert.
      iDestruct (regs_of_map_3 with "Hmap") as "(?&?&?)"; eauto; iFrame. }
    { (* Failure (contradiction) *)
      destruct Hfail; try incrementPC_inv; unfold otype_of_argument, z_of_argument in *.
      all: simplify_map_eq; eauto; congruence. }
    Unshelve. all: auto.
  Unshelve. Fail idtac. Admitted.

  Lemma wp_subseg_success_lr_sr E pc_p pc_b pc_e pc_a w dst p b e a n1 n2 a1 a2 pc_a' :
    decodeInstrW w = Subseg dst (inl n1) (inl n2)
    isCorrectPC (WCap pc_p pc_b pc_e pc_a)
    z_to_otype n1 = Some a1 z_to_otype n2 = Some a2
    isWithin a1 a2 b e = true
    (pc_a + 1)%a = Some pc_a'

    {{{ PC ↦ᵣ WCap pc_p pc_b pc_e pc_a
         pc_a ↦ₐ w
         dst ↦ᵣ WSealRange p b e a }}}
      Instr Executable @ E
      {{{ RET NextIV;
          PC ↦ᵣ WCap pc_p pc_b pc_e pc_a'
           pc_a ↦ₐ w
           dst ↦ᵣ WSealRange p a1 a2 a
      }}}.
  Proof.
    iIntros (Hinstr Hvpc Hn1 Hn2 Hwb Hpc_a' ϕ) "(>HPC & >Hpc_a & >Hdst) Hφ".
    iDestruct (map_of_regs_2 with "HPC Hdst") as "[Hmap %]".
    iApply (wp_Subseg with "[$Hmap Hpc_a]"); eauto; simplify_map_eq; eauto.
    by unfold regs_of; rewrite !dom_insert; set_solver+.
    iNext. iIntros (regs' retv) "(#Hspec & Hpc_a & Hmap)". iDestruct "Hspec" as %Hspec.

    destruct Hspec as [| | * Hfail].
    { (* Success with WSealRange (contradiction) *)
      simplify_map_eq. }
    { (* Success *)
      iApply "Hφ". iFrame. incrementPC_inv; simplify_map_eq.
      unfold otype_of_argument, z_of_argument in *. simplify_map_eq.
      rewrite (insert_commute _ PC dst) // insert_insert insert_commute // insert_insert.
      iDestruct (regs_of_map_2 with "Hmap") as "(?&?)"; eauto; iFrame. }
    { (* Failure (contradiction) *)
      destruct Hfail; try incrementPC_inv; unfold otype_of_argument, z_of_argument in *.
      all: simplify_map_eq; eauto; congruence. }
    Unshelve. all: auto.
  Unshelve. Fail idtac. Admitted.

End cap_lang_rules.