Tactic Notation "semax_frame" constr(Qframe) constr(Rframe) :=
first
[ simple eapply (semax_frame_perm Qframe Rframe);
[auto 50 with closed | solve_perm | solve_perm | unfold app; fold @app ]
| eapply semax_post_flipped';
[simple eapply (semax_frame_perm Qframe Rframe);
[auto 50 with closed | solve_perm | solve_perm | unfold app; fold @app ]
| try solve [apply perm_derives; solve_perm]]
].
Tactic Notation "semax_frame" "[" "]" constr(Rframe) :=
first
[ simple eapply (semax_frame_perm nil Rframe);
[auto 50 with closed | solve_perm | solve_perm | unfold app; fold @app ]
| eapply semax_post_flipped';
[simple eapply (semax_frame_perm nil Rframe);
[auto 50 with closed | solve_perm | solve_perm | unfold app; fold @app ]
| try solve [apply perm_derives; solve_perm]]
].

(* Specifications: *)
Lemma semax_pre_later:
forall P' Espec {cs: compspecs} Delta P1 P2 P3 c R,
ENTAIL Delta, PROPx P1 (LOCALx P2 (SEPx P3)) |-- P' ->
@semax cs Espec Delta (|> P') c R  ->
@semax cs Espec Delta (|> (PROPx P1 (LOCALx P2 (SEPx P3)))) c R.
Lemma PROP_LOCAL_SEP_cons: forall P1 P2 P3 F,
PROPx P1 (LOCALx P2 (SEPx (F :: P3))) =
`F * PROPx P1 (LOCALx P2 (SEPx P3)).
Lemma semax_frame': forall {Espec: OracleKind}{CS: compspecs},
forall Delta P1 P2 P3 s Q1 Q2 Q3 F,
@semax CS Espec Delta
(PROPx P1 (LOCALx P2 (SEPx P3))) s
(normal_ret_assert (PROPx Q1 (LOCALx Q2 (SEPx Q3)))) ->
@semax CS Espec Delta
(PROPx P1 (LOCALx P2 (SEPx (F :: P3)))) s
(normal_ret_assert (PROPx Q1 (LOCALx Q2 (SEPx (F :: Q3))))).
Lemma semax_frame'': forall {Espec: OracleKind}{CS: compspecs},
forall Delta P1 P2 P3 s t Q1 Q2 Q3 F,
@semax CS Espec Delta
(PROPx P1 (LOCALx P2 (SEPx P3))) s
(frame_ret_assert
(function_body_ret_assert t (PROPx Q1 (LOCALx Q2 (SEPx Q3)))) emp) ->
@semax CS Espec Delta
(PROPx P1 (LOCALx P2 (SEPx (F :: P3)))) s
(frame_ret_assert
(function_body_ret_assert t (PROPx Q1 (LOCALx Q2 (SEPx (F :: Q3))))) emp).