From compcert Require Export Clightdefs.
Require Export VST.veric.SeparationLogic.
Require Export VST.msl.Extensionality.
Require Export compcert.lib.Coqlib.
Require Export VST.msl.Coqlib2 VST.veric.coqlib4 VST.floyd.coqlib3.
Require Export VST.floyd.jmeq_lemmas.
Require Export VST.floyd.find_nth_tactic.
Require Export VST.veric.juicy_extspec.
Require Import VST.veric.NullExtension.

Require Import VST.floyd.assert_lemmas.

Local Open Scope logic.

(* TODO: move it *)
Lemma exp_derives:
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
       forall {A: Type}  {NA: NatDed A} (B: Type) (P Q: B -> A),
               (forall x:B, P x |-- Q x) -> (exp P |-- exp Q).
Proof.
(* Goal: None *)
intros.
(* Goal: @derives A NA (@exp A NA B P) (@exp A NA B Q) *)
apply exp_left; intro x; apply exp_right with x; auto.
Qed.

(* Goal: @eq Prop (@isSome unit (@PTree.get unit id (@PTree.set unit i tt idset0))) (@eq ident i id) *)
(* Closed and subst. copied from closed_lemmas.v. *)

Lemma closed_wrt_subst:
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
  forall {A} id e (P: environ -> A), closed_wrt_vars (eq id) P -> subst id e P = P.
Proof.
(* Goal: None *)
intros.
(* Goal: @eq (forall _ : environ, A) (@subst A id e P) P *)
unfold subst, closed_wrt_vars in *.
(* Goal: @eq (forall _ : environ, A) (fun s : environ => P (env_set s id (e s))) P *)
extensionality rho.
(* Goal: @eq A (P (env_set rho id (e rho))) (P rho) *)
symmetry.
(* Goal: @eq A (P rho) (P (env_set rho id (e rho))) *)
apply H.
(* Goal: None *)
intros.
(* Goal: or (@eq ident id i) (@eq (option val) (@Map.get val (te_of rho) i) (@Map.get val (@Map.set val id (e rho) (te_of rho)) i)) *)
destruct (eq_dec id i); auto.
(* Goal: or (@eq ident id i) (@eq (option val) (@Map.get val (te_of rho) i) (@Map.get val (@Map.set val id (e rho) (te_of rho)) i)) *)
right.
(* Goal: @eq (option val) (@Map.get val (te_of rho) i) (@Map.get val (@Map.set val id (e rho) (te_of rho)) i) *)
rewrite Map.gso; auto.
Qed.

(* End of copied from closed_lemmas.v. *)

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Lemma subst_self: forall {A: Type} (P: environ -> A) t id v Delta rho,
  (temp_types Delta) ! id = Some t ->
  tc_environ Delta rho ->
  v rho = eval_id id rho ->
  subst id v P rho = P rho.
Proof.
(* Goal: None *)
  intros.
(* Goal: @derives mpred Nveric (P rho) (odia Delta i P rho) *)
  destruct H0 as [? _].
(* Goal: @eq A (@subst A id v P rho) (P rho) *)
  specialize (H0 _ _ H).
(* Goal: @eq A (@subst A id v P rho) (P rho) *)
  destruct H0 as [v' [? ?]].
(* Goal: @subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho *)
  unfold subst.
(* Goal: @eq environ (mkEnviron ge ve te) (mkEnviron ge ve (@Map.set val i v te)) *)
  f_equal.
(* Goal: @eq environ (env_set rho id (v rho)) rho *)
  unfold env_set, eval_id in *; destruct rho; simpl in *.
(* Goal: @eq environ (mkEnviron ge ve te) (mkEnviron ge ve (@Map.set val i v te)) *)
  f_equal.
(* Goal: @eq (Map.t val) (@Map.set val id (v (mkEnviron ge ve te)) te) te *)
  rewrite H1, H0.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  simpl.
(* Goal: @eq (Map.t val) (@Map.set val id v' te) te *)
  apply Map.ext; intros i.
(* Goal: @eq (option val) (@Map.get val (@Map.set val id v' te) i) (@Map.get val te i) *)
  destruct (Pos.eq_dec id i).
  + subst.
(* Goal: @eq (option val) (@Map.get val (@Map.set val i v' te) i) (@Map.get val te i) *)
    rewrite Map.gss; symmetry; auto.
  + rewrite Map.gso by auto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    auto.
Qed.

Definition obox (Delta: tycontext) (i: ident) (P: environ -> mpred): environ -> mpred :=
  ALL v: _,
    match ((temp_types Delta) ! i) with
    | Some t => !! (tc_val' t v) --> subst i (`v) P
    | _ => TT
    end.

Definition odia (Delta: tycontext) (i: ident) (P: environ -> mpred): environ -> mpred :=
  EX v: _,
    match ((temp_types Delta) ! i) with
    | Some t => !! (tc_val' t v) && subst i (`v) P
    | _ => FF
    end.

Lemma obox_closed_wrt: forall Delta id P, closed_wrt_vars (eq id) (obox Delta id P).
Proof.
(* Goal: None *)
  intros.
(* Goal: None *)
  hnf; intros.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  unfold obox; simpl.
(* Goal: None *)
  apply allp_congr; intros.
(* Goal: @subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho *)
  unfold subst.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  destruct ((temp_types Delta) ! id); auto.
(* Goal: @eq environ (mkEnviron ge ve te) (mkEnviron ge ve (@Map.set val i v te)) *)
  f_equal.
(* Goal: @eq environ (mkEnviron ge ve te) (mkEnviron ge ve (@Map.set val i v te)) *)
  f_equal.
(* Goal: @derives mpred Nveric (P rho) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho) *)
  unfold_lift.
(* Goal: @eq environ (env_set rho id v) (env_set (mkEnviron (ge_of rho) (ve_of rho) te') id v) *)
  unfold env_set.
(* Goal: @eq environ (mkEnviron ge ve te) (mkEnviron ge ve (@Map.set val i v te)) *)
  f_equal.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  simpl.
(* Goal: @eq (Map.t val) (@Map.set val id v (te_of rho)) (@Map.set val id v te') *)
  apply Map.ext; intros j.
(* Goal: @eq (option val) (@Map.get val (@Map.set val id v (te_of rho)) j) (@Map.get val (@Map.set val id v te') j) *)
  destruct (ident_eq id j).
  + subst.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    rewrite !Map.gss; auto.
  + rewrite !Map.gso by congruence.
(* Goal: @eq (option val) (@Map.get val (te_of rho) j) (@Map.get val te' j) *)
    destruct (H j); [congruence |].
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    auto.
Qed.

Lemma odia_closed_wrt: forall Delta id P, closed_wrt_vars (eq id) (odia Delta id P).
Proof.
(* Goal: None *)
  intros.
(* Goal: None *)
  hnf; intros.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  unfold odia; simpl.
(* Goal: None *)
  apply exp_congr; intros.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  destruct ((temp_types Delta) ! id); auto.
(* Goal: @eq environ (mkEnviron ge ve te) (mkEnviron ge ve (@Map.set val i v te)) *)
  f_equal.
(* Goal: @subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho *)
  unfold subst.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  simpl.
(* Goal: @eq environ (mkEnviron ge ve te) (mkEnviron ge ve (@Map.set val i v te)) *)
  f_equal.
(* Goal: @derives mpred Nveric (P rho) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho) *)
  unfold_lift.
(* Goal: @eq environ (env_set rho id v) (env_set (mkEnviron (ge_of rho) (ve_of rho) te') id v) *)
  unfold env_set.
(* Goal: @eq environ (mkEnviron ge ve te) (mkEnviron ge ve (@Map.set val i v te)) *)
  f_equal.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  simpl.
(* Goal: @eq (Map.t val) (@Map.set val id v (te_of rho)) (@Map.set val id v te') *)
  apply Map.ext; intros j.
(* Goal: @eq (option val) (@Map.get val (@Map.set val id v (te_of rho)) j) (@Map.get val (@Map.set val id v te') j) *)
  destruct (ident_eq id j).
  + subst.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    rewrite !Map.gss; auto.
  + rewrite !Map.gso by congruence.
(* Goal: @eq (option val) (@Map.get val (te_of rho) j) (@Map.get val te' j) *)
    destruct (H j); [congruence |].
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    auto.
Qed.

Lemma subst_obox: forall Delta id v (P: environ -> mpred), subst id (`v) (obox Delta id P) = obox Delta id P.
Proof.
(* Goal: None *)
  intros.
(* Goal: @eq Prop (@isSome unit (@PTree.get unit id (@PTree.set unit i tt idset0))) (@eq ident i id) *)
  apply closed_wrt_subst.
(* Goal: @closed_wrt_vars mpred (@eq ident id) (obox Delta id P) *)
  apply obox_closed_wrt.
Qed.

Lemma subst_odia: forall Delta id v (P: environ -> mpred), subst id (`v) (odia Delta id P) = odia Delta id P.
Proof.
(* Goal: None *)
  intros.
(* Goal: @eq Prop (@isSome unit (@PTree.get unit id (@PTree.set unit i tt idset0))) (@eq ident i id) *)
  apply closed_wrt_subst.
(* Goal: @closed_wrt_vars mpred (@eq ident i) (odia Delta i P) *)
  apply odia_closed_wrt.
Qed.

Definition temp_guard (Delta : tycontext) (i: ident): Prop :=
  (temp_types Delta) ! i <> None.

Lemma obox_closed: forall Delta i P, temp_guard Delta i -> closed_wrt_vars (eq i) P -> obox Delta i P = P.
Proof.
(* Goal: None *)
  intros.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (obox Delta i P) (obox Delta i Q)) (obox Delta i (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) P Q)) *)
  unfold obox.
(* Goal: @eq (forall _ : environ, mpred) (@allp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun v : val => match @PTree.get type i (temp_types Delta) with | Some t => @imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) P) | None => @TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end)) P *)
  hnf in H.
(* Goal: @derives mpred Nveric (P rho) (@exp mpred Nveric val (fun x : val => match @PTree.get type i (temp_types Delta) with | Some t => fun x0 : environ => @andp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) P x0) | None => fun _ : environ => @prop mpred Nveric False end rho)) *)
  destruct ((temp_types Delta) ! i); [| tauto].
(* Goal: @eq (forall _ : environ, mpred) (@allp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun v : val => @imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) P))) P *)
  apply pred_ext.
  + apply (allp_left _ Vundef).
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    rewrite closed_wrt_subst by auto.
(* Goal: @derives mpred Nveric (P rho) (P (env_set rho i (@liftx (LiftEnviron val) v rho))) *)
    apply derives_refl'.
(* Goal: @eq (forall _ : environ, mpred) (@imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t Vundef)) P) P *)
    apply prop_imp, tc_val'_Vundef.
(* Goal: None *)
  + apply allp_right; intros.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    rewrite closed_wrt_subst by auto.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) P (@imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) P) *)
    apply imp_right2.
Qed.

Lemma obox_odia: forall Delta i P, temp_guard Delta i -> obox Delta i (odia Delta i P) = odia Delta i P.
Proof.
(* Goal: None *)
  intros.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  apply obox_closed; auto.
(* Goal: @closed_wrt_vars mpred (@eq ident i) (odia Delta i P) *)
  apply odia_closed_wrt.
Qed.

Lemma obox_K: forall Delta i P Q, P |-- Q -> obox Delta i P |-- obox Delta i Q.
Proof.
(* Goal: None *)
  intros.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) P)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun b : val => @subst mpred id (@eval_expr CS e) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) b) (@eval_expr CS e)))) (@subst mpred id (@liftx (LiftEnviron val) b) P)))) *)
  intro rho.
(* Goal: @eq Prop (@isSome unit (@PTree.get unit id (@PTree.set unit i tt idset0))) (@eq ident i id) *)
  unfold obox, subst.
(* Goal: None *)
  simpl; apply allp_derives; intros.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  destruct ((temp_types Delta) ! i); auto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  apply imp_derives; auto.
Qed.

Lemma obox_T: forall Delta i (P: environ -> mpred),
  temp_guard Delta i ->
  local (tc_environ Delta) && obox Delta i P |-- P.
Proof.
(* Goal: None *)
  intros.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  intro rho; simpl.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (local (tc_environ Delta) rho) (P rho)) (odia Delta i P rho) *)
  unfold local, lift1.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
  normalize.
(* Goal: @derives mpred Nveric (P rho) (odia Delta i P rho) *)
  destruct H0 as [? _].
(* Goal: @derives mpred Nveric (P rho) (odia Delta i P rho) *)
  hnf in H, H0.
(* Goal: @derives mpred Nveric (P rho) (odia Delta i P rho) *)
  specialize (H0 i).
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  unfold obox; simpl.
(* Goal: @derives mpred Nveric (P rho) (@exp mpred Nveric val (fun x : val => match @PTree.get type i (temp_types Delta) with | Some t => fun x0 : environ => @andp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) P x0) | None => fun _ : environ => @prop mpred Nveric False end rho)) *)
  destruct ((temp_types Delta) ! i); [| tauto].
(* Goal: @derives mpred Nveric (P rho) (@exp mpred Nveric val (fun x : val => @andp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) P rho))) *)
  specialize (H0 t eq_refl).
(* Goal: @ex val (fun v : val => and (@eq (option val) (@Map.get val (@Map.set val i x te) j) (@Some val v)) (tc_val' tj v)) *)
  destruct H0 as [v [? ?]].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@allp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun v : val => match @PTree.get type i (temp_types Delta) with | Some t => @imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) Q) | None => @TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end)) (@wand (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) match @PTree.get type i (temp_types Delta) with | Some t => @imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) P) | None => @TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end match @PTree.get type i (temp_types Delta) with | Some t => @imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) P Q)) | None => @TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end) *)
  apply (allp_left _ v).
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  rewrite prop_imp by auto.
(* Goal: @subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho *)
  unfold subst.
(* Goal: @derives mpred Nveric (P rho) (P (env_set rho i (@liftx (LiftEnviron val) v rho))) *)
  apply derives_refl'.
(* Goal: @eq environ (mkEnviron ge ve te) (mkEnviron ge ve (@Map.set val i v te)) *)
  f_equal.
(* Goal: @derives mpred Nveric (P rho) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho) *)
  unfold_lift.
(* Goal: @eq environ rho (env_set rho i v) *)
  destruct rho.
(* Goal: @eq environ (mkEnviron ge ve te) (env_set (mkEnviron ge ve te) i v) *)
  unfold env_set; simpl in *.
(* Goal: @eq environ (mkEnviron ge ve te) (mkEnviron ge ve (@Map.set val i v te)) *)
  f_equal.
(* Goal: @eq tenviron te (@Map.set val i v te) *)
  apply Map.ext; intro j.
(* Goal: @ex val (fun v : val => and (@eq (option val) (@Map.get val (@Map.set val i x te) j) (@Some val v)) (tc_val' tj v)) *)
  destruct (ident_eq i j).
  + subst.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    rewrite Map.gss; auto.
  + rewrite Map.gso by auto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    auto.
Qed.

Lemma odia_D: forall Delta i (P: environ -> mpred),
  temp_guard Delta i ->
  local (tc_environ Delta) && P |-- odia Delta i P.
Proof.
(* Goal: None *)
  intros.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  intro rho; simpl.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (local (tc_environ Delta) rho) (P rho)) (odia Delta i P rho) *)
  unfold local, lift1.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
  normalize.
(* Goal: @derives mpred Nveric (P rho) (odia Delta i P rho) *)
  destruct H0 as [? _].
(* Goal: @derives mpred Nveric (P rho) (odia Delta i P rho) *)
  hnf in H, H0.
(* Goal: @derives mpred Nveric (P rho) (odia Delta i P rho) *)
  specialize (H0 i).
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  unfold odia; simpl.
(* Goal: @derives mpred Nveric (P rho) (@exp mpred Nveric val (fun x : val => match @PTree.get type i (temp_types Delta) with | Some t => fun x0 : environ => @andp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) P x0) | None => fun _ : environ => @prop mpred Nveric False end rho)) *)
  destruct ((temp_types Delta) ! i); [| tauto].
(* Goal: @derives mpred Nveric (P rho) (@exp mpred Nveric val (fun x : val => @andp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) P rho))) *)
  specialize (H0 t eq_refl).
(* Goal: @ex val (fun v : val => and (@eq (option val) (@Map.get val (@Map.set val i x te) j) (@Some val v)) (tc_val' tj v)) *)
  destruct H0 as [v [? ?]].
(* Goal: @derives mpred Nveric (P rho) (@exp mpred Nveric val (fun x : val => @andp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) P rho))) *)
  apply (exp_right v).
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  rewrite prop_true_andp by auto.
(* Goal: @subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho *)
  unfold subst.
(* Goal: @derives mpred Nveric (P rho) (P (env_set rho i (@liftx (LiftEnviron val) v rho))) *)
  apply derives_refl'.
(* Goal: @eq environ (mkEnviron ge ve te) (mkEnviron ge ve (@Map.set val i v te)) *)
  f_equal.
(* Goal: @derives mpred Nveric (P rho) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho) *)
  unfold_lift.
(* Goal: @eq environ rho (env_set rho i v) *)
  destruct rho.
(* Goal: @eq environ (mkEnviron ge ve te) (env_set (mkEnviron ge ve te) i v) *)
  unfold env_set; simpl in *.
(* Goal: @eq environ (mkEnviron ge ve te) (mkEnviron ge ve (@Map.set val i v te)) *)
  f_equal.
(* Goal: @eq tenviron te (@Map.set val i v te) *)
  apply Map.ext; intro j.
