You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1228 lines
45 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

(*
* 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 ();