Record match_genvs (ge1: t A V) (ge2: t B W): Prop := {
  mge_next:
    genv_next ge2 = genv_next ge1;
  mge_symb:
    forall id, PTree.get id (genv_symb ge2) = PTree.get id (genv_symb ge1);
  mge_defs:
    forall b, option_rel R (PTree.get b (genv_defs ge1)) (PTree.get b (genv_defs ge2))
}.Record match_genvs (ge1: t A V) (ge2: t B W): Prop := {
  mge_next:
    genv_next ge2 = genv_next ge1;
  mge_symb:
    forall id, PTree.get id (genv_symb ge2) = PTree.get id (genv_symb ge1);
  mge_defs:
    forall b, option_rel R (PTree.get b (genv_defs ge1)) (PTree.get b (genv_defs ge2))
}.Record match_genvs (ge1: t A V) (ge2: t B W): Prop := {
  mge_next:
    genv_next ge2 = genv_next ge1;
  mge_symb:
    forall id, PTree.get id (genv_symb ge2) = PTree.get id (genv_symb ge1);
  mge_defs:
    forall b, option_rel R (PTree.get b (genv_defs ge1)) (PTree.get b (genv_defs ge2))
}.Record match_genvs (ge1: t A V) (ge2: t B W): Prop := {
  mge_next:
    genv_next ge2 = genv_next ge1;
  mge_symb:
    forall id, PTree.get id (genv_symb ge2) = PTree.get id (genv_symb ge1);
  mge_defs:
    forall b, option_rel R (PTree.get b (genv_defs ge1)) (PTree.get b (genv_defs ge2))
}.