(* Goal: @ex val (fun v : val => and (@eq (option val) (@Map.get val (@Map.set val i x te) j) (@Some val v)) (tc_val' tj v)) *)
  destruct (ident_eq i j).
  + subst.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    rewrite Map.gss; auto.
  + rewrite Map.gso by auto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    auto.
Qed.

Lemma odia_derives_EX_subst: forall Delta i P,
  odia Delta i P |-- EX v : val, subst i (` v) P.
Proof.
(* Goal: None *)
  intros.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (odia Delta i P) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun v : val => @subst mpred i (@liftx (LiftEnviron val) v) P)) *)
  unfold odia.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun v : val => match @PTree.get type i (temp_types Delta) with | Some t => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) P) | None => @FF (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun v : val => @subst mpred i (@liftx (LiftEnviron val) v) P)) *)
  apply exp_derives.
(* Goal: forall v : val, @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@allp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun v0 : val => match @PTree.get type i (temp_types Delta) with | Some t => @imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v0)) (@subst mpred i (@liftx (LiftEnviron val) v0) P) | None => @TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end)) (@allp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun v0 : val => match @PTree.get type i (temp_types Delta) with | Some t => @imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v0)) (@subst mpred i (@liftx (LiftEnviron val) v0) Q) | None => @TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end))) match @PTree.get type i (temp_types Delta) with | Some t => @imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) P Q)) | None => @TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end *)
  intros v.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) match @PTree.get type i (temp_types Delta) with | Some t => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) P) | None => @FF (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end (@subst mpred i (@liftx (LiftEnviron val) v) P) *)
  destruct ((temp_types Delta) ! i); [| apply FF_left].
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  apply andp_left2; auto.
Qed.

Lemma obox_left2: forall Delta i P Q,
  temp_guard Delta i ->
  local (tc_environ Delta) && P |-- Q ->  
  local (tc_environ Delta) && obox Delta i P |-- obox Delta i Q.
Proof.
(* Goal: None *)
  intros.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (allp_fun_id Delta) (obox Delta i P))) (obox Delta i Q) *)
  unfold local, lift1 in *.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  intro rho; simpl.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
  normalize.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  unfold obox; simpl.
(* Goal: @derives mpred Nveric (@allp mpred Nveric val (fun x : val => match @PTree.get type i (temp_types Delta) with | Some t => fun x0 : environ => @imp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) P x0) | None => fun _ : environ => @prop mpred Nveric True end rho)) (@allp mpred Nveric val (fun x : val => match @PTree.get type i (temp_types Delta) with | Some t => fun x0 : environ => @imp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) Q x0) | None => fun _ : environ => @prop mpred Nveric True end rho)) *)
  apply allp_derives; intros x.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  destruct ((temp_types Delta) ! i) eqn:?H; auto.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (allp_fun_id Delta rho) (@imp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) P rho))) (@imp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) Q rho)) *)
  rewrite <- imp_andp_adjoint.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
  normalize.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  unfold TT; rewrite prop_imp by auto.
(* Goal: @derives mpred Nveric (P rho) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho) *)
  unfold subst; unfold_lift.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (allp_fun_id Delta rho) (P (env_set rho i x))) (Q (env_set rho i x)) *)
  specialize (H0 (env_set rho i x)).
(* Goal: @derives mpred Nveric (@andp mpred Nveric (allp_fun_id Delta rho) (P (env_set rho i x))) (Q (env_set rho i x)) *)
  simpl in H0.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (allp_fun_id Delta rho) (P (env_set rho i x))) (Q (env_set rho i x)) *)
  assert (tc_environ Delta (env_set rho i x)).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
  {
(* Goal: tc_environ Delta (env_set rho i x) *)
    clear H0.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    destruct rho, H1 as [? [? ?]]; split; [| split]; simpl in *; auto.
(* Goal: typecheck_temp_environ (@Map.set val i x te) (temp_types Delta) *)
    clear H1 H4.
(* Goal: typecheck_temp_environ (@Map.set val i x te) (temp_types Delta) *)
    hnf in H0 |- *.
(* Goal: forall (id : positive) (ty : type) (_ : @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type ty)), @ex val (fun v : val => and (@eq (option val) (@Map.get val (@Map.set val i x te) id) (@Some val v)) (tc_val' ty v)) *)
    intros j tj H1; specialize (H0 j tj H1).
(* Goal: @ex val (fun v : val => and (@eq (option val) (@Map.get val (@Map.set val i x te) j) (@Some val v)) (tc_val' tj v)) *)
    destruct H0 as [v [? ?]].
(* Goal: @ex val (fun v : val => and (@eq (option val) (@Map.get val (@Map.set val i x te) j) (@Some val v)) (tc_val' tj v)) *)
    destruct (ident_eq i j).
    + exists x.
(* Goal: @eq Prop (@isSome unit (@PTree.get unit id (@PTree.set unit i tt idset0))) (@eq ident i id) *)
      subst.
(* Goal: and (@eq (option val) (@Map.get val (@Map.set val j x te) j) (@Some val x)) (tc_val' tj x) *)
      rewrite H2 in H1; inv H1.
(* Goal: and (@eq (option val) (@Map.get val (@Map.set val j x te) j) (@Some val x)) (tc_val' tj x) *)
      rewrite Map.gss.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
      split; auto.
    + exists v.
(* Goal: and (@eq (option val) (@Map.get val (@Map.set val i x te) j) (@Some val v)) (tc_val' tj v) *)
      rewrite Map.gso by auto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
      split; auto.
  }
(* Goal: @derives mpred Nveric (@andp mpred Nveric (allp_fun_id Delta rho) (P (env_set rho i x))) (Q (env_set rho i x)) *)
  normalize in H0.
Qed.

Lemma obox_left2': forall Delta i P Q,
  temp_guard Delta i ->
  local (tc_environ Delta) && (allp_fun_id Delta && P) |-- Q ->  
  local (tc_environ Delta) && (allp_fun_id Delta && obox Delta i P) |-- obox Delta i Q.
Proof.
(* Goal: None *)
  intros.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (allp_fun_id Delta) (obox Delta i P))) (obox Delta i Q) *)
  unfold local, lift1 in *.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  intro rho; simpl.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
  normalize.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  unfold obox; simpl.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (allp_fun_id Delta rho) (@allp mpred Nveric val (fun x : val => match @PTree.get type i (temp_types Delta) with | Some t => fun x0 : environ => @imp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) P x0) | None => fun _ : environ => @prop mpred Nveric True end rho))) (@allp mpred Nveric val (fun x : val => match @PTree.get type i (temp_types Delta) with | Some t => fun x0 : environ => @imp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) Q x0) | None => fun _ : environ => @prop mpred Nveric True end rho)) *)
  apply allp_right; intros x.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (allp_fun_id Delta rho) (@allp mpred Nveric val (fun x : val => match @PTree.get type i (temp_types Delta) with | Some t => fun x0 : environ => @imp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) P x0) | None => fun _ : environ => @prop mpred Nveric True end rho))) (match @PTree.get type i (temp_types Delta) with | Some t => fun x0 : environ => @imp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) Q x0) | None => fun _ : environ => @prop mpred Nveric True end rho) *)
  rewrite andp_comm; apply imp_andp_adjoint.
(* Goal: @derives mpred Nveric (@allp mpred Nveric val (fun x : val => match @PTree.get type i (temp_types Delta) with | Some t => fun x0 : environ => @imp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) P x0) | None => fun _ : environ => @prop mpred Nveric True end rho)) (@imp mpred Nveric (allp_fun_id Delta rho) (match @PTree.get type i (temp_types Delta) with | Some t => fun x0 : environ => @imp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) Q x0) | None => fun _ : environ => @prop mpred Nveric True end rho)) *)
  apply (allp_left _ x).
(* Goal: @derives mpred Nveric (match @PTree.get type i (temp_types Delta) with | Some t => fun x0 : environ => @imp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) P x0) | None => fun _ : environ => @prop mpred Nveric True end rho) (@imp mpred Nveric (allp_fun_id Delta rho) (match @PTree.get type i (temp_types Delta) with | Some t => fun x0 : environ => @imp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) Q x0) | None => fun _ : environ => @prop mpred Nveric True end rho)) *)
  apply imp_andp_adjoint; rewrite andp_comm.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (allp_fun_id Delta rho) (match @PTree.get type i (temp_types Delta) with | Some t => fun x0 : environ => @imp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) P x0) | None => fun _ : environ => @prop mpred Nveric True end rho)) (match @PTree.get type i (temp_types Delta) with | Some t => fun x0 : environ => @imp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) Q x0) | None => fun _ : environ => @prop mpred Nveric True end rho) *)
  destruct ((temp_types Delta) ! i) eqn:?H; [| apply prop_right; auto].
(* Goal: @derives mpred Nveric (@andp mpred Nveric (allp_fun_id Delta rho) (@imp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) P rho))) (@imp mpred Nveric (@prop mpred Nveric (tc_val' t x)) (@subst mpred i (@liftx (LiftEnviron val) x) Q rho)) *)
  rewrite <- imp_andp_adjoint.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
  normalize.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  unfold TT; rewrite prop_imp by auto.
(* Goal: @derives mpred Nveric (P rho) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho) *)
  unfold subst; unfold_lift.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (allp_fun_id Delta rho) (P (env_set rho i x))) (Q (env_set rho i x)) *)
  specialize (H0 (env_set rho i x)).
(* Goal: @derives mpred Nveric (@andp mpred Nveric (allp_fun_id Delta rho) (P (env_set rho i x))) (Q (env_set rho i x)) *)
  simpl in H0.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (allp_fun_id Delta rho) (P (env_set rho i x))) (Q (env_set rho i x)) *)
  assert (tc_environ Delta (env_set rho i x)).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
  {
(* Goal: tc_environ Delta (env_set rho i x) *)
    clear H0.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    destruct rho, H1 as [? [? ?]]; split; [| split]; simpl in *; auto.
(* Goal: typecheck_temp_environ (@Map.set val i x te) (temp_types Delta) *)
    clear H1 H4.
(* Goal: typecheck_temp_environ (@Map.set val i x te) (temp_types Delta) *)
    hnf in H0 |- *.
(* Goal: forall (id : positive) (ty : type) (_ : @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type ty)), @ex val (fun v : val => and (@eq (option val) (@Map.get val (@Map.set val i x te) id) (@Some val v)) (tc_val' ty v)) *)
    intros j tj H1; specialize (H0 j tj H1).
(* Goal: @ex val (fun v : val => and (@eq (option val) (@Map.get val (@Map.set val i x te) j) (@Some val v)) (tc_val' tj v)) *)
    destruct H0 as [v [? ?]].
(* Goal: @ex val (fun v : val => and (@eq (option val) (@Map.get val (@Map.set val i x te) j) (@Some val v)) (tc_val' tj v)) *)
    destruct (ident_eq i j).
    + exists x.
(* Goal: @eq Prop (@isSome unit (@PTree.get unit id (@PTree.set unit i tt idset0))) (@eq ident i id) *)
      subst.
(* Goal: and (@eq (option val) (@Map.get val (@Map.set val j x te) j) (@Some val x)) (tc_val' tj x) *)
      rewrite H2 in H1; inv H1.
(* Goal: and (@eq (option val) (@Map.get val (@Map.set val j x te) j) (@Some val x)) (tc_val' tj x) *)
      rewrite Map.gss.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
      split; auto.
    + exists v.
(* Goal: and (@eq (option val) (@Map.get val (@Map.set val i x te) j) (@Some val v)) (tc_val' tj v) *)
      rewrite Map.gso by auto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
      split; auto.
  }
(* Goal: @derives mpred Nveric (@andp mpred Nveric (allp_fun_id Delta rho) (P (env_set rho i x))) (Q (env_set rho i x)) *)
  normalize in H0.
Qed.

Lemma obox_sepcon: forall Delta i P Q,
  obox Delta i P * obox Delta i Q |-- obox Delta i (P * Q).
Proof.
(* Goal: None *)
  intros.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (obox Delta i P) (obox Delta i Q)) (obox Delta i (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) P Q)) *)
  unfold obox.
(* Goal: or (@eq ident id i) (@eq (option val) (@Map.get val (te_of rho) i) (@Map.get val (@Map.set val id (e rho) (te_of rho)) i)) *)
  apply allp_right.
(* Goal: forall v : val, @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@allp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun v0 : val => match @PTree.get type i (temp_types Delta) with | Some t => @imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v0)) (@subst mpred i (@liftx (LiftEnviron val) v0) P) | None => @TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end)) (@allp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun v0 : val => match @PTree.get type i (temp_types Delta) with | Some t => @imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v0)) (@subst mpred i (@liftx (LiftEnviron val) v0) Q) | None => @TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end))) match @PTree.get type i (temp_types Delta) with | Some t => @imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) P Q)) | None => @TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end *)
  intros v.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) P (@wand (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) P)) *)
  apply wand_sepcon_adjoint.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@allp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun v : val => match @PTree.get type i (temp_types Delta) with | Some t => @imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) Q) | None => @TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end)) (@wand (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) match @PTree.get type i (temp_types Delta) with | Some t => @imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) P) | None => @TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end match @PTree.get type i (temp_types Delta) with | Some t => @imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) P Q)) | None => @TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end) *)
  apply (allp_left _ v).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) P (@wand (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) P)) *)
  apply wand_sepcon_adjoint.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) P (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) P) *)
  rewrite sepcon_comm.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) P (@wand (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) P)) *)
  apply wand_sepcon_adjoint.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@allp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun v : val => match @PTree.get type i (temp_types Delta) with | Some t => @imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) Q) | None => @TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end)) (@wand (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) match @PTree.get type i (temp_types Delta) with | Some t => @imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) P) | None => @TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end match @PTree.get type i (temp_types Delta) with | Some t => @imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) P Q)) | None => @TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end) *)
  apply (allp_left _ v).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) P (@wand (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) P)) *)
  apply wand_sepcon_adjoint.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) P (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) P) *)
  rewrite sepcon_comm.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) match @PTree.get type i (temp_types Delta) with | Some t => @imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) P) | None => @TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end match @PTree.get type i (temp_types Delta) with | Some t => @imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) Q) | None => @TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end) match @PTree.get type i (temp_types Delta) with | Some t => @imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) P Q)) | None => @TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) end *)
  destruct ((temp_types Delta) ! i); [| apply TT_right].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) P)) (@imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) Q))) (@imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (tc_val' t v)) (@subst mpred i (@liftx (LiftEnviron val) v) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) P Q))) *)
  apply imp_andp_adjoint.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
  normalize.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric)) (@subst mpred i (@liftx (LiftEnviron val) v) P)) (@imp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric)) (@subst mpred i (@liftx (LiftEnviron val) v) Q))) (@subst mpred i (@liftx (LiftEnviron val) v) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) P Q)) *)
  unfold TT.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  rewrite !prop_imp by auto.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@subst mpred i (@liftx (LiftEnviron val) v) P) (@subst mpred i (@liftx (LiftEnviron val) v) Q)) (@subst mpred i (@liftx (LiftEnviron val) v) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) P Q)) *)
  rewrite subst_sepcon.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  auto.
Qed.
  
Definition oboxopt Delta ret P :=
  match ret with
  | Some id => obox Delta id P
  | _ => P
  end.

Definition odiaopt Delta ret P :=
  match ret with
  | Some id => odia Delta id P
  | _ => P
  end.

Definition temp_guard_opt (Delta : tycontext) (i: option ident): Prop :=
  match i with
  | Some i => temp_guard Delta i
  | None => True
  end.

Lemma substopt_oboxopt: forall Delta id v (P: environ -> mpred), substopt id (`v) (oboxopt Delta id P) = oboxopt Delta id P.
Proof.
(* Goal: None *)
  intros.
(* Goal: @eq (forall _ : environ, mpred) (@substopt mpred id (@liftx (LiftEnviron val) v) (oboxopt Delta id P)) (oboxopt Delta id P) *)
  destruct id; [| auto].
(* Goal: @eq (forall _ : environ, mpred) (@substopt mpred (@Some ident i) (@liftx (LiftEnviron val) v) (oboxopt Delta (@Some ident i) P)) (oboxopt Delta (@Some ident i) P) *)
  apply subst_obox.
Qed.

Lemma oboxopt_closed: forall Delta i P,
  temp_guard_opt Delta i ->
  closed_wrt_vars (fun id => isSome (match i with Some i' => insert_idset i' idset0 | None => idset0 end) ! id) P ->
  oboxopt Delta i P = P.
Proof.
(* Goal: None *)
  intros.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (oboxopt Delta i P) (oboxopt Delta i Q)) (oboxopt Delta i (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) P Q)) *)
  destruct i.
  + simpl in H0 |- *.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    apply obox_closed; auto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    replace (eq i) with ((fun id : ident => isSome (insert_idset i idset0) ! id)); auto.
(* Goal: @eq (forall _ : ident, Prop) (fun id : ident => @isSome unit (@PTree.get unit id (insert_idset i idset0))) (@eq ident i) *)
    extensionality id.
(* Goal: @eq Prop (@isSome unit (@PTree.get unit id (insert_idset i idset0))) (@eq ident i id) *)
    unfold insert_idset.
(* Goal: @eq Prop (@isSome unit (@PTree.get unit id (@PTree.set unit i tt idset0))) (@eq ident i id) *)
    destruct (ident_eq id i).
(* Goal: @eq Prop (@isSome unit (@PTree.get unit id (@PTree.set unit i tt idset0))) (@eq ident i id) *)
    - subst.
(* Goal: @eq Prop (@isSome unit (@PTree.get unit i (@PTree.set unit i tt idset0))) (@eq ident i i) *)
      rewrite PTree.gss.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
      simpl.
(* Goal: @eq Prop False (@eq ident i id) *)
      apply prop_ext.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
      tauto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    - rewrite PTree.gso by auto.
(* Goal: @eq Prop (@isSome unit (@PTree.get unit id idset0)) (@eq ident i id) *)
      unfold idset0.
(* Goal: @eq Prop (@isSome unit (@PTree.get unit id (PTree.empty unit))) (@eq ident i id) *)
      rewrite PTree.gempty.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
      simpl.
(* Goal: @eq Prop False (@eq ident i id) *)
      assert (i <> id) by congruence.
(* Goal: @eq Prop False (@eq ident i id) *)
      apply prop_ext.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
      tauto.
  + auto.
Qed.

Lemma oboxopt_T: forall Delta i (P: environ -> mpred),
  temp_guard_opt Delta i ->
  local (tc_environ Delta) && oboxopt Delta i P |-- P.
Proof.
(* Goal: None *)
  intros.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) P) (odiaopt Delta i P) *)
  destruct i; [| apply andp_left2, derives_refl].
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  apply obox_T; auto.
Qed.

