Hint Resolve ENTAIL_break_normal ENTAIL_continue_normal ENTAIL_return_normal.
Hint Extern 0 (ENTAIL _, _ |-- _) =>
match goal with |- ENTAIL _, ?A |-- ?B => constr_eq A B; simple apply ENTAIL_refl end.
Ltac forward_if_tac post :=
check_Delta; check_POSTCONDITION;
repeat (apply -> seq_assoc; abbreviate_semax);
repeat apply -> semax_seq_skip;
first [ignore (post: environ->mpred)
| fail 1 "Invariant (first argument to forward_if) must have type (environ->mpred)"];
match goal with
| |- semax _ _ (Sifthenelse _ _ _) (overridePost post _) =>
forward_if'_new
| |- semax _ _ (Sswitch _ _) _ =>
forward_switch'
| |- semax _ _ (Sifthenelse _ _ _) ?P =>
apply (semax_post_flipped (overridePost post P));
[ forward_if'_new
| try subst P; unfold abbreviate;
simpl_ret_assert;
try (match goal with |- ?A => no_evars A end;
try apply ENTAIL_refl;
try solve [normalize])
| intros; try subst P; unfold abbreviate;
simpl_ret_assert;
try (match goal with |- ?A => no_evars A end;
try apply ENTAIL_refl;
try solve [normalize])
..
]
| |- semax _ _ (Ssequence (Sifthenelse _ _ _) _) _ =>
apply semax_seq with post;
[forward_if'_new
| abbreviate_semax;
simpl_ret_assert (*autorewrite with ret_assert*)]
| |- semax _ _ (Ssequence (Sswitch _ _) _) _ =>
apply semax_seq with post;
[forward_switch'
| abbreviate_semax;
simpl_ret_assert (*autorewrite with ret_assert*)]
end.
Ltac remove_LOCAL name Q :=
let i := eval hnf in (find_LOCAL_index name O Q) in
match i with
| Some ?i' =>
let r := eval cbv iota zeta beta delta [delete_nth] in (delete_nth i' Q) in
constr:(r)
| None =>
constr:(Q)
end.
Ltac remove_LOCAL2 Qr Q :=
match Qr with
| nil => constr:(Q)
| cons ?Qr_head ?Qr_tail =>
match Qr_head with
| temp ?name _ =>
let Q' := remove_LOCAL name Q in remove_LOCAL2 Qr_tail Q'
| _ =>
remove_LOCAL2 Qr_tail Q
end
end.
Tactic Notation "forward_if" constr(post) :=
lazymatch type of post with
| Prop =>
match goal with
| |- semax _ (PROPx (?P) ?Q) _ _ =>
forward_if_tac (PROPx (post :: P) Q)
end
| list Prop =>
match goal with
| |- semax _ (PROPx (?P) ?Q) _ _ =>
let P' := eval cbv iota zeta beta delta [app] in (post ++ P) in
forward_if_tac (PROPx P' Q)
end
| localdef =>
match goal with
| |- semax _ (PROPx (?P) (LOCALx ?Q ?R)) _ _ =>
let Q' := remove_LOCAL2 constr:(cons post nil) Q in
forward_if_tac (PROPx (P) (LOCALx (post :: Q') R))
end
| list localdef =>
match goal with
| |- semax _ (PROPx (?P) (LOCALx ?Q ?R)) _ _ =>
let Q' := remove_LOCAL2 post Q in
let Q'' := eval cbv iota zeta beta delta [app] in (post ++ Q') in
forward_if_tac (PROPx (P) (LOCALx Q'' R))
end
| _ => forward_if_tac post
end.
Tactic Notation "forward_if" :=
forward_if'_new.
Ltac normalize :=
try match goal with |- context[subst] =>  autorewrite with subst typeclass_instances end;
try match goal with |- context[ret_assert] =>  autorewrite with ret_assert typeclass_instances end;
match goal with
| |- semax _ _ _ _ =>
floyd.seplog_tactics.normalize;
repeat
(first [ simpl_tc_expr
| simple apply semax_extract_PROP; fancy_intros true
| move_from_SEP
]; cbv beta; msl.log_normalize.normalize)
| |- _  =>
floyd.seplog_tactics.normalize
end.
Ltac renormalize :=
progress (autorewrite with subst norm1 norm2); normalize;
repeat (progress (autorewrite with subst norm1 norm2); normalize).

(* Specifications: *)
Lemma eqb_ident_true: forall i, eqb_ident i i = true.
Lemma eqb_ident_false: forall i j, i<>j -> eqb_ident i j = false.
Hint Rewrite eqb_ident_true : subst.