Section PRESERVATION.
Variable prog: program.
Variable tprog: program.
Hypothesis TRANSL: match_prog prog tprog.
Let ge := Genv.globalenv prog.
Let tge := Genv.globalenv tprog.
(** * Correctness of the code transformation *)
(** We now show that the transformed code after constant propagation has the same semantics as the original code. *)
Proof (Genv.find_symbol_match TRANSL).
Proof (Genv.senv_match TRANSL).
Inductive match_pc (f: function) (rs: regset) (m: mem): nat -> node -> node -> Prop :=
| match_pc_base: forall n pc,
match_pc f rs m n pc pc
| match_pc_nop: forall n pc s pcx,
f.(fn_code)!pc = Some (Inop s) ->
match_pc f rs m n s pcx ->
match_pc f rs m (S n) pc pcx
| match_pc_cond: forall n pc cond args s1 s2 pcx,
f.(fn_code)!pc = Some (Icond cond args s1 s2) ->
(forall b,
eval_condition cond rs##args m = Some b ->
match_pc f rs m n (if b then s1 else s2) pcx) ->
match_pc f rs m (S n) pc pcx.
(** The proof of semantic preservation is a simulation argument based on "option" diagrams of the following form: << n st1 --------------- st2 |                   | t|                   |t or (? and n' < n) |                   | v                   v st1'--------------- st2' n' >> The left vertical arrow represents a transition in the original RTL code.  The top horizontal bar is the [match_states] invariant between the initial state [st1] in the original RTL code and an initial state [st2] in the transformed code. This invariant expresses that all code fragments appearing in [st2] are obtained by [transf_code] transformation of the corresponding fragments in [st1].  Moreover, the state [st1] must match its compile-time approximations at the current program point. These two parts of the diagram are the hypotheses.  In conclusions, we want to prove the other two parts: the right vertical arrow, which is a transition in the transformed RTL code, and the bottom horizontal bar, which means that the [match_state] predicate holds between the final states [st1'] and [st2']. *)
Inductive match_stackframes: stackframe -> stackframe -> Prop :=
match_stackframe_intro:
forall res sp pc rs f rs' cu,
linkorder cu prog ->
regs_lessdef rs rs' ->
match_stackframes
(Stackframe res f sp pc rs)
(Stackframe res (transf_function (romem_for cu) f) sp pc rs').
Inductive match_states: nat -> state -> state -> Prop :=
| match_states_intro:
forall s sp pc rs m f s' pc' rs' m' cu n
(LINK: linkorder cu prog)
(STACKS: list_forall2 match_stackframes s s')
(PC: match_pc f rs m n pc pc')
(REGS: regs_lessdef rs rs')
(MEM: Mem.extends m m'),
match_states n (State s f sp pc rs m)
(State s' (transf_function (romem_for cu) f) sp pc' rs' m')
| match_states_call:
forall s f args m s' args' m' cu
(LINK: linkorder cu prog)
(STACKS: list_forall2 match_stackframes s s')
(ARGS: Val.lessdef_list args args')
(MEM: Mem.extends m m'),
match_states O (Callstate s f args m)
(Callstate s' (transf_fundef (romem_for cu) f) args' m')
| match_states_return:
forall s v m s' v' m'
(STACKS: list_forall2 match_stackframes s s')
(RES: Val.lessdef v v')
(MEM: Mem.extends m m'),
list_forall2 match_stackframes s s' ->
match_states O (Returnstate s v m)
(Returnstate s' v' m').
Ltac TransfInstr :=
match goal with
| H1: (PTree.get ?pc (fn_code ?f) = Some ?instr),
H2: (analyze ?rm ?f)#?pc = VA.State ?ae ?am |- _ =>
generalize (transf_instr_at rm _ _ _ H1); unfold transf_instr; rewrite H2
end.
(** The proof of simulation proceeds by case analysis on the transition taken in the source code. *)
(** The preservation of the observable behavior of the program then follows. *)

Theorem transf_program_correct:
forward_simulation (RTL.semantics prog) (RTL.semantics tprog).