(*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *)

Require Import Equivalence.
Require Import Morphisms.
Require Import Setoid.
Require Import EquivDec.
Require Import Program.
Require Import String.
Require Import List.
Require Import Arith.
Require Import Utils.
Require Import DataSystem.
Require Import cNNRC.
Require Import cNNRCEq.
Require Import TcNNRC.

Section TcNNRCEq.
  (* Named Nested Relational Calculus *)

  (* A different kind of equivalence for rewrites *)

  Context {m:basic_model}.
  Context {τcenv:tbindings}.

  Definition tnncr_core_rewrites_to (e1 e2:nnrc) : Prop :=
    forall (τenv : tbindings) (τout:rtype),
      nnrc_core_type τcenv τenv e1 τout ->
      (nnrc_core_type τcenv τenv e2 τout)
      /\ (forall (cenv env:bindings),
             bindings_type cenv τcenv ->
             bindings_type env τenv ->
             nnrc_core_eval brand_relation_brands cenv env e1
             = nnrc_core_eval brand_relation_brands cenv env e2).

  Notation "e1 ⇒ᶜᶜ e2" := (tnncr_core_rewrites_to e1 e2) (at level 80).

  Open Scope nnrc_scope.

  Lemma data_normalized_bindings_type_map env τenv :
    bindings_type env τenv ->
    Forall (data_normalized brand_relation_brands) (map snd env).
  Proof.
    rewrite Forall_map.
    apply bindings_type_Forall_normalized.
  Qed.

  Hint Resolve data_normalized_bindings_type_map : qcert.

  Lemma nnrc_base_rewrites_typed_with_untyped (e1 e2:nnrc) :
    e1 ≡ᶜᶜ e2 ->
    (forall {τenv: tbindings}
            {τout:rtype},
        nnrc_core_type τcenv τenv e1 τout
        -> nnrc_core_type τcenv τenv e2 τout)
    -> e1 ⇒ᶜᶜ e2.
  Proof.
    intros.
    unfold tnncr_core_rewrites_to; simpl; intros.
    split; auto 2; intros.
    apply H; qeauto.
  Qed.

  (****************
   * Proper stuff *
   ****************)

  Hint Constructors nnrc_core_type : qcert.
  Hint Constructors unary_op_type : qcert.
  Hint Constructors binary_op_type : qcert.

  Global Instance  tnncr_core_rewrites_to_pre : PreOrder tnncr_core_rewrites_to.
  Proof.
    constructor; red; intros.
    - unfold tnncr_core_rewrites_to; intros.
      split; try assumption; intros.
      reflexivity.
    - unfold tnncr_core_rewrites_to in *; intros.
      specialize (H τenv τout H1).
      elim H; clear H; intros.
      specialize (H0 τenv τout H).
      elim H0; clear H0; intros.
      split; try assumption; intros.
      rewrite (H2 cenv env); try assumption.
      rewrite (H3 cenv env); try assumption.
      reflexivity.
  Qed.

  (* NNRCVar *)

  Global Instance nnrc_base_var_tproper:
    Proper (eq ==> tnncr_core_rewrites_to) NNRCVar.
  Proof.
    unfold Proper, respectful, tnncr_core_rewrites_to; intros.
    rewrite <- H.
    split; try assumption.
    intros; reflexivity.
  Qed.

  (* NNRCConst *)

  Global Instance nnrc_base_const_tproper:
    Proper (eq ==> tnncr_core_rewrites_to) NNRCConst.
  Proof.
    unfold Proper, respectful, tnncr_core_rewrites_to; intros.
    rewrite <- H.
    split; try assumption.
    intros; reflexivity.
  Qed.

  (* NNRCBinop *)

  Global Instance nnrc_base_binop_tproper:
    Proper (eq ==> tnncr_core_rewrites_to
               ==> tnncr_core_rewrites_to
               ==> tnncr_core_rewrites_to) NNRCBinop.
  Proof.
    unfold Proper, respectful, tnncr_core_rewrites_to; intros.
    rewrite H in *; clear H.
    inversion H2; clear H2; subst.
    econstructor; eauto.
    specialize (H0 τenv τ₁ H8); elim H0; clear H0 H8; intros.
    specialize (H1 τenv τ₂ H9); elim H1; clear H1 H9; intros.
    econstructor; eauto; intros.
    intros.
    specialize (H0 τenv τ₁ H8); elim H0; clear H0 H8; intros.
    specialize (H1 τenv τ₂ H9); elim H1; clear H1 H9; intros.
    simpl.
    rewrite (H3 cenv env H H2); rewrite (H4 cenv env H H2); reflexivity.
  Qed.

  (* NNRCUnop *)

  Global Instance nnrc_base_unop_tproper :
    Proper (eq ==> tnncr_core_rewrites_to ==> tnncr_core_rewrites_to) NNRCUnop.
  Proof.
    unfold Proper, respectful, tnncr_core_rewrites_to; intros.
    rewrite H in *; clear H.
    inversion H1; clear H1; subst.
    econstructor; eauto.
    econstructor; eauto.
    specialize (H0  τenv τ₁ H6); elim H0; clear H0 H6; intros; assumption.
    intros.
    specialize (H0  τenv τ₁ H6); elim H0; clear H0 H6; intros.
    simpl. rewrite (H2 cenv env H H1); reflexivity.
  Qed.

  (* NNRCLet *)

  Global Instance nnrc_base_let_tproper :
    Proper (eq ==> tnncr_core_rewrites_to ==> tnncr_core_rewrites_to ==> tnncr_core_rewrites_to) NNRCLet.
  Proof.
    unfold Proper, respectful, tnncr_core_rewrites_to; intros.
    inversion H2; clear H2; subst.
    specialize (H0 τenv τ₁ H8); elim H0; clear H0 H8; intros.
    specialize (H1 ((y, τ₁) :: τenv) τout H9); elim H1; clear H1 H9; intros.
    econstructor; qeauto.
    intros; simpl.
    rewrite (H0 cenv env H3 H4).
    case_eq (nnrc_core_eval brand_relation_brands cenv env y0); intros; try reflexivity.
    rewrite (H2 cenv ((y, d) :: env) H3); try reflexivity.
    unfold bindings_type.
    apply Forall2_cons; try assumption.
    simpl; split; try reflexivity.
    generalize (@typed_nnrc_core_yields_typed_data _ _ τ₁ cenv env τenv y0 H3 H4 H); intros.
    elim H6; intros.
    rewrite H5 in H7.
    elim H7; clear H7; intros.
    inversion H7; assumption.
  Qed.

  (* NNRCFor *)

  Lemma dcoll_wt (l:list data) (τ:rtype) (τenv:tbindings) (cenv env:bindings) (e:nnrc):
    bindings_type cenv τcenv ->
    bindings_type env τenv ->
    nnrc_core_type τcenv τenv e (Coll τ) ->
    nnrc_core_eval brand_relation_brands cenv env e = Some (dcoll l) ->
    forall x:data, In x l -> (data_type x τ).
  Proof.
    intros.
    generalize (@typed_nnrc_core_yields_typed_data _ _ (Coll τ) cenv env τenv e H H0 H1); intros.
    elim H4; clear H4; intros.
    elim H4; clear H4; intros.
    rewrite H4 in H2.
    inversion H2; clear H2.
    subst.
    dependent induction H5.
    rtype_equalizer.
    subst.
    rewrite Forall_forall in H2.
    apply (H2 x0 H3).
  Qed.

  Global Instance nnrc_base_for_tproper :
    Proper (eq ==> tnncr_core_rewrites_to ==> tnncr_core_rewrites_to ==> tnncr_core_rewrites_to) NNRCFor.
  Proof.
    unfold Proper, respectful, tnncr_core_rewrites_to; intros.
    inversion H2; clear H2; subst.
    specialize (H0 τenv (Coll τ₁) H8); elim H0; clear H0 H8; intros.
    specialize (H1 ((y, τ₁) :: τenv) τ₂ H9); elim H1; clear H1 H9; intros.
    econstructor; qeauto.
    intros; simpl.
    rewrite (H0 cenv env H3 H4).
    case_eq (nnrc_core_eval brand_relation_brands cenv env y0); intros; try reflexivity.
    destruct d; try reflexivity.
    assert (forall x, In x l -> (data_type x τ₁)) by
        (apply (dcoll_wt l τ₁ τenv cenv env y0); assumption).
    clear H5 H.
    induction l; try reflexivity.
    simpl in *.
    assert (forall x : data, In x l -> data_type x τ₁)
      by (intros; apply (H6 x); right; assumption).
    specialize (IHl H); clear H.
    rewrite (H2 cenv ((y, a) :: env) H3).
    destruct (nnrc_core_eval brand_relation_brands cenv ((y, a) :: env) y1); try reflexivity.
    destruct ((lift_map (fun d1 : data => nnrc_core_eval brand_relation_brands cenv ((y, d1) :: env) x1) l)); destruct ((lift_map (fun d1 : data => nnrc_core_eval brand_relation_brands cenv ((y, d1) :: env) y1) l)); simpl in *; try congruence.
    unfold bindings_type.
    apply Forall2_cons; try assumption.
    simpl; split; try reflexivity.
    apply (H6 a); left; reflexivity.
  Qed.

  (* NNRCIf *)

  Global Instance nnrc_base_if_tproper :
    Proper (tnncr_core_rewrites_to ==> tnncr_core_rewrites_to
                             ==> tnncr_core_rewrites_to
                             ==> tnncr_core_rewrites_to) NNRCIf.
  Proof.
    unfold Proper, respectful, tnncr_core_rewrites_to; intros.
    inversion H2; clear H2; subst.
    specialize (H τenv Bool H7); elim H; clear H H7; intros.
    specialize (H0 τenv τout H9); elim H0; clear H0 H9; intros.
    specialize (H1 τenv τout H10); elim H1; clear H1 H10; intros.
    econstructor; qeauto.
    intros; simpl.
    rewrite (H2 cenv env H5 H6). rewrite (H3 cenv env H5 H6). rewrite (H4 cenv env H5 H6).
    reflexivity.
  Qed.

  (* NNRCEither *)

  Global Instance nnrc_base_either_tproper :
    Proper (tnncr_core_rewrites_to ==> eq ==> tnncr_core_rewrites_to ==> eq ==> tnncr_core_rewrites_to ==> tnncr_core_rewrites_to) NNRCEither.
  Proof.
    unfold Proper, respectful, tnncr_core_rewrites_to; intros.
    subst.
    inversion H4; clear H4; subst.
    destruct (H _ _ H10).
    destruct (H1 _ _ H11).
    destruct (H3 _ _ H12).
    clear H H1 H3.
    simpl.
    split; [qeauto | ]; intros.
    rewrite H2; trivial.
    destruct (@typed_nnrc_core_yields_typed_data _ _ _ _ _ _ _ H H1 H0) as [?[??]].
    rewrite H3.
    apply data_type_Either_inv in H8.
    destruct H8 as [[?[??]]|[?[??]]]; subst.
    - apply (H5 _ _ H). constructor; simpl; intuition; eauto.
    - eapply (H7 _ _ H). constructor; simpl; intuition; eauto.
  Qed.

