(* linked list, for free blocks. p points to a linked list of len blocks, each of sz bytes, of the form (sz,nxt,_) with link nxt, terminated at r. Using nat for ease of termination check, at cost of Z conversions. *)
Fixpoint mmlist (sz: Z) (len: nat) (p: val) (r: val): mpred :=
match len with
| O => !! (ptr_eq p r) && emp
| (S n) => EX q:val, !! is_pointer_or_null q &&
data_at Tsh tuint (offset_val (-WORD) p) (Vint(Int.repr sz))
* data_at Tsh (tptr tvoid) p q
* memory_block Tsh (sz - WORD) (offset_val WORD p)
* mmlist sz n q r
end.
(* module invariant: Each element of array points to a null-terminated list of right size blocks.  This version folds over index list, which makes it easy to express the block size per bin; it may facilitate per-index update. *)
Definition mm_inv (arr: val): mpred :=
EX bins: list val, EX lens: list nat,
!! (Zlength bins = BINS /\ Zlength lens = BINS)  &&
data_at Tsh (tarray (tptr tvoid) BINS) bins arr
* fold_right (fun (i: nat) => fun (mp: mpred) =>
(mmlist (bin2sizeZ (Z.of_nat i)) (nth i lens O) (nth i bins nullval) nullval) * mp )
emp
(seq 0 (Z.to_nat BINS)).
(* copy of malloc_spec' from floyd library, with mm_inv added *)
Definition malloc_spec'' :=
DECLARE _malloc
WITH n:Z, bin:val
PRE [ 1%positive OF tuint ]
PROP (0 <= n <= Int.max_unsigned)
LOCAL (temp 1%positive (Vint (Int.repr n)); gvar _bin bin)
SEP ( mm_inv bin )
POST [ tptr tvoid ] EX p:_,
PROP ()
LOCAL (temp ret_temp p)
SEP ( mm_inv bin;
if eq_dec p nullval then emp
else (malloc_token Tsh n p * memory_block Tsh n p)).
Definition free_spec'' := (* copy from floyd lib, with mm_inv added *)
DECLARE _free
WITH p:_, n:_, bin:_
PRE [ 1%positive OF tptr tvoid ]
PROP ()
LOCAL (temp 1%positive p; gvar _bin bin)
SEP (malloc_token Tsh n p; memory_block Tsh n p; mm_inv bin)
POST [ Tvoid ]
PROP ()
LOCAL ()
SEP (mm_inv bin).
Definition malloc_small_spec :=
DECLARE _malloc_small
WITH n:Z, bin:_
PRE [ 1%positive OF tuint ]
PROP (0 <= n <= bin2sizeZ(BINS-1))
LOCAL (temp 1%positive (Vint (Int.repr n)); gvar _bin bin)
SEP ( mm_inv bin )
POST [ tptr tvoid ] EX p:_,
PROP ()
LOCAL (temp ret_temp p)
SEP ( mm_inv bin;
if eq_dec p nullval then emp
else (malloc_token' Tsh n p * memory_block Tsh n p)).
Definition free_small_spec :=
DECLARE _free_small
WITH p:_, n:_, s:_
PRE [ 1%positive OF tptr tvoid, 2%positive OF tint ]
PROP ( n = s )
LOCAL (temp 1%positive p; temp 2%positive (Vint (Int.repr s)))
SEP (malloc_token' Tsh n p; memory_block Tsh n p)
POST [ tvoid ]
PROP ()
LOCAL ()
SEP ().
Definition fill_bin_spec :=
DECLARE _fill_bin
WITH b: _
PRE [ _b OF tint ]
PROP(0 <= b < BINS) LOCAL (temp _b (Vint (Int.repr b))) SEP ()
POST [ (tptr tvoid) ] EX p:_, EX len:Z,
PROP( len > 0 )
LOCAL(temp ret_temp p)
SEP ( mmlist (bin2sizeZ b) (Z.to_nat len) p nullval ).
Definition main_spec :=
DECLARE _main
WITH u : unit
PRE  [] main_pre prog nil u
POST [ tint ]  main_post prog nil u.
Definition Gprog : funspecs :=
ltac:(with_library prog [
sbrk_spec; bin2size_spec; size2bin_spec; fill_bin_spec;
malloc_small_spec; free_small_spec; malloc_spec''; free_spec'';
main_spec]).

Lemma body_bin2size: semax_body Vprog Gprog f_bin2size bin2size_spec.
Definition fill_bin_dummy (b:Z) (p:val) (qNs:val*Z*Z) :=
PROP(True)LOCAL(temp _q (let '(q, _, _) := qNs in q);
temp _p p;
temp _s (Vint (Int.repr (let '(_,_,s) := qNs in s)));
temp _b (Vint (Int.repr b)))
SEP().