Lemma odiaopt_D: forall Delta i (P: environ -> mpred),
  temp_guard_opt Delta i ->
  local (tc_environ Delta) && P |-- odiaopt Delta i P.
Proof.
(* Goal: None *)
  intros.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) P) (odiaopt Delta i P) *)
  destruct i; [| apply andp_left2, derives_refl].
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  apply odia_D; auto.
Qed.

Lemma oboxopt_odiaopt: forall Delta i P, temp_guard_opt Delta i -> oboxopt Delta i (odiaopt Delta i P) = odiaopt Delta i P.
Proof.
(* Goal: None *)
  intros.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  destruct i; auto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  apply obox_odia; auto.
Qed.

Lemma oboxopt_K: forall Delta i P Q, P |-- Q -> oboxopt Delta i P |-- oboxopt Delta i Q.
Proof.
(* Goal: None *)
  intros.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) P)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun b : val => @subst mpred id (@eval_expr CS e) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) b) (@eval_expr CS e)))) (@subst mpred id (@liftx (LiftEnviron val) b) P)))) *)
  intro rho.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  destruct i; auto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  apply obox_K; auto.
Qed.

Lemma odiaopt_derives_EX_substopt: forall Delta i P,
  odiaopt Delta i P |-- EX v : val, substopt i (` v) P.
Proof.
(* Goal: None *)
  intros.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (odiaopt Delta i P) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun v : val => @substopt mpred i (@liftx (LiftEnviron val) v) P)) *)
  destruct i; [apply odia_derives_EX_subst |].
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  simpl.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  intros; apply (exp_right Vundef); auto.
Qed.

Lemma oboxopt_left2: forall Delta i P Q,
  temp_guard_opt Delta i ->
  local (tc_environ Delta) && P |-- Q ->  
  local (tc_environ Delta) && oboxopt Delta i P |-- oboxopt Delta i Q.
Proof.
(* Goal: None *)
  intros.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (oboxopt Delta i P)) (oboxopt Delta i Q) *)
  destruct i; [apply obox_left2; auto |].
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  auto.
Qed.

Lemma oboxopt_left2': forall Delta i P Q,
  temp_guard_opt Delta i ->
  local (tc_environ Delta) && (allp_fun_id Delta && P) |-- Q ->  
  local (tc_environ Delta) && (allp_fun_id Delta && oboxopt Delta i P) |-- oboxopt Delta i Q.
Proof.
(* Goal: None *)
  intros.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (allp_fun_id Delta) (oboxopt Delta i P))) (oboxopt Delta i Q) *)
  destruct i; [apply obox_left2'; auto |].
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  auto.
Qed.

Lemma oboxopt_sepcon: forall Delta i P Q,
  oboxopt Delta i P * oboxopt Delta i Q |-- oboxopt Delta i (P * Q).
Proof.
(* Goal: None *)
  intros.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (oboxopt Delta i P) (oboxopt Delta i Q)) (oboxopt Delta i (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) P Q)) *)
  destruct i.
  + apply obox_sepcon.
  + apply derives_refl.
Qed.

Module Type CLIGHT_SEPARATION_HOARE_LOGIC_COMPLETE_CONSEQUENCE.

Declare Module CSHL_Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF.

Import CSHL_Def.

Axiom semax_conseq:
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
  forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall P' (R': ret_assert) P c (R: ret_assert) ,
    local (tc_environ Delta) && ((allp_fun_id Delta) && P) |-- |==> |> FF || P' ->
    local (tc_environ Delta) && ((allp_fun_id Delta) && RA_normal R') |-- |==> |> FF || RA_normal R ->
    local (tc_environ Delta) && ((allp_fun_id Delta) && RA_break R') |-- |==> |> FF || RA_break R ->
    local (tc_environ Delta) && ((allp_fun_id Delta) && RA_continue R') |-- |==> |> FF || RA_continue R ->
    (forall vl, local (tc_environ Delta) && ((allp_fun_id Delta) && RA_return R' vl) |-- |==> |> FF || RA_return R vl) ->
   @semax CS Espec Delta P' c R' -> @semax CS Espec Delta P c R.

End CLIGHT_SEPARATION_HOARE_LOGIC_COMPLETE_CONSEQUENCE.

Module GenCConseqFacts
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (CConseq: CLIGHT_SEPARATION_HOARE_LOGIC_COMPLETE_CONSEQUENCE with Module CSHL_Def := Def).

Import Def.
Import CConseq.

Lemma semax_pre_post_indexed_bupd:
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
  forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
 forall P' (R': ret_assert) P c (R: ret_assert) ,
    local (tc_environ Delta) && P |-- |==> |> FF || P' ->
    local (tc_environ Delta) && RA_normal R' |-- |==> |> FF || RA_normal R ->
    local (tc_environ Delta) && RA_break R' |-- |==> |> FF || RA_break R ->
    local (tc_environ Delta) && RA_continue R' |-- |==> |> FF || RA_continue R ->
    (forall vl, local (tc_environ Delta) && RA_return R' vl |-- |==> |> FF || RA_return R vl) ->
   @semax CS Espec Delta P' c R' -> @semax CS Espec Delta P c R.
Proof.
(* Goal: None *)
  intros.
  eapply semax_conseq; [.. | exact H4]; try intros;
  match goal with
  | |- ?A && (_ && ?B) |-- _ => apply derives_trans with (A && B); [solve_andp | auto]
  end.
Qed.

Lemma semax_pre_post_bupd:
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
  forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
 forall P' (R': ret_assert) P c (R: ret_assert) ,
    local (tc_environ Delta) && P |-- |==> P' ->
    local (tc_environ Delta) && RA_normal R' |-- |==> RA_normal R ->
    local (tc_environ Delta) && RA_break R' |-- |==> RA_break R ->
    local (tc_environ Delta) && RA_continue R' |-- |==> RA_continue R ->
    (forall vl, local (tc_environ Delta) && RA_return R' vl |-- |==> RA_return R vl) ->
   @semax CS Espec Delta P' c R' -> @semax CS Espec Delta P c R.
Proof.
(* Goal: None *)
  intros.
  eapply semax_pre_post_indexed_bupd; [.. | exact H4]; try intros;
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  try apply derives_bupd_derives_bupd0; auto.
Qed.

Lemma semax_pre_indexed_bupd:
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
 forall P' Espec {cs: compspecs} Delta P c R,
     local (tc_environ Delta) && P |-- |==> |> FF || P' ->
     @semax cs Espec Delta P' c R  -> @semax cs Espec Delta P c R.
Proof.
  intros; eapply semax_pre_post_indexed_bupd; eauto;
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) P) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) P) *)
  intros; reduce2derives; apply derives_refl.
Qed.

Lemma semax_post_indexed_bupd:
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
 forall (R': ret_assert) Espec {cs: compspecs} Delta (R: ret_assert) P c,
   local (tc_environ Delta) && RA_normal R' |-- |==> |> FF || RA_normal R ->
   local (tc_environ Delta) && RA_break R' |-- |==> |> FF || RA_break R ->
   local (tc_environ Delta) && RA_continue R' |-- |==> |> FF || RA_continue R ->
   (forall vl, local (tc_environ Delta) && RA_return R' vl |-- |==> |> FF || RA_return R vl) ->
   @semax cs Espec Delta P c R' ->  @semax cs Espec Delta P c R.
Proof.
(* Goal: None *)
  intros; eapply semax_pre_post_indexed_bupd; try eassumption.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (RA_continue Q)) (@bupd (forall _ : environ, mpred) own.gname compcert_rmaps.RML.R.preds (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@LiftBupdSepLog environ mpred own.gname compcert_rmaps.RML.R.preds Nveric Sveric Bveric) (@orp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@FF (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric))) (RA_continue Q))) *)
  apply derives_bupd0_refl.
Qed.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Lemma semax_post''_indexed_bupd: forall R' Espec {cs: compspecs} Delta R P c,
           local (tc_environ Delta) && R' |-- |==> |> FF || RA_normal R ->
      @semax cs Espec Delta P c (normal_ret_assert R') ->
      @semax cs Espec Delta P c R.
(* Goal: None *)
Proof. intros. eapply semax_post_indexed_bupd; eauto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
 simpl RA_normal; auto.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
 simpl RA_break; normalize.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
 simpl RA_continue; normalize.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
 intro vl; simpl RA_return; normalize.
Qed.

Lemma semax_pre_bupd:
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
 forall P' Espec {cs: compspecs} Delta P c R,
     local (tc_environ Delta) && P |-- |==> P' ->
     @semax cs Espec Delta P' c R  -> @semax cs Espec Delta P c R.
Proof.
intros; eapply semax_pre_post_bupd; eauto;
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
intros; apply andp_left2, bupd_intro; auto.
Qed.

Lemma semax_post_bupd:
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
 forall (R': ret_assert) Espec {cs: compspecs} Delta (R: ret_assert) P c,
   local (tc_environ Delta) && RA_normal R' |-- |==> RA_normal R ->
   local (tc_environ Delta) && RA_break R' |-- |==> RA_break R ->
   local (tc_environ Delta) && RA_continue R' |-- |==> RA_continue R ->
   (forall vl, local (tc_environ Delta) && RA_return R' vl |-- |==> RA_return R vl) ->
   @semax cs Espec Delta P c R' ->  @semax cs Espec Delta P c R.
Proof.
(* Goal: None *)
  intros; eapply semax_pre_post_bupd; try eassumption.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) P) (@bupd (forall _ : environ, mpred) own.gname compcert_rmaps.RML.R.preds (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@LiftBupdSepLog environ mpred own.gname compcert_rmaps.RML.R.preds Nveric Sveric Bveric) P) *)
  apply derives_bupd_refl.
Qed.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Lemma semax_post'_bupd: forall R' Espec {cs: compspecs} Delta R P c,
           local (tc_environ Delta) && R' |-- |==> R ->
      @semax cs Espec Delta P c (normal_ret_assert R') ->
      @semax cs Espec Delta P c (normal_ret_assert R).
(* Goal: None *)
Proof. intros. eapply semax_post_bupd; eauto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
 simpl RA_normal; auto.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
 simpl RA_break; normalize.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
 simpl RA_continue; normalize.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
 intro vl; simpl RA_return; normalize.
Qed.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Lemma semax_post''_bupd: forall R' Espec {cs: compspecs} Delta R P c,
           local (tc_environ Delta) && R' |-- |==> RA_normal R ->
      @semax cs Espec Delta P c (normal_ret_assert R') ->
      @semax cs Espec Delta P c R.
(* Goal: None *)
Proof. intros. eapply semax_post_bupd; eauto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
 simpl RA_normal; auto.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
 simpl RA_break; normalize.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
 simpl RA_continue; normalize.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
 intro vl; simpl RA_return; normalize.
Qed.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Lemma semax_pre_post'_bupd: forall P' R' Espec {cs: compspecs} Delta R P c,
      local (tc_environ Delta) && P |-- |==> P' ->
      local (tc_environ Delta) && R' |-- |==> R ->
      @semax cs Espec Delta P' c (normal_ret_assert R') ->
      @semax cs Espec Delta P c (normal_ret_assert R).
(* Goal: None *)
Proof. intros.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
 eapply semax_pre_bupd; eauto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
 eapply semax_post'_bupd; eauto.
Qed.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Lemma semax_pre_post''_bupd: forall P' R' Espec {cs: compspecs} Delta R P c,
      local (tc_environ Delta) && P |-- |==> P' ->
      local (tc_environ Delta) && R' |-- |==> RA_normal R ->
      @semax cs Espec Delta P' c (normal_ret_assert R') ->
      @semax cs Espec Delta P c R.
(* Goal: None *)
Proof. intros.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
 eapply semax_pre_bupd; eauto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
 eapply semax_post''_bupd; eauto.
Qed.

End GenCConseqFacts.

Module Type CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE.

Declare Module CSHL_Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF.

Import CSHL_Def.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Axiom semax_pre_post : forall {Espec: OracleKind}{CS: compspecs},
 forall P' (R': ret_assert) Delta P c (R: ret_assert) ,
    (local (tc_environ Delta) && P |-- P') ->
    local (tc_environ Delta) && RA_normal R' |-- RA_normal R ->
    local (tc_environ Delta) && RA_break R' |-- RA_break R ->
    local (tc_environ Delta) && RA_continue R' |-- RA_continue R ->
    (forall vl, local (tc_environ Delta) && RA_return R' vl |-- RA_return R vl) ->
   @semax CS Espec Delta P' c R' -> @semax CS Espec Delta P c R.

End CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE.

Module GenConseq
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (CConseq: CLIGHT_SEPARATION_HOARE_LOGIC_COMPLETE_CONSEQUENCE with Module CSHL_Def := Def): CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE with Module CSHL_Def := Def.

Module CSHL_Def := Def.
Module CConseqFacts := GenCConseqFacts (Def) (CConseq).
Import CSHL_Def.
Import CConseq.
Import CConseqFacts.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Lemma semax_pre_post : forall {Espec: OracleKind}{CS: compspecs},
 forall P' (R': ret_assert) Delta P c (R: ret_assert) ,
    (local (tc_environ Delta) && P |-- P') ->
    local (tc_environ Delta) && RA_normal R' |-- RA_normal R ->
    local (tc_environ Delta) && RA_break R' |-- RA_break R ->
    local (tc_environ Delta) && RA_continue R' |-- RA_continue R ->
    (forall vl, local (tc_environ Delta) && RA_return R' vl |-- RA_return R vl) ->
   @semax CS Espec Delta P' c R' -> @semax CS Espec Delta P c R.
Proof.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  intros; eapply semax_pre_post_bupd; eauto; intros; eapply derives_trans, bupd_intro; auto.
Qed.

End GenConseq.

Module GenConseqFacts
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (Conseq: CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE with Module CSHL_Def := Def).

Import Def.
Import Conseq.

(* Copied from canon.v *)

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Lemma semax_pre: forall {Espec: OracleKind}{cs: compspecs},
 forall P' Delta P c R,
     local (tc_environ Delta) && P |-- P' ->
     @semax cs Espec Delta P' c R  -> @semax cs Espec Delta P c R.
Proof.
  intros; eapply semax_pre_post; eauto;
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) P) P *)
  intros; apply ENTAIL_refl.
Qed.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Lemma semax_pre_simple: forall {Espec: OracleKind}{cs: compspecs},
 forall P' Delta P c R,
     P |-- P' ->
     @semax cs Espec Delta P' c R  -> @semax cs Espec Delta P c R.
Proof.
(* Goal: None *)
intros; eapply semax_pre; [| eauto].
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
apply andp_left2; auto.
Qed.

Lemma semax_post:
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
 forall (R': ret_assert) Espec {cs: compspecs} Delta (R: ret_assert) P c,
   local (tc_environ Delta) && RA_normal R' |-- RA_normal R ->
   local (tc_environ Delta) && RA_break R' |-- RA_break R ->
   local (tc_environ Delta) && RA_continue R' |-- RA_continue R ->
   (forall vl, local (tc_environ Delta) && RA_return R' vl |-- RA_return R vl) ->
   @semax cs Espec Delta P c R' ->  @semax cs Espec Delta P c R.
Proof.
(* Goal: None *)
intros; eapply semax_pre_post; try eassumption.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) P) P *)
apply ENTAIL_refl.
Qed.

Lemma semax_post_simple:
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
 forall (R': ret_assert) Espec {cs: compspecs} Delta (R: ret_assert) P c,
   RA_normal R' |-- RA_normal R ->
   RA_break R' |-- RA_break R ->
   RA_continue R' |-- RA_continue R ->
   (forall vl, RA_return R' vl |-- RA_return R vl) ->
   @semax cs Espec Delta P c R' ->  @semax cs Espec Delta P c R.
Proof.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  intros; eapply semax_post; [.. | eauto]; intros; reduce2derives; auto.
Qed.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Lemma semax_post': forall R' Espec {cs: compspecs} Delta R P c,
           local (tc_environ Delta) && R' |-- R ->
      @semax cs Espec Delta P c (normal_ret_assert R') ->
      @semax cs Espec Delta P c (normal_ret_assert R).
(* Goal: None *)
Proof. intros. eapply semax_post; eauto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
 simpl RA_normal; auto.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
 simpl RA_break; normalize.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
 simpl RA_continue; normalize.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
 intro vl; simpl RA_return; normalize.
Qed.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Lemma semax_pre_post': forall P' R' Espec {cs: compspecs} Delta R P c,
      local (tc_environ Delta) && P |-- P' ->
      local (tc_environ Delta) && R' |-- R ->
      @semax cs Espec Delta P' c (normal_ret_assert R') ->
      @semax cs Espec Delta P c (normal_ret_assert R).
(* Goal: None *)
Proof. intros.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
 eapply semax_pre; eauto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
 eapply semax_post'; eauto.
Qed.

(* Copied from canon.v end. *)

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Lemma semax_post'': forall R' Espec {cs: compspecs} Delta R P c,
           local (tc_environ Delta) && R' |-- RA_normal R ->
      @semax cs Espec Delta P c (normal_ret_assert R') ->
      @semax cs Espec Delta P c R.
(* Goal: None *)
Proof. intros. eapply semax_post; eauto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
 simpl RA_normal; auto.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
 simpl RA_break; normalize.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
 simpl RA_continue; normalize.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
 intro vl; simpl RA_return; normalize.
Qed.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Lemma semax_pre_post'': forall P' R' Espec {cs: compspecs} Delta R P c,
      local (tc_environ Delta) && P |-- P' ->
      local (tc_environ Delta) && R' |-- RA_normal R ->
      @semax cs Espec Delta P' c (normal_ret_assert R') ->
      @semax cs Espec Delta P c R.
(* Goal: None *)
Proof. intros.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
 eapply semax_pre; eauto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
 eapply semax_post''; eauto.
Qed.

End GenConseqFacts.

Module Type CLIGHT_SEPARATION_HOARE_LOGIC_EXTRACTION.

Declare Module CSHL_Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF.

Import CSHL_Def.

Axiom semax_extract_exists:
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
  forall {CS: compspecs} {Espec: OracleKind},
  forall (A : Type)  (P : A -> environ->mpred) c (Delta: tycontext) (R: ret_assert),
  (forall x, @semax CS Espec Delta (P x) c R) ->
   @semax CS Espec Delta (EX x:A, P x) c R.

End CLIGHT_SEPARATION_HOARE_LOGIC_EXTRACTION.

Module GenExtrFacts
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (Conseq: CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE with Module CSHL_Def := Def)
       (Extr: CLIGHT_SEPARATION_HOARE_LOGIC_EXTRACTION with Module CSHL_Def := Def).

Module ConseqFacts := GenConseqFacts (Def) (Conseq).
Import Def.
Import Conseq.
Import ConseqFacts.
Import Extr.

Lemma semax_extract_prop:
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
  forall {CS: compspecs} {Espec: OracleKind},
  forall Delta (PP: Prop) P c Q,
           (PP -> @semax CS Espec Delta P c Q) ->
           @semax CS Espec Delta (!!PP && P) c Q.
Proof.
(* Goal: None *)
  intros.
(* Goal: None *)
  eapply semax_pre with (EX H: PP, P).
  + apply andp_left2.
(* Goal: None *)
    apply derives_extract_prop; intros.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) P (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) PP (fun _ : PP => P)) *)
    apply (exp_right H0), derives_refl.
  + apply semax_extract_exists, H.
Qed.

Lemma semax_orp:
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
  forall {CS: compspecs} {Espec: OracleKind},
  forall Delta P1 P2 c Q,
           @semax CS Espec Delta P1 c Q ->
           @semax CS Espec Delta P2 c Q ->
           @semax CS Espec Delta (P1 || P2) c Q.
Proof.
(* Goal: None *)
  intros.
(* Goal: None *)
  eapply semax_pre with (EX b: bool, if b then P1 else P2).
  + apply andp_left2.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@orp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) P1 P2) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) bool (fun b : bool => if b then P1 else P2)) *)
    apply orp_left.
    - apply (exp_right true), derives_refl.
    - apply (exp_right false), derives_refl.
  + apply semax_extract_exists.
(* Goal: None *)
    intros.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    destruct x; auto.
Qed.

End GenExtrFacts.

Module GenIExtrFacts
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (CConseq: CLIGHT_SEPARATION_HOARE_LOGIC_COMPLETE_CONSEQUENCE with Module CSHL_Def := Def)
       (Extr: CLIGHT_SEPARATION_HOARE_LOGIC_EXTRACTION with Module CSHL_Def := Def).

Module Conseq := GenConseq (Def) (CConseq).
Module CConseqFacts := GenCConseqFacts (Def) (CConseq).
Module ExtrFacts := GenExtrFacts (Def) (Conseq) (Extr).
Import Def.
Import CConseq.
Import CConseqFacts.
Import Extr.
Import ExtrFacts.

Lemma semax_extract_later_prop:
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
  forall {CS: compspecs} {Espec: OracleKind},
  forall Delta (PP: Prop) P c Q,
           (PP -> @semax CS Espec Delta P c Q) ->
           @semax CS Espec Delta ((|> !!PP) && P) c Q.
Proof.
(* Goal: None *)
  intros.
(* Goal: None *)
  apply semax_extract_prop in H.
(* Goal: None *)
  eapply semax_pre_post_indexed_bupd; [.. | exact H].
  + apply andp_left2.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) PP)) P) (@bupd (forall _ : environ, mpred) own.gname compcert_rmaps.RML.R.preds (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@LiftBupdSepLog environ mpred own.gname compcert_rmaps.RML.R.preds Nveric Sveric Bveric) (@orp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@FF (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) PP) P))) *)
    eapply derives_trans; [| apply bupd_intro].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) PP)) P) (@orp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@FF (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) PP) P)) *)
    rewrite orp_comm, distrib_andp_orp.
(* Goal: or (@eq ident id i) (@eq (option val) (@Map.get val (te_of rho) i) (@Map.get val (@Map.set val id (e rho) (te_of rho)) i)) *)
    apply andp_right.
    - apply andp_left1.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) PP)) (@orp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) PP) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@FF (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric)))) *)
      apply later_prop.
    - apply orp_right1.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P))) *)
      solve_andp.
  + apply derives_bupd0_refl.
  + apply derives_bupd0_refl.
  + apply derives_bupd0_refl.
  + intros; apply derives_bupd0_refl.
Qed.

End GenIExtrFacts.

Module Type CLIGHT_SEPARATION_HOARE_LOGIC_STORE_FORWARD.

Declare Module CSHL_Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF.

Import CSHL_Def.

Axiom semax_store_forward:
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
  forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
 forall e1 e2 sh P,
   writable_share sh ->
   @semax CS Espec Delta
          (|> ( (tc_lvalue Delta e1) &&  (tc_expr Delta (Ecast e2 (typeof e1)))  &&
             (`(mapsto_ sh (typeof e1)) (eval_lvalue e1) * P)))
          (Sassign e1 e2)
          (normal_ret_assert
             (`(mapsto sh (typeof e1)) (eval_lvalue e1) (`force_val (`(sem_cast (typeof e2) (typeof e1)) (eval_expr e2))) * P)).

End CLIGHT_SEPARATION_HOARE_LOGIC_STORE_FORWARD.

Module Type CLIGHT_SEPARATION_HOARE_LOGIC_STORE_BACKWARD.

Declare Module CSHL_Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF.

Import CSHL_Def.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Axiom semax_store_backward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext) e1 e2 P,
   @semax CS Espec Delta
          (EX sh: share, !! writable_share sh && |> ( (tc_lvalue Delta e1) &&  (tc_expr Delta (Ecast e2 (typeof e1)))  &&
             ((`(mapsto_ sh (typeof e1)) (eval_lvalue e1)) * (`(mapsto sh (typeof e1)) (eval_lvalue e1) (`force_val (`(sem_cast (typeof e2) (typeof e1)) (eval_expr e2))) -* P))))
          (Sassign e1 e2)
          (normal_ret_assert P).

End CLIGHT_SEPARATION_HOARE_LOGIC_STORE_BACKWARD.

Module StoreF2B
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (Conseq: CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE with Module CSHL_Def := Def)
       (Extr: CLIGHT_SEPARATION_HOARE_LOGIC_EXTRACTION with Module CSHL_Def := Def)
       (StoreF: CLIGHT_SEPARATION_HOARE_LOGIC_STORE_FORWARD with Module CSHL_Def := Def):
       CLIGHT_SEPARATION_HOARE_LOGIC_STORE_BACKWARD with Module CSHL_Def := Def.

Module CSHL_Def := Def.
Module ConseqFacts := GenConseqFacts (Def) (Conseq).
Module ExtrFacts := GenExtrFacts (Def) (Conseq) (Extr).
Import Def.
Import Conseq.
Import ConseqFacts.
Import Extr.
Import ExtrFacts.
Import StoreF.
  
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Theorem semax_store_backward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext) e1 e2 P,
   @semax CS Espec Delta
          (EX sh: share, !! writable_share sh && |> ( (tc_lvalue Delta e1) &&  (tc_expr Delta (Ecast e2 (typeof e1)))  &&
             ((`(mapsto_ sh (typeof e1)) (eval_lvalue e1)) * (`(mapsto sh (typeof e1)) (eval_lvalue e1) (`force_val (`(sem_cast (typeof e2) (typeof e1)) (eval_expr e2))) -* P))))
          (Sassign e1 e2)
          (normal_ret_assert P).
Proof.
(* Goal: None *)
  intros.
(* Goal: None *)
  eapply semax_post'; [.. | eapply (semax_extract_exists _ _ _ _ (normal_ret_assert P))].
  + apply andp_left2.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) P P *)
    change (RA_normal (existential_ret_assert (fun _ : share => normal_ret_assert P))) with (EX _: share, P).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) P) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) P) *)
    apply derives_refl.
  + intros sh.
(* Goal: None *)
    apply semax_extract_prop; intro SH.
(* Goal: None *)
    eapply semax_post'; [.. | eapply semax_store_forward; auto].
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@tc_temp_id id (typeof e) CS Delta e rho) (@andp mpred Nveric (@prop mpred Nveric (@eq environ (env_set rho id (eval_id id rho)) rho)) (P rho))) (@andp mpred Nveric (@prop mpred Nveric (@eq val (@eval_expr CS e rho) (@eval_expr CS e (env_set rho id (eval_id id rho))))) (P (env_set rho id (eval_id id rho)))) *)
    apply andp_left2.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow (option val) (LiftEnviron val)) force_val (@liftx (Tarrow val (LiftEnviron (option val))) (sem_cast (typeof e2) (typeof e1)) (@eval_expr CS e2)))) (@wand (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow (option val) (LiftEnviron val)) force_val (@liftx (Tarrow val (LiftEnviron (option val))) (sem_cast (typeof e2) (typeof e1)) (@eval_expr CS e2)))) P)) P *)
    apply modus_ponens_wand.
Qed.

End StoreF2B.

Module StoreB2F
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (Conseq: CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE with Module CSHL_Def := Def)
       (StoreB: CLIGHT_SEPARATION_HOARE_LOGIC_STORE_BACKWARD with Module CSHL_Def := Def):
       CLIGHT_SEPARATION_HOARE_LOGIC_STORE_FORWARD with Module CSHL_Def := Def.

Module CSHL_Def := Def.
Module ConseqFacts := GenConseqFacts (Def) (Conseq).
Import Def.
Import Conseq.
Import ConseqFacts.
Import StoreB.

Theorem semax_store_forward:
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
  forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
 forall e1 e2 sh P,
   writable_share sh ->
   @semax CS Espec Delta
          (|> ( (tc_lvalue Delta e1) &&  (tc_expr Delta (Ecast e2 (typeof e1)))  &&
             (`(mapsto_ sh (typeof e1)) (eval_lvalue e1) * P)))
          (Sassign e1 e2)
          (normal_ret_assert
             (`(mapsto sh (typeof e1)) (eval_lvalue e1) (`force_val (`(sem_cast (typeof e2) (typeof e1)) (eval_expr e2))) * P)).
Proof.
(* Goal: None *)
  intros.
(* Goal: None *)
  eapply semax_pre; [| apply semax_store_backward].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) P))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) share (fun sh : share => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) expr (fun e2 : expr => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) type (fun t2 : type => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun v3 : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (and (@eq expr (Ecast e1 t1) (Ecast e2 t2)) (and (@eq (option type) (typeof_temp Delta id) (@Some type t2)) (and (@eq bool (cast_pointer_to_bool (typeof e2) t2) false) (readable_share sh))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e2) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t2) (@liftx (LiftEnviron val) (eval_cast (typeof e2) t2 v3))))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e2)) (@eval_lvalue CS e2) (@liftx (LiftEnviron val) v3)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@liftx (LiftEnviron val) (force_val (sem_cast (typeof e2) t2 v3))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))))))))) *)
  apply (exp_right sh).
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
  normalize.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@tc_temp_id id (typeof e) CS Delta e rho) (@andp mpred Nveric (@prop mpred Nveric (@eq environ (env_set rho id (eval_id id rho)) rho)) (P rho))) (@andp mpred Nveric (@prop mpred Nveric (@eq val (@eval_expr CS e rho) (@eval_expr CS e (env_set rho id (eval_id id rho))))) (P (env_set rho id (eval_id id rho)))) *)
  apply andp_left2.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (@tc_expr CS Delta (Ecast e2 (typeof e1)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh (typeof e1)) (@eval_lvalue CS e1)) P))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (@tc_expr CS Delta (Ecast e2 (typeof e1)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh (typeof e1)) (@eval_lvalue CS e1)) (@wand (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) P))))) *)
  apply later_derives.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  apply andp_derives; auto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  apply sepcon_derives; auto.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) P (@wand (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) P)) *)
  apply wand_sepcon_adjoint.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) P (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) P) *)
  rewrite sepcon_comm.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) P) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) P) *)
  apply derives_refl.
Qed.

End StoreB2F.

Module Type CLIGHT_SEPARATION_HOARE_LOGIC_CALL_FORWARD.

Declare Module CSHL_Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF.

Import CSHL_Def.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Axiom semax_call_forward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
    forall A P Q NEP NEQ ts x (F: environ -> mpred) ret argsig retsig cc a bl,
           Cop.classify_fun (typeof a) =
           Cop.fun_case_f (type_of_params argsig) retsig cc ->
           (retsig = Tvoid -> ret = None) ->
          tc_fn_return Delta ret retsig ->
  @semax CS Espec Delta
          ((|>((tc_expr Delta a) && (tc_exprlist Delta (snd (split argsig)) bl)))  &&
         (`(func_ptr (mk_funspec  (argsig,retsig) cc A P Q NEP NEQ)) (eval_expr a) &&
          |>(F * `(P ts x: environ -> mpred) (make_args' (argsig,retsig) (eval_exprlist (snd (split argsig)) bl)))))
         (Scall ret a bl)
         (normal_ret_assert
            (EX old:val, substopt ret (`old) F * maybe_retval (Q ts x) retsig ret)).

End CLIGHT_SEPARATION_HOARE_LOGIC_CALL_FORWARD.

Module Type CLIGHT_SEPARATION_HOARE_LOGIC_CALL_BACKWARD.

Declare Module CSHL_Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF.

Import CSHL_Def.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Axiom semax_call_backward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
    forall ret a bl R,
  @semax CS Espec Delta
         (EX argsig: _, EX retsig: _, EX cc: _,
          EX A: _, EX P: _, EX Q: _, EX NEP: _, EX NEQ: _, EX ts: _, EX x: _,
         !! (Cop.classify_fun (typeof a) =
             Cop.fun_case_f (type_of_params argsig) retsig cc /\
             (retsig = Tvoid -> ret = None) /\
             tc_fn_return Delta ret retsig) &&
          (|>((tc_expr Delta a) && (tc_exprlist Delta (snd (split argsig)) bl)))  &&
         `(func_ptr (mk_funspec  (argsig,retsig) cc A P Q NEP NEQ)) (eval_expr a) &&
          |>((`(P ts x: environ -> mpred) (make_args' (argsig,retsig) (eval_exprlist (snd (split argsig)) bl))) * oboxopt Delta ret (maybe_retval (Q ts x) retsig ret -* R)))
         (Scall ret a bl)
         (normal_ret_assert R).

End CLIGHT_SEPARATION_HOARE_LOGIC_CALL_BACKWARD.

Module CallF2B
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (Conseq: CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE with Module CSHL_Def := Def)
       (Extr: CLIGHT_SEPARATION_HOARE_LOGIC_EXTRACTION with Module CSHL_Def := Def)
       (CallF: CLIGHT_SEPARATION_HOARE_LOGIC_CALL_FORWARD with Module CSHL_Def := Def):
       CLIGHT_SEPARATION_HOARE_LOGIC_CALL_BACKWARD with Module CSHL_Def := Def.

Module CSHL_Def := Def.
Module ConseqFacts := GenConseqFacts (Def) (Conseq).
Module ExtrFacts := GenExtrFacts (Def) (Conseq) (Extr).
Import Def.
Import Conseq.
Import ConseqFacts.
Import Extr.
Import ExtrFacts.
Import CallF.
  
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Theorem semax_call_backward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
    forall ret a bl R,
  @semax CS Espec Delta
         (EX argsig: _, EX retsig: _, EX cc: _,
          EX A: _, EX P: _, EX Q: _, EX NEP: _, EX NEQ: _, EX ts: _, EX x: _,
         !! (Cop.classify_fun (typeof a) =
             Cop.fun_case_f (type_of_params argsig) retsig cc /\
             (retsig = Tvoid -> ret = None) /\
             tc_fn_return Delta ret retsig) &&
          (|>((tc_expr Delta a) && (tc_exprlist Delta (snd (split argsig)) bl)))  &&
         `(func_ptr (mk_funspec  (argsig,retsig) cc A P Q NEP NEQ)) (eval_expr a) &&
          |>((`(P ts x: environ -> mpred) (make_args' (argsig,retsig) (eval_exprlist (snd (split argsig)) bl))) * oboxopt Delta ret (maybe_retval (Q ts x) retsig ret -* R)))
         (Scall ret a bl)
         (normal_ret_assert R).
Proof.
(* Goal: None *)
  intros.
  apply semax_extract_exists; intro argsig.
  apply semax_extract_exists; intro retsig.
  apply semax_extract_exists; intro cc.
  apply semax_extract_exists; intro A.
  apply semax_extract_exists; intro P.
  apply semax_extract_exists; intro Q.
  apply semax_extract_exists; intro NEP.
  apply semax_extract_exists; intro NEQ.
  apply semax_extract_exists; intro ts.
  apply semax_extract_exists; intro x.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@andp mpred Nveric (@tc_temp_id id (typeof e) CS Delta e rho) (@prop mpred Nveric (@eq environ (env_set rho id (eval_id id rho)) rho)))) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@eq val (@eval_expr CS e rho) (@eval_expr CS e (env_set rho id (eval_id id rho))))) (P (env_set rho id (eval_id id rho)))) *)
  rewrite !andp_assoc.
(* Goal: None *)
  apply semax_extract_prop; intros [? [? ?]].
  eapply semax_pre_post'; [.. | apply semax_call_forward; auto].
  + apply andp_left2.
    apply andp_derives; [apply derives_refl |].
    apply andp_derives; [apply derives_refl |].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (@tc_expr CS Delta (Ecast e2 (typeof e1)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh (typeof e1)) (@eval_lvalue CS e1)) P))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (@tc_expr CS Delta (Ecast e2 (typeof e1)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh (typeof e1)) (@eval_lvalue CS e1)) (@wand (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) P))))) *)
    apply later_derives.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) P (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) P) *)
    rewrite sepcon_comm.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) P) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) P) *)
    apply derives_refl.
  + unfold RA_normal, normal_ret_assert.
    rewrite <- exp_sepcon1.
    rewrite <- corable_andp_sepcon1 by (intro; apply corable_prop).
    rewrite wand_sepcon_adjoint.
    rewrite exp_andp2; apply exp_left; intros old.
    rewrite substopt_oboxopt.
    apply oboxopt_T.
    destruct ret; hnf in H1 |- *; [destruct ((temp_types Delta) ! i) |]; auto; congruence.
  + auto.
  + auto.
  + auto.
