(** An output trace is a trace composed only of output events,
  that is, events that do not take any result from the outside world. *)

Definition output_event (ev: event) : Prop :=
  match ev with
  | Event_syscall _ _ _ => False
  | Event_vload _ _ _ _ => False
  | Event_vstore _ _ _ _ => True
  | Event_annot _ _ => True
  | _ => False
  end.Fixpoint output_trace (t: trace) : Prop :=
  match t with
  | nil => True
  | ev :: t' => output_event ev /\ output_trace t'
  end.(** * Semantics of volatile memory accesses *)

Inductive volatile_load (ge: Senv.t):
                   memory_chunk -> mem -> block -> ptrofs -> trace -> val -> Prop :=
  | volatile_load_vol: forall chunk m b ofs id ev v,
      Senv.block_is_volatile ge b = true ->
      Senv.find_symbol ge id = Some b ->
      eventval_match ge ev (type_of_chunk chunk) v ->
      volatile_load ge chunk m b ofs
                      (Event_vload chunk id ofs ev :: nil)
                      (Val.load_result chunk v)
  | volatile_load_nonvol: forall chunk m b ofs v,
      Senv.block_is_volatile ge b = false ->
      Mem.load chunk m b (Ptrofs.unsigned ofs) = Some v ->
      volatile_load ge chunk m b ofs E0 v.(** * Semantics of volatile memory accesses *)

Inductive volatile_load (ge: Senv.t):
                   memory_chunk -> mem -> block -> ptrofs -> trace -> val -> Prop :=
  | volatile_load_vol: forall chunk m b ofs id ev v,
      Senv.block_is_volatile ge b = true ->
      Senv.find_symbol ge id = Some b ->
      eventval_match ge ev (type_of_chunk chunk) v ->
      volatile_load ge chunk m b ofs
                      (Event_vload chunk id ofs ev :: nil)
                      (Val.load_result chunk v)
  | volatile_load_nonvol: forall chunk m b ofs v,
      Senv.block_is_volatile ge b = false ->
      Mem.load chunk m b (Ptrofs.unsigned ofs) = Some v ->
      volatile_load ge chunk m b ofs E0 v.(** * Semantics of volatile memory accesses *)

Inductive volatile_load (ge: Senv.t):
                   memory_chunk -> mem -> block -> ptrofs -> trace -> val -> Prop :=
  | volatile_load_vol: forall chunk m b ofs id ev v,
      Senv.block_is_volatile ge b = true ->
      Senv.find_symbol ge id = Some b ->
      eventval_match ge ev (type_of_chunk chunk) v ->
      volatile_load ge chunk m b ofs
                      (Event_vload chunk id ofs ev :: nil)
                      (Val.load_result chunk v)
  | volatile_load_nonvol: forall chunk m b ofs v,
      Senv.block_is_volatile ge b = false ->
      Mem.load chunk m b (Ptrofs.unsigned ofs) = Some v ->
      volatile_load ge chunk m b ofs E0 v.Inductive volatile_store (ge: Senv.t):
                  memory_chunk -> mem -> block -> ptrofs -> val -> trace -> mem -> Prop :=
  | volatile_store_vol: forall chunk m b ofs id ev v,
      Senv.block_is_volatile ge b = true ->
      Senv.find_symbol ge id = Some b ->
      eventval_match ge ev (type_of_chunk chunk) (Val.load_result chunk v) ->
      volatile_store ge chunk m b ofs v
                      (Event_vstore chunk id ofs ev :: nil)
                      m
  | volatile_store_nonvol: forall chunk m b ofs v m',
      Senv.block_is_volatile ge b = false ->
      Mem.store chunk m b (Ptrofs.unsigned ofs) v = Some m' ->
      volatile_store ge chunk m b ofs v E0 m'.Inductive volatile_store (ge: Senv.t):
                  memory_chunk -> mem -> block -> ptrofs -> val -> trace -> mem -> Prop :=
  | volatile_store_vol: forall chunk m b ofs id ev v,
      Senv.block_is_volatile ge b = true ->
      Senv.find_symbol ge id = Some b ->
      eventval_match ge ev (type_of_chunk chunk) (Val.load_result chunk v) ->
      volatile_store ge chunk m b ofs v
                      (Event_vstore chunk id ofs ev :: nil)
                      m
  | volatile_store_nonvol: forall chunk m b ofs v m',
      Senv.block_is_volatile ge b = false ->
      Mem.store chunk m b (Ptrofs.unsigned ofs) v = Some m' ->
      volatile_store ge chunk m b ofs v E0 m'.Inductive volatile_store (ge: Senv.t):
                  memory_chunk -> mem -> block -> ptrofs -> val -> trace -> mem -> Prop :=
  | volatile_store_vol: forall chunk m b ofs id ev v,
      Senv.block_is_volatile ge b = true ->
      Senv.find_symbol ge id = Some b ->
      eventval_match ge ev (type_of_chunk chunk) (Val.load_result chunk v) ->
      volatile_store ge chunk m b ofs v
                      (Event_vstore chunk id ofs ev :: nil)
                      m
  | volatile_store_nonvol: forall chunk m b ofs v m',
      Senv.block_is_volatile ge b = false ->
      Mem.store chunk m b (Ptrofs.unsigned ofs) v = Some m' ->
      volatile_store ge chunk m b ofs v E0 m'.(** * Semantics of external functions *)

