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]]
].

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))))).