Qed.

End CallF2B.

Module CallB2F
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (Conseq: CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE with Module CSHL_Def := Def)
       (CallB: CLIGHT_SEPARATION_HOARE_LOGIC_CALL_BACKWARD with Module CSHL_Def := Def):
       CLIGHT_SEPARATION_HOARE_LOGIC_CALL_FORWARD with Module CSHL_Def := Def.

Module CSHL_Def := Def.
Module ConseqFacts := GenConseqFacts (Def) (Conseq).
Import Def.
Import Conseq.
Import ConseqFacts.
Import CallB.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Theorem semax_call_forward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
    forall A P Q NEP NEQ ts x (F: environ -> mpred) ret argsig retsig cc a bl,
           Cop.classify_fun (typeof a) =
           Cop.fun_case_f (type_of_params argsig) retsig cc ->
           (retsig = Tvoid -> ret = None) ->
          tc_fn_return Delta ret retsig ->
  @semax CS Espec Delta
          ((|>((tc_expr Delta a) && (tc_exprlist Delta (snd (split argsig)) bl)))  &&
         (`(func_ptr (mk_funspec  (argsig,retsig) cc A P Q NEP NEQ)) (eval_expr a) &&
          |>(F * `(P ts x: environ -> mpred) (make_args' (argsig,retsig) (eval_exprlist (snd (split argsig)) bl)))))
         (Scall ret a bl)
         (normal_ret_assert
            (EX old:val, substopt ret (`old) F * maybe_retval (Q ts x) retsig ret)).
Proof.
(* Goal: None *)
  intros.
  eapply semax_pre; [| apply semax_call_backward].
  apply (exp_right argsig), (exp_right retsig), (exp_right cc), (exp_right A), (exp_right P), (exp_right Q), (exp_right NEP), (exp_right NEQ), (exp_right ts), (exp_right x).
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@andp mpred Nveric (@tc_temp_id id (typeof e) CS Delta e rho) (@prop mpred Nveric (@eq environ (env_set rho id (eval_id id rho)) rho)))) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@eq val (@eval_expr CS e rho) (@eval_expr CS e (env_set rho id (eval_id id rho))))) (P (env_set rho id (eval_id id rho)))) *)
  rewrite !andp_assoc.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) P))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (and (@eq expr (Ecast e1 t1) (Ecast e1 t1)) (and (@eq (option type) (typeof_temp Delta id) (@Some type t1)) (and (@eq bool (cast_pointer_to_bool (typeof e1) t1) false) (readable_share sh))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (LiftEnviron val) v2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@liftx (LiftEnviron val) (force_val (sem_cast (typeof e1) t1 v2))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))))) *)
  apply andp_right; [apply prop_right; auto |].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) P)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS e)))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))) *)
  apply andp_right; [solve_andp |].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) P)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS e)))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))) *)
  apply andp_right; [solve_andp |].
  rewrite andp_comm, imp_andp_adjoint.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@tc_temp_id id (typeof e) CS Delta e rho) (@andp mpred Nveric (@prop mpred Nveric (@eq environ (env_set rho id (eval_id id rho)) rho)) (P rho))) (@andp mpred Nveric (@prop mpred Nveric (@eq val (@eval_expr CS e rho) (@eval_expr CS e (env_set rho id (eval_id id rho))))) (P (env_set rho id (eval_id id rho)))) *)
  apply andp_left2.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@tc_temp_id id (typeof e) CS Delta e rho) (@andp mpred Nveric (@prop mpred Nveric (@eq environ (env_set rho id (eval_id id rho)) rho)) (P rho))) (@andp mpred Nveric (@prop mpred Nveric (@eq val (@eval_expr CS e rho) (@eval_expr CS e (env_set rho id (eval_id id rho))))) (P (env_set rho id (eval_id id rho)))) *)
  apply andp_left2.
  rewrite <- imp_andp_adjoint, andp_comm.
  apply later_left2.
  rewrite <- corable_andp_sepcon1 by (intro; apply corable_prop).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) P (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (Tarrow val (LiftEnviron val)) (@Basics.compose val (option val) val force_val (sem_cast (typeof e2) (typeof e1))) (@eval_expr CS e2))) P) *)
  rewrite sepcon_comm.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  apply sepcon_derives; auto.
  eapply derives_trans; [apply (odiaopt_D _ ret) |].
    1: destruct ret; hnf in H1 |- *; [destruct ((temp_types Delta) ! i) |]; auto; congruence.
  rewrite <- oboxopt_odiaopt.
    2: destruct ret; hnf in H1 |- *; [destruct ((temp_types Delta) ! i) |]; auto; congruence.
  apply oboxopt_K.
  rewrite <- wand_sepcon_adjoint.
  rewrite <- exp_sepcon1.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  apply sepcon_derives; auto.
  apply odiaopt_derives_EX_substopt.
Qed.

End CallB2F.

Module Type CLIGHT_SEPARATION_HOARE_LOGIC_SET_FORWARD.

Declare Module CSHL_Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF.

Import CSHL_Def.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Axiom semax_set_forward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall (P: environ->mpred) id e,
    @semax CS Espec Delta
        (|> ( (tc_expr Delta e) &&
             (tc_temp_id id (typeof e) Delta e) &&
          P))
          (Sset id e)
        (normal_ret_assert
          (EX old:val, local (`eq (eval_id id) (subst id (`old) (eval_expr e))) &&
                            subst id (`old) P)).

End CLIGHT_SEPARATION_HOARE_LOGIC_SET_FORWARD.

Module Type CLIGHT_SEPARATION_HOARE_LOGIC_SET_BACKWARD.

Declare Module CSHL_Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF.

Import CSHL_Def.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Axiom semax_set_backward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall (P: environ->mpred) id e,
    @semax CS Espec Delta
        (|> ( (tc_expr Delta e) &&
             (tc_temp_id id (typeof e) Delta e) &&
             subst id (eval_expr e) P))
          (Sset id e) (normal_ret_assert P).

End CLIGHT_SEPARATION_HOARE_LOGIC_SET_BACKWARD.

Module Type CLIGHT_SEPARATION_HOARE_LOGIC_LOAD_FORWARD.

Declare Module CSHL_Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF.

Import CSHL_Def.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Axiom semax_load_forward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall  sh id P e1 t2 (v2: val),
    typeof_temp Delta id = Some t2 ->
    is_neutral_cast (typeof e1) t2 = true ->
    readable_share sh ->
    local (tc_environ Delta) && P |-- `(mapsto sh (typeof e1)) (eval_lvalue e1) (` v2) * TT ->
    @semax CS Espec Delta
       (|> ( (tc_lvalue Delta e1) &&
       local (`(tc_val (typeof e1) v2)) &&
          P))
       (Sset id e1)
       (normal_ret_assert (EX old:val, local (`eq (eval_id id) (` v2)) &&
                                          (subst id (`old) P))).

End CLIGHT_SEPARATION_HOARE_LOGIC_LOAD_FORWARD.

Module Type CLIGHT_SEPARATION_HOARE_LOGIC_LOAD_BACKWARD.

Declare Module CSHL_Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF.

Import CSHL_Def.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Axiom semax_load_backward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall (P: environ->mpred) id e1,
    @semax CS Espec Delta
        (EX sh: share, EX t2: type, EX v2: val,
              !! (typeof_temp Delta id = Some t2 /\
                  is_neutral_cast (typeof e1) t2 = true /\
                  readable_share sh) &&
         |> ( (tc_lvalue Delta e1) &&
              local (`(tc_val (typeof e1) v2)) &&
              (`(mapsto sh (typeof e1)) (eval_lvalue e1) (`v2) * TT) &&
              subst id (`v2) P))
        (Sset id e1) (normal_ret_assert P).

End CLIGHT_SEPARATION_HOARE_LOGIC_LOAD_BACKWARD.

Module Type CLIGHT_SEPARATION_HOARE_LOGIC_CAST_LOAD_FORWARD.

Declare Module CSHL_Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF.

Import CSHL_Def.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Axiom semax_cast_load_forward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall sh id P e1 t1 (v2: val),
    typeof_temp Delta id = Some t1 ->
   cast_pointer_to_bool (typeof e1) t1 = false ->
    readable_share sh ->
    local (tc_environ Delta) && P |-- `(mapsto sh (typeof e1)) (eval_lvalue e1) (`v2) * TT ->
    @semax CS Espec Delta
       (|> ( (tc_lvalue Delta e1) &&
       local (`(tc_val t1) (`(eval_cast (typeof e1) t1 v2))) &&
          P))
       (Sset id (Ecast e1 t1))
       (normal_ret_assert (EX old:val, local (`eq (eval_id id) (subst id (`old) (`(eval_cast (typeof e1) t1 v2)))) &&
                                          (subst id (`old) P))).

End CLIGHT_SEPARATION_HOARE_LOGIC_CAST_LOAD_FORWARD.

Module Type CLIGHT_SEPARATION_HOARE_LOGIC_CAST_LOAD_BACKWARD.

Declare Module CSHL_Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF.

Import CSHL_Def.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Axiom semax_cast_load_backward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall (P: environ->mpred) id e,
    @semax CS Espec Delta
        (EX sh: share, EX e1: expr, EX t1: type, EX v2: val,
              !! (e = Ecast e1 t1 /\
                  typeof_temp Delta id = Some t1 /\
                  cast_pointer_to_bool (typeof e1) t1 = false /\
                  readable_share sh) &&
         |> ( (tc_lvalue Delta e1) &&
              local (`(tc_val t1) (`(eval_cast (typeof e1) t1 v2))) &&
              (`(mapsto sh (typeof e1)) (eval_lvalue e1) (`v2) * TT) &&
              subst id (`(force_val (sem_cast (typeof e1) t1 v2))) P))
        (Sset id e) (normal_ret_assert P).

End CLIGHT_SEPARATION_HOARE_LOGIC_CAST_LOAD_BACKWARD.

Module LoadF2B
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (Conseq: CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE with Module CSHL_Def := Def)
       (Extr: CLIGHT_SEPARATION_HOARE_LOGIC_EXTRACTION with Module CSHL_Def := Def)
       (LoadF: CLIGHT_SEPARATION_HOARE_LOGIC_LOAD_FORWARD with Module CSHL_Def := Def):
       CLIGHT_SEPARATION_HOARE_LOGIC_LOAD_BACKWARD with Module CSHL_Def := Def.

Module CSHL_Def := Def.
Module ConseqFacts := GenConseqFacts (Def) (Conseq).
Module ExtrFacts := GenExtrFacts (Def) (Conseq) (Extr).
Import Def.
Import Conseq.
Import ConseqFacts.
Import Extr.
Import ExtrFacts.
Import LoadF.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Theorem semax_load_backward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall (P: environ->mpred) id e1,
    @semax CS Espec Delta
        (EX sh: share, EX t2: type, EX v2: val,
              !! (typeof_temp Delta id = Some t2 /\
                  is_neutral_cast (typeof e1) t2 = true /\
                  readable_share sh) &&
         |> ( (tc_lvalue Delta e1) &&
              local (`(tc_val (typeof e1) v2)) &&
              (`(mapsto sh (typeof e1)) (eval_lvalue e1) (`v2) * TT) &&
              subst id (`v2) P))
        (Sset id e1) (normal_ret_assert P).
Proof.
(* Goal: None *)
  intros.
(* Goal: None *)
  apply semax_extract_exists; intro sh.
(* Goal: None *)
  apply semax_extract_exists; intro t2.
(* Goal: None *)
  apply semax_extract_exists; intro v2.
(* Goal: None *)
  apply semax_extract_prop; intros [? [? ?]].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) P)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (LiftEnviron val) v2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@liftx (LiftEnviron val) (force_val (sem_cast (typeof e1) t1 v2))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))) *)
  rewrite (andp_assoc _ _ (subst _ _ _)).
(* Goal: None *)
  eapply semax_post'; [.. | eapply semax_load_forward; eauto].
  + rewrite exp_andp2.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun x : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) x) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) x) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) P))))) P *)
    apply exp_left; intros old.
(* Goal: @eq Prop (@isSome unit (@PTree.get unit id (@PTree.set unit i tt idset0))) (@eq ident i id) *)
    autorewrite with subst.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@liftx (LiftEnviron val) v2))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@subst mpred id (@liftx (LiftEnviron val) old) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (LiftEnviron val) v2))) (@TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric))) (@subst mpred id (@liftx (LiftEnviron val) v2) P)))) P *)
    apply derives_trans with (local (tc_environ Delta) && (local ((` eq) (eval_id id) (` v2))) && subst id (` v2) P); [solve_andp |].
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
    intro rho; unfold local, lift1; unfold_lift; simpl.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (fun _ : environ => force_val (sem_cast (typeof e1) t1 v2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (fun _ : environ => force_val (sem_cast (typeof e1) t1 v2)) x)) rho)) (@subst mpred id (fun _ : environ => eval_id id rho) P rho)) *)
    unfold typeof_temp in H.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (fun _ : environ => force_val (sem_cast (typeof e1) t1 v2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (fun _ : environ => force_val (sem_cast (typeof e1) t1 v2)) x)) rho)) (@subst mpred id (fun _ : environ => eval_id id rho) P rho)) *)
    destruct ((temp_types Delta) ! id) eqn:?H; inv H.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
    normalize.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    erewrite subst_self by eauto; auto.
  + solve_andp.