(** For each external function, its behavior is defined by a predicate relating:
- the global symbol environment
- the values of the arguments passed to this function
- the memory state before the call
- the result value of the call
- the memory state after the call
- the trace generated by the call (can be empty).
*)

Definition extcall_sem : Type :=
  Senv.t -> list val -> mem -> trace -> val -> mem -> Prop.(** We now specify the expected properties of this predicate. *)

Definition loc_out_of_bounds (m: mem) (b: block) (ofs: Z) : Prop :=
  ~Mem.perm m b ofs Max Nonempty.Definition loc_not_writable (m: mem) (b: block) (ofs: Z) : Prop :=
  ~Mem.perm m b ofs Max Writable.Definition loc_unmapped (f: meminj) (b: block) (ofs: Z): Prop :=
  f b = None.Definition loc_out_of_reach (f: meminj) (m: mem) (b: block) (ofs: Z): Prop :=
  forall b0 delta,
  f b0 = Some(b, delta) -> ~Mem.perm m b0 (ofs - delta) Max Nonempty.Definition inject_separated (f f': meminj) (m1 m2: mem): Prop :=
  forall b1 b2 delta,
  f b1 = None -> f' b1 = Some(b2, delta) ->
  ~Mem.valid_block m1 b1 /\ ~Mem.valid_block m2 b2.Definition option_func {A B} (of: option (A -> B)) (a:A): option B:=
  match of with
    None => None
  | Some f => Some (f a)
  end.Inductive inject_event: meminj -> event -> event -> Prop :=
  | INJ_syscall: forall f s t v, inject_event f (Event_syscall s t v) (Event_syscall s t v)
  | INJ_vload : forall f mc id n v, inject_event f (Event_vload mc id n v) (Event_vload mc id n v)
  | INJ_vstore : forall f mc id n v, inject_event f (Event_vstore mc id n v) (Event_vstore mc id n v)
  | INJ_annot : forall f st t, inject_event f (Event_annot st t) (Event_annot st t)
  | INJ_acq : forall f v dm dc v' dm' dc',
      Val.inject f v v ->
      inject_delta_map f dm dm' ->
      inject_delta_content f dc dc' ->
      inject_event f (Event_acq v dm dc) (Event_acq v' dm' dc')
  | INJ_rel : forall f v dm dc v' dm' dc',
      Val.inject f v v -> 
      inject_delta_map f dm dm' ->
      inject_delta_content f dc dc' ->
      inject_event f (Event_rel v dm dc) (Event_rel v' dm' dc')
  | INJ_spawn : forall f v dm1 dc1 dm2 dc2 v' dm1' dc1' dm2' dc2',
      Val.inject f v v -> 
      inject_delta_map f dm1 dm1' ->
      inject_delta_map f dm2 dm2' ->
      inject_delta_content f dc1 dc1' ->
      inject_delta_content f dc2 dc2' ->
      inject_event f (Event_spawn v dm1 dc1 dm2 dc2) (Event_spawn v' dm1' dc1' dm2' dc2').Inductive inject_event: meminj -> event -> event -> Prop :=
  | INJ_syscall: forall f s t v, inject_event f (Event_syscall s t v) (Event_syscall s t v)
  | INJ_vload : forall f mc id n v, inject_event f (Event_vload mc id n v) (Event_vload mc id n v)
  | INJ_vstore : forall f mc id n v, inject_event f (Event_vstore mc id n v) (Event_vstore mc id n v)
  | INJ_annot : forall f st t, inject_event f (Event_annot st t) (Event_annot st t)
  | INJ_acq : forall f v dm dc v' dm' dc',
      Val.inject f v v ->
      inject_delta_map f dm dm' ->
      inject_delta_content f dc dc' ->
      inject_event f (Event_acq v dm dc) (Event_acq v' dm' dc')
  | INJ_rel : forall f v dm dc v' dm' dc',
      Val.inject f v v -> 
      inject_delta_map f dm dm' ->
      inject_delta_content f dc dc' ->
      inject_event f (Event_rel v dm dc) (Event_rel v' dm' dc')
  | INJ_spawn : forall f v dm1 dc1 dm2 dc2 v' dm1' dc1' dm2' dc2',
      Val.inject f v v -> 
      inject_delta_map f dm1 dm1' ->
      inject_delta_map f dm2 dm2' ->
      inject_delta_content f dc1 dc1' ->
      inject_delta_content f dc2 dc2' ->
      inject_event f (Event_spawn v dm1 dc1 dm2 dc2) (Event_spawn v' dm1' dc1' dm2' dc2').Inductive inject_event: meminj -> event -> event -> Prop :=
  | INJ_syscall: forall f s t v, inject_event f (Event_syscall s t v) (Event_syscall s t v)
  | INJ_vload : forall f mc id n v, inject_event f (Event_vload mc id n v) (Event_vload mc id n v)
  | INJ_vstore : forall f mc id n v, inject_event f (Event_vstore mc id n v) (Event_vstore mc id n v)
  | INJ_annot : forall f st t, inject_event f (Event_annot st t) (Event_annot st t)
  | INJ_acq : forall f v dm dc v' dm' dc',
      Val.inject f v v ->
      inject_delta_map f dm dm' ->
      inject_delta_content f dc dc' ->
      inject_event f (Event_acq v dm dc) (Event_acq v' dm' dc')
  | INJ_rel : forall f v dm dc v' dm' dc',
      Val.inject f v v -> 
      inject_delta_map f dm dm' ->
      inject_delta_content f dc dc' ->
      inject_event f (Event_rel v dm dc) (Event_rel v' dm' dc')
  | INJ_spawn : forall f v dm1 dc1 dm2 dc2 v' dm1' dc1' dm2' dc2',
      Val.inject f v v -> 
      inject_delta_map f dm1 dm1' ->
      inject_delta_map f dm2 dm2' ->
      inject_delta_content f dc1 dc1' ->
      inject_delta_content f dc2 dc2' ->
      inject_event f (Event_spawn v dm1 dc1 dm2 dc2) (Event_spawn v' dm1' dc1' dm2' dc2').Inductive inject_event: meminj -> event -> event -> Prop :=
  | INJ_syscall: forall f s t v, inject_event f (Event_syscall s t v) (Event_syscall s t v)
  | INJ_vload : forall f mc id n v, inject_event f (Event_vload mc id n v) (Event_vload mc id n v)
  | INJ_vstore : forall f mc id n v, inject_event f (Event_vstore mc id n v) (Event_vstore mc id n v)
  | INJ_annot : forall f st t, inject_event f (Event_annot st t) (Event_annot st t)
  | INJ_acq : forall f v dm dc v' dm' dc',
      Val.inject f v v ->
      inject_delta_map f dm dm' ->
      inject_delta_content f dc dc' ->
      inject_event f (Event_acq v dm dc) (Event_acq v' dm' dc')
  | INJ_rel : forall f v dm dc v' dm' dc',
      Val.inject f v v -> 
      inject_delta_map f dm dm' ->
      inject_delta_content f dc dc' ->
      inject_event f (Event_rel v dm dc) (Event_rel v' dm' dc')
  | INJ_spawn : forall f v dm1 dc1 dm2 dc2 v' dm1' dc1' dm2' dc2',
      Val.inject f v v -> 
      inject_delta_map f dm1 dm1' ->
      inject_delta_map f dm2 dm2' ->
      inject_delta_content f dc1 dc1' ->
      inject_delta_content f dc2 dc2' ->
      inject_event f (Event_spawn v dm1 dc1 dm2 dc2) (Event_spawn v' dm1' dc1' dm2' dc2').Inductive inject_event: meminj -> event -> event -> Prop :=
  | INJ_syscall: forall f s t v, inject_event f (Event_syscall s t v) (Event_syscall s t v)
  | INJ_vload : forall f mc id n v, inject_event f (Event_vload mc id n v) (Event_vload mc id n v)
  | INJ_vstore : forall f mc id n v, inject_event f (Event_vstore mc id n v) (Event_vstore mc id n v)
  | INJ_annot : forall f st t, inject_event f (Event_annot st t) (Event_annot st t)
  | INJ_acq : forall f v dm dc v' dm' dc',
      Val.inject f v v ->
      inject_delta_map f dm dm' ->
      inject_delta_content f dc dc' ->
      inject_event f (Event_acq v dm dc) (Event_acq v' dm' dc')
  | INJ_rel : forall f v dm dc v' dm' dc',
      Val.inject f v v -> 
      inject_delta_map f dm dm' ->
      inject_delta_content f dc dc' ->
      inject_event f (Event_rel v dm dc) (Event_rel v' dm' dc')
  | INJ_spawn : forall f v dm1 dc1 dm2 dc2 v' dm1' dc1' dm2' dc2',
      Val.inject f v v -> 
      inject_delta_map f dm1 dm1' ->
      inject_delta_map f dm2 dm2' ->
      inject_delta_content f dc1 dc1' ->
      inject_delta_content f dc2 dc2' ->
      inject_event f (Event_spawn v dm1 dc1 dm2 dc2) (Event_spawn v' dm1' dc1' dm2' dc2').Inductive inject_event: meminj -> event -> event -> Prop :=
  | INJ_syscall: forall f s t v, inject_event f (Event_syscall s t v) (Event_syscall s t v)
  | INJ_vload : forall f mc id n v, inject_event f (Event_vload mc id n v) (Event_vload mc id n v)
  | INJ_vstore : forall f mc id n v, inject_event f (Event_vstore mc id n v) (Event_vstore mc id n v)
  | INJ_annot : forall f st t, inject_event f (Event_annot st t) (Event_annot st t)
  | INJ_acq : forall f v dm dc v' dm' dc',
      Val.inject f v v ->
      inject_delta_map f dm dm' ->
      inject_delta_content f dc dc' ->
      inject_event f (Event_acq v dm dc) (Event_acq v' dm' dc')
  | INJ_rel : forall f v dm dc v' dm' dc',
      Val.inject f v v -> 
      inject_delta_map f dm dm' ->
      inject_delta_content f dc dc' ->
      inject_event f (Event_rel v dm dc) (Event_rel v' dm' dc')
  | INJ_spawn : forall f v dm1 dc1 dm2 dc2 v' dm1' dc1' dm2' dc2',
      Val.inject f v v -> 
      inject_delta_map f dm1 dm1' ->
      inject_delta_map f dm2 dm2' ->
      inject_delta_content f dc1 dc1' ->
      inject_delta_content f dc2 dc2' ->
      inject_event f (Event_spawn v dm1 dc1 dm2 dc2) (Event_spawn v' dm1' dc1' dm2' dc2').Inductive inject_event: meminj -> event -> event -> Prop :=
  | INJ_syscall: forall f s t v, inject_event f (Event_syscall s t v) (Event_syscall s t v)
  | INJ_vload : forall f mc id n v, inject_event f (Event_vload mc id n v) (Event_vload mc id n v)
  | INJ_vstore : forall f mc id n v, inject_event f (Event_vstore mc id n v) (Event_vstore mc id n v)
  | INJ_annot : forall f st t, inject_event f (Event_annot st t) (Event_annot st t)
  | INJ_acq : forall f v dm dc v' dm' dc',
      Val.inject f v v ->
      inject_delta_map f dm dm' ->
      inject_delta_content f dc dc' ->
      inject_event f (Event_acq v dm dc) (Event_acq v' dm' dc')
  | INJ_rel : forall f v dm dc v' dm' dc',
      Val.inject f v v -> 
      inject_delta_map f dm dm' ->
      inject_delta_content f dc dc' ->
      inject_event f (Event_rel v dm dc) (Event_rel v' dm' dc')
  | INJ_spawn : forall f v dm1 dc1 dm2 dc2 v' dm1' dc1' dm2' dc2',
      Val.inject f v v -> 
      inject_delta_map f dm1 dm1' ->
      inject_delta_map f dm2 dm2' ->
      inject_delta_content f dc1 dc1' ->
      inject_delta_content f dc2 dc2' ->
      inject_event f (Event_spawn v dm1 dc1 dm2 dc2) (Event_spawn v' dm1' dc1' dm2' dc2').Inductive inject_event: meminj -> event -> event -> Prop :=
  | INJ_syscall: forall f s t v, inject_event f (Event_syscall s t v) (Event_syscall s t v)
  | INJ_vload : forall f mc id n v, inject_event f (Event_vload mc id n v) (Event_vload mc id n v)
  | INJ_vstore : forall f mc id n v, inject_event f (Event_vstore mc id n v) (Event_vstore mc id n v)
  | INJ_annot : forall f st t, inject_event f (Event_annot st t) (Event_annot st t)
  | INJ_acq : forall f v dm dc v' dm' dc',
      Val.inject f v v ->
      inject_delta_map f dm dm' ->
      inject_delta_content f dc dc' ->
      inject_event f (Event_acq v dm dc) (Event_acq v' dm' dc')
  | INJ_rel : forall f v dm dc v' dm' dc',
      Val.inject f v v -> 
      inject_delta_map f dm dm' ->
      inject_delta_content f dc dc' ->
      inject_event f (Event_rel v dm dc) (Event_rel v' dm' dc')
  | INJ_spawn : forall f v dm1 dc1 dm2 dc2 v' dm1' dc1' dm2' dc2',
      Val.inject f v v -> 
      inject_delta_map f dm1 dm1' ->
      inject_delta_map f dm2 dm2' ->
      inject_delta_content f dc1 dc1' ->
      inject_delta_content f dc2 dc2' ->
      inject_event f (Event_spawn v dm1 dc1 dm2 dc2) (Event_spawn v' dm1' dc1' dm2' dc2').Inductive inject_trace: meminj -> trace -> trace -> Prop :=
| injt_nil : forall f, inject_trace f nil nil
| injt_cons: forall f e t e' t',
    inject_event f e e' ->
    inject_trace f t t' ->
    inject_trace f (cons e t) (cons e' t').Inductive inject_trace: meminj -> trace -> trace -> Prop :=
| injt_nil : forall f, inject_trace f nil nil
| injt_cons: forall f e t e' t',
    inject_event f e e' ->
    inject_trace f t t' ->
    inject_trace f (cons e t) (cons e' t').Inductive inject_trace: meminj -> trace -> trace -> Prop :=
| injt_nil : forall f, inject_trace f nil nil
| injt_cons: forall f e t e' t',
    inject_event f e e' ->
    inject_trace f t t' ->
    inject_trace f (cons e t) (cons e' t').Definition injection_full (f:meminj) (m:mem):=
  forall b ,
    Mem.valid_block m b ->
    ~ f b = None.

(* Specifications: *)
Lemma flat_injection_full: forall m0, injection_full (Mem.flat_inj (Mem.nextblock m0)) m0.
Lemma nextblock_full: forall f m m', injection_full f m -> Mem.nextblock m' = Mem.nextblock m -> injection_full f m'.
Lemma store_full: forall f chunk m b ofs v m', injection_full f m -> Mem.store chunk m b ofs v = Some m' -> injection_full f m'.
Lemma storebytes_full: forall f m b ofs ls m', injection_full f m -> Mem.storebytes m b ofs ls = Some m' -> injection_full f m'.
Lemma free_full: forall f m ls lo hi m', injection_full f m -> Mem.free m ls lo hi = Some m' -> injection_full f m'.
Lemma free_list_full: forall f ls m m', injection_full f m -> Mem.free_list m ls = Some m' -> injection_full f m'.
Lemma alloc_full m lo hi m' b (ALLOC: Mem.alloc m lo hi = (m',b)) j1 (FULL : injection_full j1 m) j' sp' z (J : j' b = Some (sp', z)) (K : inject_incr j1 j'): injection_full j' m'.