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.
infer_clone/sledge/semantics/llvm_to_llair_sem_propScrip...

2176 lines
84 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 do involve the semantics *)
open HolKernel boolLib bossLib Parse lcsymtacs;
open listTheory arithmeticTheory pred_setTheory finite_mapTheory wordsTheory integer_wordTheory;
open optionTheory rich_listTheory pathTheory alistTheory pairTheory sumTheory;
open settingsTheory miscTheory memory_modelTheory;
open llvmTheory llvm_propTheory llvm_ssaTheory llairTheory llair_propTheory llvm_to_llairTheory;
open llvm_to_llair_propTheory;
new_theory "llvm_to_llair_sem_prop";
set_grammar_ancestry ["llvm", "llair", "llair_prop", "llvm_to_llair", "llvm_ssa", "llvm_to_llair_prop"];
numLib.prefer_num ();
Definition translate_trace_def:
(translate_trace gmap Tau = Tau)
(translate_trace gmap Error = Error)
(translate_trace gmap (Exit i) = (Exit i))
(translate_trace gmap (W gv bytes) = W (translate_glob_var gmap gv) bytes)
End
Inductive v_rel:
(∀w. v_rel (FlatV (PtrV w)) (FlatV (IntV (w2i w) llair$pointer_size)))
(∀w. v_rel (FlatV (W1V w)) (FlatV (IntV (w2i w) 1)))
(∀w. v_rel (FlatV (W8V w)) (FlatV (IntV (w2i w) 8)))
(∀w. v_rel (FlatV (W32V w)) (FlatV (IntV (w2i w) 32)))
(∀w. v_rel (FlatV (W64V w)) (FlatV (IntV (w2i w) 64)))
(∀vs1 vs2.
list_rel v_rel vs1 vs2
v_rel (AggV vs1) (AggV vs2))
End
Definition take_to_call_def:
(take_to_call [] = [])
(take_to_call (i::is) =
if terminator i is_call i then [i] else i :: take_to_call is)
End
Inductive pc_rel:
(* LLVM side points to a normal instruction *)
(∀prog emap ip bp d b idx b' prev_i gmap (*rest*).
(* Both are valid pointers to blocks in the same function *)
dest_fn ip.f = label_to_fname bp
alookup prog ip.f = Some d
alookup d.blocks ip.b = Some b
ip.i = Offset idx
idx < length b.body
get_block (translate_prog prog) bp b'
(* The LLVM side is at the start of a block, or immediately following a
* call, which will also start a new block in llair *)
(idx 0 get_instr prog (ip with i := Offset (idx - 1)) (Inl prev_i)
is_call prev_i)
(bp, b')::rest =
fst (translate_instrs (translate_label (dest_fn ip.f) ip.b (num_calls (take idx b.body)))
gmap emap (get_regs_to_keep d) (take_to_call (drop idx b.body)))
pc_rel prog gmap emap ip bp)
(* If the LLVM side points to phi instructions, the llair side
* should point to a block generated from them *)
(∀prog gmap emap ip from_l phis to_l bp.
bp = Mov_name (dest_fn ip.f) (option_map dest_label from_l) to_l
get_instr prog ip (Inr (from_l, phis))
ip.b = Some (Lab to_l)
(* We should have just jumped here from block from_l *)
(∃d b. alookup prog ip.f = Some d
alookup d.blocks from_l = Some b
ip.b set (map Some (instr_to_labs (last b.body)))) (*
get_block (translate_prog prog) bp
(generate_move_block (dest_fn ip.f) gmap emap phis from_l (Lab to_l)) *)
pc_rel prog gmap emap ip bp)
End
(* Define when an LLVM state is related to a llair one.
* Parameterised on a map for locals relating LLVM registers to llair
* expressions that compute the value in that register. This corresponds to part
* of the translation's state.
*)
Definition emap_invariant_def:
emap_invariant prog emap s s' r =
∃v v' e.
v_rel v.value v'
flookup s.locals r = Some v
flookup emap r = Some e eval_exp s' e v'
End
Definition local_state_rel_def:
local_state_rel prog emap s s'
(* Live LLVM registers are mapped and have a related value in the emap
* (after evaluating) *)
(∀r. r live prog s.ip emap_invariant prog emap s s' r)
End
Definition globals_rel_def:
globals_rel gmap gl gl'
BIJ (translate_glob_var gmap) (fdom gl) (fdom gl')
∀k. k fdom gl
nfits (w2n (snd (gl ' k))) llair$pointer_size
w2n (snd (gl ' k)) = gl' ' (translate_glob_var gmap k)
End
Definition mem_state_rel_def:
mem_state_rel prog gmap emap (s:llvm$state) (s':llair$state)
local_state_rel prog emap s s'
reachable prog s.ip
globals_rel gmap s.globals s'.glob_addrs
heap_ok s.heap
erase_tags s.heap = s'.heap
s.status = s'.status
End
(* Define when an LLVM state is related to a llair one
* Parameterised on a map for locals relating LLVM registers to llair
* expressions that compute the value in that register. This corresponds to part
* of the translation's state.
*)
Definition state_rel_def:
state_rel prog gmap emap (s:llvm$state) (s':llair$state)
(s.status = Partial pc_rel prog gmap emap s.ip s'.bp)
mem_state_rel prog gmap emap s s'
End
Theorem mem_state_ignore_bp[simp]:
∀prog gmap emap s s' b.
mem_state_rel prog gmap emap s (s' with bp := b)
mem_state_rel prog gmap emap s s'
Proof
rw [local_state_rel_def, mem_state_rel_def, emap_invariant_def] >> eq_tac >> rw [] >>
first_x_assum drule >> rw [] >>
`eval_exp (s' with bp := b) e v' eval_exp s' e v'`
by (irule eval_exp_ignores >> rw []) >>
metis_tac []
QED
Triviality lemma:
((s:llair$state) with status := Complete code).locals = s.locals
((s:llair$state) with status := Complete code).glob_addrs = s.glob_addrs
Proof
rw []
QED
Theorem mem_state_rel_exited:
∀prog gmap emap s s' code.
mem_state_rel prog gmap emap s s'
mem_state_rel prog gmap emap (s with status := Complete code) (s' with status := Complete code)
Proof
rw [mem_state_rel_def, local_state_rel_def, emap_invariant_def] >>
metis_tac [eval_exp_ignores, lemma]
QED
Theorem mem_state_rel_no_update:
∀prog gmap emap s1 s1' v res_v r i i'.
assigns prog s1.ip = {}
mem_state_rel prog gmap emap s1 s1'
i next_ips prog s1.ip
mem_state_rel prog gmap emap (s1 with ip := i) s1'
Proof
rw [mem_state_rel_def, local_state_rel_def, emap_invariant_def]
>- (
first_x_assum (qspec_then `r` mp_tac) >> simp [Once live_gen_kill, PULL_EXISTS] >>
metis_tac [next_ips_same_func])
>- metis_tac [next_ips_reachable]
QED
Theorem exp_assigns_sing:
∀inst prog ip r t.
get_instr prog ip (Inl inst) classify_instr inst = Exp r t assigns prog ip = {(r,t)}
Proof
rw [get_instr_cases, EXTENSION, IN_DEF, assigns_cases, PULL_EXISTS] >>
Cases_on `el idx b.body` >> fs [classify_instr_def, instr_assigns_def] >>
Cases_on `p` >> fs [classify_instr_def, instr_assigns_def]
QED
Theorem mem_state_rel_update:
∀prog gmap emap s1 s1' regs_to_keep v res_v r e i inst.
good_emap s1.ip.f prog regs_to_keep gmap emap
get_instr prog s1.ip (Inl inst)
classify_instr inst = Exp r t
r regs_to_keep
mem_state_rel prog gmap emap s1 s1'
eval_exp s1' (translate_instr_to_exp gmap emap inst) res_v
v_rel v.value res_v
i next_ips prog s1.ip
mem_state_rel prog gmap emap
(s1 with <|ip := i; locals := s1.locals |+ (r, v) |>)
s1'
Proof
rw [mem_state_rel_def, local_state_rel_def, emap_invariant_def, good_emap_def]
>- (
rw [FLOOKUP_UPDATE]
>- (
HINT_EXISTS_TAC >> rw [] >>
first_x_assum (qspec_then `s1.ip` mp_tac) >> simp [] >> rw [] >>
first_x_assum (qspecl_then [`r`, `t`, `inst`] mp_tac) >> rw []) >>
`i.f = s1.ip.f` by metis_tac [next_ips_same_func] >> simp [] >>
first_x_assum irule >>
simp [Once live_gen_kill, PULL_EXISTS, METIS_PROVE [] ``x y (~y x)``] >>
drule exp_assigns_sing >> rw [] >>
metis_tac [exp_assigns_sing])
>- metis_tac [next_ips_reachable]
QED
Theorem emap_inv_updates_keep_same_ip1:
∀prog emap ip s s' vs res_vs rtys r t.
list_rel v_rel (map (\v. v.value) vs) res_vs
length rtys = length vs
(r,t) set rtys
all_distinct (map fst rtys)
flookup emap r = Some (Var (translate_reg r t) F)
emap_invariant prog emap
(s with locals := s.locals |++ zip (map fst rtys, vs))
(s' with locals := s'.locals |++ zip (map (\(r,ty). translate_reg r ty) rtys, res_vs))
r
Proof
rw [emap_invariant_def, flookup_fupdate_list] >>
CASE_TAC >> rw []
>- (
fs [ALOOKUP_NONE, MAP_REVERSE] >> rfs [MAP_ZIP] >> fs [MEM_MAP] >>
metis_tac [FST]) >>
rename [`alookup (reverse (zip _)) _ = Some v`] >>
fs [Once MEM_SPLIT_APPEND_last] >>
fs [alookup_some, MAP_EQ_APPEND, reverse_eq_append] >> rw [] >>
rfs [zip_eq_append] >> rw [] >> rw [] >>
fs [] >> rw [] >>
qpat_x_assum `reverse _ ++ _ = zip _` (mp_tac o GSYM) >> rw [zip_eq_append] >>
fs [] >> rw [] >>
rename [`[_] = zip (x,y)`] >>
Cases_on `x` >> Cases_on `y` >> fs [] >>
rw [] >> fs [LIST_REL_SPLIT1] >> rw [] >>
HINT_EXISTS_TAC >> rw [] >>
rw [Once eval_exp_cases, flookup_fupdate_list] >>
qmatch_goalsub_abbrev_tac `reverse (zip (a, b))` >>
`length a = length b`
by (
rw [Abbr `a`, Abbr `b`] >>
metis_tac [LIST_REL_LENGTH, LENGTH_MAP, LENGTH_ZIP, LENGTH_REVERSE, ADD_COMM, ADD_ASSOC]) >>
CASE_TAC >> rw [] >> fs [alookup_some, reverse_eq_append]
>- (fs [ALOOKUP_NONE] >> rfs [MAP_REVERSE, MAP_ZIP] >> fs [Abbr `a`]) >>
rfs [zip_eq_append] >>
unabbrev_all_tac >>
rw [] >>
qpat_x_assum `reverse _ ++ _ = zip _` (mp_tac o GSYM) >> rw [zip_eq_append] >>
fs [] >> rw [] >>
rename [`[_] = zip (a,b)`] >>
Cases_on `a` >> Cases_on `b` >> fs [] >>
rw [] >> fs [] >> rw [] >>
fs [ALOOKUP_NONE] >> fs [] >>
rev_full_simp_tac pure_ss [SWAP_REVERSE_SYM] >>
rw [] >> fs [MAP_REVERSE] >> rfs [MAP_ZIP] >>
fs [MIN_DEF] >>
BasicProvers.EVERY_CASE_TAC >> fs [] >>
rfs [] >> rw [] >>
fs [MAP_MAP_o, combinTheory.o_DEF, LAMBDA_PROD] >>
rename [`map fst l1 ++ [_] ++ map fst l2 = l3 ++ [_] ++ l4`,
`map _ l1 ++ [translate_reg _ _] ++ _ = l5 ++ _ ++ l6`,
`l7 ++ [v1:llair$flat_v reg_v] ++ l8 = l9 ++ [v2] ++ l10`] >>
`map fst l1 = l3 map fst l2 = l4`
by (
irule append_split_last >>
qexists_tac `h` >> rw [MEM_MAP] >>
CCONTR_TAC >> fs [] >>
`all_distinct (map fst l1 ++ [fst y] ++ map fst l2)` by metis_tac [] >>
fs [ALL_DISTINCT_APPEND, MEM_MAP] >>
metis_tac [FST, pair_CASES]) >>
`length l2 = length l6` suffices_by metis_tac [append_split_eq, LIST_REL_LENGTH, LENGTH_MAP] >>
rename1 `translate_reg r t` >>
`~mem (translate_reg r t) (map (λ(r,ty). translate_reg r ty) l2)`
by (
rw [MEM_MAP] >> pairarg_tac >> fs [] >>
rename1 `translate_reg r1 t1 = translate_reg r2 t2` >>
Cases_on `r1` >> Cases_on `r2` >> rw [translate_reg_def] >>
metis_tac [MEM_MAP, FST]) >>
metis_tac [append_split_last, LENGTH_MAP]
QED
Theorem emap_inv_updates_keep_same_ip2:
∀prog emap s s' vs res_vs rtys r regs_to_keep gmap.
is_ssa prog
good_emap s.ip.f prog regs_to_keep gmap emap
r live prog s.ip
assigns prog s.ip = set rtys
emap_invariant prog emap s s' r
list_rel v_rel (map (\v. v.value) vs) res_vs
length rtys = length vs
reachable prog s.ip
¬mem r (map fst rtys)
emap_invariant prog emap
(s with locals := s.locals |++ zip (map fst rtys, vs))
(s' with locals := s'.locals |++ zip (map (\(r,ty). translate_reg r ty) rtys, res_vs))
r
Proof
rw [emap_invariant_def, alistTheory.flookup_fupdate_list] >> rw [] >>
CASE_TAC >> rw []
>- (
qexists_tac `v'` >> rw [] >>
qmatch_goalsub_abbrev_tac `eval_exp s_upd _ _` >>
`DRESTRICT s_upd.locals (exp_uses e) = DRESTRICT s'.locals (exp_uses e)
s_upd.glob_addrs = s'.glob_addrs`
suffices_by metis_tac [eval_exp_ignores_unused] >>
rw [Abbr `s_upd`] >>
qmatch_goalsub_abbrev_tac `_ |++ l = _` >>
`l = []` suffices_by rw [FUPDATE_LIST_THM] >>
rw [Abbr `l`, FILTER_EQ_NIL, LAMBDA_PROD] >>
`(λ(p1,p2:llair$flat_v reg_v). p1 exp_uses e) = (\x. fst x exp_uses e)`
by (rw [EXTENSION, IN_DEF] >> pairarg_tac >> rw []) >>
`length rtys = length res_vs` by metis_tac [LIST_REL_LENGTH, LENGTH_MAP] >>
rw [every_zip_fst, EVERY_MAP] >> rw [LAMBDA_PROD] >>
rw [EVERY_EL] >> pairarg_tac >> rw [] >>
qmatch_goalsub_rename_tac `translate_reg r1 ty1 exp_uses _` >>
fs [good_emap_def] >>
first_x_assum (qspec_then `s.ip` mp_tac) >> rw [] >>
first_x_assum drule >> simp [] >>
disch_then (qspec_then `translate_reg r1 ty1` mp_tac) >> rw [] >>
CCONTR_TAC >> fs [] >>
`ip_equiv ip2 s.ip`
by (
fs [is_ssa_def, EXTENSION, IN_DEF] >>
Cases_on `r1` >> fs [translate_reg_def, untranslate_reg_def] >>
rename1 `Reg reg = fst regty` >>
Cases_on `regty` >> fs [] >> rw [] >>
`assigns prog s.ip (Reg reg, ty1)`
suffices_by metis_tac [reachable_dominates_same_func, FST] >>
metis_tac [EL_MEM, IN_DEF]) >>
metis_tac [dominates_irrefl, ip_equiv_dominates2]) >>
drule ALOOKUP_MEM >> rw [MEM_MAP, MEM_ZIP] >>
metis_tac [EL_MEM, LIST_REL_LENGTH, LENGTH_MAP]
QED
Theorem local_state_rel_next_ip:
∀prog emap ip2 s s'.
local_state_rel prog emap s s'
ip2 next_ips prog s.ip
(∀r. r assigns prog s.ip emap_invariant prog emap s s' (fst r))
local_state_rel prog emap (s with ip := ip2) s'
Proof
rw [local_state_rel_def, emap_invariant_def] >>
Cases_on `r live prog s.ip` >> fs [] >>
pop_assum mp_tac >> simp [Once live_gen_kill, PULL_EXISTS] >> rw [] >>
first_x_assum (qspec_then `ip2` mp_tac) >> rw [] >>
first_x_assum drule >> rw [] >>
ntac 3 HINT_EXISTS_TAC >> rw [] >>
first_x_assum irule >> rw [] >>
metis_tac [next_ips_same_func]
QED
Theorem local_state_rel_updates_keep:
∀rtys prog emap s s' vs res_vs i regs_to_keep gmap.
is_ssa prog
good_emap s.ip.f prog regs_to_keep gmap emap
all_distinct (map fst rtys)
set rtys = assigns prog s.ip
(¬∃inst r t. get_instr prog s.ip (Inl inst) classify_instr inst = Exp r t r regs_to_keep)
local_state_rel prog emap s s'
length vs = length rtys
list_rel v_rel (map (\v. v.value) vs) res_vs
i next_ips prog s.ip
reachable prog s.ip
local_state_rel prog emap
(s with <| ip := i; locals := s.locals |++ zip (map fst rtys, vs) |>)
(s' with locals := s'.locals |++ zip (map (\(r,ty). translate_reg r ty) rtys, res_vs))
Proof
rw [] >> irule local_state_rel_next_ip >>
fs [local_state_rel_def] >> rw []
>- (
irule emap_inv_updates_keep_same_ip1 >> rw [] >>
fs [good_emap_def] >>
first_x_assum (qspec_then `s.ip` mp_tac) >> rw [] >>
qexists_tac `snd r` >> rw [] >>
first_x_assum irule >> rw [] >>
fs [assigns_cases, IN_DEF, not_exp_def] >>
metis_tac []) >>
Cases_on `mem r (map fst rtys)`
>- (
irule emap_inv_updates_keep_same_ip1 >> rw [] >>
`∃t. (r,t) set rtys` by (fs [MEM_MAP] >> metis_tac [FST, pair_CASES]) >>
rfs [good_emap_def] >>
first_x_assum (qspec_then `s.ip` mp_tac) >> rw [] >>
`(∃inst. get_instr prog s.ip (Inl inst)) (∃phis. get_instr prog s.ip (Inr phis))`
by (fs [IN_DEF, assigns_cases] >> metis_tac []) >>
metis_tac [FST, PAIR_EQ, SND,not_exp_def])
>- (
irule emap_inv_updates_keep_same_ip2 >> rw [] >>
metis_tac [])
QED
Theorem local_state_rel_update_keep:
∀prog emap s s' v res_v r i ty regs_to_keep gmap.
is_ssa prog
good_emap s.ip.f prog regs_to_keep gmap emap
assigns prog s.ip = {(r,ty)}
(¬∃inst r t. get_instr prog s.ip (Inl inst) classify_instr inst = Exp r t r regs_to_keep)
local_state_rel prog emap s s'
v_rel v.value res_v
reachable prog s.ip
i next_ips prog s.ip
local_state_rel prog emap
(s with <| ip := i; locals := s.locals |+ (r, v) |>)
(s' with locals := s'.locals |+ (translate_reg r ty, res_v))
Proof
rw [] >>
drule local_state_rel_updates_keep >>
disch_then (qspecl_then [`[(r,ty)]`, `emap`, `s`, `s'`] mp_tac) >>
simp [] >> disch_then drule >>
disch_then (qspecl_then [`[v]`, `[res_v]`] mp_tac) >>
simp [] >> disch_then drule >>
rw [FUPDATE_LIST_THM]
QED
Theorem mem_state_rel_update_keep:
∀prog gmap emap s s' v res_v r ty i inst regs_to_keep.
is_ssa prog
good_emap s.ip.f prog regs_to_keep gmap emap
assigns prog s.ip = {(r,ty)}
(¬∃inst r t. get_instr prog s.ip (Inl inst) classify_instr inst = Exp r t r regs_to_keep)
mem_state_rel prog gmap emap s s'
v_rel v.value res_v
reachable prog s.ip
i next_ips prog s.ip
mem_state_rel prog gmap emap
(s with <| ip := i; locals := s.locals |+ (r, v) |>)
(s' with locals := s'.locals |+ (translate_reg r ty, res_v))
Proof
rw [mem_state_rel_def]
>- (
irule local_state_rel_update_keep >> rw [] >>
metis_tac [get_instr_func, INL_11, instr_class_11, instr_class_distinct,
classify_instr_def])
>- metis_tac [next_ips_reachable]
QED
Triviality lemma:
((s:llair$state) with heap := h).locals = s.locals
((s:llair$state) with heap := h).glob_addrs = s.glob_addrs
Proof
rw []
QED
Theorem mem_state_rel_heap_update:
∀prog gmap emap s s' h h'.
mem_state_rel prog gmap emap s s'
heap_ok h
erase_tags h = erase_tags h'
mem_state_rel prog gmap emap (s with heap := h) (s' with heap := h')
Proof
rw [mem_state_rel_def, erase_tags_def, local_state_rel_def] >>
rw [heap_component_equality] >>
fs [fmap_eq_flookup, FLOOKUP_o_f] >> rw [] >>
first_x_assum (qspec_then `x` mp_tac) >>
BasicProvers.EVERY_CASE_TAC >> rw [] >>
fs [emap_invariant_def]
>- metis_tac [eval_exp_ignores, lemma]
>- metis_tac [eval_exp_ignores, lemma] >>
Cases_on `x'` >> Cases_on `x''` >> fs []
QED
Theorem v_rel_bytes:
∀v v'. v_rel v v' llvm_value_to_bytes v = llair_value_to_bytes v'
Proof
ho_match_mp_tac v_rel_ind >>
rw [v_rel_cases, llvm_value_to_bytes_def, llair_value_to_bytes_def] >>
rw [value_to_bytes_def, llvmTheory.unconvert_value_def, w2n_i2n,
llairTheory.unconvert_value_def, llairTheory.pointer_size_def,
llvmTheory.pointer_size_def] >>
pop_assum mp_tac >>
qid_spec_tac `vs1` >>
Induct_on `vs2` >> rw [] >> rw []
QED
Theorem bytes_v_rel_lem:
(∀f s bs t.
f = (λn t w. convert_value t w)
s = type_to_shape t
first_class_type t
(quotient_pair$### v_rel $=)
(bytes_to_value f s bs)
(bytes_to_value (λn t w. convert_value t w) (type_to_shape (translate_ty t)) bs))
(∀f n s bs t.
f = (λn t w. convert_value t w)
s = type_to_shape t
first_class_type t
(quotient_pair$### (list_rel v_rel) $=)
(read_array f n s bs)
(read_array (λn t w. convert_value t w) n (type_to_shape (translate_ty t)) bs))
(∀f ss bs ts.
f = (λn t w. convert_value t w)
ss = map type_to_shape ts
every first_class_type ts
(quotient_pair$### (list_rel v_rel) $=)
(read_str f ss bs)
(read_str (λn t w. convert_value t w) (map (type_to_shape o translate_ty) ts) bs))
Proof
ho_match_mp_tac bytes_to_value_ind >>
rw [llvmTheory.type_to_shape_def, translate_ty_def, type_to_shape_def,
sizeof_def, llvmTheory.sizeof_def, bytes_to_value_def, pointer_size_def,
convert_value_def, llvmTheory.convert_value_def, quotient_pairTheory.PAIR_REL]
>- (
Cases_on `t'` >>
fs [llvmTheory.type_to_shape_def, llvmTheory.sizeof_def, llvmTheory.first_class_type_def] >>
TRY (Cases_on `s`) >>
rw [llvmTheory.sizeof_def, le_read_num_def, translate_size_def,
convert_value_def, llvmTheory.convert_value_def, translate_ty_def,
type_to_shape_def, bytes_to_value_def, sizeof_def, llvmTheory.sizeof_def] >>
simp [v_rel_cases] >> rw [word_0_w2i, w2i_1] >>
fs [pointer_size_def, llvmTheory.pointer_size_def] >>
qmatch_goalsub_abbrev_tac `l2n 256 l` >>
qmatch_goalsub_abbrev_tac `n2i n dim` >>
`n < 2 ** dim`
by (
qspecl_then [`l`, `256`] mp_tac numposrepTheory.l2n_lt >>
rw [] >>
`256 ** length l 2 ** dim` suffices_by decide_tac >>
`256 = 2 ** 8` by rw [] >>
full_simp_tac bool_ss [] >>
REWRITE_TAC [GSYM EXP_EXP_MULT] >>
rw [EXP_BASE_LE_MONO] >>
unabbrev_all_tac >> rw []) >>
metis_tac [w2i_n2w, dimword_def, dimindex_8, dimindex_32, dimindex_64])
>- (
Cases_on `t` >>
fs [llvmTheory.type_to_shape_def, llvmTheory.sizeof_def, llvmTheory.first_class_type_def] >>
rw [PAIR_MAP] >>
pairarg_tac >> fs [type_to_shape_def, translate_ty_def, bytes_to_value_def] >>
first_x_assum (qspec_then `t'` mp_tac) >> simp [] >>
simp [v_rel_cases] >>
pairarg_tac >> fs [] >>
pairarg_tac >> fs [] >> rw [])
>- (
Cases_on `t` >>
fs [llvmTheory.type_to_shape_def, llvmTheory.sizeof_def, llvmTheory.first_class_type_def] >>
rw [PAIR_MAP] >>
fs [type_to_shape_def, translate_ty_def, bytes_to_value_def] >>
pairarg_tac >> fs [PAIR_MAP] >>
first_x_assum (qspec_then `l` mp_tac) >> simp [] >>
simp [v_rel_cases] >>
pairarg_tac >> fs [] >>
pairarg_tac >> fs [MAP_MAP_o] >> rw [] >> fs [ETA_THM])
>- (
rpt (pairarg_tac >> fs []) >>
first_x_assum (qspec_then `t` mp_tac) >> rw [] >>
first_x_assum (qspec_then `t` mp_tac) >> rw [])
>- (
Cases_on `ts` >> fs [bytes_to_value_def] >>
rpt (pairarg_tac >> fs []) >>
first_x_assum (qspec_then `h` mp_tac) >> simp [] >> strip_tac >>
fs [] >> rfs [] >> fs [] >>
first_x_assum (qspec_then `t` mp_tac) >> simp [] >> strip_tac >>
fs [MAP_MAP_o] >> rw [])
QED
Theorem bytes_v_rel:
∀t bs.
first_class_type t
v_rel (fst (bytes_to_llvm_value t bs))
(fst (bytes_to_llair_value (translate_ty t) bs))
Proof
rw [bytes_to_llvm_value_def, bytes_to_llair_value_def] >>
qspecl_then [`bs`, `t`] mp_tac (CONJUNCT1 (SIMP_RULE (srw_ss()) [] bytes_v_rel_lem)) >>
rw [quotient_pairTheory.PAIR_REL] >>
pairarg_tac >> fs [] >>
pairarg_tac >> fs []
QED
Triviality n2i_lem:
∀n. nfits n llair$pointer_size
n2i n llair$pointer_size = IntV (w2i (n2w n : word64)) llair$pointer_size
Proof
rw [pointer_size_def] >>
`2 ** 64 = dimword (:64)` by rw [dimword_64] >>
full_simp_tac bool_ss [nfits_def] >>
drule w2i_n2w >> rw []
QED
Theorem translate_constant_correct_lem:
(∀c s prog gmap emap s' v.
mem_state_rel prog gmap emap s s'
eval_const s.globals c v
∃v'. eval_exp s' (translate_const gmap c) v' v_rel v v')
(∀(cs : (ty # const) list) s prog gmap emap s' vs.
mem_state_rel prog gmap emap s s'
list_rel (eval_const s.globals o snd) cs vs
∃v'. list_rel (eval_exp s') (map (translate_const gmap o snd) cs) v' list_rel v_rel vs v')
(∀(tc : ty # const) s prog gmap emap s' v.
mem_state_rel prog gmap emap s s'
eval_const s.globals (snd tc) v
∃v'. eval_exp s' (translate_const gmap (snd tc)) v' v_rel v v')
Proof
ho_match_mp_tac const_induction >> rw [translate_const_def] >>
pop_assum mp_tac >> simp [Once eval_const_cases]
>- (
rw [Once eval_exp_cases] >>
simp [Once eval_const_cases, translate_size_def, v_rel_cases] >>
metis_tac [truncate_2comp_i2w_w2i, dimindex_1, dimindex_8, dimindex_32, dimindex_64])
>- (
rw [Once eval_exp_cases] >>
simp [v_rel_cases, PULL_EXISTS, MAP_MAP_o] >>
fs [combinTheory.o_DEF, LAMBDA_PROD] >> rw [] >>
first_x_assum drule >> disch_then irule >>
fs [LIST_REL_EL_EQN] >> rw [] >> rfs [] >>
first_x_assum drule >>
simp [EL_MAP] >>
Cases_on `el n cs` >> simp [])
>- (
rw [Once eval_exp_cases] >>
simp [v_rel_cases, PULL_EXISTS, MAP_MAP_o] >>
fs [combinTheory.o_DEF, LAMBDA_PROD] >> rw [] >>
first_x_assum drule >> disch_then irule >>
fs [LIST_REL_EL_EQN] >> rw [] >> rfs [] >>
first_x_assum drule >>
simp [EL_MAP] >>
Cases_on `el n cs` >> simp [])
(* TODO: unimplemented GEP stuff *)
>- cheat
>- (
rw [Once eval_exp_cases] >> simp [v_rel_cases] >>
fs [mem_state_rel_def, globals_rel_def] >>
first_x_assum (qspec_then `g` mp_tac) >> rw [] >>
qexists_tac `w2n w` >> rw [] >> fs [FLOOKUP_DEF]
>- (
rfs [] >>
qpat_x_assum `w2n _ = _` (mp_tac o GSYM) >> rw [] >>
simp [n2i_lem])
>- rfs [BIJ_DEF, INJ_DEF, SURJ_DEF])
>- metis_tac []
QED
Theorem translate_constant_correct:
∀c s prog gmap emap s' g v.
mem_state_rel prog gmap emap s s'
eval_const s.globals c v
∃v'. eval_exp s' (translate_const gmap c) v' v_rel v v'
Proof
metis_tac [translate_constant_correct_lem]
QED
Theorem translate_const_no_reg[simp]:
∀gmap c. r exp_uses (translate_const gmap c)
Proof
ho_match_mp_tac translate_const_ind >>
rw [translate_const_def, exp_uses_def, MEM_MAP, METIS_PROVE [] ``x y (~x y)``]
>- (pairarg_tac >> fs [] >> metis_tac [])
>- (pairarg_tac >> fs [] >> metis_tac [])
(* TODO: unimplemented GEP stuff *)
>- cheat
QED
Theorem translate_arg_correct:
∀s a v prog gmap emap s'.
mem_state_rel prog gmap emap s s'
eval s a v
arg_to_regs a live prog s.ip
∃v'. eval_exp s' (translate_arg gmap emap a) v' v_rel v.value v'
Proof
Cases_on `a` >> rw [eval_cases, translate_arg_def] >> rw []
>- metis_tac [translate_constant_correct] >>
CASE_TAC >> fs [PULL_EXISTS, mem_state_rel_def, local_state_rel_def, emap_invariant_def, arg_to_regs_def] >>
res_tac >> rfs [] >> metis_tac [eval_exp_ignores]
QED
Theorem is_allocated_mem_state_rel:
∀prog gmap emap s1 s1'.
mem_state_rel prog gmap emap s1 s1'
(∀i. is_allocated i s1.heap is_allocated i s1'.heap)
Proof
rw [mem_state_rel_def, is_allocated_def, erase_tags_def] >>
pop_assum mp_tac >> pop_assum (mp_tac o GSYM) >> rw []
QED
Theorem restricted_i2w_11:
∀i (w:'a word). INT_MIN (:'a) i i INT_MAX (:'a) (i2w i : 'a word) = i2w (w2i w) i = w2i w
Proof
rw [i2w_def]
>- (
Cases_on `n2w (Num (-i)) = INT_MINw` >>
rw [w2i_neg, w2i_INT_MINw] >>
fs [word_L_def] >>
`∃j. 0 j i = -j` by intLib.COOPER_TAC >>
rw [] >>
fs [] >>
`INT_MIN (:'a) < dimword (:'a)` by metis_tac [INT_MIN_LT_DIMWORD] >>
`Num j MOD dimword (:'a) = Num j`
by (irule LESS_MOD >> intLib.COOPER_TAC) >>
fs []
>- intLib.COOPER_TAC
>- (
`Num j < INT_MIN (:'a)` by intLib.COOPER_TAC >>
fs [w2i_n2w_pos, integerTheory.INT_OF_NUM]))
>- (
fs [GSYM INT_MAX, INT_MAX_def] >>
`Num i < INT_MIN (:'a)` by intLib.COOPER_TAC >>
rw [w2i_n2w_pos, integerTheory.INT_OF_NUM] >>
intLib.COOPER_TAC)
QED
Theorem translate_sub_correct:
∀prog gmap emap s1 s1' nsw nuw ty v1 v1' v2 v2' e2' e1' result.
do_sub nuw nsw v1 v2 ty = Some result
eval_exp s1' e1' v1'
v_rel v1.value v1'
eval_exp s1' e2' v2'
v_rel v2.value v2'
∃v3'.
eval_exp s1' (Sub (translate_ty ty) e1' e2') v3'
v_rel result.value v3'
Proof
rw [] >>
simp [Once eval_exp_cases] >>
fs [do_sub_def] >> rw [] >>
rfs [v_rel_cases] >> rw [] >> fs [] >>
BasicProvers.EVERY_CASE_TAC >> fs [PULL_EXISTS, translate_ty_def, translate_size_def] >>
pairarg_tac >> fs [] >>
fs [PAIR_MAP, wordsTheory.FST_ADD_WITH_CARRY] >>
rw [] >>
qmatch_goalsub_abbrev_tac `w2i (-1w * w1 + w2)` >>
qexists_tac `w2i w2` >> qexists_tac `w2i w1` >> simp [] >>
unabbrev_all_tac >> rw []
>- (
irule restricted_i2w_11 >> simp [word_sub_i2w] >>
`dimindex (:1) = 1` by rw [] >>
drule truncate_2comp_i2w_w2i >>
rw [word_sub_i2w] >>
metis_tac [w2i_ge, w2i_le, SIMP_CONV (srw_ss()) [] ``INT_MIN (:1)``,
SIMP_CONV (srw_ss()) [] ``INT_MAX (:1)``])
>- (
irule restricted_i2w_11 >> simp [word_sub_i2w] >>
`dimindex (:8) = 8` by rw [] >>
drule truncate_2comp_i2w_w2i >>
rw [word_sub_i2w] >>
metis_tac [w2i_ge, w2i_le, SIMP_CONV (srw_ss()) [] ``INT_MIN (:8)``,
SIMP_CONV (srw_ss()) [] ``INT_MAX (:8)``])
>- (
irule restricted_i2w_11 >> simp [word_sub_i2w] >>
`dimindex (:32) = 32` by rw [] >>
drule truncate_2comp_i2w_w2i >>
rw [word_sub_i2w] >>
metis_tac [w2i_ge, w2i_le, SIMP_CONV (srw_ss()) [] ``INT_MIN (:32)``,
SIMP_CONV (srw_ss()) [] ``INT_MAX (:32)``])
>- (
irule restricted_i2w_11 >> simp [word_sub_i2w] >>
`dimindex (:64) = 64` by rw [] >>
drule truncate_2comp_i2w_w2i >>
rw [word_sub_i2w] >>
metis_tac [w2i_ge, w2i_le, SIMP_CONV (srw_ss()) [] ``INT_MIN (:64)``,
SIMP_CONV (srw_ss()) [] ``INT_MAX (:64)``])
QED
Theorem translate_extract_correct:
∀prog gmap emap s1 s1' a v v1' e1' cs vs ns result.
mem_state_rel prog gmap emap s1 s1'
list_rel (eval_const s1.globals) cs vs
map signed_v_to_num vs = map Some ns
extract_value v ns = Some result
eval_exp s1' e1' v1'
v_rel v v1'
∃v2'.
eval_exp s1' (foldl (λe c. Select e (translate_const gmap c)) e1' cs) v2'
v_rel result v2'
Proof
Induct_on `cs` >> rw [] >> rfs [] >> fs [extract_value_def]
>- metis_tac [] >>
first_x_assum irule >>
Cases_on `ns` >> fs [] >>
qmatch_goalsub_rename_tac `translate_const gmap c` >>
qmatch_assum_rename_tac `eval_const _ _ v3` >>
`∃v2'. eval_exp s1' (translate_const gmap c) v2' v_rel v3 v2'`
by metis_tac [translate_constant_correct] >>
Cases_on `v` >> fs [extract_value_def] >>
qpat_x_assum `v_rel (AggV _) _` mp_tac >>
simp [Once v_rel_cases] >> rw [] >>
simp [Once eval_exp_cases, PULL_EXISTS] >>
fs [LIST_REL_EL_EQN] >>
qmatch_assum_rename_tac `_ = map Some is` >>
Cases_on `v3` >> fs [signed_v_to_num_def, signed_v_to_int_def] >> rw [] >>
`∃i. v2' = FlatV i` by fs [v_rel_cases] >> fs [] >>
qmatch_assum_rename_tac `option_join _ = Some x` >>
`∃size. i = IntV (&x) size` suffices_by metis_tac [] >> rw [] >>
qpat_x_assum `v_rel _ _` mp_tac >>
simp [v_rel_cases] >> rw [] >> fs [signed_v_to_int_def] >> rw [] >>
intLib.COOPER_TAC
QED
Theorem translate_update_correct:
∀prog gmap emap s1 s1' a v1 v1' v2 v2' e2 e2' e1' cs vs ns result.
mem_state_rel prog gmap emap s1 s1'
list_rel (eval_const s1.globals) cs vs
map signed_v_to_num vs = map Some ns
insert_value v1 v2 ns = Some result
eval_exp s1' e1' v1'
v_rel v1 v1'
eval_exp s1' e2' v2'
v_rel v2 v2'
∃v3'.
eval_exp s1' (translate_updatevalue gmap e1' e2' cs) v3'
v_rel result v3'
Proof
Induct_on `cs` >> rw [] >> rfs [] >> fs [insert_value_def, translate_updatevalue_def]
>- metis_tac [] >>
simp [Once eval_exp_cases, PULL_EXISTS] >>
Cases_on `ns` >> fs [] >>
Cases_on `v1` >> fs [insert_value_def] >>
rename [`insert_value (el x _) _ ns`] >>
Cases_on `insert_value (el x l) v2 ns` >> fs [] >> rw [] >>
qpat_x_assum `v_rel (AggV _) _` mp_tac >> simp [Once v_rel_cases] >> rw [] >>
simp [v_rel_cases] >>
qmatch_goalsub_rename_tac `translate_const gmap c` >>
qexists_tac `vs2` >> simp [] >>
qmatch_assum_rename_tac `eval_const _ _ v3` >>
`∃v4'. eval_exp s1' (translate_const gmap c) v4' v_rel v3 v4'`
by metis_tac [translate_constant_correct] >>
`∃idx_size. v4' = FlatV (IntV (&x) idx_size)`
by (
pop_assum mp_tac >> simp [Once v_rel_cases] >>
rw [] >> fs [signed_v_to_num_def, signed_v_to_int_def] >>
intLib.COOPER_TAC) >>
first_x_assum drule >>
disch_then drule >>
disch_then drule >>
disch_then drule >>
disch_then (qspecl_then [`el x vs2`, `v2'`, `e2'`, `Select e1' (translate_const gmap c)`] mp_tac) >>
simp [Once eval_exp_cases] >>
metis_tac [EVERY2_LUPDATE_same, LIST_REL_LENGTH, LIST_REL_EL_EQN]
QED
val sizes = [``:1``, ``:8``, ``:32``, ``:64``];
val trunc_thms =
LIST_CONJ (map (fn x => SIMP_RULE (srw_ss()) [] (INST_TYPE [``:'a`` |-> x] truncate_2comp_i2w_w2i))
sizes);
val signed2unsigned_thms =
LIST_CONJ (map (fn x => SIMP_RULE (srw_ss()) [] (INST_TYPE [``:'a`` |-> x] (GSYM w2n_signed2unsigned)))
sizes);
Definition good_cast_def:
(good_cast Trunc (FlatV (IntV i size)) from_bits to_t
from_bits = size llair$sizeof_bits to_t < from_bits)
(good_cast Zext (FlatV (IntV i size)) from_bits to_t
from_bits = size from_bits < sizeof_bits to_t)
(good_cast Sext (FlatV (IntV i size)) from_bits to_t
from_bits = size from_bits < sizeof_bits to_t)
(good_cast Ptrtoint _ _ _ T)
(good_cast Inttoptr _ _ _ T)
End
Theorem translate_cast_correct:
∀prog gmap emap s1' cop from_bits to_ty v1 v1' e1' result.
do_cast cop v1.value to_ty = Some result
eval_exp s1' e1' v1'
v_rel v1.value v1'
good_cast cop v1' from_bits (translate_ty to_ty)
∃v3'.
eval_exp s1' ((if (cop = Zext) then Unsigned else Signed)
(if cop = Trunc then sizeof_bits (translate_ty to_ty) else from_bits)
e1' (translate_ty to_ty)) v3'
v_rel result v3'
Proof
rw [] >> simp [Once eval_exp_cases, PULL_EXISTS, Once v_rel_cases]
>- ( (* Zext *)
fs [do_cast_def, OPTION_JOIN_EQ_SOME, unsigned_v_to_num_some, w64_cast_some,
translate_ty_def, sizeof_bits_def, translate_size_def] >>
rw [] >>
rfs [v_rel_cases] >> rw [] >>
qmatch_assum_abbrev_tac `eval_exp _ _ (FlatV (IntV i s))` >>
qexists_tac `i` >> qexists_tac `s` >> rw [] >>
unabbrev_all_tac >>
fs [good_cast_def, translate_ty_def, sizeof_bits_def, translate_size_def] >>
rw [trunc_thms, signed2unsigned_thms] >>
rw [GSYM w2w_def, w2w_w2w, WORD_ALL_BITS] >>
rw [w2i_w2w_expand])
>- ( (* Trunc *)
fs [do_cast_def] >> rw [] >>
fs [OPTION_JOIN_EQ_SOME, w64_cast_some, unsigned_v_to_num_some,
signed_v_to_int_some, mk_ptr_some] >>
rw [sizeof_bits_def, translate_ty_def, translate_size_def] >>
rfs [] >> fs [v_rel_cases] >>
rw [] >>
qmatch_assum_abbrev_tac `eval_exp _ _ (FlatV (IntV i s))` >>
qexists_tac `s` >> qexists_tac `i` >> rw [] >>
unabbrev_all_tac >>
fs [good_cast_def, translate_ty_def, sizeof_bits_def, translate_size_def] >>
rw [w2w_n2w, GSYM w2w_def, trunc_thms, pointer_size_def] >>
rw [i2w_w2i_extend, WORD_w2w_OVER_MUL] >>
rw [w2w_w2w, WORD_ALL_BITS, word_bits_w2w] >>
rw [word_mul_def]) >>
Cases_on `cop` >> fs [] >> rw []
>- ( (* Sext *)
fs [do_cast_def] >> rw [] >>
fs [OPTION_JOIN_EQ_SOME, w64_cast_some, unsigned_v_to_num_some,
signed_v_to_int_some, mk_ptr_some] >>
rw [sizeof_bits_def, translate_ty_def, translate_size_def] >>
rfs [] >> fs [v_rel_cases] >>
rw [] >>
qmatch_assum_abbrev_tac `eval_exp _ _ (FlatV (IntV i s))` >>
qexists_tac `s` >> qexists_tac `i` >> rw [] >>
unabbrev_all_tac >>
fs [good_cast_def, translate_ty_def, sizeof_bits_def, translate_size_def] >>
rw [trunc_thms, w2w_i2w] >>
irule (GSYM w2i_i2w)
>- (
`w2i w INT_MAX (:1) INT_MIN (:1) w2i w` by metis_tac [w2i_le, w2i_ge] >>
fs [] >> intLib.COOPER_TAC)
>- (
`w2i w INT_MAX (:1) INT_MIN (:1) w2i w` by metis_tac [w2i_le, w2i_ge] >>
fs [] >> intLib.COOPER_TAC)
>- (
`w2i w INT_MAX (:1) INT_MIN (:1) w2i w` by metis_tac [w2i_le, w2i_ge] >>
fs [] >> intLib.COOPER_TAC)
>- (
`w2i w INT_MAX (:8) INT_MIN (:8) w2i w` by metis_tac [w2i_le, w2i_ge] >>
fs [] >> intLib.COOPER_TAC)
>- (
`w2i w INT_MAX (:8) INT_MIN (:8) w2i w` by metis_tac [w2i_le, w2i_ge] >>
fs [] >> intLib.COOPER_TAC)
>- (
`w2i w INT_MAX (:32) INT_MIN (:32) w2i w` by metis_tac [w2i_le, w2i_ge] >>
fs [] >> intLib.COOPER_TAC))
(* TODO: pointer to int and int to pointer casts *)
>> cheat
QED
Theorem const_idx_uses[simp]:
∀cs gmap e.
exp_uses (foldl (λe c. Select e (translate_const gmap c)) e cs) = exp_uses e
Proof
Induct_on `cs` >> rw [exp_uses_def] >> rw [EXTENSION]
QED
Theorem exp_uses_trans_upd_val[simp]:
∀cs gmap e1 e2. exp_uses (translate_updatevalue gmap e1 e2 cs) =
(if cs = [] then {} else exp_uses e1) exp_uses e2
Proof
Induct_on `cs` >> rw [exp_uses_def, translate_updatevalue_def] >>
rw [EXTENSION] >>
metis_tac []
QED
(* TODO: identify some lemmas to cut down on the duplicated proof in the very
* similar cases *)
Theorem translate_instr_to_exp_correct:
∀gmap emap instr r t s1 s1' s2 prog l regs_to_keep.
prog_ok prog is_ssa prog
good_emap s1.ip.f prog regs_to_keep gmap emap
classify_instr instr = Exp r t
mem_state_rel prog gmap emap s1 s1'
get_instr prog s1.ip (Inl instr)
step_instr prog s1 instr l s2
is_implemented instr
∃pv s2'.
l = Tau
s2.ip = inc_pc s1.ip
mem_state_rel prog gmap emap s2 s2'
(r regs_to_keep s1' = s2')
(r regs_to_keep
step_inst s1' (Move [(translate_reg r t, translate_instr_to_exp gmap emap instr)]) Tau s2')
Proof
recInduct translate_instr_to_exp_ind >>
simp [translate_instr_to_exp_def, classify_instr_def] >>
conj_tac
>- ( (* Sub *)
rw [step_instr_cases, get_instr_cases, update_result_def] >>
qpat_x_assum `Sub _ _ _ _ _ _ = el _ _` (assume_tac o GSYM) >>
`bigunion (image arg_to_regs {a1; a2}) live prog s1.ip`
by (
simp [Once live_gen_kill, SUBSET_DEF, uses_cases, IN_DEF, get_instr_cases,
instr_uses_def] >>
metis_tac []) >>
fs [] >>
first_x_assum (mp_then.mp_then mp_then.Any mp_tac translate_arg_correct) >>
disch_then drule >> disch_then drule >>
first_x_assum (mp_then.mp_then mp_then.Any mp_tac translate_arg_correct) >>
disch_then drule >> disch_then drule >> rw [] >>
drule translate_sub_correct >>
simp [] >>
disch_then (qspecl_then [`s1'`, `v'`, `v''`] mp_tac) >> simp [] >>
disch_then drule >> disch_then drule >> rw [] >>
rename1 `eval_exp _ (Sub _ _ _) res_v` >>
rename1 `r _` >>
simp [inc_pc_def, llvmTheory.inc_pc_def] >>
`assigns prog s1.ip = {(r,ty)}`
by rw [assigns_cases, EXTENSION, IN_DEF, get_instr_cases, instr_assigns_def] >>
`reachable prog s1.ip` by fs [mem_state_rel_def] >>
`s1.ip with i := inc_bip (Offset idx) next_ips prog s1.ip`
by (
drule prog_ok_nonterm >>
simp [get_instr_cases, PULL_EXISTS] >>
ntac 3 (disch_then drule) >>
simp [terminator_def, next_ips_cases, IN_DEF, inc_pc_def]) >>
Cases_on `r regs_to_keep` >> rw []
>- (
irule mem_state_rel_update >> rw []
>- (
fs [get_instr_cases, classify_instr_def, translate_instr_to_exp_def] >>
metis_tac [])
>- metis_tac [])
>- (
simp [step_inst_cases, PULL_EXISTS] >>
qexists_tac `res_v` >> rw [] >>
rw [update_results_def, GSYM FUPDATE_EQ_FUPDATE_LIST] >>
irule mem_state_rel_update_keep >> rw [] >>
qexists_tac `regs_to_keep` >> rw [] >>
CCONTR_TAC >> fs [] >>
drule exp_assigns_sing >> disch_then drule >> rw [] >>
metis_tac [])) >>
conj_tac
>- ( (* Extractvalue *)
rw [step_instr_cases, get_instr_cases, update_result_def] >>
qpat_x_assum `Extractvalue _ _ _ = el _ _` (assume_tac o GSYM) >>
`arg_to_regs a live prog s1.ip`
by (
simp [Once live_gen_kill, SUBSET_DEF, uses_cases, IN_DEF, get_instr_cases,
instr_uses_def]) >>
drule translate_extract_correct >> rpt (disch_then drule) >>
drule translate_arg_correct >> disch_then drule >>
simp [] >> strip_tac >>
disch_then drule >> simp [] >> rw [] >>
rename1 `eval_exp _ (foldl _ _ _) res_v` >>
rw [inc_pc_def, llvmTheory.inc_pc_def] >>
rename1 `r _` >>
`assigns prog s1.ip = {(r,THE (extract_type t (map cidx_to_num cs)))}`
by rw [assigns_cases, EXTENSION, IN_DEF, get_instr_cases, instr_assigns_def] >>
`reachable prog s1.ip` by fs [mem_state_rel_def] >>
`s1.ip with i := inc_bip (Offset idx) next_ips prog s1.ip`
by (
drule prog_ok_nonterm >>
simp [get_instr_cases, PULL_EXISTS] >>
ntac 3 (disch_then drule) >>
simp [terminator_def, next_ips_cases, IN_DEF, inc_pc_def]) >>
Cases_on `r regs_to_keep` >> rw []
>- (
simp [step_inst_cases, PULL_EXISTS] >>
qexists_tac `res_v` >> rw [] >>
rw [update_results_def, GSYM FUPDATE_EQ_FUPDATE_LIST] >>
irule mem_state_rel_update_keep >> rw [] >>
qexists_tac `regs_to_keep` >> rw [] >>
CCONTR_TAC >> fs [] >>
drule exp_assigns_sing >> disch_then drule >> rw [] >>
metis_tac [])
>- (
irule mem_state_rel_update >> rw []
>- (
fs [get_instr_cases, classify_instr_def, translate_instr_to_exp_def] >>
metis_tac [])
>- metis_tac [])) >>
conj_tac
>- ( (* Updatevalue *)
rw [step_instr_cases, get_instr_cases, update_result_def] >>
qpat_x_assum `Insertvalue _ _ _ _ = el _ _` (assume_tac o GSYM) >>
`arg_to_regs a1 live prog s1.ip
arg_to_regs a2 live prog s1.ip`
by (
ONCE_REWRITE_TAC [live_gen_kill] >>
simp [SUBSET_DEF, uses_cases, IN_DEF, get_instr_cases,
instr_uses_def]) >>
drule translate_update_correct >> rpt (disch_then drule) >>
first_x_assum (mp_then.mp_then mp_then.Any mp_tac translate_arg_correct) >>
disch_then drule >> disch_then drule >>
first_x_assum (mp_then.mp_then mp_then.Any mp_tac translate_arg_correct) >>
disch_then drule >> disch_then drule >>
simp [] >> strip_tac >> strip_tac >>
disch_then (qspecl_then [`v'`, `v''`] mp_tac) >> simp [] >>
disch_then drule >> disch_then drule >>
rw [] >>
rename1 `eval_exp _ (translate_updatevalue _ _ _ _) res_v` >>
rw [inc_pc_def, llvmTheory.inc_pc_def] >>
rename1 `r _` >>
`assigns prog s1.ip = {(r,t1)}`
by rw [assigns_cases, EXTENSION, IN_DEF, get_instr_cases, instr_assigns_def] >>
`reachable prog s1.ip` by fs [mem_state_rel_def] >>
`s1.ip with i := inc_bip (Offset idx) next_ips prog s1.ip`
by (
drule prog_ok_nonterm >>
simp [get_instr_cases, PULL_EXISTS] >>
ntac 3 (disch_then drule) >>
simp [terminator_def, next_ips_cases, IN_DEF, inc_pc_def]) >>
Cases_on `r regs_to_keep` >> rw []
>- (
simp [step_inst_cases, PULL_EXISTS] >>
qexists_tac `res_v` >> rw [] >>
rw [update_results_def, GSYM FUPDATE_EQ_FUPDATE_LIST] >>
irule mem_state_rel_update_keep >> rw [] >>
qexists_tac `regs_to_keep` >> rw [] >>
CCONTR_TAC >> fs [] >>
drule exp_assigns_sing >> disch_then drule >> rw [] >>
metis_tac [])
>- (
irule mem_state_rel_update >> rw []
>- (
fs [get_instr_cases, classify_instr_def, translate_instr_to_exp_def] >>
metis_tac [])
>- metis_tac [])) >>
conj_tac
>- ( (* Cast *)
simp [step_instr_cases, get_instr_cases, update_result_def] >>
rpt strip_tac >>
qpat_x_assum `Cast _ _ _ _ = el _ _` (assume_tac o GSYM) >>
`arg_to_regs a1 live prog s1.ip`
by (
simp [Once live_gen_kill, SUBSET_DEF, uses_cases, IN_DEF, get_instr_cases,
instr_uses_def] >>
metis_tac []) >>
fs [] >>
first_x_assum (mp_then.mp_then mp_then.Any mp_tac translate_arg_correct) >>
disch_then drule >> disch_then drule >> strip_tac >>
drule translate_cast_correct >> ntac 2 (disch_then drule) >>
simp [] >>
disch_then (qspec_then `sizeof_bits (translate_ty t1)` mp_tac) >>
impl_tac
(* TODO: prog_ok should enforce that the type is consistent *)
>- cheat >>
strip_tac >>
rename1 `eval_exp _ _ res_v` >>
simp [inc_pc_def, llvmTheory.inc_pc_def] >>
rename1 `r _` >>
`assigns prog s1.ip = {(r,t)}`
by rw [assigns_cases, EXTENSION, IN_DEF, get_instr_cases, instr_assigns_def] >>
`reachable prog s1.ip` by fs [mem_state_rel_def] >>
`s1.ip with i := inc_bip (Offset idx) next_ips prog s1.ip`
by (
drule prog_ok_nonterm >>
simp [get_instr_cases, PULL_EXISTS] >>
ntac 3 (disch_then drule) >>
simp [terminator_def, next_ips_cases, IN_DEF, inc_pc_def]) >>
Cases_on `r regs_to_keep` >> simp []
>- (
simp [step_inst_cases, PULL_EXISTS] >>
qexists_tac `res_v` >> rw [] >>
fs [] >>
rw [update_results_def, GSYM FUPDATE_EQ_FUPDATE_LIST] >>
irule mem_state_rel_update_keep >> rw [] >>
qexists_tac `regs_to_keep` >> rw [] >>
CCONTR_TAC >> fs [] >>
drule exp_assigns_sing >> disch_then drule >> rw [] >>
metis_tac [])
>- (
irule mem_state_rel_update >> rw []
>- (
fs [get_instr_cases, classify_instr_def, translate_instr_to_exp_def] >>
metis_tac [])
>- metis_tac [])) >>
rw [is_implemented_def]
QED
Triviality eval_exp_help:
(s1 with heap := h).locals = s1.locals
Proof
rw []
QED
Theorem translate_instr_to_inst_correct:
∀gmap emap instr r t s1 s1' s2 prog l regs_to_keep.
classify_instr instr = Non_exp
prog_ok prog is_ssa prog
good_emap s1.ip.f prog regs_to_keep gmap emap
mem_state_rel prog gmap emap s1 s1'
get_instr prog s1.ip (Inl instr)
step_instr prog s1 instr l s2
∃pv s2'.
s2.ip = inc_pc s1.ip
mem_state_rel prog gmap emap s2 s2'
step_inst s1' (translate_instr_to_inst gmap emap instr) (translate_trace gmap l) s2'
Proof
rw [step_instr_cases] >>
fs [classify_instr_def, translate_instr_to_inst_def]
>- ( (* Load *)
fs [step_inst_cases, get_instr_cases, PULL_EXISTS] >>
qpat_x_assum `Load _ _ _ = el _ _` (assume_tac o GSYM) >>
`arg_to_regs a1 live prog s1.ip`
by (
simp [Once live_gen_kill, SUBSET_DEF, uses_cases, IN_DEF, get_instr_cases,
instr_uses_def] >>
metis_tac []) >>
fs [] >>
first_x_assum (mp_then.mp_then mp_then.Any mp_tac translate_arg_correct) >>
disch_then drule >> disch_then drule >> rw [] >>
qpat_x_assum `v_rel (FlatV _) _` mp_tac >> simp [Once v_rel_cases] >> rw [] >>
`∃n. r = Reg n` by (Cases_on `r` >> metis_tac []) >>
qexists_tac `n` >> qexists_tac `translate_ty t` >>
HINT_EXISTS_TAC >> rw [] >>
qexists_tac `freeable` >> rw [translate_trace_def]
>- rw [inc_pc_def, llvmTheory.inc_pc_def, update_result_def]
>- (
simp [GSYM translate_reg_def, llvmTheory.inc_pc_def, update_result_def,
update_results_def, GSYM FUPDATE_EQ_FUPDATE_LIST,
extend_emap_non_exp_def] >>
irule mem_state_rel_update_keep >>
rw []
>- rw [assigns_cases, IN_DEF, EXTENSION, get_instr_cases, instr_assigns_def]
>- (
`s1.ip with i := inc_bip (Offset idx) = inc_pc s1.ip` by rw [inc_pc_def] >>
simp [] >> irule prog_ok_nonterm >>
simp [get_instr_cases, terminator_def])
>- metis_tac [next_ips_reachable, mem_state_rel_def]
>- (
fs [w2n_i2n, pointer_size_def, mem_state_rel_def] >>
metis_tac [bytes_v_rel, get_bytes_erase_tags])
>- (
qexists_tac `regs_to_keep` >> rw [] >>
CCONTR_TAC >> fs [get_instr_cases] >>
fs [] >> rw [] >> fs [] >> rw [] >>
rfs [classify_instr_def]))
>- rw [translate_reg_def]
>- (
fs [w2n_i2n, pointer_size_def, mem_state_rel_def] >>
metis_tac [is_allocated_erase_tags]))
>- ( (* Store *)
fs [step_inst_cases, get_instr_cases, PULL_EXISTS] >>
qpat_x_assum `Store _ _ = el _ _` (assume_tac o GSYM) >>
`bigunion (image arg_to_regs {a1; a2}) live prog s1.ip`
by (
simp [Once live_gen_kill, SUBSET_DEF, uses_cases, IN_DEF, get_instr_cases,
instr_uses_def] >>
metis_tac []) >>
fs [] >>
first_x_assum (mp_then.mp_then mp_then.Any mp_tac translate_arg_correct) >>
disch_then drule >> disch_then drule >>
first_x_assum (mp_then.mp_then mp_then.Any mp_tac translate_arg_correct) >>
disch_then drule >> disch_then drule >> rw [] >>
qpat_x_assum `v_rel (FlatV _) _` mp_tac >> simp [Once v_rel_cases] >> rw [] >>
drule v_rel_bytes >> rw [] >>
fs [w2n_i2n, pointer_size_def] >>
HINT_EXISTS_TAC >> rw [] >>
qexists_tac `freeable` >> rw [] >>
qexists_tac `v'` >> rw []
>- rw [llvmTheory.inc_pc_def, inc_pc_def]
>- (
simp [llvmTheory.inc_pc_def] >>
irule mem_state_rel_no_update >> rw []
>- rw [assigns_cases, EXTENSION, IN_DEF, get_instr_cases, instr_assigns_def]
>- (
`s1.ip with i := inc_bip (Offset idx) = inc_pc s1.ip` by rw [inc_pc_def] >>
simp [] >> irule prog_ok_nonterm >>
simp [get_instr_cases, terminator_def]) >>
irule mem_state_rel_heap_update >>
rw [set_bytes_unchanged, erase_tags_set_bytes] >>
fs [mem_state_rel_def, extend_emap_non_exp_def] >>
metis_tac [set_bytes_heap_ok])
>- (
fs [mem_state_rel_def] >>
fs [is_allocated_def, heap_component_equality, erase_tags_def] >>
metis_tac [])
>- (
fs [get_obs_cases, llvmTheory.get_obs_cases] >> rw [translate_trace_def] >>
fs [mem_state_rel_def, globals_rel_def]
>- (
fs [FLOOKUP_DEF] >>
first_x_assum drule >> rw []
>- metis_tac [BIJ_DEF, SURJ_DEF] >>
pop_assum (mp_tac o GSYM) >> rw [w2n_i2n])
>- (
CCONTR_TAC >> fs [FRANGE_DEF] >>
fs [BIJ_DEF, SURJ_DEF, INJ_DEF] >>
first_x_assum drule >> rw [] >>
CCONTR_TAC >> fs [] >> rw [] >>
first_x_assum drule >> rw [] >>
CCONTR_TAC >> fs [] >> rw [] >>
`i2n (IntV (w2i w) (dimindex (:64))) = w2n w` by metis_tac [w2n_i2n, dimindex_64] >>
fs [] >> rw [] >>
fs [METIS_PROVE [] ``~x y (x y)``] >>
first_x_assum drule >> rw [] >>
metis_tac [pair_CASES, SND])))
QED
Theorem classify_instr_term_call:
∀i. (classify_instr i = Term terminator i)
(classify_instr i = Call is_call i terminator i)
Proof
Cases >> rw [classify_instr_def, is_call_def, terminator_def] >>
Cases_on `p` >> rw [classify_instr_def]
QED
Definition untranslate_glob_var_def:
untranslate_glob_var (Var_name n ty) = Glob_var n
End
Definition untranslate_trace_def:
(untranslate_trace Tau = Tau)
(untranslate_trace Error = Error)
(untranslate_trace (Exit i) = (Exit i))
(untranslate_trace (W gv bytes) = W (untranslate_glob_var gv) bytes)
End
Theorem un_translate_glob_inv:
∀x t. untranslate_glob_var (translate_glob_var gmap x) = x
Proof
Cases_on `x` >> rw [translate_glob_var_def] >>
CASE_TAC >> rw [untranslate_glob_var_def]
QED
Theorem un_translate_trace_inv:
∀x. untranslate_trace (translate_trace gmap x) = x
Proof
Cases >> rw [translate_trace_def, untranslate_trace_def] >>
metis_tac [un_translate_glob_inv]
QED
Theorem take_to_call_lem:
∀i idx body.
idx < length body el idx body = i ¬terminator i ¬is_call i
take_to_call (drop idx body) = i :: take_to_call (drop (idx + 1) body)
Proof
Induct_on `idx` >> rw []
>- (Cases_on `body` >> fs [take_to_call_def] >> rw []) >>
Cases_on `body` >> fs [] >>
simp [ADD1]
QED
Theorem inc_translate_label:
∀f l x. inc_label (translate_label f l x) = translate_label f l (x + 1)
Proof
rw [] >> Cases_on `l` >> rw [translate_label_def, inc_label_def] >>
Cases_on `x'` >> rw [translate_label_def, inc_label_def]
QED
Theorem translate_instrs_correct1:
∀prog s1 tr s2.
multi_step prog s1 tr s2
∀s1' regs_to_keep b' gmap emap d b idx rest l.
prog_ok prog is_ssa prog
mem_state_rel prog gmap emap s1 s1'
good_emap s1.ip.f prog regs_to_keep gmap emap
alookup prog s1.ip.f = Some d
alookup d.blocks s1.ip.b = Some b
s1.ip.i = Offset idx
(l,b')::rest =
fst (translate_instrs (translate_label (dest_fn s1.ip.f) s1.ip.b (num_calls (take idx b.body)))
gmap emap regs_to_keep (take_to_call (drop idx b.body)))
every is_implemented b.body
∃s2' tr'.
step_block (translate_prog prog) s1' b'.cmnd b'.term tr' s2'
filter ($ Tau) tr' = filter ($ Tau) (map (translate_trace gmap) tr)
state_rel prog gmap emap s2 s2'
Proof
ho_match_mp_tac multi_step_ind >> rw_tac std_ss []
>- (
fs [last_step_cases]
>- ( (* Phi (not handled here) *)
fs [get_instr_cases])
>- ( (* Terminator *)
rename1 `Inl instr` >>
`is_implemented instr`
by (fs [get_instr_cases] >> metis_tac [EVERY_MEM, EL_MEM]) >>
`(∃code. l = Exit code) l = Tau `
by (
fs [llvmTheory.step_cases] >>
`i' = instr` by metis_tac [get_instr_func, INL_11] >>
fs [step_instr_cases] >> rfs [terminator_def]) >>
fs [get_instr_cases, translate_trace_def] >> rw [] >>
`el idx b.body = el 0 (drop idx b.body)` by rw [EL_DROP] >>
fs [] >>
Cases_on `drop idx b.body` >> fs [DROP_NIL] >> rw []
>- ( (* Exit *)
fs [llvmTheory.step_cases, get_instr_cases, step_instr_cases,
translate_instrs_def, take_to_call_def, classify_instr_def,
translate_instr_to_term_def, translate_instr_to_inst_def,
llvmTheory.get_obs_cases] >>
simp [Once step_block_cases, step_term_cases, PULL_EXISTS, step_inst_cases] >>
drule translate_arg_correct >>
disch_then drule >> impl_tac
>- (
`get_instr prog s1.ip (Inl (Exit a))` by rw [get_instr_cases] >>
drule get_instr_live >>
simp [uses_cases, SUBSET_DEF, IN_DEF, PULL_EXISTS] >>
rw [] >> first_x_assum irule >>
disj1_tac >>
metis_tac [instr_uses_def]) >>
rw [] >>
qexists_tac `s1' with status := Complete code` >>
qexists_tac `[Exit code]` >>
rw []
>- (
rfs [translate_instrs_def, classify_instr_def] >>
rw [translate_instr_to_term_def] >>
fs [v_rel_cases] >> fs [signed_v_to_int_def] >> metis_tac []) >>
rw [state_rel_def] >>
metis_tac [mem_state_rel_exited]) >>
fs [take_to_call_def] >>
rfs [] >>
fs [translate_instrs_def] >>
Cases_on `el idx b.body` >> fs [terminator_def, classify_instr_def, translate_trace_def] >> rw []
>- fs [is_implemented_def]
>- ( (* Br *)
simp [translate_instr_to_term_def, Once step_block_cases] >>
simp [step_term_cases, PULL_EXISTS, RIGHT_AND_OVER_OR, EXISTS_OR_THM] >>
pairarg_tac >> rw [] >>
fs [llvmTheory.step_cases] >>
drule get_instr_live >> disch_tac >>
drule translate_arg_correct >>
fs [step_instr_cases] >> fs [] >>
TRY (fs [get_instr_cases] >> NO_TAC) >>
`a = a'` by fs [get_instr_cases] >>
disch_then drule >>
impl_tac
>- (
fs [SUBSET_DEF, IN_DEF] >> rfs [uses_cases, get_instr_cases, instr_uses_def] >>
fs [IN_DEF]) >>
disch_tac >> fs [] >>
fs [v_rel_cases, GSYM PULL_EXISTS] >>
GEN_EXISTS_TAC "idx'" `w2i tf` >> simp [GSYM PULL_EXISTS] >> conj_tac
>- metis_tac [] >>
rename1 `el _ _ = Br e lab1 lab2` >>
qpat_abbrev_tac `target = if tf = 0w then l2 else l1` >>
`last b.body = Br e l1 l2
<|f := s1.ip.f; b := Some target; i := Phi_ip s1.ip.b|> next_ips prog s1.ip`
by (
fs [prog_ok_def, get_instr_cases] >>
last_x_assum drule >> disch_then drule >>
strip_tac >> conj_asm1_tac
>- (
CCONTR_TAC >>
`Br a l1 l2 set (front (b.body))`
by (
`mem (Br a l1 l2) (front b.body ++ [last b.body])`
by metis_tac [EL_MEM, APPEND_FRONT_LAST] >>
fs [] >> metis_tac []) >>
fs [EVERY_MEM] >> first_x_assum drule >> rw [terminator_def])
>- (
rw [next_ips_cases, IN_DEF, assigns_cases] >>
disj1_tac >>
qexists_tac `Br a l1 l2` >>
rw [instr_next_ips_def, Abbr `target`] >>
fs [get_instr_cases, instr_to_labs_def] >>
metis_tac [blockHeader_nchotomy])) >>
qmatch_goalsub_abbrev_tac `state_rel _ _ _ _ (_ with bp := target')` >>
rw [state_rel_def]
>- (
fs [get_instr_cases] >>
`every (λlab. ∃b phis landing. alookup d.blocks (Some lab) = Some b b.h = Head phis landing)
(instr_to_labs (last b.body))`
by (fs [prog_ok_def, EVERY_MEM] >> metis_tac []) >>
rfs [instr_to_labs_def] >>
rw [Once pc_rel_cases, get_instr_cases, get_block_cases, PULL_EXISTS] >>
fs [GSYM PULL_EXISTS, Abbr `target`] >>
rw [MEM_MAP, instr_to_labs_def] >>
`s1.ip.b = option_map Lab l' dest_fn s1.ip.f = f`
by (
Cases_on `s1.ip.b` >>
fs [translate_label_def] >>
Cases_on `x` >>
fs [translate_label_def]) >>
rw [OPTION_MAP_COMPOSE, combinTheory.o_DEF, dest_label_def, Abbr
`target'`, word_0_w2i, METIS_PROVE [w2i_eq_0] ``∀w. 0 = w2i w w = 0w``] >>
TRY (Cases_on `l'` >> rw [] >> NO_TAC))
>- (
fs [mem_state_rel_def, local_state_rel_def, emap_invariant_def] >> rw []
>- (
qpat_x_assum `∀r. r live _ _ P r` mp_tac >>
simp [Once live_gen_kill] >> disch_then (qspec_then `r` mp_tac) >>
impl_tac >> rw [] >>
rw [PULL_EXISTS] >>
disj1_tac >>
qexists_tac `<|f := s1.ip.f; b := Some target; i := Phi_ip s1.ip.b|>` >>
rw [] >>
rw [IN_DEF, assigns_cases] >>
CCONTR_TAC >> fs [] >>
imp_res_tac get_instr_func >> fs [] >> rw [] >>
fs [instr_assigns_def])
>- (
fs [reachable_def] >>
qexists_tac `path ++ [<|f := s1.ip.f; b := Some target; i := Phi_ip s1.ip.b|>]` >>
rw_tac std_ss [good_path_append, GSYM APPEND] >> rw []
>- (rw [Once good_path_cases] >> fs [next_ips_cases, IN_DEF] >> metis_tac [])
>- metis_tac [ip_equiv_next_ips, ip_equiv_sym]
>- metis_tac [ip_equiv_refl])))
>- fs [is_implemented_def]
>- fs [is_implemented_def]
>- ( (* Exit *)
fs [llvmTheory.step_cases, get_instr_cases, step_instr_cases])
>- fs [is_implemented_def])
>- ( (* Call *)
rename1 `Inl instr` >>
`is_implemented instr`
by (fs [get_instr_cases] >> metis_tac [EVERY_MEM, EL_MEM]) >>
Cases_on `instr` >>
fs [is_call_def, is_implemented_def])
>- ( (* Stuck *)
rw [translate_trace_def] >>
(* TODO: need to know that stuck LLVM instructions translate to stuck
* llair instructions. This will follow from knowing that when a llair
* instruction takes a step, the LLVM source can take the same step, ie,
* the backward direction of the proof. *)
cheat))
>- ( (* Middle of the block *)
fs [llvmTheory.step_cases] >> TRY (fs [get_instr_cases] >> NO_TAC) >>
`i' = i` by metis_tac [get_instr_func, INL_11] >> fs [] >>
rename [`step_instr _ _ _ _ s2`, `state_rel _ _ _ s3 _`,
`mem_state_rel _ _ _ s1 s1'`] >>
Cases_on `∃r t. classify_instr i = Exp r t` >> fs [] >>
`is_implemented i`
by (fs [get_instr_cases] >> metis_tac [EVERY_MEM, EL_MEM])
>- ( (* instructions that compile to expressions *)
drule translate_instr_to_exp_correct >>
ntac 6 (disch_then drule) >>
rw [] >> fs [translate_trace_def] >>
`reachable prog (inc_pc s1.ip)`
by metis_tac [prog_ok_nonterm, next_ips_reachable, mem_state_rel_def] >>
first_x_assum drule >>
simp [inc_pc_def, inc_bip_def] >>
disch_then drule >>
`take_to_call (drop idx b.body) = i :: take_to_call (drop (idx + 1) b.body)`
by (
irule take_to_call_lem >> simp [] >>
fs [get_instr_cases]) >>
`num_calls (take (idx + 1) b.body) = num_calls (take idx b.body)`
by (fs [get_instr_cases] >> rw [num_calls_def, TAKE_EL_SNOC, FILTER_SNOC]) >>
fs [translate_instrs_def, inc_translate_label] >>
Cases_on `r regs_to_keep` >> fs [] >> rw []
>- (
`emap = emap |+ (r,translate_instr_to_exp gmap emap i)`
by (
fs [good_emap_def, fmap_eq_flookup, FLOOKUP_UPDATE] >>
rw [] >> metis_tac []) >>
metis_tac []) >>
pairarg_tac >> fs [] >> rw [] >>
`emap |+ (r,Var (translate_reg r t) F) = emap`
by (
fs [good_emap_def, fmap_eq_flookup, FLOOKUP_UPDATE] >>
rw [] >>
`(r,t) assigns prog s1.ip`
by (
drule exp_assigns_sing >>
disch_then drule >>
rw []) >>
metis_tac [FST, SND, not_exp_def]) >>
fs [] >>
rename1 `translate_instrs _ _ _ _ _ = (bs, emap1)` >>
Cases_on `bs` >> fs [add_to_first_block_def] >>
rename1 `translate_instrs _ _ _ _ _ = (b1::bs, _)` >>
Cases_on `b1` >> fs [add_to_first_block_def] >> rw [] >>
rename1 `state_rel prog gmap emap3 s3 s3'` >>
qexists_tac `s3'` >> rw [] >>
qexists_tac `Tau::tr'` >> rw [] >>
simp [Once step_block_cases] >>
metis_tac [])
>- ( (* Non-expression instructions *)
Cases_on `classify_instr i` >> fs [classify_instr_term_call]
>- (
drule translate_instr_to_inst_correct >>
ntac 6 (disch_then drule) >>
strip_tac >> fs [] >>
first_x_assum drule >> simp [inc_pc_def, inc_bip_def] >>
disch_then (qspecl_then [`regs_to_keep`] mp_tac) >> simp [] >>
strip_tac >>
`take_to_call (drop idx b.body) = i :: take_to_call (drop (idx + 1) b.body)`
by (
irule take_to_call_lem >> simp [] >>
fs [get_instr_cases]) >>
`num_calls (take (idx + 1) b.body) = num_calls (take idx b.body)`
by (fs [get_instr_cases] >> rw [num_calls_def, TAKE_EL_SNOC, FILTER_SNOC]) >>
fs [translate_instrs_def, inc_translate_label] >>
pairarg_tac >> fs [] >>
`extend_emap_non_exp emap i = emap`
by (
Cases_on `∀r t. instr_assigns i {(r,t)}`
>- metis_tac [extend_emap_non_exp_no_assigns] >>
fs [] >>
drule extend_emap_non_exp_assigns >>
rw [] >> fs [good_emap_def] >>
first_x_assum (qspec_then `s1.ip` mp_tac) >> rw [] >>
last_x_assum (qspec_then `i` mp_tac) >>
simp [not_exp_def] >>
disch_then (qspec_then `(r,t)` mp_tac) >>
impl_tac
>- (
fs [IN_DEF, assigns_cases, EXTENSION] >>
metis_tac []) >>
rw [fmap_eq_flookup, FLOOKUP_UPDATE] >> rw [] >> rw []) >>
fs [] >>
rename1 `translate_instrs _ _ _ _ _ = (bs, emap1)` >>
Cases_on `bs` >> fs [add_to_first_block_def] >>
rename1 `translate_instrs _ _ _ _ _ = (b1::bs, _)` >>
Cases_on `b1` >> fs [add_to_first_block_def] >> fs [] >>
rw [] >>
rename1 `state_rel prog gmap emap3 s3 s3'` >>
qexists_tac `s3'` >> simp [] >>
qexists_tac `translate_trace gmap l::tr'` >> rw [] >>
simp [Once step_block_cases]
>- (disj2_tac >> qexists_tac `s2'` >> rw [])
>- (disj2_tac >> qexists_tac `s2'` >> rw [])
>- metis_tac [])
>- metis_tac [classify_instr_term_call]))
QED
Theorem do_phi_vals:
∀prog gmap emap from_l s s' phis updates.
mem_state_rel prog gmap emap s s'
list_rel (do_phi from_l s) phis updates
BIGUNION (set (map (phi_uses from_l) phis)) live prog s.ip
∃es vs.
list_rel v_rel (map (λx. (snd x).value) updates) vs
list_rel (eval_exp s') es vs
map fst updates = map fst (map phi_assigns phis)
map (λx. case x of Phi r t largs =>
case option_map (λarg. translate_arg gmap emap arg) (alookup largs from_l) of
None => (translate_reg r t,Nondet)
| Some e => (translate_reg r t,e))
phis
= map2 (\p. λe. case p of Phi r t largs => (translate_reg r t, e)) phis es
Proof
Induct_on `phis` >> rw [] >> fs [] >>
first_x_assum drule >> disch_then drule >> rw [PULL_EXISTS] >>
Cases_on `h` >> fs [do_phi_cases] >>
drule translate_arg_correct >>
disch_then drule >>
impl_tac
>- (fs [phi_uses_def] >> rfs []) >>
rw [PULL_EXISTS, phi_assigns_def] >> metis_tac []
QED
Triviality case_phi_lift:
∀f g. f (case x of Phi x y z => g x y z) = case x of Phi x y z => f (g x y z)
Proof
Cases_on `x` >> rw []
QED
Triviality id2:
(λ(v,r). (v,r)) = I
Proof
rw [FUN_EQ_THM] >> Cases_on `x` >> rw []
QED
Theorem build_phi_block_correct_helper[local]:
∀phis es.
map (λx. case x of
Phi r t largs =>
case option_map (λarg. translate_arg gmap emap arg) (alookup largs from_l) of
None => (translate_reg r t,Nondet)
| Some e => (translate_reg r t,e)) phis =
map2 (λp e. case p of Phi r t largs => (translate_reg r t,e)) phis es
length phis = length es
es = map (λx. case x of Phi r t largs =>
case option_map (λarg. translate_arg gmap emap arg) (alookup largs from_l) of
None => Nondet
| Some e => e)
phis
Proof
Induct >> rw [] >> Cases_on `es` >> fs [] >>
CASE_TAC >> fs [] >> CASE_TAC >> fs []
QED
Theorem build_phi_block_correct:
∀prog s1 s1' to_l from_l phis updates f gmap emap entry bloc regs_to_keep.
prog_ok prog is_ssa prog
good_emap s1.ip.f prog regs_to_keep gmap emap
get_instr prog s1.ip (Inr (from_l,phis))
list_rel (do_phi from_l s1) phis updates
mem_state_rel prog gmap emap s1 s1'
BIGUNION (set (map (phi_uses from_l) phis)) live prog s1.ip
bloc = generate_move_block f gmap emap phis from_l to_l
∃s2'.
s2'.bp = translate_label f (Some to_l) 0
step_block (translate_prog prog) s1' bloc.cmnd bloc.term [Tau; Tau] s2'
mem_state_rel prog gmap emap
(inc_pc (s1 with locals := s1.locals |++ updates)) s2'
Proof
rw [translate_header_def, generate_move_block_def] >>
rw [Once step_block_cases] >>
rw [Once step_block_cases] >>
rw [step_term_cases, PULL_EXISTS] >>
simp [Once eval_exp_cases, truncate_2comp_def] >>
drule do_phi_vals >> ntac 2 (disch_then drule) >>
rw [] >> drule build_phi_block_correct_helper >>
pop_assum kall_tac >>
`length phis = length es` by metis_tac [LENGTH_MAP, LIST_REL_LENGTH] >>
disch_then drule >>
rw [] >> fs [LIST_REL_MAP1, combinTheory.o_DEF, case_phi_lift] >>
simp [step_inst_cases, PULL_EXISTS] >>
qexists_tac `0` >> qexists_tac `vs` >> rw []
>- (
simp [LIST_REL_MAP1, combinTheory.o_DEF] >> fs [LIST_REL_EL_EQN] >>
rw [] >>
first_x_assum (qspec_then `n` mp_tac) >> simp [] >>
CASE_TAC >> simp [] >> CASE_TAC >> simp [build_move_for_lab_def] >>
CASE_TAC >> simp [] >> fs []) >>
fs [header_to_emap_upd_def] >>
simp [llvmTheory.inc_pc_def, update_results_def] >>
`s1.ip with i := inc_bip s1.ip.i next_ips prog s1.ip`
by (
simp [next_ips_cases, IN_DEF, inc_pc_def] >> disj2_tac >>
qexists_tac `from_l` >> qexists_tac `phis` >>
fs [get_instr_cases, EXISTS_OR_THM, inc_bip_def, prog_ok_def] >>
res_tac >> Cases_on `b.body` >> fs []) >>
fs [mem_state_rel_def] >> rw []
>- (
first_assum (mp_then.mp_then mp_then.Any mp_tac local_state_rel_updates_keep) >>
rpt (disch_then (fn x => first_assum (mp_then.mp_then mp_then.Any mp_tac x))) >>
disch_then
(qspecl_then [`map (λ(x:phi). case x of Phi r t _ => (r,t)) phis`,
`map snd updates`, `vs`] mp_tac) >>
simp [] >> impl_tac >> rw [id2]
>- (
fs [prog_ok_def] >>
first_x_assum drule >>
simp [MAP_MAP_o, combinTheory.o_DEF] >>
`(λp. case p of Phi r v1 v2 => r) = (λx. fst (case x of Phi r t v2 => (r,t)))`
by (rw [FUN_EQ_THM] >> CASE_TAC >> rw []) >>
rw [])
>- (
rw [EXTENSION, IN_DEF, assigns_cases] >> eq_tac >> rw [] >> fs [LIST_TO_SET_MAP]
>- (
disj2_tac >> qexists_tac `from_l` >> qexists_tac `phis` >> rw [] >>
HINT_EXISTS_TAC >> CASE_TAC >> rw [phi_assigns_def])
>- metis_tac [get_instr_func, sum_distinct]
>- (
rw [] >> rename1 `mem x1 phis1` >>
qexists_tac `x1` >> Cases_on `x1` >> rw [phi_assigns_def] >>
metis_tac [get_instr_func, INR_11, PAIR_EQ]))
>- (
rw [assigns_cases, EXTENSION, IN_DEF] >>
metis_tac [get_instr_func, sum_distinct, INR_11, PAIR_EQ])
>- metis_tac [LENGTH_MAP]
>- rw [LIST_REL_MAP1, combinTheory.o_DEF] >>
`map fst (map (λx. case x of Phi r t v2 => (r,t)) phis) =
map fst (map phi_assigns phis)`
by (rw [LIST_EQ_REWRITE, EL_MAP] >> CASE_TAC >> rw [phi_assigns_def]) >>
fs [MAP_MAP_o, combinTheory.o_DEF, case_phi_lift] >>
`zip (map (λx. fst (phi_assigns x)) phis, map snd updates) = updates`
by (
qpat_x_assum `map fst _ = map (λx. fst (phi_assigns x)) _` mp_tac >>
simp [LIST_EQ_REWRITE, EL_MAP] >>
`length phis = length updates` by metis_tac [LIST_REL_LENGTH] >>
rw [EL_ZIP, LENGTH_MAP, EL_MAP] >>
rename1 `_ = el n updates` >>
first_x_assum drule >>
Cases_on `el n updates` >> rw []) >>
`(λx. case x of Phi r t v2 => translate_reg r t) = (λx. fst (build_move_for_lab gmap emap from_l x))`
by (
rw [FUN_EQ_THM] >>
CASE_TAC >> rw [build_move_for_lab_def] >> CASE_TAC >> rw []) >>
fs [])
>- (irule next_ips_reachable >> qexists_tac `s1.ip` >> rw [])
QED
Theorem translate_instrs_take_to_call:
∀l gmap emap regs body.
body [] terminator (last body)
fst (translate_instrs l gmap emap regs (take_to_call body)) =
[HD (fst (translate_instrs l gmap emap regs body))]
Proof
Induct_on `body` >> rw [translate_instrs_def, take_to_call_def] >>
rename1 `classify_instr inst` >> Cases_on `classify_instr inst` >> fs [] >>
fs [] >> rw [] >> fs []
>- metis_tac [classify_instr_lem, instr_class_distinct]
>- metis_tac [classify_instr_lem, instr_class_distinct]
>- metis_tac [classify_instr_lem, instr_class_distinct]
>- (
Cases_on `body` >> fs []
>- rw [translate_instrs_def] >>
pairarg_tac >> rw [])
>- metis_tac [classify_instr_lem, instr_class_distinct]
>- metis_tac [classify_instr_lem, instr_class_distinct]
>- metis_tac [classify_instr_lem, instr_class_distinct]
>- (
Cases_on `body` >> fs []
>- rw [translate_instrs_def] >>
pairarg_tac >> rw [])
>- (
`body []` by (Cases_on `body` >> fs []) >>
fs [LAST_DEF] >>
pairarg_tac >> fs [] >> pairarg_tac >> fs [] >>
`bs = [HD bs']` by metis_tac [FST] >>
Cases_on `bs'` >> fs []
>- metis_tac [translate_instrs_not_empty] >>
Cases_on `h` >> fs [add_to_first_block_def])
>- (
`body []` by (Cases_on `body` >> fs []) >>
fs [LAST_DEF] >>
pairarg_tac >> fs [])
>- (
`body []` by (Cases_on `body` >> fs []) >>
fs [LAST_DEF] >>
pairarg_tac >> fs [] >> pairarg_tac >> fs [] >>
`bs = [HD bs']` by metis_tac [FST] >>
Cases_on `bs'` >> fs []
>- metis_tac [translate_instrs_not_empty] >>
Cases_on `h` >> fs [add_to_first_block_def])
>- metis_tac [classify_instr_lem, instr_class_distinct]
QED
Theorem multi_step_to_step_block:
∀prog emap s1 tr s2 s1'.
prog_ok prog is_ssa prog
dominator_ordered prog
good_emap s1.ip.f prog (get_regs_to_keep (THE (alookup prog s1.ip.f))) (get_gmap prog) emap
multi_step prog s1 tr s2
s1.status = Partial
state_rel prog (get_gmap prog) emap s1 s1'
every (\(l, d). every (\(l, b). every is_implemented b.body) d.blocks) prog
∃s2' b tr'.
get_block (translate_prog prog) s1'.bp b
step_block (translate_prog prog) s1' b.cmnd b.term tr' s2'
filter ($ Tau) tr' = filter ($ Tau) (map (translate_trace (get_gmap prog)) tr)
state_rel prog (get_gmap prog) emap s2 s2'
Proof
rw [] >> ntac 2 (pop_assum mp_tac) >> simp [Once state_rel_def] >> rw [Once pc_rel_cases]
>- (
(* Non-phi instruction *)
drule translate_instrs_correct1 >> simp [] >>
disch_then drule >>
disch_then drule >>
rfs [] >> disch_then drule >>
impl_tac
>- (
fs [EVERY_MEM] >> rw [] >>
`mem (s1.ip.f, d) prog` by fs [alookup_some] >>
first_x_assum drule >> rw [] >>
`mem (s1.ip.b, b) d.blocks` by fs [alookup_some] >>
first_x_assum drule >> rw []) >>
rw [] >>
rename1 `step_block _ s1' b1.cmnd b1.term tr1 s2'` >>
qexists_tac `s2'` >> qexists_tac `b1` >> qexists_tac `tr1` >> simp []) >>
(* Phi instruction *)
reverse (fs [Once multi_step_cases])
>- metis_tac [get_instr_func, sum_distinct] >>
qpat_x_assum `last_step _ _ _ _` mp_tac >>
simp [last_step_cases] >> strip_tac
>- (
fs [llvmTheory.step_cases]
>- metis_tac [get_instr_func, sum_distinct] >>
fs [translate_trace_def] >> rw [] >>
`(from_l', phis') = (from_l, phis) x = (from_l, phis)` by metis_tac [get_instr_func, INR_11] >>
fs [] >> rw [] >>
rfs [MEM_MAP] >>
Cases_on `s1.ip.f` >> fs [dest_fn_def] >>
drule get_block_translate_prog_mov >> rpt (disch_then drule) >> rw [PULL_EXISTS] >>
`∃block l. alookup d.blocks (Some (Lab to_l)) = Some block block.h = Head phis l`
by (
fs [prog_ok_def, EVERY_MEM] >>
last_x_assum drule >> disch_then drule >> rw [] >>
first_x_assum drule >> rw [] >>
rw [] >>
fs [get_instr_cases] >>
rfs [] >> rw [] >> fs []) >>
`every (λ(l,b). every is_implemented b.body) d.blocks`
by (
`mem (Fn s, d) prog` by fs [alookup_some] >>
fs [EVERY_MEM] >> rw [] >> pairarg_tac >> fs [] >> rw [] >>
first_x_assum drule >> simp [] >>
disch_then drule >> simp []) >>
first_x_assum drule >> rw [] >>
qmatch_assum_abbrev_tac `get_block _ _ bloc` >>
GEN_EXISTS_TAC "b" `bloc` >>
rw [] >>
qpat_x_assum `_ = Fn _` (assume_tac o GSYM) >> fs [] >>
drule build_phi_block_correct >> rpt (disch_then drule) >>
simp [Abbr `bloc`] >>
disch_then (qspecl_then [`Lab to_l`, `s`] mp_tac) >>
simp [] >>
impl_tac
>- (
drule get_instr_live >> rw [SUBSET_DEF, uses_cases, IN_DEF] >>
first_x_assum irule >> disj2_tac >> metis_tac []) >>
rw [] >>
qexists_tac `s2'` >>
rw [CONJ_ASSOC, LEFT_EXISTS_AND_THM, RIGHT_EXISTS_AND_THM]
>- (qexists_tac `[Tau; Tau]` >> rw []) >>
fs [state_rel_def] >> rw [] >>
fs [llvmTheory.inc_pc_def] >>
fs [pc_rel_cases, get_instr_cases, PULL_EXISTS, translate_label_def,
dest_fn_def, inc_bip_def, label_to_fname_def] >>
fs [] >> rw [] >> fs [get_block_cases, PULL_EXISTS, label_to_fname_def] >>
rfs [] >> rw [] >>
qpat_x_assum `Fn _ = _` (assume_tac o GSYM) >> fs [] >>
drule alookup_translate_prog >> rw [] >>
rw [GSYM PULL_EXISTS, dest_fn_def]
>- (fs [prog_ok_def] >> res_tac >> fs [] >> Cases_on `b'.body` >> fs []) >>
rw [PULL_EXISTS, translate_def_def] >>
`b'.body [] terminator (last b'.body)
every (λi. ¬terminator i) (front b'.body)
every (λb. (snd b).h = Entry fst b = None) d.blocks
0 num_calls b'.body`
by (
fs [prog_ok_def] >> res_tac >> fs [] >>
fs [EVERY_MEM]) >>
qmatch_goalsub_abbrev_tac `translate_blocks f gmap _ regs edg _` >>
`translate_blocks f gmap fempty regs edg d.blocks = translate_blocks f gmap emap regs edg d.blocks`
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]) >>
rw [] >>
drule alookup_translate_blocks >> rpt (disch_then drule) >>
impl_tac
>- (
fs [prog_ok_def, EVERY_MEM] >> rw [] >>
irule ALOOKUP_ALL_DISTINCT_MEM >> rw [] >>
imp_res_tac ALOOKUP_MEM >>
res_tac >> fs []) >>
simp [translate_label_def] >>
rw [] >> rw [dest_label_def, num_calls_def] >>
rw [translate_instrs_take_to_call] >>
qmatch_goalsub_abbrev_tac `_ = HD (fst (translate_instrs a1 b1 c1 d1 e1))` >>
Cases_on `translate_instrs a1 b1 c1 d1 e1` >> rw [] >>
rename1 `_ = HD bl` >> Cases_on `bl` >> rw []
>- metis_tac [translate_instrs_not_empty, classify_instr_lem] >>
rename1 `(_,_) = bl` >> Cases_on `bl` >> rw [] >>
metis_tac [translate_instrs_first_lab])
>- metis_tac [get_instr_func, sum_distinct]
>- metis_tac [get_instr_func, sum_distinct]
>- (
(* TODO: LLVM "eval" gets stuck *)
cheat)
QED
Theorem step_block_to_multi_step:
∀prog s1 s1' tr s2' b.
state_rel prog gmap emap s1 s1'
get_block (translate_prog prog) s1'.bp b
step_block (translate_prog prog) s1' b.cmnd b.term tr s2'
∃s2.
multi_step prog s1 (map untranslate_trace tr) s2
state_rel prog gmap emap s2 s2'
Proof
(* TODO, LLVM can simulate llair direction *)
cheat
QED
Theorem trans_trace_not_tau:
∀types. ($ Tau) translate_trace types = ($ Tau)
Proof
rw [FUN_EQ_THM] >> eq_tac >> rw [translate_trace_def] >>
TRY (Cases_on `y`) >> fs [translate_trace_def]
QED
Theorem untrans_trace_not_tau:
∀types. ($ Tau) untranslate_trace = ($ Tau)
Proof
rw [FUN_EQ_THM] >> eq_tac >> rw [untranslate_trace_def] >>
TRY (Cases_on `y`) >> fs [untranslate_trace_def]
QED
Theorem translate_prog_correct_lem1:
∀path.
okpath (multi_step prog) path finite path
∀emap s1'.
prog_ok prog
is_ssa prog
dominator_ordered prog
good_emap (first path).ip.f prog (get_regs_to_keep (THE (alookup prog (first path).ip.f))) (get_gmap prog) emap
state_rel prog (get_gmap prog) emap (first path) s1'
every (\(l, d). every (\(l, b). every is_implemented b.body) d.blocks) prog
∃path'.
finite path'
okpath (step (translate_prog prog)) path'
first path' = s1'
LMAP (filter ($ Tau)) (labels path') =
LMAP (map (translate_trace (get_gmap prog)) o filter ($ Tau)) (labels path)
state_rel prog (get_gmap prog) emap (last path) (last path')
Proof
ho_match_mp_tac finite_okpath_ind >> rw []
>- (qexists_tac `stopped_at s1'` >> rw [] >> metis_tac []) >>
fs [] >>
rename1 `state_rel _ _ _ s1 s1'` >>
Cases_on `s1.status Partial`
>- fs [Once multi_step_cases, llvmTheory.step_cases, last_step_cases] >>
fs [] >>
drule multi_step_to_step_block >> simp [] >>
rpt (disch_then drule) >> rw [] >>
(* TODO: this won't be true once calls are added *)
`s1.ip.f = (first path).ip.f` by cheat >>
fs [] >>
first_x_assum drule >> disch_then drule >> rw [] >>
qexists_tac `pcons s1' tr' path'` >> rw [] >>
rw [FILTER_MAP, combinTheory.o_DEF, trans_trace_not_tau] >>
simp [step_cases] >> qexists_tac `b` >> simp [] >>
qpat_x_assum `state_rel _ _ _ _ s1'` mp_tac >>
rw [state_rel_def, mem_state_rel_def]
QED
Theorem translate_prog_correct_lem2:
∀path'.
okpath (step (translate_prog prog)) path' finite path'
∀s1.
prog_ok prog
state_rel prog gmap emap s1 (first path')
∃path.
finite path
okpath (multi_step prog) path
first path = s1
labels path = LMAP (map untranslate_trace) (labels path')
state_rel prog gmap emap (last path) (last path')
Proof
ho_match_mp_tac finite_okpath_ind >> rw []
>- (qexists_tac `stopped_at s1` >> rw []) >>
fs [step_cases] >>
drule step_block_to_multi_step >> ntac 2 (disch_then drule) >> rw [] >>
first_x_assum drule >> rw [] >>
qexists_tac `pcons s1 (map untranslate_trace r) path` >> rw []
QED
Theorem translate_global_var_11:
∀path.
okpath (step (translate_prog prog)) path finite path
∀x t1 bytes t2 l.
labels path = fromList l
MEM (W (Var_name x t1) bytes) (flat l)
MEM (W (Var_name x t2) bytes) (flat l)
t1 = t2
Proof
(* TODO, LLVM can simulate llair direction *)
cheat
QED
Theorem prefix_take_filter_lemma:
∀l lsub.
lsub l
filter (λy. Tau y) lsub =
take (length (filter (λy. Tau y) lsub)) (filter (λy. Tau y) l)
Proof
Induct_on `lsub` >> rw [] >>
Cases_on `l` >> fs [] >> rw []
QED
Theorem multi_step_lab_label:
∀prog s1 ls s2.
multi_step prog s1 ls s2 s2.status Partial
∃ls'. (∃i. ls = ls' ++ [Exit i]) ls = ls' ++ [Error]
Proof
ho_match_mp_tac multi_step_ind >> rw [] >> fs [] >>
fs [last_step_cases, llvmTheory.step_cases, step_instr_cases,
update_result_def, llvmTheory.inc_pc_def] >>
rw [] >> fs []
QED
Theorem prefix_filter_len_eq:
∀l1 l2 x.
l1 l2 ++ [x]
length (filter P l1) = length (filter P (l2 ++ [x]))
P x
l1 = l2 ++ [x]
Proof
Induct_on `l1` >> rw [FILTER_APPEND] >>
Cases_on `l2` >> fs [] >> rw [] >> rfs [ADD1] >>
first_x_assum irule >> rw [FILTER_APPEND]
QED
Theorem translate_prog_correct:
∀prog s1 s1' emap.
prog_ok prog is_ssa prog dominator_ordered prog
good_emap s1.ip.f prog (get_regs_to_keep (THE (alookup prog s1.ip.f))) (get_gmap prog) emap
state_rel prog (get_gmap prog) emap s1 s1'
every (\(l, d). every (\(l, b). every is_implemented b.body) d.blocks) prog
multi_step_sem prog s1 = image (I ## map untranslate_trace) (sem (translate_prog prog) s1')
Proof
rw [sem_def, multi_step_sem_def, EXTENSION] >> eq_tac >> rw []
>- (
drule translate_prog_correct_lem1 >> simp [] >>
rpt (disch_then drule) >> rw [EXISTS_PROD] >>
PairCases_on `x` >> rw [] >>
qexists_tac `map (translate_trace (get_gmap prog)) x1` >> rw []
>- rw [MAP_MAP_o, combinTheory.o_DEF, un_translate_trace_inv] >>
qexists_tac `path'` >> rw [] >>
fs [IN_DEF, observation_prefixes_cases, toList_some] >> rw [] >>
`∃labs. labels path' = fromList labs`
by (
fs [GSYM finite_labels] >>
imp_res_tac llistTheory.LFINITE_toList >>
fs [toList_some]) >>
fs [] >>
rfs [lmap_fromList, combinTheory.o_DEF, MAP_MAP_o] >>
simp [FILTER_FLAT, MAP_FLAT, MAP_MAP_o, combinTheory.o_DEF, FILTER_MAP]
>- fs [state_rel_def, mem_state_rel_def]
>- fs [state_rel_def, mem_state_rel_def] >>
rename [`labels path' = fromList l'`, `labels path = fromList l`,
`state_rel _ _ _ (last path) (last path')`, `lsub flat l`] >>
Cases_on `lsub = flat l` >> fs []
>- (
qexists_tac `flat l'` >>
rw [FILTER_FLAT, MAP_FLAT, MAP_MAP_o, combinTheory.o_DEF] >>
fs [state_rel_def, mem_state_rel_def]) >>
`filter (λy. Tau y) (flat l') = map (translate_trace (get_gmap prog)) (filter (λy. Tau y) (flat l))`
by rw [FILTER_FLAT, MAP_FLAT, MAP_MAP_o, combinTheory.o_DEF, FILTER_MAP] >>
qexists_tac `take_prop ($ Tau) (length (filter ($ Tau) lsub)) (flat l')` >>
rw [] >> rw [GSYM MAP_TAKE]
>- metis_tac [prefix_take_filter_lemma] >>
CCONTR_TAC >> fs [] >>
`(last path).status = (last path').status` by fs [state_rel_def, mem_state_rel_def] >>
drule take_prop_eq >> strip_tac >>
`length (filter (λy. Tau y) (flat l')) = length (filter (λy. Tau y) (flat l))`
by rw [] >>
fs [] >> drule filter_is_prefix >>
disch_then (qspec_then `$ Tau` assume_tac) >>
drule IS_PREFIX_LENGTH >> strip_tac >> fs [] >>
`length (filter (λy. Tau y) lsub) = length (filter (λy. Tau y) (flat l))` by rw [] >>
fs [] >> rw [] >>
qspec_then `path` assume_tac finite_path_end_cases >> rfs [] >> fs [] >> rw []
>- (`l = []` by metis_tac [llistTheory.fromList_EQ_LNIL] >> fs [] >> rfs []) >>
rfs [labels_plink] >>
rename1 `LAPPEND (labels path) [|last_l'|] = _` >>
`toList (LAPPEND (labels path) [|last_l'|]) = Some l` by metis_tac [llistTheory.from_toList] >>
drule llistTheory.toList_LAPPEND_APPEND >> strip_tac >>
fs [llistTheory.toList_THM] >> rw [] >>
drule multi_step_lab_label >> strip_tac >> rfs [] >> fs [] >>
drule prefix_filter_len_eq >> rw [] >>
qexists_tac `$ Tau` >> rw [])
>- (
fs [toList_some] >>
drule translate_prog_correct_lem2 >> simp [] >>
disch_then drule >> rw [] >>
qexists_tac `path'` >> rw [] >>
fs [IN_DEF, observation_prefixes_cases, toList_some] >> rw [] >>
rfs [lmap_fromList] >>
simp [GSYM MAP_FLAT, FILTER_MAP, untrans_trace_not_tau]
>- fs [state_rel_def, mem_state_rel_def]
>- fs [state_rel_def, mem_state_rel_def] >>
qexists_tac `map untranslate_trace l2'` >>
simp [GSYM MAP_FLAT, FILTER_MAP, untrans_trace_not_tau] >>
`INJ untranslate_trace (set l2' set (flat l2)) UNIV`
by (
drule is_prefix_subset >> rw [SUBSET_DEF] >>
`set l2' set (flat l2) = set (flat l2)` by (rw [EXTENSION] >> metis_tac []) >>
simp [] >>
simp [INJ_DEF] >> rpt gen_tac >>
Cases_on `x` >> Cases_on `y` >> simp [untranslate_trace_def] >>
Cases_on `a` >> Cases_on `a'` >> simp [untranslate_glob_var_def] >>
metis_tac [translate_global_var_11]) >>
fs [INJ_MAP_EQ_IFF, inj_map_prefix_iff] >> rw [] >>
fs [state_rel_def, mem_state_rel_def])
QED
export_theory ();