Qed.

End LoadF2B.

Module LoadB2F
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (Conseq: CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE with Module CSHL_Def := Def)
       (LoadB: CLIGHT_SEPARATION_HOARE_LOGIC_LOAD_BACKWARD with Module CSHL_Def := Def):
       CLIGHT_SEPARATION_HOARE_LOGIC_LOAD_FORWARD with Module CSHL_Def := Def.

Module CSHL_Def := Def.
Module ConseqFacts := GenConseqFacts (Def) (Conseq).
Import Def.
Import Conseq.
Import ConseqFacts.
Import LoadB.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Theorem semax_load_forward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall  sh id P e1 t2 (v2: val),
    typeof_temp Delta id = Some t2 ->
    is_neutral_cast (typeof e1) t2 = true ->
    readable_share sh ->
    local (tc_environ Delta) && P |-- `(mapsto sh (typeof e1)) (eval_lvalue e1) (` v2) * TT ->
    @semax CS Espec Delta
       (|> ( (tc_lvalue Delta e1) &&
       local (`(tc_val (typeof e1) v2)) &&
          P))
       (Sset id e1)
       (normal_ret_assert (EX old:val, local (`eq (eval_id id) (` v2)) &&
                                          (subst id (`old) P))).
Proof.
(* Goal: None *)
  intros.
(* Goal: None *)
  eapply semax_pre; [| apply semax_load_backward].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) P))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) share (fun sh : share => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) expr (fun e2 : expr => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) type (fun t2 : type => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun v3 : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (and (@eq expr (Ecast e1 t1) (Ecast e2 t2)) (and (@eq (option type) (typeof_temp Delta id) (@Some type t2)) (and (@eq bool (cast_pointer_to_bool (typeof e2) t2) false) (readable_share sh))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e2) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t2) (@liftx (LiftEnviron val) (eval_cast (typeof e2) t2 v3))))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e2)) (@eval_lvalue CS e2) (@liftx (LiftEnviron val) v3)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@liftx (LiftEnviron val) (force_val (sem_cast (typeof e2) t2 v3))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))))))))) *)
  apply (exp_right sh).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (LiftEnviron Prop) (tc_val (typeof e1) v2)))) P))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) type (fun t2 : type => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun v3 : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (and (@eq (option type) (typeof_temp Delta id) (@Some type t2)) (and (@eq bool (is_neutral_cast (typeof e1) t2) true) (readable_share sh)))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (LiftEnviron Prop) (tc_val (typeof e1) v3)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (LiftEnviron val) v3)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@liftx (LiftEnviron val) v3) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@liftx (LiftEnviron val) v2))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))))))) *)
  apply (exp_right t2).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) P))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun v3 : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (and (@eq expr (Ecast e1 t1) (Ecast e1 t1)) (and (@eq (option type) (typeof_temp Delta id) (@Some type t1)) (and (@eq bool (cast_pointer_to_bool (typeof e1) t1) false) (readable_share sh))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v3))))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (LiftEnviron val) v3)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@liftx (LiftEnviron val) (force_val (sem_cast (typeof e1) t1 v3))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) (@subst mpred id (@liftx (LiftEnviron val) old) P)))))))) *)
  apply (exp_right v2).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) P))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (and (@eq expr (Ecast e1 t1) (Ecast e1 t1)) (and (@eq (option type) (typeof_temp Delta id) (@Some type t1)) (and (@eq bool (cast_pointer_to_bool (typeof e1) t1) false) (readable_share sh))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (LiftEnviron val) v2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@liftx (LiftEnviron val) (force_val (sem_cast (typeof e1) t1 v2))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))))) *)
  apply andp_right; [apply prop_right; auto |].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) P))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P)))))) *)
  apply later_ENTAIL.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) P)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (LiftEnviron val) v2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@liftx (LiftEnviron val) (force_val (sem_cast (typeof e1) t1 v2))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))) *)
  rewrite (andp_assoc _ _ (subst _ _ _)).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) P)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))) *)
  apply andp_ENTAIL; [apply ENTAIL_refl |].
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  apply andp_right; auto.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) P) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P)))) *)
  rewrite subst_exp.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) P) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun b : val => @subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) b) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) b) P)))) *)
  intros rho.
  change (local (tc_environ Delta) rho && P rho
  |-- EX b : val,
       subst id (` v2) (local ((` eq) (eval_id id) (` v2)) && subst id (` b) P) rho).
(* Goal: @derives mpred Nveric (@andp mpred Nveric (local (tc_environ Delta) rho) (P rho)) (@exp mpred Nveric val (fun b : val => @subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) b) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) b) P)) rho)) *)
  apply (exp_right (eval_id id rho)).