End TcNNRCEq.

Notation "e1 ⇒ᶜᶜ e2" := (tnncr_core_rewrites_to e1 e2) (at level 80) : nnrc_scope.


From mathcomp.ssreflect
Require Import ssreflect ssrbool ssrnat eqtype ssrfun seq.
From mathcomp
Require Import path.
Require Import Eqdep.
Require Import Relation_Operators.
From fcsl
Require Import axioms pred prelude ordtype finmap pcm unionmap heap.
From DiSeL
Require Import Freshness State EqTypeX Protocols Worlds NetworkSem Rely.
From DiSeL
Require Import Actions Injection Process Always HoareTriples InferenceRules.
From DiSeL
Require Import InductiveInv While.
From DiSeL
Require Import CalculatorProtocol CalculatorInvariant.
From DiSeL
Require Import CalculatorClientLib.
From DiSeL
Require Import SeqLib.

Section CalculatorServerLib.

Variable l : Label.
Variable f : input -> option nat.
Variable prec : input -> bool.
Variables (cs cls : seq nid).
Notation nodes := (cs ++ cls).
Hypothesis Huniq : uniq nodes.

Notation cal := (CalculatorProtocol f prec cs cls l).
Notation sts := (snd_trans cal).
Notation rts := (rcv_trans cal).
Notation W := (mkWorld cal).

