|
|
(*
|
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
|
*
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
* LICENSE file in the root directory of this source tree.
|
|
|
*)
|
|
|
|
|
|
(* Proofs about llvm to llair translation that don't involve the semantics *)
|
|
|
|
|
|
open HolKernel boolLib bossLib Parse lcsymtacs;
|
|
|
open listTheory arithmeticTheory pred_setTheory finite_mapTheory;
|
|
|
open optionTheory rich_listTheory alistTheory pairTheory sumTheory;
|
|
|
open settingsTheory miscTheory;
|
|
|
open llvmTheory llvm_propTheory llvm_ssaTheory llairTheory llair_propTheory llvm_to_llairTheory;
|
|
|
|
|
|
new_theory "llvm_to_llair_prop";
|
|
|
|
|
|
set_grammar_ancestry ["llvm", "llair", "llair_prop", "llvm_to_llair", "llvm_ssa"];
|
|
|
|
|
|
numLib.prefer_num ();
|
|
|
|
|
|
(* ----- Theorems about prog_ok ----- *)
|
|
|
|
|
|
Theorem prog_ok_terminator_last:
|
|
|
∀prog d f.
|
|
|
prog_ok prog ∧
|
|
|
alookup prog (Fn f) = Some d
|
|
|
⇒
|
|
|
every (λ(l,b). ∀i. i < length b.body ∧ classify_instr (el i b.body) = Term ⇒ Suc i = length b.body) d.blocks
|
|
|
Proof
|
|
|
rw [prog_ok_def] >> rpt (first_x_assum drule) >>
|
|
|
rw [] >> fs [EVERY_MEM] >> rw [] >>
|
|
|
pairarg_tac >> rw [] >>
|
|
|
`mem (Fn f,d) prog` by metis_tac [ALOOKUP_MEM] >>
|
|
|
last_x_assum drule >> rw [] >> fs [] >>
|
|
|
`alookup d.blocks l = Some b` by metis_tac [ALOOKUP_ALL_DISTINCT_MEM] >>
|
|
|
last_x_assum drule >> rw [] >>
|
|
|
CCONTR_TAC >> fs [] >>
|
|
|
`Suc i < length b.body` by decide_tac >> fs [] >>
|
|
|
`terminator (el i b.body)`
|
|
|
by (
|
|
|
Cases_on `el i b.body` >> fs [terminator_def, classify_instr_def] >>
|
|
|
Cases_on `p` >> fs [terminator_def, classify_instr_def]) >>
|
|
|
`~mem (el i b.body) (front b.body)` by metis_tac [] >>
|
|
|
metis_tac [mem_el_front]
|
|
|
QED
|
|
|
|
|
|
Theorem prog_ok_nonterm:
|
|
|
∀prog i ip.
|
|
|
prog_ok prog ∧ get_instr prog ip (Inl i) ∧ ¬terminator i ⇒ inc_pc ip ∈ next_ips prog ip
|
|
|
Proof
|
|
|
rw [next_ips_cases, IN_DEF, get_instr_cases, PULL_EXISTS] >>
|
|
|
`terminator (last b.body) ∧ b.body ≠ []` by metis_tac [prog_ok_def] >>
|
|
|
Cases_on `length b.body = idx + 1`
|
|
|
>- (
|
|
|
drule LAST_EL >>
|
|
|
rw [] >> fs [DECIDE ``PRE (x + 1) = x``]) >>
|
|
|
Cases_on `el idx b.body` >>
|
|
|
fs [instr_next_ips_def, terminator_def] >>
|
|
|
rw [EXISTS_OR_THM, inc_pc_def, inc_bip_def]
|
|
|
QED
|
|
|
|
|
|
(* ----- The invariant on emaps ----- *)
|
|
|
(* Essentially that the emap is what the llvm->llair translation generates in
|
|
|
* the end. Such emaps enjoy the nice property that they don't change when used
|
|
|
* as the input to a translation function, since they have all of the bindings
|
|
|
* in them already. *)
|
|
|
Definition untranslate_reg_def:
|
|
|
untranslate_reg (Var_name x t) = Reg x
|
|
|
End
|
|
|
|
|
|
Definition not_exp_def:
|
|
|
not_exp x regs_to_keep ⇔
|
|
|
(∀r t. x ≠ Exp r t) ∨ (∃r t. x = Exp r t ∧ r ∈ regs_to_keep)
|
|
|
End
|
|
|
|
|
|
(* This captures the variable->expression mapping that the compiler will have
|
|
|
* built *)
|
|
|
Definition good_emap_def:
|
|
|
good_emap f prog regs_to_keep gmap emap ⇔
|
|
|
∀ip.
|
|
|
f = ip.f ⇒
|
|
|
(∀r t inst.
|
|
|
get_instr prog ip (Inl inst) ∧ classify_instr inst = Exp r t ∧ r ∉ regs_to_keep
|
|
|
⇒
|
|
|
flookup emap r = Some (translate_instr_to_exp gmap emap inst)) ∧
|
|
|
(∀inst phis.
|
|
|
(get_instr prog ip (Inl inst) ∧ not_exp (classify_instr inst) regs_to_keep ∨
|
|
|
get_instr prog ip (Inr phis))
|
|
|
⇒
|
|
|
∀rt. rt ∈ assigns prog ip ⇒
|
|
|
flookup emap (fst rt) = Some (Var (translate_reg (fst rt) (snd rt)) F)) ∧
|
|
|
(* for each r |-> e mapping in emap, each register e is dominated by an
|
|
|
* assignment to that register for the entire live range of r *)
|
|
|
(∀r e r'. flookup emap r = Some e ∧ r ∈ live prog ip ∧ r' ∈ exp_uses e ⇒
|
|
|
∃ip2. untranslate_reg r' ∈ image fst (assigns prog ip2) ∧ dominates prog ip2 ip)
|
|
|
End
|
|
|
|
|
|
Theorem good_emap_header_unchanged:
|
|
|
∀f prog r gmap emap phis land from l.
|
|
|
good_emap f prog r gmap emap ∧
|
|
|
get_instr prog <| f := f; b := l; i := Phi_ip from |> (Inr (from, phis))
|
|
|
⇒
|
|
|
emap |++ header_to_emap_upd (Head phis land) = emap
|
|
|
Proof
|
|
|
rw [good_emap_def] >>
|
|
|
irule fupdate_list_elim >> simp [header_to_emap_upd_def, MEM_MAP, PULL_EXISTS] >>
|
|
|
rpt gen_tac >> CASE_TAC >> rw [] >>
|
|
|
first_x_assum (qspec_then `<|f := f; b := l; i := Phi_ip from|>` mp_tac) >>
|
|
|
rw [] >> res_tac >>
|
|
|
rename1 `flookup _ r1 = Some (Var (translate_reg r1 ty) _)` >>
|
|
|
first_x_assum (qspec_then `(r1,ty)` mp_tac) >> simp [] >>
|
|
|
disch_then irule >>
|
|
|
rw [assigns_cases, IN_DEF] >> disj2_tac >>
|
|
|
qexists_tac `from` >> qexists_tac `phis` >> rw [LIST_TO_SET_MAP] >>
|
|
|
metis_tac [phi_assigns_def]
|
|
|
QED
|
|
|
|
|
|
Theorem fupdate_elim_lookup:
|
|
|
∀k v f. flookup f k = Some v ⇒ f |+ (k,v) = f
|
|
|
Proof
|
|
|
rw [FLOOKUP_DEF] >> metis_tac [FUPDATE_ELIM]
|
|
|
QED
|
|
|
|
|
|
Theorem good_emap_translate_unchanged_lem:
|
|
|
∀f prog gmap emap regs_to_keep bl bs emap' l i d j.
|
|
|
good_emap (Fn f) prog regs_to_keep gmap emap ∧
|
|
|
alookup prog (Fn f) = Some d ∧
|
|
|
alookup d.blocks l = Some bl ∧
|
|
|
j ≤ length bl.body ∧
|
|
|
translate_instrs (Lab_name f (option_map dest_label l) i) gmap emap regs_to_keep (drop j bl.body) = (bs,emap')
|
|
|
⇒
|
|
|
emap = emap'
|
|
|
Proof
|
|
|
Induct_on `length bl.body - j` >>
|
|
|
rw []
|
|
|
>- (
|
|
|
`length bl.body = j` by decide_tac >>
|
|
|
rw [] >> fs [DROP_LENGTH_NIL, translate_instrs_def]) >>
|
|
|
first_x_assum (qspecl_then [`bl`, `j + 1`] mp_tac) >> simp [] >>
|
|
|
rpt (disch_then drule) >>
|
|
|
`j < length bl.body` by decide_tac >>
|
|
|
fs [DROP_EL_CONS, translate_instrs_def] >>
|
|
|
BasicProvers.EVERY_CASE_TAC >> fs [] >>
|
|
|
TRY (pairarg_tac >> fs []) >> disch_then irule >>
|
|
|
rw [] >> fs [inc_label_def]
|
|
|
>- (
|
|
|
`emap |+ (r,Var (translate_reg r t) F) = emap` suffices_by metis_tac [] >>
|
|
|
irule fupdate_elim_lookup >>
|
|
|
fs [good_emap_def] >>
|
|
|
first_x_assum (qspec_then `<| f := Fn f; b := l; i := Offset j |>` mp_tac) >>
|
|
|
rw [get_instr_cases, not_exp_def] >>
|
|
|
first_x_assum (qspec_then `(r,t)` mp_tac) >> simp [] >>
|
|
|
disch_then irule >> simp [assigns_cases, IN_DEF] >>
|
|
|
disj1_tac >> qexists_tac `el j bl.body` >>
|
|
|
rw [get_instr_cases] >>
|
|
|
Cases_on `el j bl.body` >> fs [classify_instr_def, instr_assigns_def] >>
|
|
|
Cases_on `p` >> fs [classify_instr_def, instr_assigns_def])
|
|
|
>- (
|
|
|
`emap |+ (r,translate_instr_to_exp gmap emap (el j bl.body)) = emap`
|
|
|
suffices_by metis_tac [] >>
|
|
|
irule fupdate_elim_lookup >>
|
|
|
fs [good_emap_def] >>
|
|
|
first_x_assum (qspec_then `<| f := Fn f; b := l; i := Offset j |>` mp_tac) >>
|
|
|
rw [get_instr_cases, not_exp_def])
|
|
|
>- (
|
|
|
`extend_emap_non_exp emap (el j bl.body) = emap` suffices_by metis_tac [] >>
|
|
|
Cases_on `el j bl.body` >> rw [extend_emap_non_exp_def] >>
|
|
|
irule fupdate_elim_lookup >>
|
|
|
fs [good_emap_def] >>
|
|
|
first_x_assum (qspec_then `<| f := Fn f; b := l; i := Offset j |>` mp_tac) >>
|
|
|
rw [get_instr_cases, not_exp_def] >>
|
|
|
qmatch_goalsub_abbrev_tac `translate_reg _ t'` >>
|
|
|
first_x_assum (qspec_then `(r,t')` mp_tac) >> simp [] >>
|
|
|
disch_then irule >> simp [assigns_cases, IN_DEF] >>
|
|
|
disj1_tac >> qexists_tac `el j bl.body` >>
|
|
|
rw [get_instr_cases] >>
|
|
|
fs [classify_instr_def, instr_assigns_def])
|
|
|
>- (
|
|
|
`extend_emap_non_exp emap (el j bl.body) = emap` suffices_by metis_tac [] >>
|
|
|
Cases_on `el j bl.body` >> rw [extend_emap_non_exp_def] >>
|
|
|
irule fupdate_elim_lookup >>
|
|
|
fs [good_emap_def] >>
|
|
|
first_x_assum (qspec_then `<| f := Fn f; b := l; i := Offset j |>` mp_tac) >>
|
|
|
rw [get_instr_cases, not_exp_def] >>
|
|
|
qmatch_goalsub_abbrev_tac `translate_reg _ t'` >>
|
|
|
first_x_assum (qspec_then `(r,t')` mp_tac) >> simp [] >>
|
|
|
disch_then irule >> simp [assigns_cases, IN_DEF] >>
|
|
|
disj1_tac >> qexists_tac `el j bl.body` >>
|
|
|
rw [get_instr_cases] >>
|
|
|
fs [classify_instr_def, instr_assigns_def])
|
|
|
QED
|
|
|
|
|
|
Theorem good_emap_translate_unchanged:
|
|
|
∀f prog gmap emap regs_to_keep bl bs emap' l i d.
|
|
|
good_emap (Fn f) prog regs_to_keep gmap emap ∧
|
|
|
alookup prog (Fn f) = Some d ∧
|
|
|
alookup d.blocks l = Some bl ∧
|
|
|
translate_instrs (Lab_name f (option_map dest_label l) i) gmap emap regs_to_keep bl.body = (bs,emap')
|
|
|
⇒
|
|
|
emap = emap'
|
|
|
Proof
|
|
|
metis_tac [good_emap_translate_unchanged_lem, DECIDE ``!x. 0 ≤ length x``, DROP_0]
|
|
|
QED
|
|
|
|
|
|
(* ------ Reasoning about emaps that are equal up to the live variables ----- *)
|
|
|
(* We can then prove that the translation is invariant under switching similar
|
|
|
* emaps *)
|
|
|
|
|
|
Definition similar_emap_def:
|
|
|
similar_emap live emap1 emap2 ⇔
|
|
|
DRESTRICT emap1 live = DRESTRICT emap2 live
|
|
|
End
|
|
|
|
|
|
Theorem similar_emap_sym:
|
|
|
∀s emap1 emap2. similar_emap s emap1 emap2 ⇔ similar_emap s emap2 emap1
|
|
|
Proof
|
|
|
rw [similar_emap_def] >> metis_tac []
|
|
|
QED
|
|
|
|
|
|
Theorem similar_emap_subset:
|
|
|
∀s1 s2 emap1 emap2.
|
|
|
similar_emap s1 emap1 emap2 ∧
|
|
|
s2 ⊆ s1
|
|
|
⇒
|
|
|
similar_emap s2 emap1 emap2
|
|
|
Proof
|
|
|
rw [similar_emap_def, SUBSET_DEF, fmap_eq_flookup, FLOOKUP_DRESTRICT] >> rw [] >>
|
|
|
last_x_assum (qspec_then `x` mp_tac) >> rw []
|
|
|
QED
|
|
|
|
|
|
Theorem extend_similar_emap:
|
|
|
∀s emap1 emap2 s2 l.
|
|
|
similar_emap s emap1 emap2 ∧
|
|
|
set (map fst l) = s2
|
|
|
⇒
|
|
|
similar_emap (s ∪ s2) (emap1 |++ l) (emap2 |++ l)
|
|
|
Proof
|
|
|
rw [similar_emap_def, fmap_eq_flookup, FLOOKUP_DRESTRICT] >>
|
|
|
rw []
|
|
|
>- (first_x_assum (qspec_then `x` mp_tac) >> rw [flookup_fupdate_list]) >>
|
|
|
rw [flookup_fupdate_list] >>
|
|
|
CASE_TAC >> fs [ALOOKUP_NONE, MEM_MAP] >> rfs [] >>
|
|
|
metis_tac []
|
|
|
QED
|
|
|
|
|
|
Theorem similar_emap_lemma:
|
|
|
∀s emap1 emap2 l.
|
|
|
similar_emap s emap1 emap2
|
|
|
⇒
|
|
|
similar_emap s (emap1 |++ l) (emap2 |++ l)
|
|
|
Proof
|
|
|
rw [similar_emap_def]
|
|
|
QED
|
|
|
|
|
|
Theorem similar_emap_diff:
|
|
|
∀s emap1 emap2 l s2.
|
|
|
similar_emap (s DIFF s2) emap1 emap2 ∧
|
|
|
s2 = set (map fst l)
|
|
|
⇒
|
|
|
similar_emap s (emap1 |++ l) (emap2 |++ l)
|
|
|
Proof
|
|
|
rw [similar_emap_def, fmap_eq_flookup, FLOOKUP_DRESTRICT] >> rw [] >>
|
|
|
first_x_assum (qspec_then `x` mp_tac) >>
|
|
|
rw [flookup_fupdate_list] >>
|
|
|
CASE_TAC >> rw [] >> fs [ALOOKUP_NONE, MEM_MAP] >>
|
|
|
metis_tac []
|
|
|
QED
|
|
|
|
|
|
Theorem extend_similar_emap2:
|
|
|
∀inst is emap1 emap2 reg t e.
|
|
|
similar_emap (fst (instrs_live (inst::is))) emap1 emap2 ∧
|
|
|
instr_assigns inst = {(reg, t)}
|
|
|
⇒
|
|
|
similar_emap (fst (instrs_live is)) (emap1 |+ (reg,e)) (emap2 |+ (reg,e))
|
|
|
Proof
|
|
|
rw [similar_emap_def, instrs_live_def, DRESTRICT_FUPDATE, fmap_eq_flookup,
|
|
|
FLOOKUP_UPDATE, FLOOKUP_DRESTRICT] >>
|
|
|
CASE_TAC >> rw [] >>
|
|
|
first_x_assum (qspec_then `x` mp_tac) >> rw [] >>
|
|
|
pairarg_tac >> fs [] >> fs []
|
|
|
QED
|
|
|
|
|
|
Theorem extend_similar_emap3:
|
|
|
∀inst emap1 emap2 reg t e.
|
|
|
similar_emap {reg} (emap1 |+ (reg,e)) (emap2 |+ (reg,e))
|
|
|
Proof
|
|
|
rw [similar_emap_def, fmap_eq_flookup, FLOOKUP_UPDATE, FLOOKUP_DRESTRICT]
|
|
|
QED
|
|
|
|
|
|
Theorem extend_similar_emap4:
|
|
|
∀inst emap1 emap2 is.
|
|
|
similar_emap (fst (instrs_live (inst::is))) emap1 emap2 ∧
|
|
|
classify_instr inst = Non_exp
|
|
|
⇒
|
|
|
similar_emap (fst (instrs_live is)) (extend_emap_non_exp emap1 inst) (extend_emap_non_exp emap2 inst)
|
|
|
Proof
|
|
|
rw [similar_emap_def, instrs_live_def, DRESTRICT_FUPDATE, fmap_eq_flookup,
|
|
|
FLOOKUP_DRESTRICT] >>
|
|
|
CASE_TAC >> rw [] >>
|
|
|
first_x_assum (qspec_then `x` mp_tac) >> rw [] >>
|
|
|
pairarg_tac >> fs [] >> fs [] >>
|
|
|
Cases_on `inst` >>
|
|
|
rw [extend_emap_non_exp_def, FLOOKUP_UPDATE] >>
|
|
|
fs [instr_assigns_def, instr_uses_def, classify_instr_def] >> rw [] >>
|
|
|
fs [] >>
|
|
|
Cases_on `p` >> fs [classify_instr_def]
|
|
|
QED
|
|
|
|
|
|
Theorem similar_emap_union:
|
|
|
∀s1 s2 emap1 emap2.
|
|
|
similar_emap (s1 ∪ s2) emap1 emap2 ⇔
|
|
|
similar_emap s1 emap1 emap2 ∧ similar_emap s2 emap1 emap2
|
|
|
Proof
|
|
|
rw [similar_emap_def, fmap_eq_flookup, FLOOKUP_DRESTRICT] >>
|
|
|
metis_tac []
|
|
|
QED
|
|
|
|
|
|
Theorem similar_emap_insert:
|
|
|
∀s1 s2 emap1 emap2.
|
|
|
similar_emap (s1 INSERT s2) emap1 emap2 ⇔
|
|
|
similar_emap {s1} emap1 emap2 ∧ similar_emap s2 emap1 emap2
|
|
|
Proof
|
|
|
rw [similar_emap_def, fmap_eq_flookup, FLOOKUP_DRESTRICT] >>
|
|
|
metis_tac []
|
|
|
QED
|
|
|
|
|
|
Theorem similar_emap_translate_arg:
|
|
|
∀gmap emap1 a s emap2.
|
|
|
similar_emap s emap1 emap2 ∧
|
|
|
arg_to_regs a ⊆ s
|
|
|
⇒
|
|
|
translate_arg gmap emap1 a = translate_arg gmap emap2 a
|
|
|
Proof
|
|
|
Cases_on `a` >> rw [translate_arg_def] >>
|
|
|
fs [arg_to_regs_def, similar_emap_def, fmap_eq_flookup, FLOOKUP_DRESTRICT] >>
|
|
|
first_x_assum (qspec_then `r` mp_tac) >> rw []
|
|
|
QED
|
|
|
|
|
|
Theorem similar_emap_translate_instr_to_exp:
|
|
|
∀gmap emap1 inst is emap2 r t.
|
|
|
similar_emap (fst (instrs_live (inst::is))) emap1 emap2 ∧
|
|
|
classify_instr inst = Exp r t ∧
|
|
|
is_implemented inst
|
|
|
⇒
|
|
|
translate_instr_to_exp gmap emap1 inst = translate_instr_to_exp gmap emap2 inst
|
|
|
Proof
|
|
|
ho_match_mp_tac translate_instr_to_exp_ind >>
|
|
|
rw [translate_instr_to_exp_def, classify_instr_def, instrs_live_def] >>
|
|
|
pairarg_tac >> fs [instr_uses_def, instr_assigns_def] >>
|
|
|
drule similar_emap_translate_arg >>
|
|
|
TRY (disch_then irule) >>
|
|
|
rw [SUBSET_DEF] >>
|
|
|
fs [is_implemented_def]
|
|
|
QED
|
|
|
|
|
|
Theorem similar_emap_translate_instr_to_inst:
|
|
|
∀gmap emap1 inst is emap2 r t.
|
|
|
similar_emap (fst (instrs_live (inst::is))) emap1 emap2 ∧
|
|
|
classify_instr inst = Non_exp ∧
|
|
|
is_implemented inst
|
|
|
⇒
|
|
|
translate_instr_to_inst gmap emap1 inst = translate_instr_to_inst gmap emap2 inst
|
|
|
Proof
|
|
|
ho_match_mp_tac translate_instr_to_inst_ind >>
|
|
|
rw [translate_instr_to_inst_def, classify_instr_def, instrs_live_def] >>
|
|
|
pairarg_tac >> fs [instr_uses_def, instr_assigns_def] >>
|
|
|
drule similar_emap_translate_arg >>
|
|
|
TRY (disch_then irule) >>
|
|
|
rw [SUBSET_DEF]
|
|
|
>- (rename1 `Extractvalue _ x _` >> Cases_on `x` >> fs [classify_instr_def])
|
|
|
>- (rename1 `Insertvalue _ x _ _` >> Cases_on `x` >> fs [classify_instr_def]) >>
|
|
|
fs [is_implemented_def]
|
|
|
QED
|
|
|
|
|
|
Theorem similar_emap_translate_instr_to_term:
|
|
|
∀inst l gmap emap1 is emap2 r t.
|
|
|
similar_emap (fst (instrs_live (inst::is))) emap1 emap2 ∧
|
|
|
classify_instr inst = Term ∧
|
|
|
is_implemented inst
|
|
|
⇒
|
|
|
translate_instr_to_term l gmap emap1 inst = translate_instr_to_term l gmap emap2 inst
|
|
|
Proof
|
|
|
ho_match_mp_tac classify_instr_ind >>
|
|
|
rw [translate_instr_to_term_def, classify_instr_def, instrs_live_def,
|
|
|
instr_uses_def]
|
|
|
>- fs [is_implemented_def]
|
|
|
>- (
|
|
|
CASE_TAC >> rw [] >>
|
|
|
irule similar_emap_translate_arg >>
|
|
|
pairarg_tac >>
|
|
|
fs [similar_emap_union, SUBSET_DEF] >>
|
|
|
metis_tac [])
|
|
|
>- fs [is_implemented_def]
|
|
|
>- (
|
|
|
irule similar_emap_translate_arg >>
|
|
|
pairarg_tac >>
|
|
|
fs [similar_emap_union, SUBSET_DEF] >>
|
|
|
metis_tac [])
|
|
|
>- fs [is_implemented_def]
|
|
|
QED
|
|
|
|
|
|
Theorem similar_emap_translate_call:
|
|
|
∀inst gmap emap1 is emap2 ret exret.
|
|
|
similar_emap (fst (instrs_live (inst::is))) emap1 emap2 ∧
|
|
|
classify_instr inst = Call ∧
|
|
|
is_implemented inst
|
|
|
⇒
|
|
|
translate_call gmap emap1 ret exret inst = translate_call gmap emap2 ret exret inst
|
|
|
Proof
|
|
|
ho_match_mp_tac classify_instr_ind >>
|
|
|
rw [translate_call_def, classify_instr_def, instrs_live_def, instr_uses_def,
|
|
|
instr_assigns_def] >>
|
|
|
pairarg_tac >> fs [similar_emap_union]
|
|
|
>- (
|
|
|
irule LIST_EQ >> rw [EL_MAP] >>
|
|
|
rename1 `el x l` >> Cases_on `el x l` >> fs [] >>
|
|
|
irule similar_emap_translate_arg >>
|
|
|
qexists_tac `bigunion (set (map (arg_to_regs ∘ snd) l))` >>
|
|
|
rw [SUBSET_DEF, MEM_MAP, PULL_EXISTS] >>
|
|
|
metis_tac [EL_MEM, SND])
|
|
|
>- fs [is_implemented_def]
|
|
|
QED
|
|
|
|
|
|
Theorem translate_header_similar_emap:
|
|
|
∀f from l gmap emap1 emap2 h.
|
|
|
similar_emap (header_uses h) emap1 emap2 ∧
|
|
|
(l = None ⇔ h = Entry)
|
|
|
⇒
|
|
|
translate_header f from l gmap emap1 h = translate_header f from l gmap emap2 h ∧
|
|
|
similar_emap (header_uses h ∪ header_assigns h)
|
|
|
(emap1 |++ header_to_emap_upd h)
|
|
|
(emap2 |++ header_to_emap_upd h)
|
|
|
Proof
|
|
|
rw [] >> Cases_on `h` >>
|
|
|
rw [translate_header_def] >> fs [header_uses_def, header_assigns_def] >>
|
|
|
rw [header_to_emap_upd_def, FUPDATE_LIST_THM] >>
|
|
|
`?l2. l = Some l2` by metis_tac [option_nchotomy] >>
|
|
|
rw [translate_header_def]
|
|
|
>- (
|
|
|
rw [LIST_EQ_REWRITE, EL_MAP, generate_move_block_def] >>
|
|
|
rename1 `build_move_for_lab _ _ _ (el i phis)` >>
|
|
|
Cases_on `el i phis` >> rw [build_move_for_lab_def] >> CASE_TAC >>
|
|
|
drule similar_emap_translate_arg >>
|
|
|
disch_then irule >>
|
|
|
rw [SUBSET_DEF, PULL_EXISTS] >>
|
|
|
qexists_tac `el x from` >>
|
|
|
qexists_tac `el i phis` >> rw [phi_uses_def] >>
|
|
|
metis_tac [EL_MEM])
|
|
|
>- (
|
|
|
irule extend_similar_emap >> rw [] >>
|
|
|
pop_assum kall_tac >>
|
|
|
Induct_on `l'` >> rw [EXTENSION] >>
|
|
|
CASE_TAC >>
|
|
|
eq_tac >> rw [phi_assigns_def])
|
|
|
QED
|
|
|
|
|
|
Theorem extend_emap_non_exp_assigns:
|
|
|
∀inst r t emap.
|
|
|
instr_assigns inst = {(r,t)} ∧
|
|
|
(classify_instr inst = Non_exp ∨ classify_instr inst = Call ∨ classify_instr inst = Term) ⇒
|
|
|
extend_emap_non_exp emap inst = emap |+ (r,Var (translate_reg r t) F)
|
|
|
Proof
|
|
|
ho_match_mp_tac instr_assigns_ind >>
|
|
|
rw [instr_assigns_def, extend_emap_non_exp_def, classify_instr_def]
|
|
|
QED
|
|
|
|
|
|
Theorem extend_emap_non_exp_no_assigns:
|
|
|
∀inst emap.
|
|
|
(∀r t. instr_assigns inst ≠ {(r,t)}) ∧
|
|
|
classify_instr inst = Non_exp ⇒
|
|
|
extend_emap_non_exp emap inst = emap ∧
|
|
|
instr_assigns inst = {}
|
|
|
Proof
|
|
|
ho_match_mp_tac instr_assigns_ind >>
|
|
|
rw [instr_assigns_def, extend_emap_non_exp_def, classify_instr_def]
|
|
|
QED
|
|
|
|
|
|
Theorem translate_instrs_similar_emap:
|
|
|
∀f l gmap emap1 emap2 regs_to_keep is i.
|
|
|
similar_emap (fst (instrs_live is)) emap1 emap2 ∧
|
|
|
(∀i. i < length is ∧ classify_instr (el i is) = Term ⇒ Suc i = length is) ∧
|
|
|
every is_implemented is
|
|
|
⇒
|
|
|
(λ(b1, emap1') (b2, emap2').
|
|
|
b1 = b2 ∧
|
|
|
∃l.
|
|
|
set (map fst l) = bigunion (set (map (image fst) (map instr_assigns is))) ∧
|
|
|
emap1' = emap1 |++ l ∧ emap2' = emap2 |++ l ∧
|
|
|
similar_emap (fst (instrs_live is) ∪ set (map fst l)) emap1' emap2')
|
|
|
(translate_instrs (Lab_name f (option_map dest_label l) i) gmap emap1 regs_to_keep is)
|
|
|
(translate_instrs (Lab_name f (option_map dest_label l) i) gmap emap2 regs_to_keep is)
|
|
|
Proof
|
|
|
Induct_on `is` >> rw [translate_instrs_def]
|
|
|
>- metis_tac [FUPDATE_LIST_THM]
|
|
|
>- metis_tac [FUPDATE_LIST_THM] >>
|
|
|
ntac 2 (pairarg_tac >> fs []) >>
|
|
|
rename1 `classify_instr inst` >>
|
|
|
Cases_on `classify_instr inst` >> fs []
|
|
|
>- (
|
|
|
rename1 `reg ∈ regs_to_keep` >>
|
|
|
`instr_assigns inst = {(reg, t)}`
|
|
|
by (
|
|
|
Cases_on `inst` >> fs [classify_instr_def, instr_assigns_def] >>
|
|
|
Cases_on `p` >> fs [classify_instr_def, instr_assigns_def]) >>
|
|
|
Cases_on `reg ∈ regs_to_keep` >> fs []
|
|
|
>- (
|
|
|
ntac 2 (pairarg_tac >> fs []) >> rpt var_eq_tac >>
|
|
|
fs [] >>
|
|
|
`similar_emap (fst (instrs_live is))
|
|
|
(emap1 |+ (reg,Var (translate_reg reg t) F))
|
|
|
(emap2 |+ (reg,Var (translate_reg reg t) F))`
|
|
|
by (
|
|
|
irule extend_similar_emap2 >>
|
|
|
qexists_tac `inst` >> rw [] >>
|
|
|
Cases_on `inst` >> fs [classify_instr_def, instr_assigns_def] >>
|
|
|
Cases_on `p` >> fs [classify_instr_def, instr_assigns_def]) >>
|
|
|
first_x_assum drule >>
|
|
|
disch_then (qspecl_then [`f`, `l`, `gmap`, `regs_to_keep`, `i`] mp_tac) >>
|
|
|
pairarg_tac >> fs [] >>
|
|
|
rw []
|
|
|
>- metis_tac [similar_emap_translate_instr_to_exp] >>
|
|
|
qexists_tac `(reg,Var (translate_reg reg t) F) :: l'` >> rw []
|
|
|
>- rw [EXTENSION, MEM_MAP]
|
|
|
>- metis_tac [FUPDATE_LIST_THM]
|
|
|
>- metis_tac [FUPDATE_LIST_THM] >>
|
|
|
fs [instrs_live_def] >> pairarg_tac >> simp [] >>
|
|
|
fs [similar_emap_union] >> rw []
|
|
|
>- metis_tac [similar_emap_lemma, FUPDATE_LIST_THM]
|
|
|
>- metis_tac [similar_emap_lemma, FUPDATE_LIST_THM] >>
|
|
|
simp [Once similar_emap_insert] >> rw [] >>
|
|
|
metis_tac [extend_similar_emap3, similar_emap_lemma])
|
|
|
>- (
|
|
|
drule similar_emap_translate_instr_to_exp >> simp [] >>
|
|
|
disch_then (qspec_then `gmap` mp_tac) >>
|
|
|
disch_tac >> fs [] >>
|
|
|
`similar_emap (fst (instrs_live is))
|
|
|
(emap1 |+ (reg,translate_instr_to_exp gmap emap2 inst))
|
|
|
(emap2 |+ (reg,translate_instr_to_exp gmap emap2 inst))`
|
|
|
by (irule extend_similar_emap2 >> qexists_tac `inst` >> rw []) >>
|
|
|
first_x_assum drule >>
|
|
|
disch_then (qspecl_then [`f`, `l`, `gmap`, `regs_to_keep`, `i`] mp_tac) >>
|
|
|
pairarg_tac >> fs [] >> rw [] >>
|
|
|
qexists_tac `(reg,translate_instr_to_exp gmap emap2 inst) :: l'` >> rw []
|
|
|
>- rw [EXTENSION, MEM_MAP]
|
|
|
>- metis_tac [FUPDATE_LIST_THM]
|
|
|
>- metis_tac [FUPDATE_LIST_THM] >>
|
|
|
fs [instrs_live_def] >> pairarg_tac >> simp [] >>
|
|
|
fs [similar_emap_union] >> rw []
|
|
|
>- metis_tac [similar_emap_lemma, FUPDATE_LIST_THM]
|
|
|
>- metis_tac [similar_emap_lemma, FUPDATE_LIST_THM] >>
|
|
|
simp [Once similar_emap_insert] >> rw [] >>
|
|
|
metis_tac [extend_similar_emap3, similar_emap_lemma]))
|
|
|
>- (
|
|
|
ntac 2 (pairarg_tac >> fs []) >> rpt var_eq_tac >>
|
|
|
drule extend_similar_emap4 >> simp [] >> disch_tac >>
|
|
|
first_x_assum drule >>
|
|
|
disch_then (qspecl_then [`f`, `l`, `gmap`, `regs_to_keep`, `i`] mp_tac) >>
|
|
|
pairarg_tac >> fs [] >>
|
|
|
rw []
|
|
|
>- metis_tac [similar_emap_translate_instr_to_inst] >>
|
|
|
Cases_on `∃r t. instr_assigns inst = {(r,t)}` >> fs []
|
|
|
>- (
|
|
|
drule extend_emap_non_exp_assigns >> rw [] >>
|
|
|
qexists_tac `(r,Var (translate_reg r t) F) :: l'` >> rw []
|
|
|
>- rw [EXTENSION]
|
|
|
>- metis_tac [FUPDATE_LIST_THM]
|
|
|
>- metis_tac [FUPDATE_LIST_THM] >>
|
|
|
fs [instrs_live_def] >> pairarg_tac >> simp [] >>
|
|
|
fs [similar_emap_union] >> rw []
|
|
|
>- metis_tac [similar_emap_lemma, FUPDATE_LIST_THM]
|
|
|
>- metis_tac [similar_emap_lemma, FUPDATE_LIST_THM] >>
|
|
|
simp [Once similar_emap_insert] >> rw [] >>
|
|
|
metis_tac [extend_similar_emap3, similar_emap_lemma])
|
|
|
>- (
|
|
|
drule extend_emap_non_exp_no_assigns >> rw [] >>
|
|
|
qexists_tac `l'` >> rw [] >>
|
|
|
fs [instrs_live_def] >> pairarg_tac >> simp [] >>
|
|
|
fs [similar_emap_union] >> rw [] >>
|
|
|
metis_tac [similar_emap_lemma, FUPDATE_LIST_THM]))
|
|
|
>- (
|
|
|
rw []
|
|
|
>- metis_tac [similar_emap_translate_instr_to_term] >>
|
|
|
`instr_assigns inst = {}`
|
|
|
by (
|
|
|
Cases_on `inst` >> fs [classify_instr_def, instr_assigns_def] >>
|
|
|
Cases_on `p` >> fs [classify_instr_def, instr_assigns_def]) >>
|
|
|
`is = []`
|
|
|
by (first_x_assum (qspec_then `0` mp_tac) >> simp []) >>
|
|
|
rw [FUPDATE_LIST_THM])
|
|
|
>- (
|
|
|
ntac 2 (pairarg_tac >> fs []) >> rpt var_eq_tac >> fs [] >>
|
|
|
`?r t. instr_assigns inst = {(r,t)}`
|
|
|
by (
|
|
|
Cases_on `inst` >> fs [classify_instr_def, instr_assigns_def] >>
|
|
|
Cases_on `p` >> fs [classify_instr_def, instr_assigns_def]) >>
|
|
|
drule extend_emap_non_exp_assigns >> simp [] >>
|
|
|
disch_tac >> fs [] >>
|
|
|
`similar_emap (fst (instrs_live is))
|
|
|
(emap1 |+ (r,Var (translate_reg r t) F))
|
|
|
(emap2 |+ (r,Var (translate_reg r t) F))`
|
|
|
by metis_tac [extend_similar_emap2] >>
|
|
|
first_x_assum drule >>
|
|
|
disch_then (qspecl_then [`f`, `l`, `gmap`, `regs_to_keep`, `i + 1`] mp_tac) >>
|
|
|
fs [inc_label_def] >> rw []
|
|
|
>- metis_tac [similar_emap_translate_call] >>
|
|
|
qexists_tac `(r,Var (translate_reg r t) F) :: l'` >> rw []
|
|
|
>- rw [EXTENSION, MEM_MAP]
|
|
|
>- metis_tac [FUPDATE_LIST_THM]
|
|
|
>- metis_tac [FUPDATE_LIST_THM] >>
|
|
|
fs [instrs_live_def] >> pairarg_tac >> simp [] >>
|
|
|
fs [similar_emap_union] >> rw []
|
|
|
>- metis_tac [similar_emap_lemma, FUPDATE_LIST_THM]
|
|
|
>- metis_tac [similar_emap_lemma, FUPDATE_LIST_THM] >>
|
|
|
simp [Once similar_emap_insert] >> rw [] >>
|
|
|
metis_tac [extend_similar_emap3, similar_emap_lemma])
|
|
|
QED
|
|
|
|
|
|
Theorem header_to_emap_upd_fst:
|
|
|
∀b.
|
|
|
set (map fst (header_to_emap_upd b.h)) =
|
|
|
{fst (phi_assigns p) | (land,p,phis) | b.h = Head phis land ∧ mem p phis}
|
|
|
Proof
|
|
|
rw [EXTENSION] >> eq_tac >> rw [MEM_MAP]
|
|
|
>- (
|
|
|
Cases_on `b.h` >> fs [header_to_emap_upd_def, MEM_MAP] >> rw [] >>
|
|
|
CASE_TAC >> rw [] >>
|
|
|
metis_tac [phi_assigns_def, FST])
|
|
|
>- (
|
|
|
rw [header_to_emap_upd_def, MEM_MAP, PULL_EXISTS] >>
|
|
|
qexists_tac `p` >> rw [] >>
|
|
|
CASE_TAC >> rw [phi_assigns_def])
|
|
|
QED
|
|
|
|
|
|
Theorem header_to_emap_upd_fst2:
|
|
|
!b. header_assigns b.h = set (map fst (header_to_emap_upd b.h))
|
|
|
Proof
|
|
|
Cases_on `b.h` >> rw [header_assigns_def, header_to_emap_upd_def] >>
|
|
|
rw [EXTENSION, MEM_MAP, PULL_EXISTS] >>
|
|
|
eq_tac >> rw []
|
|
|
>- (Cases_on `y` >> rw [phi_assigns_def] >> qexists_tac `Phi r t l'` >> rw [])
|
|
|
>- (CASE_TAC >> rw [] >> metis_tac [phi_assigns_def, FST])
|
|
|
QED
|
|
|
|
|
|
Definition block_assigns_def:
|
|
|
block_assigns b =
|
|
|
{ fst (phi_assigns p) | land,p,phis | b.h = Head phis land ∧ mem p phis } ∪
|
|
|
bigunion (image (λi. image fst (instr_assigns i)) (set b.body))
|
|
|
End
|
|
|
|
|
|
Theorem translate_block_emap_restr_live:
|
|
|
∀emap1 emap2 b f gmap r x l.
|
|
|
similar_emap (linear_live [b]) emap1 emap2 ∧
|
|
|
(l = None ⇔ b.h = Entry) ∧
|
|
|
(∀i. i < length b.body ∧ classify_instr (el i b.body) = Term ⇒ Suc i = length b.body) ∧
|
|
|
every is_implemented b.body
|
|
|
⇒
|
|
|
(λ(b1, emap1') (b2, emap2').
|
|
|
b1 = b2 ∧
|
|
|
∃l.
|
|
|
set (map fst l) = block_assigns b ∧
|
|
|
emap1' = emap1 |++ l ∧ emap2' = emap2 |++ l ∧
|
|
|
similar_emap (linear_live [b] ∪ block_assigns b) emap1' emap2')
|
|
|
(translate_block f gmap emap1 r x (l,b))
|
|
|
(translate_block f gmap emap2 r x (l,b))
|
|
|
Proof
|
|
|
rw [translate_block_def] >>
|
|
|
rpt (pairarg_tac >> fs []) >>
|
|
|
`similar_emap (header_uses b.h) emap1 emap2`
|
|
|
by (
|
|
|
fs [similar_emap_def, linear_live_def, fmap_eq_flookup, FLOOKUP_DRESTRICT, PULL_EXISTS] >>
|
|
|
rw [] >> last_x_assum (qspec_then `x'` mp_tac) >> rw [] >>
|
|
|
pairarg_tac >> fs []) >>
|
|
|
drule translate_header_similar_emap >>
|
|
|
disch_then drule >>
|
|
|
disch_then (qspecl_then [`f`, `THE (alookup x l)`, `gmap`] mp_tac) >>
|
|
|
strip_tac >>
|
|
|
`similar_emap (fst (instrs_live b.body))
|
|
|
(emap1 |++ header_to_emap_upd b.h)
|
|
|
(emap2 |++ header_to_emap_upd b.h)`
|
|
|
by (
|
|
|
fs [linear_live_def] >>
|
|
|
pairarg_tac >> fs [similar_emap_union] >>
|
|
|
irule similar_emap_diff >>
|
|
|
metis_tac [header_to_emap_upd_fst2]) >>
|
|
|
drule translate_instrs_similar_emap >>
|
|
|
disch_then (qspecl_then [`f`, `l`, `gmap`, `r`, `0`] mp_tac) >>
|
|
|
rpt (pairarg_tac >> simp []) >>
|
|
|
rw [] >> fs [] >> rw [] >>
|
|
|
simp [GSYM FUPDATE_LIST_APPEND] >>
|
|
|
qexists_tac `header_to_emap_upd b.h ++ l'` >> simp [] >>
|
|
|
conj_asm1_tac
|
|
|
>- (
|
|
|
rw [block_assigns_def] >>
|
|
|
rw [GSYM header_to_emap_upd_fst] >>
|
|
|
rw [EXTENSION, PULL_EXISTS, MEM_MAP] >>
|
|
|
metis_tac []) >>
|
|
|
irule extend_similar_emap >> rw [block_assigns_def]
|
|
|
QED
|
|
|
|
|
|
Theorem translate_blocks_emap_restr_live:
|
|
|
∀emap1 emap2 blocks f gmap r x.
|
|
|
similar_emap (linear_live (map snd blocks)) emap1 emap2 ∧
|
|
|
every (\(l,b). l = None ⇔ b.h = Entry) blocks ∧
|
|
|
every (\(l,b). (∀i. i < length b.body ∧ classify_instr (el i b.body) = Term ⇒ Suc i = length b.body))
|
|
|
blocks ∧
|
|
|
every (\(l,b). every is_implemented b.body) blocks
|
|
|
⇒
|
|
|
translate_blocks f gmap emap1 r x blocks = translate_blocks f gmap emap2 r x blocks
|
|
|
Proof
|
|
|
Induct_on `blocks` >> rw [translate_blocks_def] >>
|
|
|
pairarg_tac >> rw [] >>
|
|
|
pairarg_tac >> rw [] >>
|
|
|
qpat_x_assum `translate_block _ _ _ _ _ _ = _` mp_tac >>
|
|
|
rename1 `translate_block _ _ _ _ _ p = (b3, emap3)` >>
|
|
|
rw [] >>
|
|
|
rename1 `translate_block _ _ _ _ _ p = (b4, emap4)` >>
|
|
|
rw [APPEND_EQ_APPEND] >>
|
|
|
disj1_tac >> qexists_tac `[]` >>
|
|
|
simp [] >>
|
|
|
`?l b. p = (l,b)` by metis_tac [pair_CASES] >> fs [] >>
|
|
|
`similar_emap (linear_live [b]) emap1 emap2`
|
|
|
by (
|
|
|
fs [linear_live_def] >>
|
|
|
pairarg_tac >> fs [similar_emap_union, union_diff]) >>
|
|
|
drule translate_block_emap_restr_live >>
|
|
|
disch_then drule >>
|
|
|
simp [] >>
|
|
|
disch_then (qspecl_then [`f`, `gmap`, `r`, `x`] mp_tac) >>
|
|
|
pairarg_tac >> simp [] >>
|
|
|
fs [] >> rw [] >>
|
|
|
first_x_assum irule >>
|
|
|
fs [linear_live_def] >>
|
|
|
pairarg_tac >> fs [similar_emap_union, union_diff, block_assigns_def] >>
|
|
|
fs [GSYM header_to_emap_upd_fst, GSYM header_to_emap_upd_fst2] >>
|
|
|
irule similar_emap_diff >> rw [DIFF_UNION] >>
|
|
|
qmatch_goalsub_abbrev_tac `similar_emap (_ DIFF _ DIFF a)` >>
|
|
|
`kill ⊆ a` by metis_tac [instrs_kill_subset_assigns, SND] >>
|
|
|
ONCE_REWRITE_TAC [similar_emap_sym] >>
|
|
|
irule similar_emap_subset >>
|
|
|
qexists_tac `linear_live (map snd blocks) DIFF kill DIFF header_assigns b.h` >>
|
|
|
fs [SUBSET_DEF] >> metis_tac []
|
|
|
QED
|
|
|
|
|
|
(* ------ Theorems about lookups in the translated program ----- *)
|
|
|
(* This uses the dominor_ordered theorems and the similar_emap theorems to
|
|
|
* switch the empty emap that the translator starts the translation with to the
|
|
|
* good_emap that it ends with. The good_emap theory then lets us know that it
|
|
|
* doesn't change throughout the compilation. *)
|
|
|
|
|
|
Theorem alookup_translate_prog:
|
|
|
∀prog f d.
|
|
|
alookup prog (Fn f) = Some d
|
|
|
⇒
|
|
|
alookup (translate_prog prog).functions f = Some (translate_def f d (get_gmap prog))
|
|
|
Proof
|
|
|
rw [translate_prog_def] >>
|
|
|
qspec_tac (`get_gmap prog:glob_var |-> ty`, `gmap`) >>
|
|
|
Induct_on `prog` >>
|
|
|
rw [] >>
|
|
|
pairarg_tac >> fs [] >> rw [] >> Cases_on `fname` >> fs [dest_fn_def]
|
|
|
QED
|
|
|
|
|
|
Triviality dest_label_11:
|
|
|
dest_label x = dest_label y ⇔ x = y
|
|
|
Proof
|
|
|
Cases_on `x` >> Cases_on `y` >> rw [dest_label_def]
|
|
|
QED
|
|
|
|
|
|
Theorem alookup_translate_instrs_mov:
|
|
|
∀l gmap emap r is bs emap' f from to.
|
|
|
translate_instrs l gmap emap r is = (bs, emap') ∧
|
|
|
(∀f from to. l ≠ Mov_name f from to)
|
|
|
⇒
|
|
|
alookup bs (Mov_name f from to) = None
|
|
|
Proof
|
|
|
Induct_on `is` >> rw [translate_instrs_def] >> rw [] >>
|
|
|
BasicProvers.EVERY_CASE_TAC >> fs [] >>
|
|
|
TRY pairarg_tac >> fs [] >> rw []
|
|
|
>- (
|
|
|
rename1 `add_to_first_block _ bs1` >>
|
|
|
`bs1 = [] ∨ ∃x y bs2. bs1 = (x,y)::bs2` by metis_tac [list_CASES, pair_CASES] >>
|
|
|
fs [add_to_first_block_def] >> rw [] >>
|
|
|
first_x_assum drule >> Cases_on `l` >> fs [inc_label_def] >>
|
|
|
rw [] >> metis_tac [NOT_SOME_NONE])
|
|
|
>- (first_x_assum drule >> Cases_on `l` >> fs [inc_label_def])
|
|
|
>- (
|
|
|
rename1 `add_to_first_block _ bs1` >>
|
|
|
`bs1 = [] ∨ ∃x y bs2. bs1 = (x,y)::bs2` by metis_tac [list_CASES, pair_CASES] >>
|
|
|
fs [add_to_first_block_def] >> rw [] >>
|
|
|
first_x_assum drule >> Cases_on `l` >> fs [inc_label_def] >>
|
|
|
rw [] >> metis_tac [NOT_SOME_NONE])
|
|
|
>- (first_x_assum drule >> Cases_on `l` >> fs [inc_label_def])
|
|
|
QED
|
|
|
|
|
|
Theorem alookup_translate_header_mov:
|
|
|
∀gmap r f emap to_l from_l x to_l' from_ls h.
|
|
|
(to_l' = None ⇒ h = Entry) ∧
|
|
|
alookup (translate_header f from_ls to_l' gmap emap h)
|
|
|
(Mov_name f (option_map dest_label from_l) to_l) = Some x
|
|
|
⇒
|
|
|
to_l' = Some (Lab to_l)
|
|
|
Proof
|
|
|
rw [] >>
|
|
|
Cases_on `to_l'` >> Cases_on `h` >> fs [translate_header_def] >>
|
|
|
drule ALOOKUP_MEM >> simp [MEM_MAP] >>
|
|
|
rw [] >>
|
|
|
Cases_on `x'` >> fs [dest_label_def]
|
|
|
QED
|
|
|
|
|
|
Theorem lab_dest_lab[simp]:
|
|
|
Lab (dest_label l) = l
|
|
|
Proof
|
|
|
Cases_on `l` >> rw [dest_label_def]
|
|
|
QED
|
|
|
|
|
|
Theorem alookup_translate_header:
|
|
|
∀f to_l gmap emap phis l from_l edges from_ls.
|
|
|
(mem (Some (Lab to_l), from_ls) edges ∧ mem from_l from_ls)
|
|
|
⇒
|
|
|
alookup (translate_header f from_ls (Some (Lab to_l)) gmap emap (Head phis l)) (Mov_name f (option_map dest_label from_l) to_l) ≠ None
|
|
|
Proof
|
|
|
rw [translate_header_def, ALOOKUP_NONE, MAP_MAP_o, combinTheory.o_DEF,
|
|
|
MEM_MAP, PULL_EXISTS, dest_label_def, MEM_FLAT] >>
|
|
|
Cases_on `from_l` >> fs [] >> rw [PULL_EXISTS] >>
|
|
|
metis_tac []
|
|
|
QED
|
|
|
|
|
|
Theorem mem_get_from_ls:
|
|
|
∀to_l blocks from_l.
|
|
|
mem from_l (get_from_ls to_l blocks) ⇔
|
|
|
∃b. mem (from_l, b) blocks ∧ mem to_l (map Some (instr_to_labs (last b.body)))
|
|
|
Proof
|
|
|
ho_match_mp_tac get_from_ls_ind >> rw [get_from_ls_def] >> metis_tac []
|
|
|
QED
|
|
|
|
|
|
Theorem alookup_translate_blocks_mov:
|
|
|
∀blocks to_l f gmap regs_to_keep edges from_l phis block emap prog.
|
|
|
good_emap (Fn f) prog regs_to_keep gmap emap ∧
|
|
|
(∀l b. mem (l, b) blocks ⇒ ∃d. alookup prog (Fn f) = Some d ∧ alookup d.blocks l = Some b) ∧
|
|
|
mem (Some (Lab to_l)) (map fst blocks) ∧
|
|
|
(∃from_ls. alookup edges (Some (Lab to_l)) = Some from_ls ∧ mem from_l from_ls) ∧
|
|
|
every (\b. (snd b).h = Entry ⇔ fst b = None) blocks ∧
|
|
|
alookup blocks (Some (Lab to_l)) = Some block ∧ (∃l. block.h = Head phis l)
|
|
|
⇒
|
|
|
alookup
|
|
|
(translate_blocks f gmap emap regs_to_keep edges blocks)
|
|
|
(Mov_name f (option_map dest_label from_l) to_l) =
|
|
|
Some (generate_move_block f gmap emap phis from_l (Lab to_l))
|
|
|
Proof
|
|
|
Induct_on `blocks` >> rw [translate_blocks_def] >>
|
|
|
rename1 `alookup (bloc::blocks) (Some _) = Some _` >>
|
|
|
`∃l bl. bloc = (l,bl)` by metis_tac [pair_CASES] >>
|
|
|
fs [] >> rw [translate_block_def]
|
|
|
>- (
|
|
|
pairarg_tac >> fs [] >>
|
|
|
pairarg_tac >> fs [] >> rw [] >>
|
|
|
rw [ALOOKUP_APPEND] >>
|
|
|
BasicProvers.EVERY_CASE_TAC >> fs []
|
|
|
>- metis_tac [alookup_translate_header, ALOOKUP_MEM]
|
|
|
>- metis_tac [label_distinct, alookup_translate_instrs_mov, NOT_NONE_SOME] >>
|
|
|
fs [translate_header_def, alookup_some, MAP_EQ_APPEND] >> rw [] >>
|
|
|
Cases_on `from_l` >> Cases_on `l_from` >> fs [] >>
|
|
|
metis_tac [dest_label_11]) >>
|
|
|
BasicProvers.EVERY_CASE_TAC >> fs [] >> rw []
|
|
|
>- (
|
|
|
pairarg_tac >> fs [] >>
|
|
|
pairarg_tac >> fs [] >> rw [] >>
|
|
|
rw [ALOOKUP_APPEND] >>
|
|
|
BasicProvers.EVERY_CASE_TAC >> fs []
|
|
|
>- metis_tac [alookup_translate_header, ALOOKUP_MEM]
|
|
|
>- metis_tac [label_distinct, alookup_translate_instrs_mov, NOT_NONE_SOME] >>
|
|
|
fs [translate_header_def, alookup_some, MAP_EQ_APPEND] >> rw [] >>
|
|
|
Cases_on `from_l` >> Cases_on `l_from` >> fs [] >>
|
|
|
metis_tac [dest_label_11]) >>
|
|
|
first_x_assum drule >> simp [PULL_EXISTS] >>
|
|
|
rpt (disch_then drule) >>
|
|
|
pairarg_tac >> fs [] >>
|
|
|
fs [ALOOKUP_APPEND] >>
|
|
|
BasicProvers.EVERY_CASE_TAC >> fs [] >>
|
|
|
pairarg_tac >> fs [] >> rw [] >>
|
|
|
fs [ALOOKUP_APPEND] >>
|
|
|
BasicProvers.EVERY_CASE_TAC >> fs []
|
|
|
>- (
|
|
|
`emap |++ header_to_emap_upd bl.h = emap`
|
|
|
by (
|
|
|
Cases_on `bl.h`
|
|
|
>- rw [header_to_emap_upd_def, FUPDATE_LIST_THM] >>
|
|
|
first_assum (qspecl_then [`l'`, `bl`] assume_tac) >> fs [] >>
|
|
|
rename1 `bl.h = Head phis1 land` >>
|
|
|
`get_instr prog <| f := Fn f; b := l'; i := Phi_ip from_l |>
|
|
|
(Inr (from_l, phis1))`
|
|
|
by rw [get_instr_cases] >>
|
|
|
metis_tac [good_emap_header_unchanged]) >>
|
|
|
`emap' = emap` by metis_tac [good_emap_translate_unchanged] >>
|
|
|
metis_tac [label_distinct, alookup_translate_instrs_mov, NOT_NONE_SOME]) >>
|
|
|
rw [] >>
|
|
|
metis_tac [label_distinct, alookup_translate_instrs_mov, NOT_NONE_SOME, alookup_translate_header_mov]
|
|
|
QED
|
|
|
|
|
|
Theorem get_block_translate_prog_mov:
|
|
|
∀prog f from_l to_l d b block phis d emap.
|
|
|
prog_ok prog ∧
|
|
|
dominator_ordered prog ∧
|
|
|
good_emap (Fn f) prog (get_regs_to_keep d) (get_gmap prog) emap ∧
|
|
|
alookup prog (Fn f) = Some d ∧
|
|
|
alookup d.blocks from_l = Some b ∧
|
|
|
mem (Lab to_l) (instr_to_labs (last b.body)) ∧
|
|
|
alookup d.blocks (Some (Lab to_l)) = Some block ∧ (∃l. block.h = Head phis l) ∧
|
|
|
every (\(l,b). every is_implemented b.body) d.blocks
|
|
|
⇒
|
|
|
get_block (translate_prog prog)
|
|
|
(Mov_name f (option_map dest_label from_l) to_l)
|
|
|
(generate_move_block f (get_gmap prog) emap phis from_l (Lab to_l))
|
|
|
Proof
|
|
|
rw [get_block_cases, label_to_fname_def] >>
|
|
|
drule alookup_translate_prog >>
|
|
|
rw [] >> rw [translate_def_def] >>
|
|
|
qmatch_goalsub_abbrev_tac `translate_blocks a1 b1 _ c1 d1 e1` >>
|
|
|
`translate_blocks a1 b1 fempty c1 d1 e1 = translate_blocks a1 b1 emap c1 d1 e1`
|
|
|
by (
|
|
|
irule translate_blocks_emap_restr_live >>
|
|
|
unabbrev_all_tac >> rw []
|
|
|
>- metis_tac [prog_ok_terminator_last]
|
|
|
>- (
|
|
|
fs [prog_ok_def] >> fs [EVERY_MEM] >> rw [] >>
|
|
|
pairarg_tac >> rw [] >> metis_tac [FST, SND])
|
|
|
>- metis_tac [dominator_ordered_linear_live, similar_emap_def, DRESTRICT_IS_FEMPTY]) >>
|
|
|
unabbrev_all_tac >> rw [] >>
|
|
|
irule alookup_translate_blocks_mov >> rw []
|
|
|
>- (
|
|
|
simp [ALOOKUP_MAP_2, MEM_MAP, EXISTS_PROD] >>
|
|
|
drule ALOOKUP_MEM >> rw [mem_get_from_ls, MEM_MAP] >>
|
|
|
imp_res_tac ALOOKUP_MEM >>
|
|
|
metis_tac [])
|
|
|
>- (fs [prog_ok_def] >> res_tac >> fs [EVERY_MEM])
|
|
|
>- (
|
|
|
imp_res_tac ALOOKUP_MEM >>
|
|
|
fs [MEM_MAP] >>
|
|
|
metis_tac [FST])
|
|
|
>- (
|
|
|
fs [prog_ok_def] >>
|
|
|
qexists_tac `prog` >> rw [] >>
|
|
|
irule ALOOKUP_ALL_DISTINCT_MEM >> rw [] >>
|
|
|
fs [EVERY_MEM] >>
|
|
|
`(λ(fname,dec). all_distinct (map fst dec.blocks)) (Fn f, d)`
|
|
|
by metis_tac [ALOOKUP_MEM] >>
|
|
|
fs [])
|
|
|
QED
|
|
|
|
|
|
Theorem alookup_translate_header_lab:
|
|
|
(l = None ⇒ h = Entry)
|
|
|
⇒
|
|
|
alookup (translate_header f from_ls l gmap emap h) (translate_label f l' i) = None
|
|
|
Proof
|
|
|
Cases_on `l` >> Cases_on `h` >> fs [translate_header_def] >>
|
|
|
Cases_on `l'` >> fs [translate_label_def, ALOOKUP_NONE, MEM_MAP] >>
|
|
|
rw [dest_label_def] >>
|
|
|
CCONTR_TAC >> fs [] >> rw [] >> fs [] >>
|
|
|
Cases_on `x'` >> fs [translate_label_def]
|
|
|
QED
|
|
|
|
|
|
Theorem alookup_translate_instrs_lab:
|
|
|
∀f l' i j gmap emap regs_to_keep b bs emap' l x.
|
|
|
translate_instrs (Lab_name f (option_map dest_label l') i) gmap emap regs_to_keep b = (bs,emap') ∧
|
|
|
alookup bs (translate_label f l j) = Some x
|
|
|
⇒
|
|
|
l = l'
|
|
|
Proof
|
|
|
Induct_on `b` >> rw [translate_instrs_def] >> fs [] >>
|
|
|
rename1 `classify_instr ins` >>
|
|
|
Cases_on `classify_instr ins` >> fs []
|
|
|
>- (
|
|
|
pairarg_tac >> fs [] >>
|
|
|
Cases_on `r ∈ regs_to_keep` >> fs []
|
|
|
>- (
|
|
|
first_x_assum drule >>
|
|
|
Cases_on `bs'` >> fs [add_to_first_block_def] >> rw [] >> fs [] >>
|
|
|
rename1 `add_to_first_block _ (bl::_)` >>
|
|
|
Cases_on `bl` >> fs [add_to_first_block_def] >>
|
|
|
rename1 `lab = translate_label _ _ _` >>
|
|
|
Cases_on `lab = translate_label f l j` >> fs [] >> metis_tac []) >>
|
|
|
metis_tac [])
|
|
|
>- (
|
|
|
pairarg_tac >> fs [] >>
|
|
|
first_x_assum drule >>
|
|
|
Cases_on `bs'` >> fs [add_to_first_block_def] >> rw [] >> fs [] >>
|
|
|
rename1 `add_to_first_block _ (bl::_)` >>
|
|
|
Cases_on `bl` >> fs [add_to_first_block_def] >>
|
|
|
rename1 `lab = translate_label _ _ _` >>
|
|
|
Cases_on `lab = translate_label f l j` >> fs [] >> metis_tac [])
|
|
|
>- (
|
|
|
rw [] >> fs [ALOOKUP_def] >>
|
|
|
Cases_on `l` >> Cases_on `l'` >> fs [translate_label_def] >>
|
|
|
rename1 `translate_label _ (Some lname)` >>
|
|
|
Cases_on `lname` >> fs [translate_label_def] >> rw [])
|
|
|
>- (
|
|
|
pairarg_tac >> fs [] >> rw [] >> fs [ALOOKUP_def] >>
|
|
|
BasicProvers.EVERY_CASE_TAC >> fs [] >>
|
|
|
rw []
|
|
|
>- (
|
|
|
Cases_on `l` >> fs [inc_label_def, translate_label_def] >>
|
|
|
rename1 `translate_label _ (Some lb)` >>
|
|
|
Cases_on `lb` >> fs [inc_label_def, translate_label_def]) >>
|
|
|
fs [inc_label_def] >>
|
|
|
metis_tac [])
|
|
|
QED
|
|
|
|
|
|
Triviality every_front:
|
|
|
∀P x y. y ≠ [] ∧ every P (front (x::y)) ⇒ every P (front y)
|
|
|
Proof
|
|
|
Induct_on `y` >> rw []
|
|
|
QED
|
|
|
|
|
|
Theorem translate_instrs_first_lab:
|
|
|
∀dest_label l gmap emap regs_to_keep b bs emap l' b' emap'.
|
|
|
translate_instrs l gmap emap regs_to_keep b = ((l',b')::bs,emap')
|
|
|
⇒
|
|
|
l = l'
|
|
|
Proof
|
|
|
Induct_on `b` >> rw [translate_instrs_def] >>
|
|
|
BasicProvers.EVERY_CASE_TAC >> fs [] >>
|
|
|
TRY pairarg_tac >> fs [] >> rw [] >>
|
|
|
TRY (Cases_on `bs'`) >> fs [add_to_first_block_def] >>
|
|
|
TRY (Cases_on `h'`) >> fs [add_to_first_block_def] >>
|
|
|
metis_tac []
|
|
|
QED
|
|
|
|
|
|
Triviality lab_translate_label:
|
|
|
∀f l j f' l' j'.
|
|
|
Lab_name f (option_map dest_label l) j = translate_label f' l' j'
|
|
|
⇔
|
|
|
f = f' ∧ l = l' ∧ j = j'
|
|
|
Proof
|
|
|
rw [] >> Cases_on `l` >> Cases_on `l'` >> fs [translate_label_def] >>
|
|
|
Cases_on `x` >> fs [translate_label_def, dest_label_def] >>
|
|
|
Cases_on `x'` >> fs [translate_label_def, dest_label_def]
|
|
|
QED
|
|
|
|
|
|
Definition num_calls_def:
|
|
|
num_calls is = length (filter is_call is)
|
|
|
End
|
|
|
|
|
|
Theorem alookup_translate_instrs:
|
|
|
∀f l i j gmap emap regs_to_keep b bs emap' l x.
|
|
|
b ≠ [] ∧
|
|
|
terminator (last b) ∧
|
|
|
every (λi. ¬terminator i) (front b) ∧
|
|
|
i ≤ num_calls b ∧
|
|
|
translate_instrs (Lab_name f (option_map dest_label l) j) gmap emap regs_to_keep b = (bs,emap')
|
|
|
⇒
|
|
|
alookup bs (translate_label f l (i + j))
|
|
|
=
|
|
|
Some (snd (el i (fst (translate_instrs (Lab_name f (option_map dest_label l) j)
|
|
|
gmap emap regs_to_keep b))))
|
|
|
Proof
|
|
|
Induct_on `b` >> rw [translate_instrs_def, num_calls_def] >>
|
|
|
rename1 `classify_instr instr`
|
|
|
>- (
|
|
|
Cases_on `instr` >> fs [is_call_def, classify_instr_def] >>
|
|
|
pairarg_tac >> fs [] >> rw [] >>
|
|
|
fs [lab_translate_label]
|
|
|
>- (
|
|
|
`i = 0` by fs [] >>
|
|
|
rw [] >> fs [] >>
|
|
|
qexists_tac `emap` >> rw []) >>
|
|
|
`b ≠ []` by (Cases_on `b` >> fs [terminator_def]) >>
|
|
|
fs [LAST_DEF, inc_label_def] >>
|
|
|
`0 < i` by fs [] >>
|
|
|
`i - 1 ≤ num_calls b` by fs [num_calls_def] >>
|
|
|
drule every_front >> disch_then drule >> rw [] >>
|
|
|
first_x_assum drule >> disch_then drule >> disch_then drule >> rw [] >>
|
|
|
rw [] >>
|
|
|
rw [EL_CONS, PRE_SUB1]) >>
|
|
|
Cases_on `classify_instr instr` >> fs [LAST_DEF]
|
|
|
>- (
|
|
|
`b ≠ []`
|
|
|
by (
|
|
|
Cases_on `b = []` >> Cases_on `instr` >> fs [is_call_def, classify_instr_def] >>
|
|
|
rw [] >> fs [terminator_def]) >>
|
|
|
fs [num_calls_def] >>
|
|
|
pairarg_tac >> fs [] >>
|
|
|
drule every_front >> disch_then drule >> rw [] >> fs [] >>
|
|
|
Cases_on `r ∉ regs_to_keep` >> fs []
|
|
|
>- metis_tac [] >>
|
|
|
Cases_on `bs'` >> fs [add_to_first_block_def] >>
|
|
|
first_x_assum drule >> disch_then drule >> rw [] >> fs [] >>
|
|
|
rename1 `add_to_first_block _ (i1::is)` >>
|
|
|
Cases_on `i1` >> fs [add_to_first_block_def] >>
|
|
|
rw [] >> fs [] >>
|
|
|
drule translate_instrs_first_lab >> rw [] >>
|
|
|
fs [lab_translate_label]
|
|
|
>- (`i = 0` by fs [] >> rw []) >>
|
|
|
`0 < i` by fs [] >>
|
|
|
rw [EL_CONS])
|
|
|
>- (
|
|
|
`b ≠ []`
|
|
|
by (
|
|
|
Cases_on `b = []` >> Cases_on `instr` >> fs [is_call_def, classify_instr_def] >>
|
|
|
rw [] >> fs [terminator_def]) >>
|
|
|
fs [num_calls_def] >>
|
|
|
pairarg_tac >> fs [] >>
|
|
|
rw [] >>
|
|
|
drule every_front >> disch_then drule >> rw [] >> fs [] >>
|
|
|
Cases_on `bs'` >> fs [add_to_first_block_def] >>
|
|
|
first_x_assum drule >> disch_then drule >> rw [] >> fs [] >>
|
|
|
rename1 `add_to_first_block _ (i1::is)` >>
|
|
|
Cases_on `i1` >> fs [add_to_first_block_def] >>
|
|
|
rw [] >> fs [] >>
|
|
|
drule translate_instrs_first_lab >> rw [] >>
|
|
|
fs [lab_translate_label]
|
|
|
>- (`i = 0` by fs [] >> rw []) >>
|
|
|
`0 < i` by fs [] >>
|
|
|
rw [EL_CONS])
|
|
|
>- (
|
|
|
`b = []`
|
|
|
by (
|
|
|
Cases_on `b` >> fs [] >>
|
|
|
Cases_on `instr` >> fs [terminator_def, classify_instr_def] >>
|
|
|
Cases_on `p` >> fs [classify_instr_def]) >>
|
|
|
fs [] >> rw [] >>
|
|
|
metis_tac [lab_translate_label])
|
|
|
>- (
|
|
|
`b = []`
|
|
|
by (
|
|
|
Cases_on `b` >> fs [] >>
|
|
|
Cases_on `instr` >> fs [is_call_def, terminator_def, classify_instr_def] >>
|
|
|
Cases_on `p` >> fs [classify_instr_def]) >>
|
|
|
rw [] >> fs [] >>
|
|
|
pairarg_tac >> fs [] >> rw [] >>
|
|
|
Cases_on `l` >> fs [translate_label_def] >>
|
|
|
Cases_on `x` >> fs [translate_label_def, dest_label_def])
|
|
|
QED
|
|
|
|
|
|
Theorem classify_instr_lem:
|
|
|
(∀i. (terminator i ∨ is_call i) ⇔ classify_instr i = Term ∨ classify_instr i = Call)
|
|
|
Proof
|
|
|
strip_tac >> Cases_on `i` >> rw [terminator_def, classify_instr_def, is_call_def] >>
|
|
|
Cases_on `p` >> rw [classify_instr_def]
|
|
|
QED
|
|
|
|
|
|
Theorem translate_instrs_not_empty:
|
|
|
∀l gmap emap regs b.
|
|
|
b ≠ [] ∧ terminator (last b) ⇒
|
|
|
∀emap2. translate_instrs l gmap emap regs b ≠ ([], emap2)
|
|
|
Proof
|
|
|
Induct_on `b` >> rw [translate_instrs_def] >>
|
|
|
CASE_TAC >> rw [] >> TRY pairarg_tac >> fs []
|
|
|
>- (
|
|
|
Cases_on `bs` >> fs [add_to_first_block_def] >>
|
|
|
Cases_on `b` >> fs []
|
|
|
>- metis_tac [classify_instr_lem, instr_class_distinct]
|
|
|
>- metis_tac [] >>
|
|
|
rename1 `add_to_first_block _ (b::bs)` >>
|
|
|
Cases_on `b` >> fs [add_to_first_block_def]) >>
|
|
|
Cases_on `b` >> fs []
|
|
|
>- metis_tac [classify_instr_lem, instr_class_distinct]
|
|
|
>- metis_tac [classify_instr_lem, instr_class_distinct] >>
|
|
|
Cases_on `bs` >> fs [add_to_first_block_def]
|
|
|
>- metis_tac [] >>
|
|
|
rename1 `add_to_first_block _ (b::bs)` >>
|
|
|
Cases_on `b` >> fs [add_to_first_block_def]
|
|
|
QED
|
|
|
|
|
|
Theorem alookup_translate_blocks:
|
|
|
∀blocks l f gmap emap regs_to_keep edges b i prog.
|
|
|
b.body ≠ [] ∧
|
|
|
terminator (last b.body) ∧
|
|
|
every (λi. ¬terminator i) (front b.body) ∧
|
|
|
every (\b. (snd b).h = Entry ⇔ fst b = None) blocks ∧
|
|
|
alookup blocks l = Some b ∧
|
|
|
i ≤ num_calls b.body ∧
|
|
|
good_emap (Fn f) prog regs_to_keep gmap emap ∧
|
|
|
(∀l b. mem (l, b) blocks ⇒ ∃d. alookup prog (Fn f) = Some d ∧ alookup d.blocks l = Some b)
|
|
|
⇒
|
|
|
alookup (translate_blocks f gmap emap regs_to_keep edges blocks) (translate_label f l i)
|
|
|
=
|
|
|
Some (snd (el i (fst (translate_instrs (Lab_name f (option_map dest_label l) 0)
|
|
|
gmap emap regs_to_keep b.body))))
|
|
|
Proof
|
|
|
ho_match_mp_tac ALOOKUP_ind >> simp [translate_blocks_def] >>
|
|
|
rpt strip_tac >>
|
|
|
pairarg_tac >> fs [ALOOKUP_APPEND] >>
|
|
|
rename1 `(if l' = l then _ else _) = Some _` >>
|
|
|
Cases_on `l = l'` >> fs [translate_block_def] >> rw []
|
|
|
>- (
|
|
|
pairarg_tac >> fs [] >> rw [] >> fs [ALOOKUP_APPEND] >>
|
|
|
`l = None ⇒ b.h = Entry` by metis_tac [] >>
|
|
|
rfs [alookup_translate_header_lab] >>
|
|
|
imp_res_tac alookup_translate_instrs >>
|
|
|
fs [] >> rw [] >> rfs [] >>
|
|
|
`emap |++ header_to_emap_upd b.h = emap`
|
|
|
by (
|
|
|
drule good_emap_header_unchanged >>
|
|
|
Cases_on `b.h` >> fs [header_to_emap_upd_def, FUPDATE_LIST_THM] >>
|
|
|
disch_then irule >> rw [get_instr_cases] >>
|
|
|
metis_tac []) >>
|
|
|
fs [FUPDATE_LIST_THM])
|
|
|
>- (
|
|
|
pairarg_tac >> fs [ALOOKUP_APPEND] >> rw [] >>
|
|
|
fs [ALOOKUP_APPEND] >>
|
|
|
rename1 `header_to_emap_upd b1.h` >>
|
|
|
`emap |++ header_to_emap_upd b1.h = emap`
|
|
|
by (
|
|
|
drule good_emap_header_unchanged >>
|
|
|
Cases_on `b1.h` >> fs [header_to_emap_upd_def, FUPDATE_LIST_THM] >>
|
|
|
disch_then irule >> rw [get_instr_cases] >>
|
|
|
metis_tac []) >>
|
|
|
rename1 `alookup (translate_header _ _ _ _ _ bloc.h)` >>
|
|
|
`l' = None ⇒ bloc.h = Entry` by metis_tac [] >>
|
|
|
fs [alookup_translate_header_lab] >>
|
|
|
Cases_on `alookup bs (translate_label f l i)` >> fs [] >> rw []
|
|
|
>- (
|
|
|
`emap = emap'`
|
|
|
by (
|
|
|
drule good_emap_translate_unchanged >>
|
|
|
disch_then irule >>
|
|
|
first_x_assum (qspecl_then [`l'`, `bloc`] mp_tac) >>
|
|
|
rw [] >>
|
|
|
metis_tac []) >>
|
|
|
first_x_assum drule >>
|
|
|
disch_then (qspecl_then [`f`, `gmap`, `emap`, `regs_to_keep`, `edges`, `prog`] mp_tac) >>
|
|
|
rw [])
|
|
|
>- metis_tac [alookup_translate_instrs_lab])
|
|
|
QED
|
|
|
|
|
|
export_theory ();
|