(* Goal: @eq Prop (@isSome unit (@PTree.get unit id (@PTree.set unit i tt idset0))) (@eq ident i id) *)
  autorewrite with subst.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  unfold local, lift1; unfold_lift; simpl.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (fun _ : environ => force_val (sem_cast (typeof e1) t1 v2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (fun _ : environ => force_val (sem_cast (typeof e1) t1 v2)) x)) rho)) (@subst mpred id (fun _ : environ => eval_id id rho) P rho)) *)
  unfold typeof_temp in H.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (fun _ : environ => force_val (sem_cast (typeof e1) t1 v2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (fun _ : environ => force_val (sem_cast (typeof e1) t1 v2)) x)) rho)) (@subst mpred id (fun _ : environ => eval_id id rho) P rho)) *)
  destruct ((temp_types Delta) ! id) eqn:?H; inv H.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
  normalize.
(* Goal: @derives mpred Nveric (P rho) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (fun _ : environ => force_val (sem_cast (typeof e1) t1 v2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (fun _ : environ => force_val (sem_cast (typeof e1) t1 v2)) x)) rho)) (@subst mpred id (fun _ : environ => eval_id id rho) P rho)) *)
  apply andp_right; [| erewrite subst_self by eauto; auto].
(* Goal: or (@eq ident id i) (@eq (option val) (@Map.get val (te_of rho) i) (@Map.get val (@Map.set val id (e rho) (te_of rho)) i)) *)
  apply prop_right.
(* Goal: @subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho *)
  unfold subst.
(* Goal: @eq val (eval_id id (env_set rho id (force_val (sem_cast (typeof e1) t1 v2)))) (force_val (sem_cast (typeof e1) t1 v2)) *)
  apply eval_id_same.
Qed.

End LoadB2F.

Module CastLoadF2B
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (Conseq: CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE with Module CSHL_Def := Def)
       (Extr: CLIGHT_SEPARATION_HOARE_LOGIC_EXTRACTION with Module CSHL_Def := Def)
       (CastLoadF: CLIGHT_SEPARATION_HOARE_LOGIC_CAST_LOAD_FORWARD with Module CSHL_Def := Def):
       CLIGHT_SEPARATION_HOARE_LOGIC_CAST_LOAD_BACKWARD with Module CSHL_Def := Def.

Module CSHL_Def := Def.
Module ConseqFacts := GenConseqFacts (Def) (Conseq).
Module ExtrFacts := GenExtrFacts (Def) (Conseq) (Extr).
Import Def.
Import Conseq.
Import ConseqFacts.
Import Extr.
Import ExtrFacts.
Import CastLoadF.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Theorem semax_cast_load_backward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall (P: environ->mpred) id e,
    @semax CS Espec Delta
        (EX sh: share, EX e1: expr, EX t1: type, EX v2: val,
              !! (e = Ecast e1 t1 /\
                  typeof_temp Delta id = Some t1 /\
                  cast_pointer_to_bool (typeof e1) t1 = false /\
                  readable_share sh) &&
         |> ( (tc_lvalue Delta e1) &&
              local (`(tc_val t1) (`(eval_cast (typeof e1) t1 v2))) &&
              (`(mapsto sh (typeof e1)) (eval_lvalue e1) (`v2) * TT) &&
              subst id (`(force_val (sem_cast (typeof e1) t1 v2))) P))
        (Sset id e) (normal_ret_assert P).
Proof.
(* Goal: None *)
  intros.
(* Goal: None *)
  apply semax_extract_exists; intro sh.
(* Goal: None *)
  apply semax_extract_exists; intro e1.
(* Goal: None *)
  apply semax_extract_exists; intro t2.
(* Goal: None *)
  apply semax_extract_exists; intro v2.
(* Goal: None *)
  apply semax_extract_prop; intros [He [? [? ?]]].
(* Goal: None *)
  subst e.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) P)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (LiftEnviron val) v2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@liftx (LiftEnviron val) (force_val (sem_cast (typeof e1) t1 v2))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))) *)
  rewrite (andp_assoc _ _ (subst _ _ _)).
(* Goal: None *)
  eapply semax_post'; [.. | eapply semax_cast_load_forward; eauto].
  + rewrite exp_andp2.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun x : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) x) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) x) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) P))))) P *)
    apply exp_left; intros old.
(* Goal: @eq Prop (@isSome unit (@PTree.get unit id (@PTree.set unit i tt idset0))) (@eq ident i id) *)
    autorewrite with subst.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t2 v2))))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@sepcon (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@subst mpred id (@liftx (LiftEnviron val) old) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (LiftEnviron val) v2))) (@TT (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric))) (@subst mpred id (@liftx (LiftEnviron val) (force_val (sem_cast (typeof e1) t2 v2))) P)))) P *)
    apply derives_trans with (local (tc_environ Delta) && (local ((` eq) (eval_id id) (subst id (` old) ((` (eval_cast (typeof e1) t2)) (` v2))))) && subst id (`(force_val (sem_cast (typeof e1) t2 v2))) P); [solve_andp |].
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
    intro rho; unfold local, lift1; unfold_lift; simpl.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (fun _ : environ => force_val (sem_cast (typeof e1) t1 v2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (fun _ : environ => force_val (sem_cast (typeof e1) t1 v2)) x)) rho)) (@subst mpred id (fun _ : environ => eval_id id rho) P rho)) *)
    unfold typeof_temp in H.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (fun _ : environ => force_val (sem_cast (typeof e1) t1 v2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (fun _ : environ => force_val (sem_cast (typeof e1) t1 v2)) x)) rho)) (@subst mpred id (fun _ : environ => eval_id id rho) P rho)) *)
    destruct ((temp_types Delta) ! id) eqn:?H; inv H.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
    normalize.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    erewrite subst_self by eauto; auto.
  + solve_andp.
Qed.

End CastLoadF2B.

Module CastLoadB2F
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (Conseq: CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE with Module CSHL_Def := Def)
       (CastLoadB: CLIGHT_SEPARATION_HOARE_LOGIC_CAST_LOAD_BACKWARD with Module CSHL_Def := Def):
       CLIGHT_SEPARATION_HOARE_LOGIC_CAST_LOAD_FORWARD with Module CSHL_Def := Def.

Module CSHL_Def := Def.
Module ConseqFacts := GenConseqFacts (Def) (Conseq).
Import Def.
Import Conseq.
Import ConseqFacts.
Import CastLoadB.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Theorem semax_cast_load_forward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall sh id P e1 t1 (v2: val),
    typeof_temp Delta id = Some t1 ->
   cast_pointer_to_bool (typeof e1) t1 = false ->
    readable_share sh ->
    local (tc_environ Delta) && P |-- `(mapsto sh (typeof e1)) (eval_lvalue e1) (`v2) * TT ->
    @semax CS Espec Delta
       (|> ( (tc_lvalue Delta e1) &&
       local (`(tc_val t1) (`(eval_cast (typeof e1) t1 v2))) &&
          P))
       (Sset id (Ecast e1 t1))
       (normal_ret_assert (EX old:val, local (`eq (eval_id id) (subst id (`old) (`(eval_cast (typeof e1) t1 v2)))) &&
                                          (subst id (`old) P))).
Proof.
(* Goal: None *)
  intros.
(* Goal: None *)
  eapply semax_pre; [| apply semax_cast_load_backward].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) P))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) share (fun sh : share => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) expr (fun e2 : expr => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) type (fun t2 : type => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun v3 : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (and (@eq expr (Ecast e1 t1) (Ecast e2 t2)) (and (@eq (option type) (typeof_temp Delta id) (@Some type t2)) (and (@eq bool (cast_pointer_to_bool (typeof e2) t2) false) (readable_share sh))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e2) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t2) (@liftx (LiftEnviron val) (eval_cast (typeof e2) t2 v3))))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e2)) (@eval_lvalue CS e2) (@liftx (LiftEnviron val) v3)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@liftx (LiftEnviron val) (force_val (sem_cast (typeof e2) t2 v3))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))))))))) *)
  apply (exp_right sh).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) P))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) expr (fun e3 : expr => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) expr (fun e4 : expr => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) type (fun ty0 : type => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) share (fun sh1 : share => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) share (fun sh2 : share => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (and (@eq expr (Ebinop cmp e1 e2 ty) (Ebinop cmp e3 e4 ty0)) (and (@sepalg.nonidentity share Share.Join_ba pa_share sh1) (and (@sepalg.nonidentity share Share.Join_ba pa_share sh2) (and (@eq bool (is_comparison cmp) true) (and (@eq bool (eqb_type (typeof e3) int_or_ptr_type) false) (and (@eq bool (eqb_type (typeof e4) int_or_ptr_type) false) (@eq bool (typecheck_tid_ptr_compare Delta id) true)))))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e3) (@tc_expr CS Delta e4)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e3) (@eval_expr CS e4)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e3)) (@eval_expr CS e3)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e4)) (@eval_expr CS e4)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@eval_expr CS (Ebinop cmp e3 e4 ty0)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P)))))))))))) *)
  apply (exp_right e1).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) P))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) type (fun t2 : type => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun v3 : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (and (@eq expr (Ecast e1 t1) (Ecast e1 t2)) (and (@eq (option type) (typeof_temp Delta id) (@Some type t2)) (and (@eq bool (cast_pointer_to_bool (typeof e1) t2) false) (readable_share sh))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t2) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t2 v3))))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (LiftEnviron val) v3)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@liftx (LiftEnviron val) (force_val (sem_cast (typeof e1) t2 v3))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))))))) *)
  apply (exp_right t1).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) P))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun v3 : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (and (@eq expr (Ecast e1 t1) (Ecast e1 t1)) (and (@eq (option type) (typeof_temp Delta id) (@Some type t1)) (and (@eq bool (cast_pointer_to_bool (typeof e1) t1) false) (readable_share sh))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v3))))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (LiftEnviron val) v3)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@liftx (LiftEnviron val) (force_val (sem_cast (typeof e1) t1 v3))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) (@subst mpred id (@liftx (LiftEnviron val) old) P)))))))) *)
  apply (exp_right v2).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) P))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (and (@eq expr (Ecast e1 t1) (Ecast e1 t1)) (and (@eq (option type) (typeof_temp Delta id) (@Some type t1)) (and (@eq bool (cast_pointer_to_bool (typeof e1) t1) false) (readable_share sh))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (LiftEnviron val) v2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@liftx (LiftEnviron val) (force_val (sem_cast (typeof e1) t1 v2))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))))) *)
  apply andp_right; [apply prop_right; auto |].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) P))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P)))))) *)
  apply later_ENTAIL.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) P)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_lvalue CS Delta e1) (local (@liftx (Tarrow val (LiftEnviron Prop)) (tc_val t1) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (Tarrow val (LiftEnviron mpred))) (mapsto sh (typeof e1)) (@eval_lvalue CS e1) (@liftx (LiftEnviron val) v2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@liftx (LiftEnviron val) (force_val (sem_cast (typeof e1) t1 v2))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@liftx (LiftEnviron val) (eval_cast (typeof e1) t1 v2))))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))) *)
  rewrite (andp_assoc _ _ (subst _ _ _)).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) P)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))) *)
  apply andp_ENTAIL; [apply ENTAIL_refl |].
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  apply andp_right; auto.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) P) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P)))) *)
  rewrite subst_exp.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) P) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun b : val => @subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) b) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) b) P)))) *)
  intros rho.
  change (local (tc_environ Delta) rho && P rho
  |-- EX b : val,
       subst id (` (force_val (sem_cast (typeof e1) t1 v2))) (local ((` eq) (eval_id id) (subst id (` b) (` (eval_cast (typeof e1) t1 v2)))) && subst id (` b) P) rho).
(* Goal: @derives mpred Nveric (@andp mpred Nveric (local (tc_environ Delta) rho) (P rho)) (@exp mpred Nveric val (fun b : val => @subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) b) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) b) P)) rho)) *)
  apply (exp_right (eval_id id rho)).
(* Goal: @eq Prop (@isSome unit (@PTree.get unit id (@PTree.set unit i tt idset0))) (@eq ident i id) *)
  autorewrite with subst.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  unfold local, lift1; unfold_lift; simpl.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (fun _ : environ => force_val (sem_cast (typeof e1) t1 v2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (fun _ : environ => force_val (sem_cast (typeof e1) t1 v2)) x)) rho)) (@subst mpred id (fun _ : environ => eval_id id rho) P rho)) *)
  unfold typeof_temp in H.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (fun _ : environ => force_val (sem_cast (typeof e1) t1 v2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (fun _ : environ => force_val (sem_cast (typeof e1) t1 v2)) x)) rho)) (@subst mpred id (fun _ : environ => eval_id id rho) P rho)) *)
  destruct ((temp_types Delta) ! id) eqn:?H; inv H.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
  normalize.
(* Goal: @derives mpred Nveric (P rho) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (fun _ : environ => force_val (sem_cast (typeof e1) t1 v2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (fun _ : environ => force_val (sem_cast (typeof e1) t1 v2)) x)) rho)) (@subst mpred id (fun _ : environ => eval_id id rho) P rho)) *)
  apply andp_right; [| erewrite subst_self by eauto; auto].
(* Goal: or (@eq ident id i) (@eq (option val) (@Map.get val (te_of rho) i) (@Map.get val (@Map.set val id (e rho) (te_of rho)) i)) *)
  apply prop_right.
(* Goal: @subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho *)
  unfold subst.
(* Goal: @eq val (eval_id id (env_set rho id (force_val (sem_cast (typeof e1) t1 v2)))) (force_val (sem_cast (typeof e1) t1 v2)) *)
  apply eval_id_same.
Qed.

End CastLoadB2F.

Module SetF2B
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (Conseq: CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE with Module CSHL_Def := Def)
       (Extr: CLIGHT_SEPARATION_HOARE_LOGIC_EXTRACTION with Module CSHL_Def := Def)
       (SetF: CLIGHT_SEPARATION_HOARE_LOGIC_SET_FORWARD with Module CSHL_Def := Def):
       CLIGHT_SEPARATION_HOARE_LOGIC_SET_BACKWARD with Module CSHL_Def := Def.

Module CSHL_Def := Def.
Module ConseqFacts := GenConseqFacts (Def) (Conseq).
Module ExtrFacts := GenExtrFacts (Def) (Conseq) (Extr).
Import Def.
Import Conseq.
Import ConseqFacts.
Import Extr.
Import ExtrFacts.
Import SetF.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Theorem semax_set_backward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall (P: environ->mpred) id e,
    @semax CS Espec Delta
        (|> ( (tc_expr Delta e) &&
             (tc_temp_id id (typeof e) Delta e) &&
             subst id (eval_expr e) P))
          (Sset id e) (normal_ret_assert P).
Proof.
(* Goal: None *)
  intros.
(* Goal: None *)
  apply semax_pre with (|> (!! (exists t, ((temp_types Delta) ! id = Some t)) && (tc_expr Delta e && tc_temp_id id (typeof e) Delta e && subst id (eval_expr e) P))).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
  {
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) P))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P)))))) *)
    apply later_ENTAIL.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))) *)
    apply andp_right; [| solve_andp].
(* Goal: @derives mpred Nveric (@tc_temp_id id (typeof e) CS Delta e rho) (@prop mpred Nveric (@eq environ (env_set rho id (eval_id id rho)) rho)) *)
    unfold tc_temp_id, typecheck_temp_id.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@denote_tc_assert CS match @PTree.get type id (temp_types Delta) with | Some t => tc_andp (tc_bool (is_neutral_cast (implicit_deref (typeof e)) t) (invalid_cast (typeof e) t)) (@isCastResultType CS (implicit_deref (typeof e)) t e) | None => tc_FF (var_not_in_tycontext Delta id) end)) (@subst mpred id (@eval_expr CS e) P))) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) *)
    destruct ((temp_types Delta) ! id).
    + apply prop_right; eauto.
    + simpl denote_tc_assert.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
      normalize.
  }
(* Goal: None *)
  apply semax_pre with (|> (tc_expr Delta e && tc_temp_id id (typeof e) Delta e && (!! (exists t, ((temp_types Delta) ! id = Some t)) && subst id (eval_expr e) P))).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
  {
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) P))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P)))))) *)
    apply later_ENTAIL.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P))) *)
    solve_andp.
  }
(* Goal: None *)
  eapply semax_post'; [.. | eapply semax_set_forward; eauto].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) P))))) P *)
  rewrite exp_andp2.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun x : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) x) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) x) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) P))))) P *)
  apply exp_left; intros old.
(* Goal: @eq Prop (@isSome unit (@PTree.get unit id (@PTree.set unit i tt idset0))) (@eq ident i id) *)
  autorewrite with subst.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
  normalize.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS e)))) (@subst mpred id (@liftx (LiftEnviron val) old) (@subst mpred id (@eval_expr CS e) P)))) P *)
  destruct H as [t ?].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS e)))) (@subst mpred id (@liftx (LiftEnviron val) old) (@subst mpred id (@eval_expr CS e) P)))) P *)
  apply derives_trans with (local (tc_environ Delta) && (local ((` eq) (eval_id id) (subst id (` old) (eval_expr e)))) && subst id (` old) (subst id (eval_expr e) P)); [solve_andp |].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS e))))) (@subst mpred id (@liftx (LiftEnviron val) old) (@subst mpred id (@eval_expr CS e) P))) P *)
  set (v := `old).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id v (@eval_expr CS e))))) (@subst mpred id v (@subst mpred id (@eval_expr CS e) P))) P *)
  intro rho; unfold local, lift1; unfold_lift; simpl; subst v.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
  normalize.
(* Goal: @derives mpred Nveric (P rho) (@subst mpred id (fun x : environ => force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 x) (@eval_expr CS e2 x)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho) *)
  rewrite resubst_full.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  erewrite subst_self; eauto.
Qed.

End SetF2B.

Module SetB2F
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (Conseq: CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE with Module CSHL_Def := Def)
       (SetB: CLIGHT_SEPARATION_HOARE_LOGIC_SET_BACKWARD with Module CSHL_Def := Def):
       CLIGHT_SEPARATION_HOARE_LOGIC_SET_FORWARD with Module CSHL_Def := Def.

Module CSHL_Def := Def.
Module ConseqFacts := GenConseqFacts (Def) (Conseq).
Import Def.
Import Conseq.
Import ConseqFacts.
Import SetB.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Theorem semax_set_forward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall (P: environ->mpred) id e,
    @semax CS Espec Delta
        (|> ( (tc_expr Delta e) &&
             (tc_temp_id id (typeof e) Delta e) &&
          P))
          (Sset id e)
        (normal_ret_assert
          (EX old:val, local (`eq (eval_id id) (subst id (`old) (eval_expr e))) &&
                            subst id (`old) P)).
