(** Accessing locations *)
Definition do_deref_loc (w: world) (ty: type) (m: mem) (b: block) (ofs: ptrofs) : option (world * trace * val) :=
match access_mode ty with
| By_value chunk =>
match type_is_volatile ty with
| false => do v <- Mem.loadv chunk m (Vptr b ofs); Some(w, E0, v)
| true => do_volatile_load w chunk m b ofs
end
| By_reference => Some(w, E0, Vptr b ofs)
| By_copy => Some(w, E0, Vptr b ofs)
| _ => None
end.
Definition assign_copy_ok (ty: type) (b: block) (ofs: ptrofs) (b': block) (ofs': ptrofs) : Prop :=
(alignof_blockcopy ge ty | Ptrofs.unsigned ofs') /\ (alignof_blockcopy ge ty | Ptrofs.unsigned ofs) /\
(b' <> b \/ Ptrofs.unsigned ofs' = Ptrofs.unsigned ofs
\/ Ptrofs.unsigned ofs' + sizeof ge ty <= Ptrofs.unsigned ofs
\/ Ptrofs.unsigned ofs + sizeof ge ty <= Ptrofs.unsigned ofs').
Remark check_assign_copy:
forall (ty: type) (b: block) (ofs: ptrofs) (b': block) (ofs': ptrofs),
{ assign_copy_ok ty b ofs b' ofs' } + {~ assign_copy_ok ty b ofs b' ofs' }.
Proof with try (right; intuition omega).
intros. unfold assign_copy_ok.
assert (alignof_blockcopy ge ty > 0) by apply alignof_blockcopy_pos.
destruct (Zdivide_dec (alignof_blockcopy ge ty) (Ptrofs.unsigned ofs')); auto...
destruct (Zdivide_dec (alignof_blockcopy ge ty) (Ptrofs.unsigned ofs)); auto...
assert (Y: {b' <> b \/
Ptrofs.unsigned ofs' = Ptrofs.unsigned ofs \/
Ptrofs.unsigned ofs' + sizeof ge ty <= Ptrofs.unsigned ofs \/
Ptrofs.unsigned ofs + sizeof ge ty <= Ptrofs.unsigned ofs'} +
{~(b' <> b \/
Ptrofs.unsigned ofs' = Ptrofs.unsigned ofs \/
Ptrofs.unsigned ofs' + sizeof ge ty <= Ptrofs.unsigned ofs \/
Ptrofs.unsigned ofs + sizeof ge ty <= Ptrofs.unsigned ofs')}).
destruct (eq_block b' b); auto.
destruct (zeq (Ptrofs.unsigned ofs') (Ptrofs.unsigned ofs)); auto.
destruct (zle (Ptrofs.unsigned ofs' + sizeof ge ty) (Ptrofs.unsigned ofs)); auto.
destruct (zle (Ptrofs.unsigned ofs + sizeof ge ty) (Ptrofs.unsigned ofs')); auto.
right; intuition omega.
destruct Y... left; intuition omega.
Defined.
Definition do_assign_loc (w: world) (ty: type) (m: mem) (b: block) (ofs: ptrofs) (v: val): option (world * trace * mem) :=
match access_mode ty with
| By_value chunk =>
match type_is_volatile ty with
| false => do m' <- Mem.storev chunk m (Vptr b ofs) v; Some(w, E0, m')
| true => do_volatile_store w chunk m b ofs v
end
| By_copy =>
match v with
| Vptr b' ofs' =>
if check_assign_copy ty b ofs b' ofs' then
do bytes <- Mem.loadbytes m b' (Ptrofs.unsigned ofs') (sizeof ge ty);
do m' <- Mem.storebytes m b (Ptrofs.unsigned ofs) bytes;
Some(w, E0, m')
else None
| _ => None
end
| _ => None
end.

Lemma do_assign_loc_complete:
forall w ty m b ofs v w' t m',
assign_loc ge ty m b ofs v t m' -> possible_trace w t w' ->
do_assign_loc w ty m b ofs v = Some(w', t, m').