Tactic Notation "forward_for" constr(Inv) :=
check_Delta; check_POSTCONDITION;
repeat simple apply seq_assoc1;
lazymatch type of Inv with
| _ -> environ -> mpred => idtac
| _ => fail "Invariant (first argument to forward_for) must have type (_ -> environ -> mpred)"
end;
lazymatch goal with
| |- semax _ _ (Ssequence (Sfor _ _ _ _) _) _ =>
apply semax_convert_for_while';
[(reflexivity ||
fail "Your for-loop has a continue statement, so your forward_for needs a continue: clause")
| (reflexivity || fail "Unexpected continue statement in for-loop increment")
| apply semax_seq' with (exp Inv);
[  |  forward_while (EX x:_, Inv x); [ apply ENTAIL_refl | | |  ]  ] ]
| |- semax _ _ (Sfor _ _ _ _) _ =>
apply semax_convert_for_while;
[(reflexivity ||
fail "Your for-loop has a continue statement, so your forward_for needs a continue: clause")
| (reflexivity || fail "Unexpected continue statement in for-loop increment")
| apply semax_seq' with (exp Inv);
[  |  forward_while (EX x:_, Inv x);
[ apply ENTAIL_refl | | | eapply semax_post_flipped'; [apply semax_skip | ] ]  ] ]
end.
Ltac process_cases sign :=
match goal with
| |- semax _ _ (seq_of_labeled_statement
match select_switch_case ?N (LScons (Some ?X) ?C ?SL)
with Some _ => _ | None => _ end) _ =>
let y := constr:(adjust_for_sign sign X) in let y := eval compute in y in
rewrite (select_switch_case_signed y);
[ | reflexivity | clear; compute; split; congruence];
let E := fresh "E" in let NE := fresh "NE" in
destruct (zeq N (Int.unsigned (Int.repr y))) as [E|NE];
[ rewrite if_true; [ unfold seq_of_labeled_statement at 1 | symmetry; apply E];
apply unsigned_eq_eq in E;
match sign with
| Signed => apply repr_inj_signed in E; [ | rep_omega | rep_omega]
| Unsigned => apply repr_inj_unsigned in E; [ | rep_omega | rep_omega]
end;
try match type of E with ?a = _ => is_var a; subst a end;
repeat apply -> semax_skip_seq
| rewrite if_false by (contradict NE; symmetry; apply NE);
process_cases sign
]
| |- semax _ _ (seq_of_labeled_statement
match select_switch_case ?N (LScons None ?C ?SL)
with Some _ => _ | None => _ end) _ =>
change (select_switch_case N (LScons None C SL))
with (select_switch_case N SL);
process_cases sign
| |- semax _ _ (seq_of_labeled_statement
match select_switch_case ?N LSnil
with Some _ => _ | None => _ end) _ =>
change (select_switch_case N LSnil)
with (@None labeled_statements);
cbv iota;
unfold seq_of_labeled_statement at 1;
repeat apply -> semax_skip_seq
end.
Ltac forward_switch' :=
match goal with
| |- semax ?Delta (PROPx ?P (LOCALx ?Q (SEPx ?R))) (Sswitch ?e _) _ =>
let sign := constr:(signof e) in let sign := eval hnf in sign in
let HRE := fresh "H" in let v := fresh "v" in
evar (v: val);
do_compute_expr Delta P Q R e v HRE;
simpl in v;
let n := fresh "n" in evar (n: int);
let H := fresh in assert (H: v=Vint n) by (unfold v,n; reflexivity);
let A := fresh in
match goal with |- ?AA => set (A:=AA) end;
revert n H; normalize; intros n H; subst A;
let n' := fresh "n" in pose (n' := Int.unsigned n);
let H' := fresh in assert (H': n = Int.repr n');
[try (symmetry; apply Int.repr_unsigned)
| rewrite H,H' in HRE; clear H H';
subst n' n v;
rewrite (Int.repr_unsigned (Int.repr _)) in HRE;
eapply semax_switch_PQR;
[reflexivity | check_typecheck | exact HRE
| clear HRE; unfold select_switch at 1; unfold select_switch_default at 1;
try match goal with H := @abbreviate statement _ |- _ => clear H end;
process_cases sign ]
]
end.
Definition nofallthrough ek :=
match ek with
| EK_normal => false
| _ => true
end.
Ltac forward_if'_new :=
check_Delta; check_POSTCONDITION;
repeat apply -> semax_seq_skip;
repeat (apply seq_assoc1; try apply -> semax_seq_skip);
match goal with
| |- semax ?Delta (PROPx ?P (LOCALx ?Q (SEPx ?R))) (Sifthenelse ?e ?c1 ?c2) _ =>
let HRE := fresh "H" in let v := fresh "v" in
evar (v: val);
do_compute_expr Delta P Q R e v HRE;
simpl in v;
apply (semax_ifthenelse_PQR' _ v);
[ reflexivity | entailer | assumption
| clear HRE; subst v; apply semax_extract_PROP; intro HRE;
do_repr_inj HRE;
repeat (apply semax_extract_PROP; intro);
try rewrite Int.signed_repr in HRE by rep_omega;
repeat apply -> semax_skip_seq;
abbreviate_semax
| clear HRE; subst v; apply semax_extract_PROP; intro HRE;
do_repr_inj HRE;
repeat (apply semax_extract_PROP; intro);
try rewrite Int.signed_repr in HRE by rep_omega;
repeat apply -> semax_skip_seq;
abbreviate_semax
]
| |- semax ?Delta (PROPx ?P (LOCALx ?Q (SEPx ?R))) (Ssequence (Sifthenelse ?e ?c1 ?c2) _) _ =>
tryif (unify (orb (quickflow c1 nofallthrough) (quickflow c2 nofallthrough)) true)
then (apply semax_if_seq; forward_if'_new)
else fail "Because your if-statement is followed by another statement, you need to do 'forward_if Post', where Post is a postcondition of type (environ->mpred) or of type Prop"
| |- semax _ (@exp _ _ _ _) _ _ =>
fail "First use Intros ... to take care of the EXistentially quantified variables in the precondition"
| |- semax _ _ (Sswitch _ _) _ =>
forward_switch'
| |- semax _ _ (Ssequence (Sifthenelse _ _ _) _) _ =>
fail "forward_if failed for some unknown reason, perhaps your precondition is not in canonical form"
| |- semax _ _ (Ssequence (Sswitch _ _) _) _ =>
fail "Because your switch statement is followed by another statement, you need to do 'forward_if Post', where Post is a postcondition of type (environ->mpred) or of type Prop"
end.

(* Specifications: *)
Lemma ENTAIL_break_normal:
forall Delta R S, ENTAIL Delta, RA_break (normal_ret_assert R) |-- S.
Lemma ENTAIL_continue_normal:
forall Delta R S, ENTAIL Delta, RA_continue (normal_ret_assert R) |-- S.
Lemma ENTAIL_return_normal:
forall Delta R v S, ENTAIL Delta, RA_return (normal_ret_assert R) v |-- S.