(* *********************************************************************)
(*                                                                     *)
(*              The Compcert verified compiler                         *)
(*                                                                     *)
(*          Xavier Leroy, INRIA Paris-Rocquencourt                     *)
(*                                                                     *)
(*  Copyright Institut National de Recherche en Informatique et en     *)
(*  Automatique.  All rights reserved.  This file is distributed       *)
(*  under the terms of the GNU General Public License as published by  *)
(*  the Free Software Foundation, either version 2 of the License, or  *)
(*  (at your option) any later version.  This file is also distributed *)
(*  under the terms of the INRIA Non-Commercial License Agreement.     *)
(*                                                                     *)
(* *********************************************************************)
(** Characterization and properties of deterministic external worlds and deterministic semantics *)
(** * Deterministic worlds *)
(** One source of possible nondeterminism is that our semantics leave unspecified the results of system calls. Different results to e.g. a "read" operation can of course lead to different behaviors for the program. We address this issue by modeling a notion of deterministic external world that uniquely determines the results of external calls. *)
(** An external world is a function that, given the name of an external call and its arguments, returns either [None], meaning that this external call gets stuck, or [Some(r,w)], meaning that this external call succeeds, has result [r], and changes the world to [w]. *)
CoInductive world: Type :=
World (io: string -> list eventval -> option (eventval * world))
(vload: memory_chunk -> ident -> ptrofs -> option (eventval * world))
(vstore: memory_chunk -> ident -> ptrofs -> eventval -> option world).
Definition nextworld_io (w: world) (evname: string) (evargs: list eventval) :
option (eventval * world) :=
match w with World io vl vs => io evname evargs end.
Definition nextworld_vload (w: world) (chunk: memory_chunk) (id: ident) (ofs: ptrofs) :
option (eventval * world) :=
match w with World io vl vs => vl chunk id ofs end.
Definition nextworld_vstore (w: world) (chunk: memory_chunk) (id: ident) (ofs: ptrofs) (v: eventval):
option world :=
match w with World io vl vs => vs chunk id ofs v end.
(** A trace is possible in a given world if all events correspond to non-stuck external calls according to the given world. Two predicates are defined, for finite and infinite traces respectively: - [possible_trace w t w'], where [w] is the initial state of the world, [t] the finite trace of interest, and [w'] the state of the world after performing trace [t]. - [possible_traceinf w T], where [w] is the initial state of the world and [T] the infinite trace of interest. *)
Inductive possible_event: world -> event -> world -> Prop :=
| possible_event_syscall: forall w1 evname evargs evres w2,
nextworld_io w1 evname evargs = Some (evres, w2) ->
possible_event w1 (Event_syscall evname evargs evres) w2
| possible_event_vload: forall w1 chunk id ofs evres w2,
nextworld_vload w1 chunk id ofs = Some (evres, w2) ->
possible_event w1 (Event_vload chunk id ofs evres) w2
| possible_event_vstore: forall w1 chunk id ofs evarg w2,
nextworld_vstore w1 chunk id ofs evarg = Some w2 ->
possible_event w1 (Event_vstore chunk id ofs evarg) w2
| possible_event_annot: forall w1 id args,
possible_event w1 (Event_annot id args) w1.
Inductive possible_trace: world -> trace -> world -> Prop :=
| possible_trace_nil: forall w,
possible_trace w E0 w
| possible_trace_cons: forall w1 ev w2 t w3,
possible_event w1 ev w2 -> possible_trace w2 t w3 ->
possible_trace w1 (ev :: t) w3.
CoInductive possible_traceinf: world -> traceinf -> Prop :=
| possible_traceinf_cons: forall w1 ev w2 T,
possible_event w1 ev w2 ->
possible_traceinf w2 T ->
possible_traceinf w1 (Econsinf ev T).
Ltac possibleTraceInv :=
match goal with
| [H: possible_trace _ E0 _ |- _] =>
inversion H; clear H; subst; possibleTraceInv
| [H: possible_trace _ (_ ** _) _ |- _] =>
let P1 := fresh "P" in
let w := fresh "w" in
let P2 := fresh "P" in
elim (possible_trace_app_inv _ _ _ _ H); clear H;
intros w [P1 P2];
possibleTraceInv
| [H: possible_traceinf _ (_ *** _) |- _] =>
let P1 := fresh "P" in
let w := fresh "w" in
let P2 := fresh "P" in
elim (possible_traceinf_app_inv _ _ _ H); clear H;
intros w [P1 P2];
possibleTraceInv
| [H: exists w, possible_trace _ _ w |- _] =>
let P := fresh "P" in let w := fresh "w" in
destruct H as [w P]; possibleTraceInv
| _ => idtac
end.
Definition possible_behavior (w: world) (b: program_behavior) : Prop :=
match b with
| Terminates t r => exists w', possible_trace w t w'
| Diverges t => exists w', possible_trace w t w'
| Reacts T => possible_traceinf w T
| Goes_wrong t => exists w', possible_trace w t w'
end.
CoInductive possible_traceinf': world -> traceinf -> Prop :=
| possible_traceinf'_app: forall w1 t w2 T,
possible_trace w1 t w2 -> t <> E0 ->
possible_traceinf' w2 T ->
possible_traceinf' w1 (t *** T).

Lemma possible_traceinf'_traceinf:
forall w T, possible_traceinf' w T -> possible_traceinf w T.