Proof.
(* Goal: None *)
  intros.
(* Goal: None *)
  eapply semax_pre; [| apply semax_set_backward].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) P))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P)))))) *)
  apply later_ENTAIL.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) P)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS e)))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))) *)
  apply andp_right; [solve_andp |].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) P) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P)))) *)
  rewrite subst_exp.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) P)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun b : val => @subst mpred id (@eval_expr CS e) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) b) (@eval_expr CS e)))) (@subst mpred id (@liftx (LiftEnviron val) b) P)))) *)
  intro rho.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  simpl.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (local (tc_environ Delta) rho) (P rho)) (@exp mpred Nveric val (fun b : val => @subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) b) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) b) P)) rho)) *)
  apply (exp_right (eval_id id rho)).
(* Goal: @derives mpred Nveric (@andp mpred Nveric (local (tc_environ Delta) rho) (P rho)) (odia Delta i P rho) *)
  unfold_lift; unfold local, lift1.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  simpl.
(* Goal: @subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho *)
  unfold subst.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
  normalize.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@eq val (@eval_expr CS e rho) (@eval_expr CS e (env_set (env_set rho id (@eval_expr CS e rho)) id (eval_id id rho))))) (P (env_set (env_set rho id (@eval_expr CS e rho)) id (eval_id id rho)))) *)
  rewrite !env_set_env_set.
  assert (tc_temp_id id (typeof e) Delta e rho |-- !! (env_set rho id (eval_id id rho) = rho)).
  + unfold tc_temp_id, typecheck_temp_id.
(* Goal: @derives mpred Nveric (@denote_tc_assert CS match @PTree.get type id (temp_types Delta) with | Some t => tc_andp (tc_bool (is_neutral_cast (implicit_deref (typeof e)) t) (invalid_cast (typeof e) t)) (@isCastResultType CS (implicit_deref (typeof e)) t e) | None => tc_FF (var_not_in_tycontext Delta id) end rho) (@prop mpred Nveric (@eq environ (env_set rho id (eval_id id rho)) rho)) *)
    destruct ((temp_types Delta) ! id) eqn:?H; [| apply FF_left].
(* Goal: or (@eq ident id i) (@eq (option val) (@Map.get val (te_of rho) i) (@Map.get val (@Map.set val id (e rho) (te_of rho)) i)) *)
    apply prop_right.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    eapply env_set_eval_id; eauto.
  + rewrite (add_andp _ _ H0).
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@andp mpred Nveric (@tc_temp_id id (typeof e) CS Delta e rho) (@prop mpred Nveric (@eq environ (env_set rho id (eval_id id rho)) rho)))) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@eq val (@eval_expr CS e rho) (@eval_expr CS e (env_set rho id (eval_id id rho))))) (P (env_set rho id (eval_id id rho)))) *)
    rewrite !andp_assoc.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@tc_temp_id id (typeof e) CS Delta e rho) (@andp mpred Nveric (@prop mpred Nveric (@eq environ (env_set rho id (eval_id id rho)) rho)) (P rho))) (@andp mpred Nveric (@prop mpred Nveric (@eq val (@eval_expr CS e rho) (@eval_expr CS e (env_set rho id (eval_id id rho))))) (P (env_set rho id (eval_id id rho)))) *)
    apply andp_left2.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@tc_temp_id id (typeof e) CS Delta e rho) (@andp mpred Nveric (@prop mpred Nveric (@eq environ (env_set rho id (eval_id id rho)) rho)) (P rho))) (@andp mpred Nveric (@prop mpred Nveric (@eq val (@eval_expr CS e rho) (@eval_expr CS e (env_set rho id (eval_id id rho))))) (P (env_set rho id (eval_id id rho)))) *)
    apply andp_left2.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
    normalize.
(* Goal: @derives mpred Nveric (P rho) (@andp mpred Nveric (@prop mpred Nveric (@eq val (@eval_expr CS e rho) (@eval_expr CS e (env_set rho id (eval_id id rho))))) (P (env_set rho id (eval_id id rho)))) *)
    rewrite H1.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
    normalize.
Qed.

End SetB2F.

Module Type CLIGHT_SEPARATION_HOARE_LOGIC_PTR_CMP_FORWARD.

Declare Module CSHL_Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF.

Import CSHL_Def.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Axiom semax_ptr_compare_forward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall P id cmp e1 e2 ty sh1 sh2,
    sepalg.nonidentity sh1 -> sepalg.nonidentity sh2 ->
   is_comparison cmp = true  ->
   eqb_type (typeof e1) int_or_ptr_type = false ->
   eqb_type (typeof e2) int_or_ptr_type = false ->
   typecheck_tid_ptr_compare Delta id = true ->
   @semax CS Espec Delta
        ( |> ( (tc_expr Delta e1) &&
              (tc_expr Delta e2)  &&

          local (`(blocks_match cmp) (eval_expr e1) (eval_expr e2)) &&
          (`(mapsto_ sh1 (typeof e1)) (eval_expr e1) * TT) &&
          (`(mapsto_ sh2 (typeof e2)) (eval_expr e2) * TT) &&
          P))
          (Sset id (Ebinop cmp e1 e2 ty))
        (normal_ret_assert
          (EX old:val,
                 local (`eq (eval_id id)  (subst id `(old)
                     (eval_expr (Ebinop cmp e1 e2 ty)))) &&
                       subst id `(old) P)).

End CLIGHT_SEPARATION_HOARE_LOGIC_PTR_CMP_FORWARD.

Module Type CLIGHT_SEPARATION_HOARE_LOGIC_PTR_CMP_BACKWARD.

Declare Module CSHL_Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF.

Import CSHL_Def.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Axiom semax_ptr_compare_backward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall P id e,
   @semax CS Espec Delta
        (EX cmp: Cop.binary_operation, EX e1: expr, EX e2: expr,
         EX ty: type, EX sh1: share, EX sh2: share,
          !! (e = Ebinop cmp e1 e2 ty /\
              sepalg.nonidentity sh1 /\ sepalg.nonidentity sh2 /\
              is_comparison cmp = true /\
              eqb_type (typeof e1) int_or_ptr_type = false /\
              eqb_type (typeof e2) int_or_ptr_type = false /\
              typecheck_tid_ptr_compare Delta id = true) &&
            ( |> ( (tc_expr Delta e1) &&
              (tc_expr Delta e2)  &&
          local (`(blocks_match cmp) (eval_expr e1) (eval_expr e2)) &&
          (`(mapsto_ sh1 (typeof e1)) (eval_expr e1) * TT) &&
          (`(mapsto_ sh2 (typeof e2)) (eval_expr e2) * TT) &&
          subst id (eval_expr (Ebinop cmp e1 e2 ty)) P)))
          (Sset id e)
        (normal_ret_assert P).

End CLIGHT_SEPARATION_HOARE_LOGIC_PTR_CMP_BACKWARD.

Module PtrCmpF2B
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (Conseq: CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE with Module CSHL_Def := Def)
       (Extr: CLIGHT_SEPARATION_HOARE_LOGIC_EXTRACTION with Module CSHL_Def := Def)
       (PtrCmpF: CLIGHT_SEPARATION_HOARE_LOGIC_PTR_CMP_FORWARD with Module CSHL_Def := Def):
       CLIGHT_SEPARATION_HOARE_LOGIC_PTR_CMP_BACKWARD with Module CSHL_Def := Def.

Module CSHL_Def := Def.
Module ConseqFacts := GenConseqFacts (Def) (Conseq).
Module ExtrFacts := GenExtrFacts (Def) (Conseq) (Extr).
Import Def.
Import Conseq.
Import ConseqFacts.
Import Extr.
Import ExtrFacts.
Import PtrCmpF.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Theorem semax_ptr_compare_backward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall P id e,
   @semax CS Espec Delta
        (EX cmp: Cop.binary_operation, EX e1: expr, EX e2: expr,
         EX ty: type, EX sh1: share, EX sh2: share,
          !! (e = Ebinop cmp e1 e2 ty /\
              sepalg.nonidentity sh1 /\ sepalg.nonidentity sh2 /\
              is_comparison cmp = true /\
              eqb_type (typeof e1) int_or_ptr_type = false /\
              eqb_type (typeof e2) int_or_ptr_type = false /\
              typecheck_tid_ptr_compare Delta id = true) &&
            ( |> ( (tc_expr Delta e1) &&
              (tc_expr Delta e2)  &&
          local (`(blocks_match cmp) (eval_expr e1) (eval_expr e2)) &&
          (`(mapsto_ sh1 (typeof e1)) (eval_expr e1) * TT) &&
          (`(mapsto_ sh2 (typeof e2)) (eval_expr e2) * TT) &&
          subst id (eval_expr (Ebinop cmp e1 e2 ty)) P)))
          (Sset id e)
          (normal_ret_assert P).
Proof.
(* Goal: None *)
  intros.
(* Goal: None *)
  apply semax_extract_exists; intro cmp.
(* Goal: None *)
  apply semax_extract_exists; intro e1.
(* Goal: None *)
  apply semax_extract_exists; intro e2.
(* Goal: None *)
  apply semax_extract_exists; intro ty.
(* Goal: None *)
  apply semax_extract_exists; intro sh1.
(* Goal: None *)
  apply semax_extract_exists; intro sh2.
(* Goal: None *)
  apply semax_extract_prop; intros [He [? [? [? [? [? ?]]]]]].
(* Goal: None *)
  subst e.
(* Goal: None *)
  eapply semax_post'; [.. | eapply semax_ptr_compare_forward; eauto].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) P))))) P *)
  rewrite exp_andp2.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun x : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) x) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) x) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) P))))) P *)
  apply exp_left; intros old.
(* Goal: @eq Prop (@isSome unit (@PTree.get unit id (@PTree.set unit i tt idset0))) (@eq ident i id) *)
  autorewrite with subst.
(* Goal: @derives mpred Nveric (P rho) (@subst mpred id (fun x : environ => force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 x) (@eval_expr CS e2 x)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho) *)
  rewrite resubst_full.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  intro rho; unfold local, lift1; unfold_lift; simpl.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
  unfold typecheck_tid_ptr_compare in H4.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
  destruct ((temp_types Delta) ! id) eqn:?H; inv H4.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
  normalize.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  erewrite subst_self by eauto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  auto.
Qed.

End PtrCmpF2B.

Module PtrCmpB2F
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (Conseq: CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE with Module CSHL_Def := Def)
       (PtrCmpB: CLIGHT_SEPARATION_HOARE_LOGIC_PTR_CMP_BACKWARD with Module CSHL_Def := Def):
       CLIGHT_SEPARATION_HOARE_LOGIC_PTR_CMP_FORWARD with Module CSHL_Def := Def.

Module CSHL_Def := Def.
Module ConseqFacts := GenConseqFacts (Def) (Conseq).
Import Def.
Import Conseq.
Import ConseqFacts.
Import PtrCmpB.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Theorem semax_ptr_compare_forward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall P id cmp e1 e2 ty sh1 sh2,
    sepalg.nonidentity sh1 -> sepalg.nonidentity sh2 ->
   is_comparison cmp = true  ->
   eqb_type (typeof e1) int_or_ptr_type = false ->
   eqb_type (typeof e2) int_or_ptr_type = false ->
   typecheck_tid_ptr_compare Delta id = true ->
   @semax CS Espec Delta
        ( |> ( (tc_expr Delta e1) &&
              (tc_expr Delta e2)  &&

          local (`(blocks_match cmp) (eval_expr e1) (eval_expr e2)) &&
          (`(mapsto_ sh1 (typeof e1)) (eval_expr e1) * TT) &&
          (`(mapsto_ sh2 (typeof e2)) (eval_expr e2) * TT) &&
          P))
          (Sset id (Ebinop cmp e1 e2 ty))
        (normal_ret_assert
          (EX old:val,
                 local (`eq (eval_id id)  (subst id `(old)
                     (eval_expr (Ebinop cmp e1 e2 ty)))) &&
                       subst id `(old) P)).
Proof.
(* Goal: None *)
  intros.
(* Goal: None *)
  eapply semax_pre; [| apply semax_ptr_compare_backward].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) P))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) Cop.binary_operation (fun cmp0 : Cop.binary_operation => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) expr (fun e3 : expr => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) expr (fun e4 : expr => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) type (fun ty0 : type => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) share (fun sh1 : share => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) share (fun sh2 : share => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (and (@eq expr (Ebinop cmp e1 e2 ty) (Ebinop cmp0 e3 e4 ty0)) (and (@sepalg.nonidentity share Share.Join_ba pa_share sh1) (and (@sepalg.nonidentity share Share.Join_ba pa_share sh2) (and (@eq bool (is_comparison cmp0) true) (and (@eq bool (eqb_type (typeof e3) int_or_ptr_type) false) (and (@eq bool (eqb_type (typeof e4) int_or_ptr_type) false) (@eq bool (typecheck_tid_ptr_compare Delta id) true)))))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e3) (@tc_expr CS Delta e4)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp0) (@eval_expr CS e3) (@eval_expr CS e4)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e3)) (@eval_expr CS e3)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e4)) (@eval_expr CS e4)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@eval_expr CS (Ebinop cmp0 e3 e4 ty0)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))))))))))) *)
  apply (exp_right cmp).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) P))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) expr (fun e3 : expr => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) expr (fun e4 : expr => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) type (fun ty0 : type => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) share (fun sh1 : share => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) share (fun sh2 : share => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (and (@eq expr (Ebinop cmp e1 e2 ty) (Ebinop cmp e3 e4 ty0)) (and (@sepalg.nonidentity share Share.Join_ba pa_share sh1) (and (@sepalg.nonidentity share Share.Join_ba pa_share sh2) (and (@eq bool (is_comparison cmp) true) (and (@eq bool (eqb_type (typeof e3) int_or_ptr_type) false) (and (@eq bool (eqb_type (typeof e4) int_or_ptr_type) false) (@eq bool (typecheck_tid_ptr_compare Delta id) true)))))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e3) (@tc_expr CS Delta e4)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e3) (@eval_expr CS e4)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e3)) (@eval_expr CS e3)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e4)) (@eval_expr CS e4)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@eval_expr CS (Ebinop cmp e3 e4 ty0)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P)))))))))))) *)
  apply (exp_right e1).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) P))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) expr (fun e3 : expr => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) type (fun ty0 : type => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) share (fun sh1 : share => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) share (fun sh2 : share => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (and (@eq expr (Ebinop cmp e1 e2 ty) (Ebinop cmp e1 e3 ty0)) (and (@sepalg.nonidentity share Share.Join_ba pa_share sh1) (and (@sepalg.nonidentity share Share.Join_ba pa_share sh2) (and (@eq bool (is_comparison cmp) true) (and (@eq bool (eqb_type (typeof e1) int_or_ptr_type) false) (and (@eq bool (eqb_type (typeof e3) int_or_ptr_type) false) (@eq bool (typecheck_tid_ptr_compare Delta id) true)))))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e3)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e3)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e3)) (@eval_expr CS e3)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e3 ty0)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))))))))) *)
  apply (exp_right e2).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) P))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) type (fun ty0 : type => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) share (fun sh1 : share => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) share (fun sh2 : share => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (and (@eq expr (Ebinop cmp e1 e2 ty) (Ebinop cmp e1 e2 ty0)) (and (@sepalg.nonidentity share Share.Join_ba pa_share sh1) (and (@sepalg.nonidentity share Share.Join_ba pa_share sh2) (and (@eq bool (is_comparison cmp) true) (and (@eq bool (eqb_type (typeof e1) int_or_ptr_type) false) (and (@eq bool (eqb_type (typeof e2) int_or_ptr_type) false) (@eq bool (typecheck_tid_ptr_compare Delta id) true)))))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty0)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P)))))))))) *)
  apply (exp_right ty).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) P))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) share (fun sh1 : share => @exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) share (fun sh2 : share => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (and (@eq expr (Ebinop cmp e1 e2 ty) (Ebinop cmp e1 e2 ty)) (and (@sepalg.nonidentity share Share.Join_ba pa_share sh1) (and (@sepalg.nonidentity share Share.Join_ba pa_share sh2) (and (@eq bool (is_comparison cmp) true) (and (@eq bool (eqb_type (typeof e1) int_or_ptr_type) false) (and (@eq bool (eqb_type (typeof e2) int_or_ptr_type) false) (@eq bool (typecheck_tid_ptr_compare Delta id) true)))))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))))))) *)
  apply (exp_right sh1).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) P))) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) share (fun sh2 : share => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (and (@eq expr (Ebinop cmp e1 e2 ty) (Ebinop cmp e1 e2 ty)) (and (@sepalg.nonidentity share Share.Join_ba pa_share sh1) (and (@sepalg.nonidentity share Share.Join_ba pa_share sh2) (and (@eq bool (is_comparison cmp) true) (and (@eq bool (eqb_type (typeof e1) int_or_ptr_type) false) (and (@eq bool (eqb_type (typeof e2) int_or_ptr_type) false) (@eq bool (typecheck_tid_ptr_compare Delta id) true)))))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P)))))))) *)
  apply (exp_right sh2).
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) P))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (and (@eq expr (Ebinop cmp e1 e2 ty) (Ebinop cmp e1 e2 ty)) (and (@sepalg.nonidentity share Share.Join_ba pa_share sh1) (and (@sepalg.nonidentity share Share.Join_ba pa_share sh2) (and (@eq bool (is_comparison cmp) true) (and (@eq bool (eqb_type (typeof e1) int_or_ptr_type) false) (and (@eq bool (eqb_type (typeof e2) int_or_ptr_type) false) (@eq bool (typecheck_tid_ptr_compare Delta id) true)))))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))))) *)
  apply andp_right; [apply prop_right; repeat split; auto |].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) P))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P)))))) *)
  apply later_ENTAIL.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) P)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e1) (@tc_expr CS Delta e2)) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (blocks_match cmp) (@eval_expr CS e1) (@eval_expr CS e2)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh1 (typeof e1)) (@eval_expr CS e1)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@sepcon (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric) (@LiftSepLog' mpred Nveric Sveric) (@liftx (Tarrow val (LiftEnviron mpred)) (mapsto_ sh2 (typeof e2)) (@eval_expr CS e2)) (@TT (lifted (LiftEnviron mpred)) (@LiftNatDed' mpred Nveric)))) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P))))) *)
  apply andp_ENTAIL; [apply ENTAIL_refl |].
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) P) (@subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun old : val => @andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) old) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) old) P)))) *)
  rewrite subst_exp.