(* A server node *)
Variable sv : nid.
Hypothesis  Hs : sv \in cs.
Notation loc i := (getLocal sv (getStatelet i l)).

(***********************)
(* Server receive loop *)
(***********************)

Export CalculatorProtocol.

Program Definition tryrecv_req_act := act (@tryrecv_action_wrapper W sv
      (fun k _ t b => (k == l) && (t == req)) _).
Next Obligation. by case/andP:H=>/eqP->; rewrite domPt inE/=. Qed.

(* Receive-transition for the calculator *)
Program Definition tryrecv_req :
  {ps : reqs}, DHT [sv, W]
  (fun i => loc i = st :-> ps,
   fun (r : option perm) m =>
     match r with
     | Some (from, t, args) =>
       [/\ loc m = st :-> ((from, sv, args) :: ps),
        prec args & from \in cls]
     | None => loc m = st :-> ps
     end)
  := Do tryrecv_req_act.
Next Obligation.
apply: ghC=>i1 ps E1 C1.
apply: act_rule=>i2 R1; split=>//=; first by apply: (proj2 (rely_coh R1)).
move=>r i3 i4[_]/=St R3.
case: St=>C2; case.
- by move=>[]?->Z; subst i3;rewrite (rely_loc' _ R3) (rely_loc' _ R1).
case=>k[m][tms][from][rt][pf'][[F]]H1 H2 H3/andP[/eqP Z]H4/= Z'->; subst k i3.
move: rt  pf' (coh_s l C2) H1 H2 H3 H4 R3.
rewrite prEq=>rt  pf' cohs H1 H2 H3 H4 R3.
case: H1 H4; last by case=>//=->.
move=>Z _; subst rt; move: H3; rewrite /msg_wf/=/sr_wf=>->; split=>//.
set d := (getStatelet i2 l).
have P1: valid (dstate d) by apply: (cohVl cohs).
have P2: valid i2 by apply: (cohS (proj2 (rely_coh R1))).
have P3: l \in dom i2 by rewrite -(cohD(proj2(rely_coh R1)))domPt inE/=.
rewrite -(rely_loc' _ R1) in E1.
- by rewrite (rely_loc' _ R3)/= locE//=/sr_step Hs/= (getStK cohs E1).
case: (cohs)=>Cs _ _ _. move/esym: F=> F.
by case: Cs=>_/(_ _ _ F); rewrite /cohMsg/= H2/=; case.
Qed.

Definition receive_req_loop_cond (res : option (nid * input)) := res == None.

Definition receive_req_loop_inv (ps : reqs) :=
  fun (r : option (nid * input)) i =>
    match r with
     | Some (from, args) =>
       [/\ loc i = st :-> ((from, sv, args) :: ps),
        prec args & from \in cls]
     | None => loc i = st :-> ps
    end.

Program Definition receive_req_loop :
  {ps : reqs}, DHT [sv, W]
  (fun i => loc i = st :-> ps,
   fun (r : option (nid * input)) m =>
     exists from args,
     [/\ r = Some (from, args),
      loc m = st :-> ((from, sv, args) :: ps),
      from \in cls &
      prec args]) :=
  Do _ (@while sv W _ _ receive_req_loop_cond receive_req_loop_inv _
        (fun r => Do _ (
           r <-- tryrecv_req;
           match r with
           | Some (from, _, args) => ret _ _ (Some (from, args))
           | None => ret _ _ None
           end)) None).

Next Obligation. by apply: with_spec x. Defined.
Next Obligation.
by move:H; rewrite /receive_req_loop_inv (rely_loc' _ H0).
Qed.
Next Obligation.
apply:ghC=>i1 ps/=[/eqP H1]L1 C1; subst r.
apply: step; apply: (gh_ex (g:=ps)).
apply: call_rule=>//r i2/=; case: r; last first.
- by move=>L2 C2; apply: ret_rule=>i3 R2; rewrite -(rely_loc' _ R2) in L2.
case=>[[from to] args]E2 C2; apply: ret_rule=>i3 R2/=.
by rewrite (rely_loc' _ R2).
Qed.
Next Obligation.
apply: ghC=>i ps E1 C1; apply: (gh_ex (g:=ps)).
apply: call_rule=>//res m[].
rewrite /receive_req_loop_cond; case: res=>//=[[from args]]_ [H1 H2]C2.
by exists from, args.
Qed.

Program Definition blocking_receive_req :
  {ps : reqs}, DHT [sv, W]
  (fun i => loc i = st :-> ps,
   fun (r : nid * input) m =>
     [/\ loc m = st :-> ((r.1, sv, r.2) :: ps),
      r.1 \in cls &
      prec r.2]) :=
  Do _ (r <-- receive_req_loop;
        match r with
        | Some res => ret _ _ res
        | None => ret _ _ (0, [::])
        end).
Next Obligation.
apply: ghC=>i ps E1 C1; apply: step; apply: (gh_ex (g:=ps)).
apply: call_rule=>//res i2[from][args][Z]E2 H1 H2 C2.
by subst res; apply: ret_rule=>i3 R2/=; rewrite (rely_loc' _ R2).
Qed.

(***************************)
(* Server sending messages *)
(***************************)

(* Generic server' send that assumes a permission to respond *)

Program Definition send_ans_act to msg :=
  act (@send_action_wrapper W cal sv l (prEq cal)
        (server_send_trans f prec cs cls) _ msg to).
Next Obligation. by rewrite /cal_sends /InMem/=; left. Qed.

Program Definition send_answer (to : nid) (args : seq nat) (ans : nat) :
  {ps : reqs}, DHT [sv, W]
  (fun i => [/\ loc i = st :-> ps, to \in cls,
             (to, sv, args) \in ps &
             f args = Some ans],
   fun (r : seq nat) m =>
       [/\ loc m = st :-> (remove_elem ps (to, sv, args)) &
       r = ans :: args])
  := Do send_ans_act to (ans :: args).
Next Obligation.
apply: ghC=>i1 ps [L1]H1 H2 H3 C1.
apply: act_rule=>i2 R1.
move: (proj2 (rely_coh R1))=>C2.
case: (C2)=>_ _ _ _/(_ l); rewrite prEq=>C.
set d := (getStatelet i2 l).
split=>//[|r i3 i4[Sf]St R3].
- split=>//; first 1 last.
  + by rewrite/Actions.can_send mem_cat Hs/=
       -(cohD C2)/= domPt/= inE eqxx.
  + rewrite/Actions.filter_hooks umfilt0=>???.
    move => F.
    apply sym_eq in F.
    move: F.
    move/find_some.
    by rewrite dom0.
  split=>//; split=>//.
  exists C; rewrite -(rely_loc' _ R1) in L1; rewrite (getStK C L1).
  by apply/hasP; exists (to, sv, args)=>//=; rewrite H3 !eqxx.
rewrite (rely_loc' _ R3)=>{R3}.
case: St=>->[b]/=[][]->->/=; split=>//.
have P1: valid (dstate (getStatelet i2 l)). by apply: (cohVl C).
have P2: valid i2 by apply: (cohS (proj2 (rely_coh R1))).
have P3: l \in dom i2 by rewrite -(cohD(proj2(rely_coh R1))) domPt inE/=.
rewrite -(rely_loc' _ R1) in L1.
by rewrite (pf_irr (ss_safe_coh _ ) C) locE// (getStK C L1).
Qed.

(**************************************************)
(*
Overall Implementation effort:

2 person-hours

*)
(**************************************************)

End CalculatorServerLib.


Require Import SpecDeps.
Require Import RData.
Require Import EventReplay.
Require Import MoverTypes.
Require Import Constants.
Require Import CommonLib.
Require Import AbsAccessor.Spec.
Require Import TableAux2.Spec.
Require Import TableAux.Spec.

Local Open Scope Z_scope.

Section SpecLow.

  Definition table_destroy_aux_spec0 (g_llt: Pointer) (g_tbl: Pointer) (ll_table: Pointer) (level: Z64) (index: Z64) (map_addr: Z64) (adt: RData) : option (RData * Z64) :=
    match g_llt, g_tbl, ll_table, level, index, map_addr with
    | (_g_llt_base, _g_llt_ofst), (_g_tbl_base, _g_tbl_ofst), (_ll_table_base, _ll_table_ofst), VZ64 _level, VZ64 _index, VZ64 _map_addr =>
      let _ret := 0 in
      when'' _table_base, _table_ofst, adt == granule_map_spec (_g_tbl_base, _g_tbl_ofst) 7 adt;
      rely is_int _table_ofst;
      when' _gcnt, adt == get_g_rtt_refcount_spec (_g_tbl_base, _g_tbl_ofst) adt;
      rely is_int64 _gcnt;
      if (_gcnt =? 1) then
        let _t'6 := 1 in
        if (_gcnt =? 1) then
          when' _new_pgte, adt == table_delete_spec (_table_base, _table_ofst) (_g_llt_base, _g_llt_ofst) adt;
          rely is_int64 _new_pgte;
          rely is_int64 _index;
          when adt == pgte_write_spec (_ll_table_base, _ll_table_ofst) (VZ64 _index) (VZ64 0) adt;
          rely is_int64 (Z.land _new_pgte 504403158265495552);
          rely is_int64 ((Z.land _new_pgte 504403158265495552) / 72057594037927936);
          if (((Z.land _new_pgte 504403158265495552) / 72057594037927936) =? 2) then
            rely is_int64 _map_addr;
            when adt == invalidate_pages_in_block_spec (VZ64 _map_addr) adt;
            when adt == pgte_write_spec (_ll_table_base, _ll_table_ofst) (VZ64 _index) (VZ64 _new_pgte) adt;
            when adt == granule_put_spec (_g_tbl_base, _g_tbl_ofst) adt;
            when'' _t'5_base, _t'5_ofst == null_ptr_spec  adt;
            rely is_int _t'5_ofst;
            when adt == set_g_rtt_rd_spec (_g_tbl_base, _g_tbl_ofst) (_t'5_base, _t'5_ofst) adt;
            when adt == granule_memzero_mapped_spec (_table_base, _table_ofst) adt;
            when adt == granule_set_state_spec (_g_tbl_base, _g_tbl_ofst) 1 adt;
            when adt == buffer_unmap_spec (_table_base, _table_ofst) adt;
            Some (adt, (VZ64 _ret))
          else
            rely is_int64 _map_addr;
            when adt == invalidate_block_spec (VZ64 _map_addr) adt;
            when adt == pgte_write_spec (_ll_table_base, _ll_table_ofst) (VZ64 _index) (VZ64 _new_pgte) adt;
            when adt == granule_put_spec (_g_tbl_base, _g_tbl_ofst) adt;
            when'' _t'5_base, _t'5_ofst == null_ptr_spec  adt;
            rely is_int _t'5_ofst;
            when adt == set_g_rtt_rd_spec (_g_tbl_base, _g_tbl_ofst) (_t'5_base, _t'5_ofst) adt;
            when adt == granule_memzero_mapped_spec (_table_base, _table_ofst) adt;
            when adt == granule_set_state_spec (_g_tbl_base, _g_tbl_ofst) 1 adt;
            when adt == buffer_unmap_spec (_table_base, _table_ofst) adt;
            Some (adt, (VZ64 _ret))
        else
          rely is_int64 _level;
          when' _new_pgte, adt == table_fold_spec (_table_base, _table_ofst) (VZ64 _level) (_g_tbl_base, _g_tbl_ofst) adt;
          rely is_int64 _new_pgte;
          rely is_int64 _index;
          when adt == pgte_write_spec (_ll_table_base, _ll_table_ofst) (VZ64 _index) (VZ64 0) adt;
          rely is_int64 (Z.land _new_pgte 504403158265495552);
          rely is_int64 ((Z.land _new_pgte 504403158265495552) / 72057594037927936);
          if (((Z.land _new_pgte 504403158265495552) / 72057594037927936) =? 2) then
            rely is_int64 _map_addr;
            when adt == invalidate_pages_in_block_spec (VZ64 _map_addr) adt;
            when adt == pgte_write_spec (_ll_table_base, _ll_table_ofst) (VZ64 _index) (VZ64 _new_pgte) adt;
            when adt == granule_put_spec (_g_tbl_base, _g_tbl_ofst) adt;
            when'' _t'5_base, _t'5_ofst == null_ptr_spec  adt;
            rely is_int _t'5_ofst;
            when adt == set_g_rtt_rd_spec (_g_tbl_base, _g_tbl_ofst) (_t'5_base, _t'5_ofst) adt;
            when adt == granule_memzero_mapped_spec (_table_base, _table_ofst) adt;
            when adt == granule_set_state_spec (_g_tbl_base, _g_tbl_ofst) 1 adt;
            when adt == buffer_unmap_spec (_table_base, _table_ofst) adt;
            Some (adt, (VZ64 _ret))
          else
            rely is_int64 _map_addr;
            when adt == invalidate_block_spec (VZ64 _map_addr) adt;
            when adt == pgte_write_spec (_ll_table_base, _ll_table_ofst) (VZ64 _index) (VZ64 _new_pgte) adt;
            when adt == granule_put_spec (_g_tbl_base, _g_tbl_ofst) adt;
            when'' _t'5_base, _t'5_ofst == null_ptr_spec  adt;
            rely is_int _t'5_ofst;
            when adt == set_g_rtt_rd_spec (_g_tbl_base, _g_tbl_ofst) (_t'5_base, _t'5_ofst) adt;
            when adt == granule_memzero_mapped_spec (_table_base, _table_ofst) adt;
            when adt == granule_set_state_spec (_g_tbl_base, _g_tbl_ofst) 1 adt;
            when adt == buffer_unmap_spec (_table_base, _table_ofst) adt;
            Some (adt, (VZ64 _ret))
      else
        rely is_int64 (512 + 1);
        let _t'6 := (_gcnt =? (512 + 1)) in
        if _t'6 then
          if (_gcnt =? 1) then
            when' _new_pgte, adt == table_delete_spec (_table_base, _table_ofst) (_g_llt_base, _g_llt_ofst) adt;
            rely is_int64 _new_pgte;
            rely is_int64 _index;
            when adt == pgte_write_spec (_ll_table_base, _ll_table_ofst) (VZ64 _index) (VZ64 0) adt;
            rely is_int64 (Z.land _new_pgte 504403158265495552);
            rely is_int64 ((Z.land _new_pgte 504403158265495552) / 72057594037927936);
            if (((Z.land _new_pgte 504403158265495552) / 72057594037927936) =? 2) then
              rely is_int64 _map_addr;
              when adt == invalidate_pages_in_block_spec (VZ64 _map_addr) adt;
              when adt == pgte_write_spec (_ll_table_base, _ll_table_ofst) (VZ64 _index) (VZ64 _new_pgte) adt;
              when adt == granule_put_spec (_g_tbl_base, _g_tbl_ofst) adt;
              when'' _t'5_base, _t'5_ofst == null_ptr_spec  adt;
              rely is_int _t'5_ofst;
              when adt == set_g_rtt_rd_spec (_g_tbl_base, _g_tbl_ofst) (_t'5_base, _t'5_ofst) adt;
              when adt == granule_memzero_mapped_spec (_table_base, _table_ofst) adt;
              when adt == granule_set_state_spec (_g_tbl_base, _g_tbl_ofst) 1 adt;
              when adt == buffer_unmap_spec (_table_base, _table_ofst) adt;
              Some (adt, (VZ64 _ret))
            else
              rely is_int64 _map_addr;
              when adt == invalidate_block_spec (VZ64 _map_addr) adt;
              when adt == pgte_write_spec (_ll_table_base, _ll_table_ofst) (VZ64 _index) (VZ64 _new_pgte) adt;
              when adt == granule_put_spec (_g_tbl_base, _g_tbl_ofst) adt;
              when'' _t'5_base, _t'5_ofst == null_ptr_spec  adt;
              rely is_int _t'5_ofst;
              when adt == set_g_rtt_rd_spec (_g_tbl_base, _g_tbl_ofst) (_t'5_base, _t'5_ofst) adt;
              when adt == granule_memzero_mapped_spec (_table_base, _table_ofst) adt;
              when adt == granule_set_state_spec (_g_tbl_base, _g_tbl_ofst) 1 adt;
              when adt == buffer_unmap_spec (_table_base, _table_ofst) adt;
              Some (adt, (VZ64 _ret))
          else
            rely is_int64 _level;
            when' _new_pgte, adt == table_fold_spec (_table_base, _table_ofst) (VZ64 _level) (_g_tbl_base, _g_tbl_ofst) adt;
            rely is_int64 _new_pgte;
            rely is_int64 _index;
            when adt == pgte_write_spec (_ll_table_base, _ll_table_ofst) (VZ64 _index) (VZ64 0) adt;
            rely is_int64 (Z.land _new_pgte 504403158265495552);
            rely is_int64 ((Z.land _new_pgte 504403158265495552) / 72057594037927936);
            if (((Z.land _new_pgte 504403158265495552) / 72057594037927936) =? 2) then
              rely is_int64 _map_addr;
              when adt == invalidate_pages_in_block_spec (VZ64 _map_addr) adt;
              when adt == pgte_write_spec (_ll_table_base, _ll_table_ofst) (VZ64 _index) (VZ64 _new_pgte) adt;
              when adt == granule_put_spec (_g_tbl_base, _g_tbl_ofst) adt;
              when'' _t'5_base, _t'5_ofst == null_ptr_spec  adt;
              rely is_int _t'5_ofst;
              when adt == set_g_rtt_rd_spec (_g_tbl_base, _g_tbl_ofst) (_t'5_base, _t'5_ofst) adt;
              when adt == granule_memzero_mapped_spec (_table_base, _table_ofst) adt;
              when adt == granule_set_state_spec (_g_tbl_base, _g_tbl_ofst) 1 adt;
              when adt == buffer_unmap_spec (_table_base, _table_ofst) adt;
              Some (adt, (VZ64 _ret))
            else
              rely is_int64 _map_addr;
              when adt == invalidate_block_spec (VZ64 _map_addr) adt;
              when adt == pgte_write_spec (_ll_table_base, _ll_table_ofst) (VZ64 _index) (VZ64 _new_pgte) adt;
              when adt == granule_put_spec (_g_tbl_base, _g_tbl_ofst) adt;
              when'' _t'5_base, _t'5_ofst == null_ptr_spec  adt;
              rely is_int _t'5_ofst;
              when adt == set_g_rtt_rd_spec (_g_tbl_base, _g_tbl_ofst) (_t'5_base, _t'5_ofst) adt;
              when adt == granule_memzero_mapped_spec (_table_base, _table_ofst) adt;
              when adt == granule_set_state_spec (_g_tbl_base, _g_tbl_ofst) 1 adt;
              when adt == buffer_unmap_spec (_table_base, _table_ofst) adt;
              Some (adt, (VZ64 _ret))
        else
          let _ret := 1 in
          when adt == buffer_unmap_spec (_table_base, _table_ofst) adt;
          Some (adt, (VZ64 _ret))
     end
    .

End SpecLow.