(* Specifications: *)
Lemma add_global_match: forall ge1 ge2 id g1 g2, match_genvs ge1 ge2 -> R g1 g2 -> match_genvs (add_global ge1 (id, g1)) (add_global ge2 (id, g2)).
Lemma add_globals_match: forall gl1 gl2, list_forall2 (fun idg1 idg2 => fst idg1 = fst idg2 /\ R (snd idg1) (snd idg2)) gl1 gl2 -> forall ge1 ge2, match_genvs ge1 ge2 -> match_genvs (add_globals ge1 gl1) (add_globals ge2 gl2).
Lemma globalenvs_match: match_genvs (match_globdef match_fundef match_varinfo ctx) (globalenv p) (globalenv tp).
Theorem find_def_match_2: forall b, option_rel (match_globdef match_fundef match_varinfo ctx) (find_def (globalenv p) b) (find_def (globalenv tp) b).
Theorem find_def_match: forall b g, find_def (globalenv p) b = Some g -> exists tg, find_def (globalenv tp) b = Some tg /\ match_globdef match_fundef match_varinfo ctx g tg.
Theorem find_funct_ptr_match: forall b f, find_funct_ptr (globalenv p) b = Some f -> exists cunit tf, find_funct_ptr (globalenv tp) b = Some tf /\ match_fundef cunit f tf /\ linkorder cunit ctx.
Theorem find_funct_match: forall v f, find_funct (globalenv p) v = Some f -> exists cunit tf, find_funct (globalenv tp) v = Some tf /\ match_fundef cunit f tf /\ linkorder cunit ctx.
Theorem find_var_info_match: forall b v, find_var_info (globalenv p) b = Some v -> exists tv, find_var_info (globalenv tp) b = Some tv /\ match_globvar match_varinfo v tv.
Theorem find_symbol_match: forall (s : ident), find_symbol (globalenv tp) s = find_symbol (globalenv p) s.
Theorem senv_match: Senv.equiv (to_senv (globalenv p)) (to_senv (globalenv tp)).
Lemma store_init_data_list_match: forall idl m b ofs m', store_init_data_list (globalenv p) m b ofs idl = Some m' -> store_init_data_list (globalenv tp) m b ofs idl = Some m'.
Lemma alloc_globals_match: forall gl1 gl2, list_forall2 (match_ident_globdef match_fundef match_varinfo ctx) gl1 gl2 -> forall m m', alloc_globals (globalenv p) m gl1 = Some m' -> alloc_globals (globalenv tp) m gl2 = Some m'.
Theorem init_mem_match: forall m, init_mem p = Some m -> init_mem tp = Some m.
Theorem find_funct_ptr_transf_partial: forall b f, find_funct_ptr (globalenv p) b = Some f -> exists tf, find_funct_ptr (globalenv tp) b = Some tf /\ transf f = OK tf.
Theorem find_funct_transf_partial: forall v f, find_funct (globalenv p) v = Some f -> exists tf, find_funct (globalenv tp) v = Some tf /\ transf f = OK tf.
Theorem find_symbol_transf_partial: forall (s : ident), find_symbol (globalenv tp) s = find_symbol (globalenv p) s.
Theorem senv_transf_partial: Senv.equiv (to_senv (globalenv p)) (to_senv (globalenv tp)).
Theorem init_mem_transf_partial: forall m, init_mem p = Some m -> init_mem tp = Some m.
Theorem find_funct_ptr_transf: forall b f, find_funct_ptr (globalenv p) b = Some f -> find_funct_ptr (globalenv tp) b = Some (transf f).
Theorem find_funct_transf: forall v f, find_funct (globalenv p) v = Some f -> find_funct (globalenv tp) v = Some (transf f).
Theorem find_symbol_transf: forall (s : ident), find_symbol (globalenv tp) s = find_symbol (globalenv p) s.
Theorem senv_transf: Senv.equiv (to_senv (globalenv p)) (to_senv (globalenv tp)).
Theorem init_mem_transf: forall m, init_mem p = Some m -> init_mem tp = Some m.
Lemma add_global_match: forall ge1 ge2 id g1 g2, match_genvs ge1 ge2 -> R g1 g2 -> match_genvs (add_global ge1 (id, g1)) (add_global ge2 (id, g2)).
Lemma add_globals_match: forall gl1 gl2, list_forall2 (fun idg1 idg2 => fst idg1 = fst idg2 /\ R (snd idg1) (snd idg2)) gl1 gl2 -> forall ge1 ge2, match_genvs ge1 ge2 -> match_genvs (add_globals ge1 gl1) (add_globals ge2 gl2).
Lemma globalenvs_match: match_genvs (match_globdef match_fundef match_varinfo ctx) (globalenv p) (globalenv tp).
Theorem find_def_match_2: forall b, option_rel (match_globdef match_fundef match_varinfo ctx) (find_def (globalenv p) b) (find_def (globalenv tp) b).
Theorem find_def_match: forall b g, find_def (globalenv p) b = Some g -> exists tg, find_def (globalenv tp) b = Some tg /\ match_globdef match_fundef match_varinfo ctx g tg.
Theorem find_funct_ptr_match: forall b f, find_funct_ptr (globalenv p) b = Some f -> exists cunit tf, find_funct_ptr (globalenv tp) b = Some tf /\ match_fundef cunit f tf /\ linkorder cunit ctx.
Theorem find_funct_match: forall v f, find_funct (globalenv p) v = Some f -> exists cunit tf, find_funct (globalenv tp) v = Some tf /\ match_fundef cunit f tf /\ linkorder cunit ctx.
Theorem find_var_info_match: forall b v, find_var_info (globalenv p) b = Some v -> exists tv, find_var_info (globalenv tp) b = Some tv /\ match_globvar match_varinfo v tv.
Theorem find_symbol_match: forall (s : ident), find_symbol (globalenv tp) s = find_symbol (globalenv p) s.
Theorem senv_match: Senv.equiv (to_senv (globalenv p)) (to_senv (globalenv tp)).
Lemma store_init_data_list_match: forall idl m b ofs m', store_init_data_list (globalenv p) m b ofs idl = Some m' -> store_init_data_list (globalenv tp) m b ofs idl = Some m'.
Lemma alloc_globals_match: forall gl1 gl2, list_forall2 (match_ident_globdef match_fundef match_varinfo ctx) gl1 gl2 -> forall m m', alloc_globals (globalenv p) m gl1 = Some m' -> alloc_globals (globalenv tp) m gl2 = Some m'.
Theorem init_mem_match: forall m, init_mem p = Some m -> init_mem tp = Some m.
Theorem find_funct_ptr_transf_partial: forall b f, find_funct_ptr (globalenv p) b = Some f -> exists tf, find_funct_ptr (globalenv tp) b = Some tf /\ transf f = OK tf.
Theorem find_funct_transf_partial: forall v f, find_funct (globalenv p) v = Some f -> exists tf, find_funct (globalenv tp) v = Some tf /\ transf f = OK tf.
Theorem find_symbol_transf_partial: forall (s : ident), find_symbol (globalenv tp) s = find_symbol (globalenv p) s.
Theorem senv_transf_partial: Senv.equiv (to_senv (globalenv p)) (to_senv (globalenv tp)).
Theorem init_mem_transf_partial: forall m, init_mem p = Some m -> init_mem tp = Some m.
Theorem find_funct_ptr_transf: forall b f, find_funct_ptr (globalenv p) b = Some f -> find_funct_ptr (globalenv tp) b = Some (transf f).
Theorem find_funct_transf: forall v f, find_funct (globalenv p) v = Some f -> find_funct (globalenv tp) v = Some (transf f).
Theorem find_symbol_transf: forall (s : ident), find_symbol (globalenv tp) s = find_symbol (globalenv p) s.
Theorem senv_transf: Senv.equiv (to_senv (globalenv p)) (to_senv (globalenv tp)).
Theorem init_mem_transf: forall m, init_mem p = Some m -> init_mem tp = Some m.