Notation "'TYPE' A 'WITH'  x1 : t1 , x2 : t2 , x3 : t3 , x4 : t4 'PRE'  [ u , .. , v ] P 'POST' [ tz ] Q" :=
(mk_funspec ((cons u%formals .. (cons v%formals nil) ..), tz) cc_default A
(fun (ts: list Type) (x: t1*t2*t3*t4) =>
match x with (x1,x2,x3,x4) => P%assert end)
(fun (ts: list Type) (x: t1*t2*t3*t4) =>
match x with (x1,x2,x3,x4) => Q%assert end) _ _)
(at level 200, x1 at level 0, x2 at level 0, x3 at level 0, x4 at level 0,
P at level 100, Q at level 100).
Definition MA_spec v P (R : val -> mpred) Q := view_shift P (valid R v * (weak_precise_mpred (R v) && emp) * Q).
Definition MA_type := ProdType (ProdType (ProdType (ConstType val) Mpred) (ArrowType (ConstType val) Mpred)) Mpred.
Program Definition make_atomic_spec := DECLARE _make_atomic TYPE MA_type
WITH v : val, P : mpred, R : val -> mpred, Q : mpred
PRE [ _v OF tptr tvoid ]
PROP (MA_spec v P R Q)
LOCAL (temp _v v)
SEP (P)
POST [ tptr tatomic ]
EX p : val,
PROP ()
LOCAL (temp ret_temp p)
SEP (atomic_loc Tsh p R; Q).
Next Obligation.
Next Obligation.
Notation "'TYPE' A 'WITH'  x1 : t1 , x2 : t2 'PRE'  [ u , .. , v ] P 'POST' [ tz ] Q" :=
(mk_funspec ((cons u%formals .. (cons v%formals nil) ..), tz) cc_default A
(fun (ts: list Type) (x: t1*t2) =>
match x with (x1,x2) => P%assert end)
(fun (ts: list Type) (x: t1*t2) =>
match x with (x1,x2) => Q%assert end) _ _)
(at level 200, x1 at level 0, x2 at level 0,
P at level 100, Q at level 100).
Program Definition free_atomic_spec := DECLARE _free_atomic
TYPE ProdType (ConstType val) (ArrowType (ConstType val) Mpred)
WITH p : val, R : val -> mpred
PRE [ _tgt OF tptr tatomic ]
PROP ()
LOCAL (temp _tgt p)
SEP (atomic_loc Tsh p R)
POST [ tptr tvoid ]
EX v : val,
PROP ()
LOCAL (temp ret_temp v)
SEP (valid R v).
Next Obligation.
Next Obligation.
Definition AL_spec P (R : val -> mpred) Q := forall vx, view_shift (valid R vx * P) (valid R vx * Q vx).
Definition AL_type := ProdType (ProdType (ProdType (ConstType (share * val))
Mpred) (ArrowType (ConstType val) Mpred)) (ArrowType (ConstType val) Mpred).
Notation "'TYPE' A 'WITH'  x1 : t1 , x2 : t2 , x3 : t3 , x4 : t4 , x5 : t5 'PRE'  [ u , .. , v ] P 'POST' [ tz ] Q" :=
(mk_funspec ((cons u%formals .. (cons v%formals nil) ..), tz) cc_default A
(fun (ts: list Type) (x: t1*t2*t3*t4*t5) =>
match x with (x1,x2,x3,x4,x5) => P%assert end)
(fun (ts: list Type) (x: t1*t2*t3*t4*t5) =>
match x with (x1,x2,x3,x4,x5) => Q%assert end) _ _)
(at level 200, x1 at level 0, x2 at level 0, x3 at level 0, x4 at level 0,
x5 at level 0,
P at level 100, Q at level 100).
(* One obvious restriction on this rule that might be needed for soundness (but maybe not for SC?) is that the footprint of P be empty, and vice versa for store. *)
(* For this to work with load_acquire, Q needs to be somehow future-proof: it should be okay even if v wasn't actually the latest value of tgt. For instance, Q might only get a history that's some prefix of the latest state. *)
Program Definition load_SC_spec := DECLARE _load_SC TYPE AL_type
WITH sh : share, tgt : val, P : mpred, R : val -> mpred, Q : val -> mpred
PRE [ _tgt OF tptr tatomic ]
PROP (AL_spec P R Q; readable_share sh)
LOCAL (temp _tgt tgt)
SEP (atomic_loc sh tgt R; P)
POST [ tptr tvoid ]
EX v : val,
PROP (is_pointer_or_null v)
LOCAL (temp ret_temp v)
SEP (atomic_loc sh tgt R; Q v).
Next Obligation.
Next Obligation.
Notation "'TYPE' A 'WITH'  x1 : t1 , x2 : t2 , x3 : t3 , x4 : t4 , x5 : t5 , x6 : t6 'PRE'  [ u , .. , v ] P 'POST' [ tz ] Q" :=
(mk_funspec ((cons u%formals .. (cons v%formals nil) ..), tz) cc_default A
(fun (ts: list Type) (x: t1*t2*t3*t4*t5*t6) =>
match x with (x1,x2,x3,x4,x5,x6) => P%assert end)
(fun (ts: list Type) (x: t1*t2*t3*t4*t5*t6) =>
match x with (x1,x2,x3,x4,x5,x6) => Q%assert end) _ _)
(at level 200, x1 at level 0, x2 at level 0, x3 at level 0, x4 at level 0,
x5 at level 0, x6 at level 0,
P at level 100, Q at level 100).
Definition AS_spec v P (R : val -> mpred) Q := forall vx, view_shift (valid R vx * P)
(valid R v * (weak_precise_mpred (R v) && emp) * Q).
Definition AS_type := ProdType (ProdType (ProdType
(ConstType (share * val * val)) Mpred) (ArrowType (ConstType val) Mpred)) Mpred.
Program Definition store_SC_spec := DECLARE _store_SC
TYPE AS_type WITH sh : share, tgt : val, v : val, P : mpred, R : val -> mpred, Q : mpred
PRE [ _tgt OF tptr tatomic, _v OF tptr tvoid ]
PROP (AS_spec v P R Q; readable_share sh)
LOCAL (temp _tgt tgt; temp _v v)
SEP (atomic_loc sh tgt R; P)
POST [ tvoid ]
PROP ()
LOCAL ()
SEP (atomic_loc sh tgt R; Q).
Next Obligation.
Next Obligation.
Definition ACAS_spec c v P (R Q : val -> mpred) := forall vx, view_shift (valid R vx * P)
(valid R (if eq_dec c vx then v else vx) * (weak_precise_mpred (R (if eq_dec c vx then v else vx)) && emp) * Q vx).
Definition ACAS_type := ProdType (ProdType (ProdType (ConstType (share * val * val * val)) Mpred)
(ArrowType (ConstType val) Mpred)) (ArrowType (ConstType val) Mpred).
Notation "'TYPE' A 'WITH'  x1 : t1 , x2 : t2 , x3 : t3 , x4 : t4 , x5 : t5 , x6 : t6 , x7 : t7 'PRE'  [ u , .. , v ] P 'POST' [ tz ] Q" :=
(mk_funspec ((cons u%formals .. (cons v%formals nil) ..), tz) cc_default A
(fun (ts: list Type) (x: t1*t2*t3*t4*t5*t6*t7) =>
match x with (x1,x2,x3,x4,x5,x6,x7) => P%assert end)
(fun (ts: list Type) (x: t1*t2*t3*t4*t5*t6*t7) =>
match x with (x1,x2,x3,x4,x5,x6,x7) => Q%assert end) _ _)
(at level 200, x1 at level 0, x2 at level 0, x3 at level 0, x4 at level 0,
x5 at level 0, x6 at level 0, x7 at level 0,
P at level 100, Q at level 100).
Program Definition CAS_SC_spec := DECLARE _CAS_SC
TYPE ACAS_type WITH sh : share, tgt : val, c : val, v : val, P : mpred, R : val -> mpred, Q : val -> mpred
PRE [ _tgt OF tptr tatomic, _c OF tptr tvoid, _v OF tptr tvoid ]
PROP (ACAS_spec c v P R Q; readable_share sh)
LOCAL (temp _tgt tgt; temp _c c; temp _v v)
SEP (atomic_loc sh tgt R; P && valid_pointer c)
POST [ tint ]
EX v' : val,
PROP ()
LOCAL (temp ret_temp (if eq_dec c v' then vint 1 else vint 0))
SEP (atomic_loc sh tgt R; Q v').
Next Obligation.
Next Obligation.
Definition Gprog : funspecs := ltac:(with_library prog [acquire_spec; release_spec; makelock_spec; freelock_spec;
surely_malloc_spec; make_atomic_spec; free_atomic_spec; load_SC_spec; store_SC_spec; CAS_SC_spec]).

Lemma atomic_loc_join : forall sh1 sh2 sh p R (Hjoin : sepalg.join sh1 sh2 sh)
(Hsh1 : readable_share sh1) (Hsh2 : readable_share sh2),
atomic_loc sh1 p R * atomic_loc sh2 p R = atomic_loc sh p R.