(* *********************************************************************)
(*                                                                     *)
(*              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 INRIA Non-Commercial License Agreement.     *)
(*                                                                     *)
(* *********************************************************************)
(** Elimination of unreferenced static definitions *)
Module ISF := FSetFacts.Facts(IS).
Module ISP := FSetProperties.Properties(IS).
(** * Relational specification of the transformation *)
(** The transformed program is obtained from the original program by keeping only the global definitions that belong to a given set [u] of names.  *)
Record match_prog_1 (u: IS.t) (p tp: program) : Prop := {
match_prog_main:
tp.(prog_main) = p.(prog_main);
match_prog_public:
tp.(prog_public) = p.(prog_public);
match_prog_def:
forall id,
(prog_defmap tp)!id = if IS.mem id u then (prog_defmap p)!id else None;
match_prog_unique:
list_norepet (prog_defs_names tp)
}.
(** This set [u] (as "used") must be closed under references, and contain the entry point and the public identifiers of the program. *)
Definition ref_function (f: function) (id: ident) : Prop :=
exists pc i, f.(fn_code)!pc = Some i /\ In id (ref_instruction i).
Definition ref_fundef (fd: fundef) (id: ident) : Prop :=
match fd with Internal f => ref_function f id | External ef => False end.
Definition ref_init (il: list init_data) (id: ident) : Prop :=
exists ofs, In (Init_addrof id ofs) il.
Definition ref_def (gd: globdef fundef unit) (id: ident) : Prop :=
match gd with
| Gfun fd => ref_fundef fd id
| Gvar gv => ref_init gv.(gvar_init) id
end.
Record valid_used_set (p: program) (u: IS.t) : Prop := {
used_closed: forall id gd id',
IS.In id u -> (prog_defmap p)!id = Some gd -> ref_def gd id' ->
IS.In id' u;
used_main:
IS.In p.(prog_main) u;
used_public: forall id,
In id p.(prog_public) -> IS.In id u;
used_defined: forall id,
IS.In id u -> In id (prog_defs_names p) \/ id = p.(prog_main)
}.
Definition match_prog (p tp: program) : Prop :=
exists u: IS.t, valid_used_set p u /\ match_prog_1 u p tp.
(** * Properties of the static analysis *)
(** Monotonic evolution of the workset. *)
Inductive workset_incl (w1 w2: workset) : Prop :=
workset_incl_intro:
forall (SEEN: IS.Subset w1.(w_seen) w2.(w_seen))
(TODO: List.incl w1.(w_todo) w2.(w_todo))
(TRACK: forall id, IS.In id w2.(w_seen) ->
IS.In id w1.(w_seen) \/ List.In id w2.(w_todo)),
workset_incl w1 w2.

Lemma initial_workset_incl:
forall p, workset_incl {| w_seen := IS.empty; w_todo := nil |} (initial_workset p).