Local Open Scope logic.
Definition int_type_min_max (type_i type_hi: type): option (Z * Z) :=
match type_i, type_hi with
| Tint I32 s_i _, Tint i_hi s_hi _ =>
Some match s_i with
| Signed => (match i_hi, s_hi with
| I32, Unsigned => 0
| _, _ => Int.min_signed
end, Int.max_signed)
| Unsigned => (0, Int.max_unsigned)
end
| Tint I32 s_i _, Tlong s_hi _ =>
Some match s_i with
| Signed => match s_hi with
| Unsigned => (0, Int.max_signed)
| _ => (Int.min_signed, Int.max_signed)
end
| Unsigned => (0, Int.max_unsigned)
end
| _, _ => None
end.
Inductive range_init_hl (type_lo type_i type_hi: type): (Z -> Z -> Prop) -> Prop :=
| construct_range_init_hl:
forall int_min int_max,
is_int_type type_lo = true ->
int_type_min_max type_i type_hi = Some (int_min, int_max) ->
range_init_hl type_lo type_i type_hi (fun m n => int_min <= m <= n /\ n <= int_max).
(* Lemma range_init_hl_spec: forall (type_lo type_i type_hi: type) range, range_init_hl type_lo type_i type_hi range -> exists int_min_lo int_max_lo int_min_i int_max_i int_min_hi int_max_hi int_min int_max, is_int32_type type_lo = true /\ is_int32_type type_i = true /\ int_type_min_max type_lo = Some (int_min_lo, int_max_lo) /\ int_type_min_max type_i = Some (int_min_i, int_max_i) /\ int_type_min_max type_hi = Some (int_min_hi, int_max_hi) /\ int_min = Z.max (Z.max int_min_lo int_min_i) int_min_hi /\ int_max = Z.min int_max_i int_max_hi /\ forall m n, range m n -> m <= int_max_lo /\ int_min <= m <= n /\ int_min_hi <= n <= int_max. *)
Inductive range_init_h (type_i type_hi: type): Z -> (Z -> Prop) -> Prop :=
| construct_range_init_h:
forall int_min int_max,
int_type_min_max type_i type_hi = Some (int_min, int_max) ->
range_init_h type_i type_hi int_min (fun n =>
int_min <= n <= int_max).
Inductive Int_eqm_unsigned: int -> Z -> Prop :=
| Int_eqm_unsigned_repr: forall z, Int_eqm_unsigned (Int.repr z) z.
Inductive Int64_eqm_unsigned: int64 -> Z -> Prop :=
| Int64_eqm_unsigned_repr: forall z, Int64_eqm_unsigned (Int64.repr z) z.
Inductive Int6432_val: type -> val -> Z -> Prop :=
| Int_64_eqm_unsigned_repr: forall s i64 z,
Int64_eqm_unsigned i64 z ->
Int6432_val (Tlong s noattr) (Vlong i64) z
| Int_32_eqm_unsigned_repr: forall s i i32 z,
Int_eqm_unsigned i32 z ->
Int6432_val (Tint s i noattr) (Vint i32) z.
Inductive Sfor_inv_rec {cs: compspecs} (Delta: tycontext): ident -> Z -> Z -> expr -> Z -> (environ -> mpred) -> (environ -> mpred) -> (environ -> mpred) -> Prop :=
| Sfor_inv_rec_step': forall A _i i m hi n assert_callee inv0 inv1,
(forall x: A,
Sfor_inv_rec Delta _i i m hi n (assert_callee x) (inv0 x) (inv1 x)) ->
Sfor_inv_rec Delta _i i m hi n (exp assert_callee) (exp inv0) (exp inv1)
| Sfor_inv_rec_end: forall _i i m hi n' n P Q R T1 T2 GV (*tactic callee*),
local2ptree Q = (T1, T2, nil, GV) ->
T1 ! _i = None ->
msubst_eval_expr Delta T1 T2 GV hi = Some n' ->
Int6432_val (typeof hi) n' n ->
ENTAIL Delta, PROPx P (LOCALx Q (SEPx R)) |-- tc_expr Delta hi ->
Sfor_inv_rec Delta _i i m hi n
(PROPx P (LOCALx Q (SEPx R)))
(PROPx ((m <= i <= n) :: P) (LOCALx (temp _i (Vint (Int.repr i)) :: Q) (SEPx R)))
(PROPx P (LOCALx (temp _i (Vint (Int.repr i)) :: Q) (SEPx R))).
Inductive Sfor_inv {cs: compspecs} (Delta: tycontext):
forall (_i: ident) (m: Z) (hi: expr) (n: Z)
(assert_callee: Z -> environ -> mpred)
(inv0: environ -> mpred)
(inv1 inv2: Z -> environ -> mpred), Prop :=
| construct_Sfor_inv: forall _i m hi n assert_callee inv0 inv1,
(forall i i', exists inv0' inv0'' inv1' inv1'', Sfor_inv_rec Delta _i i' m hi n (assert_callee i) inv0'' inv1'' /\ inv0' i' = inv0'' /\ inv0 i = inv0' /\ inv1' i' = inv1'' /\ inv1 i = inv1') ->
Sfor_inv Delta _i m hi n assert_callee (EX i: Z, inv0 i i) (fun i => inv1 i i) (fun i => inv1 (i+1) i).
(* need to export range_hi? no *)
Inductive Sfor_setup {cs: compspecs} {Espec: OracleKind} (Delta: tycontext):
forall (_i: ident) (Pre: environ -> mpred) (init: statement) (hi: expr) (type_i: type)
(m n: Z) (assert_callee: Z -> environ -> mpred)
(inv0: environ -> mpred), Prop :=
| Sfor_setup_const_init: forall m' m lo _i type_i hi n Pre assert_callee inv0 range,
range_init_hl (typeof lo) type_i (typeof hi) range ->
const_only_eval_expr lo = Some (Vint m') ->
Int_eqm_unsigned m' m ->
range m n ->
ENTAIL Delta, Pre |-- assert_callee m ->
Sfor_setup Delta _i Pre (Sset _i lo) hi type_i m n assert_callee inv0
| Sfor_setup_other: forall _i Pre init hi type_i m n assert_callee inv0 range,
range_init_h type_i (typeof hi) m range ->
range n ->
@semax cs Espec Delta Pre init (normal_ret_assert inv0) ->
Sfor_setup Delta _i Pre init hi type_i m n assert_callee inv0.

Lemma Sfor_inv_spec: forall {cs: compspecs} (Delta: tycontext),
forall _i m hi n assert_callee inv0 inv1 inv2,
Sfor_inv Delta _i m hi n assert_callee inv0 inv1 inv2 ->
ENTAIL Delta, inv0 |-- EX n': val, !! (Int6432_val (typeof hi) n' n) && local (` (eq n') (eval_expr hi)) /\
ENTAIL Delta, inv0 |-- tc_expr Delta hi /\
(forall v i, subst _i (`v) (assert_callee i) = assert_callee i) /\
(forall i, local (locald_denote (temp _i (Vint (Int.repr i)))) && assert_callee i = inv1 i) /\
(forall i, local (locald_denote (temp _i (Vint (Int.repr i)))) && assert_callee (i+1) = inv2 i) /\
(EX i: Z, !! (m <= i <= n) && inv1 i = inv0).