Section MATCH_PROGRAM_GENERIC.
Context {C F1 V1 F2 V2: Type} {LC: Linker C} {LF: Linker F1} {LV: Linker V1}.
Variable match_fundef: C -> F1 -> F2 -> Prop.
Variable match_varinfo: V1 -> V2 -> Prop.
Inductive match_globvar: globvar V1 -> globvar V2 -> Prop :=
| match_globvar_intro: forall i1 i2 init ro vo,
match_varinfo i1 i2 ->
match_globvar (mkglobvar i1 init ro vo) (mkglobvar i2 init ro vo).
Inductive match_globdef (ctx: C): globdef F1 V1 -> globdef F2 V2 -> Prop :=
| match_globdef_fun: forall ctx' f1 f2,
linkorder ctx' ctx ->
match_fundef ctx' f1 f2 ->
match_globdef ctx (Gfun f1) (Gfun f2)
| match_globdef_var: forall v1 v2,
match_globvar v1 v2 ->
match_globdef ctx (Gvar v1) (Gvar v2).
Definition match_ident_globdef
(ctx: C) (ig1: ident * globdef F1 V1) (ig2: ident * globdef F2 V2) : Prop :=
fst ig1 = fst ig2 /\ match_globdef ctx (snd ig1) (snd ig2).
Definition match_program_gen (ctx: C) (p1: program F1 V1) (p2: program F2 V2) : Prop :=
list_forall2 (match_ident_globdef ctx) p1.(prog_defs) p2.(prog_defs)
/\ p2.(prog_main) = p1.(prog_main)
/\ p2.(prog_public) = p1.(prog_public).
End MATCH_PROGRAM_GENERIC.
(** In many cases, the context for [match_program_gen] is the source program or source compilation unit itself.  We provide a specialized definition for this case. *)
Definition match_program {F1 V1 F2 V2: Type} {LF: Linker F1} {LV: Linker V1}
(match_fundef: program F1 V1 -> F1 -> F2 -> Prop)
(match_varinfo: V1 -> V2 -> Prop)
(p1: program F1 V1) (p2: program F2 V2) : Prop :=
match_program_gen match_fundef match_varinfo p1 p1 p2.
(* Lemma match_program_implies: forall (A B V W: Type) (LA: Linker A) (LV: Linker V) (match_fundef1 match_fundef2: program A V -> A -> B -> Prop) (match_varinfo1 match_varinfo2: V -> W -> Prop) p p', match_program match_fundef1 match_varinfo1 p p' -> (forall cu a b, match_fundef1 cu a b -> linkorder cu p -> match_fundef2 cu a b) -> (forall v w, match_varinfo1 v w -> match_varinfo2 v w) -> match_program match_fundef2 match_varinfo2 p p'. *)
(** Relation between the program transformation functions from [AST] and the [match_program] predicate. *)
(** The following two theorems are simpler versions for the case where the function transformation does not depend on the compilation unit. *)

Theorem match_transform_program:
forall {A B V: Type} {LA: Linker A} {LV: Linker V}
(transf: A -> B)
(p: program A V),
match_program (fun cu f tf => tf = transf f) eq p (transform_program transf p).