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.

177 lines
5.8 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 a shallowly embedded concept of live variables *)
open HolKernel boolLib bossLib Parse;
open pred_setTheory;
open settingsTheory miscTheory llvmTheory llvm_propTheory;
new_theory "llvm_live";
numLib.prefer_num ();
Definition inc_pc_def:
inc_pc ip = ip with i := ip.i + 1
End
(* The set of program counters the given instruction and starting point can
* immediately reach, within a function *)
Definition next_ips_def:
(next_ips (Ret _) ip = {})
(next_ips (Br _ l1 l2) ip =
{ <| f := ip.f; b := Some l; i := 0 |> | l | l {l1; l2} })
(next_ips (Invoke _ _ _ _ l1 l2) ip =
{ <| f := ip.f; b := Some l; i := 0 |> | l | l {l1; l2} })
(next_ips Unreachable ip = {})
(next_ips (Sub _ _ _ _ _ _) ip = { inc_pc ip })
(next_ips (Extractvalue _ _ _) ip = { inc_pc ip })
(next_ips (Insertvalue _ _ _ _) ip = { inc_pc ip })
(next_ips (Alloca _ _ _) ip = { inc_pc ip })
(next_ips (Load _ _ _) ip = { inc_pc ip })
(next_ips (Store _ _) ip = { inc_pc ip })
(next_ips (Gep _ _ _ _) ip = { inc_pc ip })
(next_ips (Ptrtoint _ _ _) ip = { inc_pc ip })
(next_ips (Inttoptr _ _ _) ip = { inc_pc ip })
(next_ips (Icmp _ _ _ _ _) ip = { inc_pc ip })
(next_ips (Call _ _ _ _) ip = { inc_pc ip })
(next_ips (Cxa_allocate_exn _ _) ip = { inc_pc ip })
(* TODO: revisit throw when dealing with exceptions *)
(next_ips (Cxa_throw _ _ _) ip = { })
(next_ips (Cxa_begin_catch _ _) ip = { inc_pc ip })
(next_ips (Cxa_end_catch) ip = { inc_pc ip })
(next_ips (Cxa_get_exception_ptr _ _) ip = { inc_pc ip })
End
(* The path is a list of program counters that represent a statically feasible
* path through a function *)
Inductive good_path:
(∀prog. good_path prog [])
(∀ip i.
get_instr prog ip i
good_path prog [ip])
(∀prog path ip1 i1 ip2.
get_instr prog ip1 i1
ip2 next_ips i1 ip1
good_path prog (ip2::path)
good_path prog (ip1::ip2::path))
End
Definition arg_to_regs_def:
(arg_to_regs (Constant _) = {})
(arg_to_regs (Variable r) = {r})
End
(* The registers that an instruction uses *)
Definition uses_def:
(uses (Ret (_, a)) = arg_to_regs a)
(uses (Br a _ _) = arg_to_regs a)
(uses (Invoke _ _ a targs _ _) =
arg_to_regs a BIGUNION (set (map (arg_to_regs o snd) targs)))
(uses Unreachable = {})
(uses (Sub _ _ _ _ a1 a2) =
arg_to_regs a1 arg_to_regs a2)
(uses (Extractvalue _ (_, a) _) = arg_to_regs a)
(uses (Insertvalue _ (_, a1) (_, a2) _) =
arg_to_regs a1 arg_to_regs a2)
(uses (Alloca _ _ (_, a)) = arg_to_regs a)
(uses (Load _ _ (_, a)) = arg_to_regs a)
(uses (Store (_, a1) (_, a2)) =
arg_to_regs a1 arg_to_regs a2)
(uses (Gep _ _ (_, a) targs) =
arg_to_regs a BIGUNION (set (map (arg_to_regs o snd) targs)))
(uses (Ptrtoint _ (_, a) _) = arg_to_regs a)
(uses (Inttoptr _ (_, a) _) = arg_to_regs a)
(uses (Icmp _ _ _ a1 a2) =
arg_to_regs a1 arg_to_regs a2)
(uses (Call _ _ _ targs) =
BIGUNION (set (map (arg_to_regs o snd) targs)))
(uses (Cxa_allocate_exn _ a) = arg_to_regs a)
(uses (Cxa_throw a1 a2 a3) =
arg_to_regs a1 arg_to_regs a2 arg_to_regs a3)
(uses (Cxa_begin_catch _ a) = arg_to_regs a)
(uses (Cxa_end_catch) = { })
(uses (Cxa_get_exception_ptr _ a) = arg_to_regs a)
End
(* The registers that an instruction assigns *)
Definition assigns_def:
(assigns (Invoke r _ _ _ _ _) = {r})
(assigns (Sub r _ _ _ _ _) = {r})
(assigns (Extractvalue r _ _) = {r})
(assigns (Insertvalue r _ _ _) = {r})
(assigns (Alloca r _ _) = {r})
(assigns (Load r _ _) = {r})
(assigns (Gep r _ _ _) = {r})
(assigns (Ptrtoint r _ _) = {r})
(assigns (Inttoptr r _ _) = {r})
(assigns (Icmp r _ _ _ _) = {r})
(assigns (Call r _ _ _) = {r})
(assigns (Cxa_allocate_exn r _) = {r})
(assigns (Cxa_begin_catch r _) = {r})
(assigns (Cxa_get_exception_ptr r _) = {r})
(assigns _ = {})
End
Definition live_def:
live prog ip
{ r | ∃path instr.
good_path prog (ip::path)
get_instr prog (last (ip::path)) instr
r uses instr
∀ip2 instr2. ip2 set (front (ip::path)) get_instr prog ip2 instr2 r assigns instr2 }
End
Theorem get_instr_live:
∀prog ip instr.
get_instr prog ip instr
uses instr live prog ip
Proof
rw [live_def, SUBSET_DEF] >>
qexists_tac `[]` >> rw [Once good_path_cases] >>
qexists_tac `instr` >> simp [] >> metis_tac [IN_DEF]
QED
Triviality set_rw:
!s P. (!x. x s P x) s = P
Proof
rw [] >> eq_tac >> rw [IN_DEF] >> metis_tac []
QED
Theorem live_gen_kill:
∀prog ip instr ip'.
get_instr prog ip instr
live prog ip = BIGUNION {live prog ip' | ip' next_ips instr ip} DIFF assigns instr uses instr
Proof
rw [live_def, EXTENSION] >> eq_tac >> rw []
>- (
Cases_on `path` >> fs []
>- metis_tac [get_instr_func] >>
rename1 `ip::ip2::path` >>
qpat_x_assum `good_path _ _` mp_tac >> simp [Once good_path_cases] >> rw [] >>
Cases_on `x uses instr` >> fs [] >> simp [set_rw, PULL_EXISTS] >>
qexists_tac `ip2` >> qexists_tac `path` >> qexists_tac `instr'` >> rw [] >>
metis_tac [get_instr_func])
>- (
fs [] >>
qexists_tac `ip'::path` >> qexists_tac `instr'` >> rw []
>- (simp [Once good_path_cases] >> metis_tac []) >>
metis_tac [get_instr_func])
>- (
qexists_tac `[]` >> qexists_tac `instr` >> rw [] >>
simp [Once good_path_cases] >>
metis_tac [])
QED
export_theory ();