(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) P) (@exp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) val (fun b : val => @subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) b) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) b) P)))) *)
  intros rho.
  change (local (tc_environ Delta) rho && P rho
  |-- EX b : val,
       subst id (eval_expr (Ebinop cmp e1 e2 ty)) (local ((` eq) (eval_id id) (subst id (` b) (eval_expr (Ebinop cmp e1 e2 ty)))) && subst id (` b) P) rho).
(* Goal: @derives mpred Nveric (@andp mpred Nveric (local (tc_environ Delta) rho) (P rho)) (@exp mpred Nveric val (fun b : val => @subst mpred id (@eval_expr CS (Ebinop cmp e1 e2 ty)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (@liftx (Tarrow val (Tarrow val (LiftEnviron Prop))) (@eq val) (eval_id id) (@subst val id (@liftx (LiftEnviron val) b) (@eval_expr CS (Ebinop cmp e1 e2 ty))))) (@subst mpred id (@liftx (LiftEnviron val) b) P)) rho)) *)
  apply (exp_right (eval_id id rho)).
(* Goal: @eq Prop (@isSome unit (@PTree.get unit id (@PTree.set unit i tt idset0))) (@eq ident i id) *)
  autorewrite with subst.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (@andp mpred Nveric (@andp mpred Nveric (@tc_expr CS Delta e rho) (@tc_temp_id id (typeof e) CS Delta e rho)) (P rho))) (@subst mpred id (@eval_expr CS e) (fun x : environ => @andp mpred Nveric (@prop mpred Nveric (@eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@eval_expr CS e) x))) (@subst mpred id (fun _ : environ => eval_id id rho) P x)) rho) *)
  unfold local, lift1; unfold_lift; simpl.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
  unfold typecheck_tid_ptr_compare in H4.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
  simpl in H4.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
  destruct ((temp_types Delta) ! id) eqn:?H; inv H4.
(* Goal: @derives mpred Nveric (@andp mpred Nveric (@prop mpred Nveric (tc_environ Delta rho)) (P rho)) (@andp mpred Nveric (@prop mpred Nveric (@subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho)) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho)) *)
  normalize.
(* Goal: or (@eq ident id i) (@eq (option val) (@Map.get val (te_of rho) i) (@Map.get val (@Map.set val id (e rho) (te_of rho)) i)) *)
  apply andp_right.
(* Goal: or (@eq ident id i) (@eq (option val) (@Map.get val (te_of rho) i) (@Map.get val (@Map.set val id (e rho) (te_of rho)) i)) *)
  + apply prop_right.
(* Goal: @subst Prop id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (fun x : environ => @eq val (eval_id id x) (@subst val id (fun _ : environ => eval_id id rho) (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) x)) rho *)
    unfold subst.
(* Goal: @derives mpred Nveric (P rho) (@subst mpred id (@liftx (Tarrow val (Tarrow val (LiftEnviron val))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2))) (@eval_expr CS e1) (@eval_expr CS e2)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho) *)
    unfold_lift.
(* Goal: @eq val (eval_id id (env_set rho id (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 (env_set (env_set rho id (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho))) id (eval_id id rho))) (@eval_expr CS e2 (env_set (env_set rho id (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho))) id (eval_id id rho)))) *)
    rewrite env_set_env_set.
(* Goal: @eq val (eval_id id (env_set rho id (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)))) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 (env_set rho id (eval_id id rho))) (@eval_expr CS e2 (env_set rho id (eval_id id rho)))) *)
    rewrite eval_id_same.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    erewrite env_set_eval_id by eauto.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    auto.
  + unfold_lift.
(* Goal: @derives mpred Nveric (P rho) (@subst mpred id (fun x : environ => force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 x) (@eval_expr CS e2 x)) (@subst mpred id (fun _ : environ => eval_id id rho) P) rho) *)
    rewrite resubst_full.
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
    erewrite subst_self; eauto.
Qed.

End PtrCmpB2F.

Module Type CLIGHT_SEPARATION_HOARE_LOGIC_SSET_BACKWARD.

Declare Module CSHL_Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF.

Import CSHL_Def.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Axiom semax_set_ptr_compare_load_cast_load_backward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall (P: environ->mpred) id e,
    @semax CS Espec Delta
       ((|> ( (tc_expr Delta e) &&
             (tc_temp_id id (typeof e) Delta e) &&
             subst id (eval_expr e) P)) ||
        (EX cmp: Cop.binary_operation, EX e1: expr, EX e2: expr,
         EX ty: type, EX sh1: share, EX sh2: share,
          !! (e = Ebinop cmp e1 e2 ty /\
              sepalg.nonidentity sh1 /\ sepalg.nonidentity sh2 /\
              is_comparison cmp = true /\
              eqb_type (typeof e1) int_or_ptr_type = false /\
              eqb_type (typeof e2) int_or_ptr_type = false /\
              typecheck_tid_ptr_compare Delta id = true) &&
            ( |> ( (tc_expr Delta e1) &&
              (tc_expr Delta e2)  &&
          local (`(blocks_match cmp) (eval_expr e1) (eval_expr e2)) &&
          (`(mapsto_ sh1 (typeof e1)) (eval_expr e1) * TT) &&
          (`(mapsto_ sh2 (typeof e2)) (eval_expr e2) * TT) &&
          subst id (eval_expr (Ebinop cmp e1 e2 ty)) P))) ||
        (EX sh: share, EX t2: type, EX v2: val,
              !! (typeof_temp Delta id = Some t2 /\
                  is_neutral_cast (typeof e) t2 = true /\
                  readable_share sh) &&
         |> ( (tc_lvalue Delta e) &&
              local (`(tc_val (typeof e) v2)) &&
              (`(mapsto sh (typeof e)) (eval_lvalue e) (`v2) * TT) &&
              subst id (`v2) P)) ||
        (EX sh: share, EX e1: expr, EX t1: type, EX v2: val,
              !! (e = Ecast e1 t1 /\
                  typeof_temp Delta id = Some t1 /\
                  cast_pointer_to_bool (typeof e1) t1 = false /\
                  readable_share sh) &&
         |> ( (tc_lvalue Delta e1) &&
              local (`(tc_val t1) (`(eval_cast (typeof e1) t1 v2))) &&
              (`(mapsto sh (typeof e1)) (eval_lvalue e1) (`v2) * TT) &&
              subst id (`(force_val (sem_cast (typeof e1) t1 v2))) P)))
        (Sset id e) (normal_ret_assert P).

End CLIGHT_SEPARATION_HOARE_LOGIC_SSET_BACKWARD.

Module ToSset
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (Conseq: CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE with Module CSHL_Def := Def)
       (Extr: CLIGHT_SEPARATION_HOARE_LOGIC_EXTRACTION with Module CSHL_Def := Def)
       (SetB: CLIGHT_SEPARATION_HOARE_LOGIC_SET_BACKWARD with Module CSHL_Def := Def)
       (PtrCmpB: CLIGHT_SEPARATION_HOARE_LOGIC_PTR_CMP_BACKWARD with Module CSHL_Def := Def)
       (LoadB: CLIGHT_SEPARATION_HOARE_LOGIC_LOAD_BACKWARD with Module CSHL_Def := Def)
       (CastLoadB: CLIGHT_SEPARATION_HOARE_LOGIC_CAST_LOAD_BACKWARD with Module CSHL_Def := Def):
       CLIGHT_SEPARATION_HOARE_LOGIC_SSET_BACKWARD with Module CSHL_Def := Def.

Module CSHL_Def := Def.
Module ConseqFacts := GenConseqFacts (Def) (Conseq).
Module ExtrFacts := GenExtrFacts (Def) (Conseq) (Extr).

Import Def.
Import Conseq.
Import ConseqFacts.
Import SetB.
Import PtrCmpB.
Import LoadB.
Import CastLoadB.
Import ExtrFacts.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Theorem semax_set_ptr_compare_load_cast_load_backward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall (P: environ->mpred) id e,
    @semax CS Espec Delta
       ((|> ( (tc_expr Delta e) &&
             (tc_temp_id id (typeof e) Delta e) &&
             subst id (eval_expr e) P)) ||
        (EX cmp: Cop.binary_operation, EX e1: expr, EX e2: expr,
         EX ty: type, EX sh1: share, EX sh2: share,
          !! (e = Ebinop cmp e1 e2 ty /\
              sepalg.nonidentity sh1 /\ sepalg.nonidentity sh2 /\
              is_comparison cmp = true /\
              eqb_type (typeof e1) int_or_ptr_type = false /\
              eqb_type (typeof e2) int_or_ptr_type = false /\
              typecheck_tid_ptr_compare Delta id = true) &&
            ( |> ( (tc_expr Delta e1) &&
              (tc_expr Delta e2)  &&
          local (`(blocks_match cmp) (eval_expr e1) (eval_expr e2)) &&
          (`(mapsto_ sh1 (typeof e1)) (eval_expr e1) * TT) &&
          (`(mapsto_ sh2 (typeof e2)) (eval_expr e2) * TT) &&
          subst id (eval_expr (Ebinop cmp e1 e2 ty)) P))) ||
        (EX sh: share, EX t2: type, EX v2: val,
              !! (typeof_temp Delta id = Some t2 /\
                  is_neutral_cast (typeof e) t2 = true /\
                  readable_share sh) &&
         |> ( (tc_lvalue Delta e) &&
              local (`(tc_val (typeof e) v2)) &&
              (`(mapsto sh (typeof e)) (eval_lvalue e) (`v2) * TT) &&
              subst id (`v2) P)) ||
        (EX sh: share, EX e1: expr, EX t1: type, EX v2: val,
              !! (e = Ecast e1 t1 /\
                  typeof_temp Delta id = Some t1 /\
                  cast_pointer_to_bool (typeof e1) t1 = false /\
                  readable_share sh) &&
         |> ( (tc_lvalue Delta e1) &&
              local (`(tc_val t1) (`(eval_cast (typeof e1) t1 v2))) &&
              (`(mapsto sh (typeof e1)) (eval_lvalue e1) (`v2) * TT) &&
              subst id (`(force_val (sem_cast (typeof e1) t1 v2))) P)))
        (Sset id e) (normal_ret_assert P).
Proof.
(* Goal: None *)
  intros.
(* Goal: None *)
  apply semax_orp; [apply semax_orp; [apply semax_orp |] |].
  + apply semax_set_backward.
  + apply semax_ptr_compare_backward.
  + apply semax_load_backward.
  + apply semax_cast_load_backward.
Qed.

End ToSset.

Module Sset2Set
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (Conseq: CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE with Module CSHL_Def := Def)
       (Sset: CLIGHT_SEPARATION_HOARE_LOGIC_SSET_BACKWARD with Module CSHL_Def := Def):
       CLIGHT_SEPARATION_HOARE_LOGIC_SET_BACKWARD with Module CSHL_Def := Def.

Module CSHL_Def := Def.
Module ConseqFacts := GenConseqFacts (Def) (Conseq).

Import Def.
Import Conseq.
Import ConseqFacts.
Import Sset.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Theorem semax_set_backward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall (P: environ->mpred) id e,
    @semax CS Espec Delta
        (|> ( (tc_expr Delta e) &&
             (tc_temp_id id (typeof e) Delta e) &&
             subst id (eval_expr e) P))
          (Sset id e) (normal_ret_assert P).
Proof.
(* Goal: None *)
  intros.
  eapply semax_pre_simple; [| apply semax_set_ptr_compare_load_cast_load_backward].
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  apply orp_right1, orp_right1, orp_right1; auto.
Qed.

End Sset2Set.

Module Sset2PtrCmp
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (Conseq: CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE with Module CSHL_Def := Def)
       (Sset: CLIGHT_SEPARATION_HOARE_LOGIC_SSET_BACKWARD with Module CSHL_Def := Def):
       CLIGHT_SEPARATION_HOARE_LOGIC_PTR_CMP_BACKWARD with Module CSHL_Def := Def.

Module CSHL_Def := Def.
Module ConseqFacts := GenConseqFacts (Def) (Conseq).

Import Def.
Import Conseq.
Import ConseqFacts.
Import Sset.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Theorem semax_ptr_compare_backward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall P id e,
   @semax CS Espec Delta
        (EX cmp: Cop.binary_operation, EX e1: expr, EX e2: expr,
         EX ty: type, EX sh1: share, EX sh2: share,
          !! (e = Ebinop cmp e1 e2 ty /\
              sepalg.nonidentity sh1 /\ sepalg.nonidentity sh2 /\
              is_comparison cmp = true /\
              eqb_type (typeof e1) int_or_ptr_type = false /\
              eqb_type (typeof e2) int_or_ptr_type = false /\
              typecheck_tid_ptr_compare Delta id = true) &&
            ( |> ( (tc_expr Delta e1) &&
              (tc_expr Delta e2)  &&
          local (`(blocks_match cmp) (eval_expr e1) (eval_expr e2)) &&
          (`(mapsto_ sh1 (typeof e1)) (eval_expr e1) * TT) &&
          (`(mapsto_ sh2 (typeof e2)) (eval_expr e2) * TT) &&
          subst id (eval_expr (Ebinop cmp e1 e2 ty)) P)))
          (Sset id e)
        (normal_ret_assert P).
Proof.
(* Goal: None *)
  intros.
  eapply semax_pre_simple; [| apply semax_set_ptr_compare_load_cast_load_backward].
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  apply orp_right1, orp_right1, orp_right2; auto.
Qed.

End Sset2PtrCmp.

Module Sset2Load
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (Conseq: CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE with Module CSHL_Def := Def)
       (Sset: CLIGHT_SEPARATION_HOARE_LOGIC_SSET_BACKWARD with Module CSHL_Def := Def):
       CLIGHT_SEPARATION_HOARE_LOGIC_LOAD_BACKWARD with Module CSHL_Def := Def.

Module CSHL_Def := Def.
Module ConseqFacts := GenConseqFacts (Def) (Conseq).

Import Def.
Import Conseq.
Import ConseqFacts.
Import Sset.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Theorem semax_load_backward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall (P: environ->mpred) id e1,
    @semax CS Espec Delta
        (EX sh: share, EX t2: type, EX v2: val,
              !! (typeof_temp Delta id = Some t2 /\
                  is_neutral_cast (typeof e1) t2 = true /\
                  readable_share sh) &&
         |> ( (tc_lvalue Delta e1) &&
              local (`(tc_val (typeof e1) v2)) &&
              (`(mapsto sh (typeof e1)) (eval_lvalue e1) (`v2) * TT) &&
              subst id (`v2) P))
        (Sset id e1) (normal_ret_assert P).
Proof.
(* Goal: None *)
  intros.
  eapply semax_pre_simple; [| apply semax_set_ptr_compare_load_cast_load_backward].
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  apply orp_right1, orp_right2; auto.
Qed.

End Sset2Load.

Module Sset2CastLoad
       (Def: CLIGHT_SEPARATION_HOARE_LOGIC_DEF)
       (Conseq: CLIGHT_SEPARATION_HOARE_LOGIC_CONSEQUENCE with Module CSHL_Def := Def)
       (Sset: CLIGHT_SEPARATION_HOARE_LOGIC_SSET_BACKWARD with Module CSHL_Def := Def):
       CLIGHT_SEPARATION_HOARE_LOGIC_CAST_LOAD_BACKWARD with Module CSHL_Def := Def.

Module CSHL_Def := Def.
Module ConseqFacts := GenConseqFacts (Def) (Conseq).

Import Def.
Import Conseq.
Import ConseqFacts.
Import Sset.

(* Goal: @derives (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (local (tc_environ Delta)) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@subst mpred id (@eval_expr CS e) P))))) (@later (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@LiftIndir environ mpred Nveric Iveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@tc_expr CS Delta e) (@tc_temp_id id (typeof e) CS Delta e)) (@andp (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@prop (forall _ : environ, mpred) (@LiftNatDed' mpred Nveric) (@ex type (fun t : type => @eq (option type) (@PTree.get type id (temp_types Delta)) (@Some type t)))) (@subst mpred id (@eval_expr CS e) P)))) *)
(* Goal: None *)
Theorem semax_cast_load_backward: forall {CS: compspecs} {Espec: OracleKind} (Delta: tycontext),
  forall (P: environ->mpred) id e,
    @semax CS Espec Delta
        (EX sh: share, EX e1: expr, EX t1: type, EX v2: val,
              !! (e = Ecast e1 t1 /\
                  typeof_temp Delta id = Some t1 /\
                  cast_pointer_to_bool (typeof e1) t1 = false /\
                  readable_share sh) &&
         |> ( (tc_lvalue Delta e1) &&
              local (`(tc_val t1) (`(eval_cast (typeof e1) t1 v2))) &&
              (`(mapsto sh (typeof e1)) (eval_lvalue e1) (`v2) * TT) &&
              subst id (`(force_val (sem_cast (typeof e1) t1 v2))) P))
        (Sset id e) (normal_ret_assert P).
Proof.
(* Goal: None *)
  intros.
  eapply semax_pre_simple; [| apply semax_set_ptr_compare_load_cast_load_backward].
(* Goal: @eq val (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) (force_val2 (@sem_binary_operation' CS cmp (typeof e1) (typeof e2)) (@eval_expr CS e1 rho) (@eval_expr CS e2 rho)) *)
  apply orp_right2; auto.
Qed.

End Sset2CastLoad.

