Section SEPARATE_COMPILATION.
(** The source: a list of C compilation units *)
Variable c_units: nlist Csyntax.program.
(** The compiled code: a list of Asm compilation units, obtained by separate compilation *)
Variable asm_units: nlist Asm.program.
Hypothesis separate_compilation_succeeds:
nlist_forall2 (fun cu tcu => transf_c_program cu = OK tcu) c_units asm_units.
(** We assume that the source C compilation units can be linked together to obtain a monolithic C program [c_program]. *)
Variable c_program: Csyntax.program.
Hypothesis source_linking: link_list c_units = Some c_program.
(** Let asm_program be the result of linking the Asm units. *)
Let asm_program: Asm.program := proj1_sig compiled_linking_succeeds.
Let compiled_linking: link_list asm_units = Some asm_program := proj2_sig compiled_linking_succeeds.
(** Then, [asm_program] preserves the semantics and the specifications of [c_program], in the following sense. First, every behavior of [asm_program] improves upon one of the possible behaviors of [c_program]. *)
(** As a corollary, if [c_program] is free of undefined behaviors, the behavior of [asm_program] is one of the possible behaviors of [c_program]. *)

Theorem separate_transf_c_program_is_refinement:
(forall beh, program_behaves (Csem.semantics c_program) beh -> not_wrong beh) ->
(forall beh, program_behaves (Asm.semantics asm_program) beh -> program_behaves (Csem.semantics c_program) beh).