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