Module DS := Dataflow_Solver(VA)(NodeSetForward).
Definition mfunction_entry :=
{| am_stack := ablock_init Pbot;
am_glob := PTree.empty _;
am_nonstack := Nonstack;
am_top := Nonstack |}.
Definition analyze (rm: romem) (f: function): PMap.t VA.t :=
let lu := Liveness.last_uses f in
let entry := VA.State (einit_regs f.(fn_params)) mfunction_entry in
match DS.fixpoint f.(fn_code) successors_instr (transfer' f lu rm)
f.(fn_entrypoint) entry with
| None => PMap.init (VA.State AE.top mtop)
| Some res => res
end.
(** Constructing the approximation of read-only globals *)
Definition store_init_data (ab: ablock) (p: Z) (id: init_data) : ablock :=
match id with
| Init_int8 n => ablock_store Mint8unsigned ab p (I n)
| Init_int16 n => ablock_store Mint16unsigned ab p (I n)
| Init_int32 n => ablock_store Mint32 ab p (I n)
| Init_int64 n => ablock_store Mint64 ab p (L n)
| Init_float32 n => ablock_store Mfloat32 ab p
(if propagate_float_constants tt then FS n else ntop)
| Init_float64 n => ablock_store Mfloat64 ab p
(if propagate_float_constants tt then F n else ntop)
| Init_addrof symb ofs => ablock_store Mptr ab p (Ptr (Gl symb ofs))
| Init_space n => ab
end.
Fixpoint store_init_data_list (ab: ablock) (p: Z) (idl: list init_data)
{struct idl}: ablock :=
match idl with
| nil => ab
| id :: idl' => store_init_data_list (store_init_data ab p id) (p + init_data_size id) idl'
end.
(** When CompCert is used in separate compilation mode, the [gvar_init] initializer attached to a readonly global variable may not correspond to the actual initial value of this global.  This occurs in two cases: - an [extern const] variable, which is represented by [gvar_init = nil]; - a [const] variable without an explicit initializer, which is treated by the linker as a "common" symbol, and is represented by [gvar_init = Init_space sz :: nil].  In both cases, the variable can be defined and initialized in another compilation unit which is later linked with the current compilation unit. *)
Definition definitive_initializer (init: list init_data) : bool :=
match init with
| nil => false
| Init_space _ :: nil => false
| _ => true
end.
Definition alloc_global (rm: romem) (idg: ident * globdef fundef unit): romem :=
match idg with
| (id, Gfun f) =>
PTree.remove id rm
| (id, Gvar v) =>
if v.(gvar_readonly) && negb v.(gvar_volatile) && definitive_initializer v.(gvar_init)
then PTree.set id (store_init_data_list (ablock_init Pbot) 0 v.(gvar_init)) rm
else PTree.remove id rm
end.
Definition romem_for (p: program) : romem :=
List.fold_left alloc_global p.(prog_defs) (PTree.empty _).
(** * Soundness proof *)
(** Properties of the dataflow solution. *)

Lemma analyze_entrypoint:
forall rm f vl m bc,
(forall v, In v vl -> vmatch bc v (Ifptr Nonstack)) ->
mmatch bc m mfunction_entry ->
exists ae am,
(analyze rm f)!!(fn_entrypoint f) = VA.State ae am
/\ ematch bc (init_regs vl (fn_params f)) ae
/\ mmatch bc m am.