Instance CompSpecs : compspecs. make_compspecs prog. Defined.
Definition Vprog : varspecs. mk_varspecs prog. Defined.
Instance LS: listspec _list _tail (fun _ _ => emp).

(* Specifications: *)
Lemma butlast_snoc h t : butlast (h ++ [t]) = h.
Lemma fold_data_at sh t v : field_at sh t [] v = data_at sh t v. Proof. reflexivity. Qed.
Lemma butlast_fold h t : match t with [] => [] | _ :: _ => h :: butlast t end = butlast (h :: t). Proof. auto. Qed.
Lemma last_fold h t : match t with [] => h | _ :: _ => last t end = last (h :: t). Proof. auto. Qed.
Lemma snoc (l : list int) : l <> [] -> l = butlast l ++ [last l].
Definition merge_invariant _cond sh init_a init_b v_ret :=
(EX cond: int, EX a: list int, EX b: list int, EX merged: list int,
EX a_: val, EX b_: val, EX c_: val, EX begin: val,
PROP (merge init_a init_b = merged ++ merge a b;
cond = Int.zero <-> (a_ = nullval \/ b_ = nullval)
)
LOCAL (temp _a a_;
temp _b b_;
temp _x (if merged then v_ret else field_address (Tstruct _list noattr) [StructField _tail] c_);
lvar _ret tlist v_ret;
temp _cond (Vint cond)
)
SEP (lseg LS sh (map Vint a) a_ nullval;
lseg LS sh (map Vint b) b_ nullval;
data_at Tsh tlist (if merged then Vundef else begin) v_ret;
lseg LS sh (map Vint (butlast merged)) begin c_;
if merged then emp else data_at sh t_struct_list (Vint (last merged), Vundef) c_
))%assert.
Lemma merge_nil_r a : merge a nil = a.
Lemma merge_nil_l a : merge nil a = a.
(* TODO-LTAC - is this a missing lemma of the theory of [list_cell]?*)
Lemma list_cell_field_at sh (v : val) p :
list_cell LS sh v p = field_at sh list_struct [StructField _head] v p.
Lemma entail_rewrite A B : A |-- B -> A = A && B.
Lemma list_append_null (cs : compspecs)
(list_structid list_link : ident) (sh : share)
(ls : listspec list_structid list_link list_token) (hd mid : val)
(ct1 ct2 : list (elemtype ls)) :
lseg ls sh ct1 hd mid * lseg ls sh ct2 mid nullval
|-- lseg ls sh (ct1 ++ ct2) hd nullval.
Lemma body_merge: semax_body Vprog Gprog f_merge merge_spec.