Module LG <: LG_TYPE.
(* This is an _internal_ definition, not meant to be mentioned in proofs about _clients_ of the LG module.  It describes "known to be initialized" global LG data. *)
Definition data_ok (n: Z) (gv: globals) : mpred :=
!! (0 <= n <= Int.max_signed) &&
data_at Ews tint (Vint (Int.repr n)) (gv _LG_n) *
data_at Ews (Tstruct _foo noattr) (Vint Int.one, Vint (Int.repr n)) (gv _LG_foo).
(* This is an externally visible definition, describing global LG data whether initialized or not. *)
Definition data (n: Z) (gv: globals) : mpred :=
data_ok n gv ||
(!! (n=3) &&
data_at Ews tint (Vint (Int.repr n)) (gv _LG_n) *
data_at Ews (Tstruct _foo noattr) (Vint Int.zero, Vundef) (gv _LG_foo)).
(*  This describes the extern global variables of the LG.c file, as they would appear as processed by CompCert and Floyd. *)
Definition initialized_globals (gv: globals) :=
!! (headptr (gv _LG_n)) &&
!! (headptr (gv _LG_foo)) &&
mapsto Ews tuint (offset_val 4 (gv _LG_foo))
(Vint (Int.repr 0)) *
data_at Ews tuint (Vint (Int.repr 0)) (gv _LG_foo) *
data_at Ews tuint (Vint (Int.repr 3)) (gv _LG_n).
End LG.
(* The [init] function is not meant to be called from clients directly. Thus it can use an _internal_ abstraction, LG.data_ok, in its specification. *)
Definition init_spec :=
DECLARE _LG_init
WITH n: Z, gv: globals
PRE  []
PROP ()
LOCAL(gvars gv)
SEP(LG.data n gv)
POST [ tvoid ]
PROP()
LOCAL ()
SEP (LG.data_ok n gv).
(* The [bump] and [get] functions are meant to be called from client modules.  *)
Definition bump_spec :=
DECLARE _LG_bump
WITH n: Z, gv: globals
PRE  []
PROP (n < Int.max_signed)
LOCAL(gvars gv)
SEP(LG.data n gv)
POST [ tvoid ]
PROP()
LOCAL ()
SEP (LG.data (n+1) gv).
Definition get_spec :=
DECLARE _LG_get
WITH n: Z, gv: globals
PRE  []
PROP ()
LOCAL(gvars gv)
SEP(LG.data n gv)
POST [ tint ]
PROP()
LOCAL (temp ret_temp (Vint (Int.repr n)))
SEP (LG.data n gv).
Definition client_spec :=
DECLARE _client
WITH n: Z, gv: globals
PRE  []
PROP (n < 1000000000)
LOCAL(gvars gv)
SEP(LG.data n gv)
POST [ tint ]
PROP()
LOCAL (temp ret_temp (Vint (Int.repr (n+2))))
SEP (LG.data (n+2) gv).
Definition main_spec :=
DECLARE _main
WITH gv : globals
PRE  [] main_pre prog tt nil gv
POST [ tint ]
PROP()
LOCAL (temp ret_temp (Vint (Int.repr 5)))
SEP(TT).
Definition Gprog : funspecs :=
ltac:(with_library prog [
init_spec; bump_spec; get_spec; client_spec; main_spec]).

Lemma body_client: semax_body Vprog Gprog f_client client_spec.