1
0
mirror of https://github.com/pakt/ropc synced 2026-06-08 16:36:27 +00:00
Files
2012-09-20 03:16:35 -07:00

886 lines
32 KiB
OCaml

open Common
open Ast
open Cdefs
open Printf
let instr_type = function
(* T0, because we want them at every stage *)
| Lbl(_)
| Comment(_)
| AdvanceStack(_)
| RawHex(_)
| MovRegConst(_,_)
| MovRegReg(_,_)
| MovRegSymb(_,_)
| WriteM(_,_)
| ReadM(_,_)
| SaveFlags
| OpStack(_,_)
| BinO(_,_,_,_) -> T0
| ReadMConst(_,_)
| WriteMConst(_,_) -> T1
| LocalAddr(_,_)
| PushReg(_)
| PopReg(_) -> T2
| ReadLocal(_,_)
| WriteLocal(_,_) -> T3
(* IN: instr, gmeta list *)
(* OUT: gmeta corresponding to instr *)
let find_all_gmetas instr gms =
let find_gms f_match =
let pred gm =
let GMeta(g,_,_,_) = gm in
f_match g gm
in
List.filter pred gms
in
let is_opstack g = match g with Common.OpEsp(_,_,_) -> true | _ -> false in
let get_stack_fix gm = let GMeta(_,_,_,sf) = gm in sf in
let f_match_movreg r g gm = match g with Common.LoadConst(gr,_) -> gr=r | _ -> false in
let f_match_op_esp op r g gm = match g with Common.OpEsp(gop, gr, _) -> (gop=op && gr=r) | _ -> false in
let f_match =
match instr with
| OpStack(op, C(r)) ->
let op' = ast_op_to_gadget_op op in
f_match_op_esp op' r
| BinO(C(r0), C(r1), op, C(r2)) ->
let op' = ast_op_to_gadget_op op in
fun g gm -> g = Common.BinOp(r0, r1, op', r2)
| WriteM(C(addr_reg), C(src_reg)) ->
fun g gm -> g = Common.WriteMem(addr_reg, Int32.zero, src_reg)
| ReadM(C(dst_reg), C(addr_reg)) ->
fun g gm -> g = Common.ReadMem(dst_reg, addr_reg, Int32.zero)
(* movregsymb will be converted to mov reg const *)
| MovRegConst(C(r),_) | MovRegSymb(C(r),_) ->
f_match_movreg r
| MovRegReg(C(dst), C(src)) ->
fun g gm -> g = Common.CopyReg(dst,src)
| SaveFlags ->
fun g gm -> g = Common.Lahf
| AdvanceStack(n) ->
fun g gm -> (not (is_opstack g)) && (get_stack_fix gm = n)
(* Can match anything, but this simplifies things *)
| RawHex(_) ->
fun g gm -> get_stack_fix gm = 4
(* we don't want to lose these, so match with anything *)
| Lbl(_) | Comment(_) -> fun g gm -> true
| _ -> assert false
in
let matching_gms = find_gms f_match in
if matching_gms = [] then raise Not_found
else matching_gms
let make_implement stack_ptr frame_ptr =
let implement_t1 f_next_reg instr =
match instr with
| ReadMConst(r, addr) ->
let reg = f_next_reg () in
let mov = MovRegConst(reg, addr) in
let rm = ReadM(r, reg) in
[mov;rm]
| WriteMConst(addr,r) ->
let addr_reg = f_next_reg () in
let mov = MovRegConst(addr_reg, addr) in
let wm = WriteM(addr_reg, r) in
[mov;wm]
| _ -> assert false
in
let implement_t2 f_next_reg instr =
match instr with
| PushReg(r) ->
let addr_reg = f_next_reg () in
let rm = ReadMConst(addr_reg, stack_ptr) in
let wm1 = WriteM(addr_reg, r) in
let reg1 = f_next_reg () in
let rm2 = ReadMConst(reg1, stack_ptr) in
let reg2 = f_next_reg () in
let mov = MovRegConst(reg2, 4) in
let reg3 = f_next_reg () in
let sub = BinO(reg3, reg1, Sub, reg2) in
let wm2 = WriteMConst(stack_ptr, reg3) in
[rm;wm1;rm2;mov;sub;wm2]
| PopReg(r) ->
let reg1 = f_next_reg () in
let rm1 = ReadMConst(reg1, stack_ptr) in
let reg2 = f_next_reg () in
let mov = MovRegConst(reg2, 4) in
let reg3 = f_next_reg () in
let sub = BinO(reg3, reg1, Add, reg2) in
let wm = WriteMConst(stack_ptr, reg3) in
let rm2 = ReadM(r, reg3) in
[rm1;mov;sub;wm;rm2;]
| LocalAddr(off,r) ->
let reg1 = f_next_reg () in
let rm1 = ReadMConst(reg1, frame_ptr) in
let reg2 = f_next_reg () in
let mov = MovRegConst(reg2, off) in
let add = BinO(r, reg1, Add, reg2) in
[rm1;mov;add;]
| _ -> assert false
in
let implement_t3 f_next_reg instr =
match instr with
| ReadLocal(off, r) ->
let addr_reg = f_next_reg () in
let la = LocalAddr(off, addr_reg) in
let rm = ReadM(r, addr_reg) in
[la;rm]
| WriteLocal(off, r) ->
let addr_reg = f_next_reg () in
let la = LocalAddr(off, addr_reg) in
let wm = WriteM(addr_reg, r) in
[la;wm]
(* Caller should be aware these are special *)
| Lbl(_)
| Comment(_) -> assert false
| _ -> assert false
in
let implement instr =
let type2idx = function T3 -> 2 | T2 -> 1 | T1 -> 0 | T0 -> assert false in
let init () =
let f_next_reg = make_reg_generator () in
let funs = [implement_t1;implement_t2;implement_t3] in
let funs = List.map (fun f -> f f_next_reg) funs in
funs
in
let funs = init () in
let typ = instr_type instr in
let idx = type2idx typ in
let f_implement = List.nth funs idx in
f_implement instr
in
implement
let arg_dumper instr =
match instr with
| AdvanceStack(_) -> []
| RawHex(_) -> []
| MovRegConst(a1,_) -> [a1]
| MovRegReg(a1,a2) -> [a1;a2]
| MovRegSymb(a1,_) -> [a1]
| WriteM(a1,a2) -> [a1;a2]
| ReadM(a1,a2) -> [a1;a2]
| SaveFlags -> []
| OpStack(_,a1) -> [a1]
| BinO(a1,a2,_,a3) -> [a1;a2;a3]
| ReadMConst(a1,_)
| WriteMConst(_,a1) -> [a1]
| LocalAddr(_,a1)
| PushReg(a1)
| PopReg(a1) -> [a1]
| ReadLocal(_,a1)
| WriteLocal(_,a1) -> [a1]
| Lbl(_)
| Comment(_) -> []
let number_of_args instr = List.length (arg_dumper instr)
let arg_positions instr arg =
let args = arg_dumper instr in
let enum (i,l) x = (i+1,(i,x)::l) in
let _, args = List.fold_left enum (0,[]) args in
let args = List.filter (fun (_,a) -> a=arg) args in
let positions = List.map fst args in
positions
(* get possible regs at position pos for instructions matching type of instr.
* for example: BinOp(r0,_,+,_) 0 -> possible values for r0 *)
let possible_regs_t0 gms instr =
let f_binop op =
let f acc g =
match g with
| Common.BinOp(r0, r1, op', r2) -> if op = op' then ([r0;r1;r2]::acc) else acc
| _ -> acc
in
f
in
let f_op_esp op =
let f acc g =
match g with
| Common.OpEsp(op', r, _) -> if op = op' then ([r]::acc) else acc
| _ -> acc
in
f
in
let f_write_mem acc g =
match g with
| Common.WriteMem(r0, _, r1) -> ([r0;r1]::acc)
| _ -> acc
in
let f_read_mem acc g =
match g with
| Common.ReadMem(r0, r1, _) -> ([r0;r1]::acc)
| _ -> acc
in
let f_load_const acc g =
match g with
| Common.LoadConst(r,_) -> ([r]::acc)
| _ -> acc
in
let f_copy_reg acc g =
match g with
| Common.CopyReg(r0,r1) -> ([r0;r1]::acc)
| _ -> acc
in
(* [[a1;..];[b1..]] -> [a1;b1],[[..];[..]] *)
let group_args regs =
let f (heads,tails) l =
match l with
| hd::tl -> (hd::heads, tl::tails)
| [] -> assert false
in
let rec aux acc ll =
match ll with
| (hd::_)::tll -> (* at least one non-empty list *)
let (heads,tails) = List.fold_left f ([],[]) ll in
aux (heads::acc) tails
| _ -> List.rev acc
in
aux [] regs
in
let make_sets groups =
let f acc l =
let set = Cdefs.set_from_list l in
set::acc
in
let sets = List.fold_left f [] groups in
List.rev sets
in
let f_collect =
match instr with
| OpStack(op, _) ->
let op' = ast_op_to_gadget_op op in
f_op_esp op'
| WriteM(_, _) -> f_write_mem
| BinO(_, _, op, _) ->
let op' = ast_op_to_gadget_op op in
f_binop op'
| ReadM(_, _) -> f_read_mem
(* movregsymb will be converted to mov reg const *)
| MovRegConst(_,_) | MovRegSymb(_,_) -> f_load_const
| MovRegReg(_, _) -> f_copy_reg
| _ -> assert false
in
(* regs is a list of lists *)
let regs = List.fold_left f_collect [] gms in
let groups = group_args regs in
let sets = make_sets groups in
sets
let matching_func_for_instr instr =
let f_match =
match instr with
| OpStack(op, _) ->
( fun instr -> match instr with OpStack(op'',_) -> op'' = op | _ -> false)
| WriteM(_, _) ->
( fun instr -> match instr with WriteM(_,_) -> true | _ -> false)
| BinO(_, _, op, _) ->
( fun instr -> match instr with BinO(_,_,op'',_) -> op'' = op | _ -> false)
| ReadM(_, _) ->
( fun instr -> match instr with ReadM(_,_) -> true | _ -> false)
(* movregsymb will be converted to mov reg const *)
| MovRegConst(_,_) | MovRegSymb(_,_) ->
( fun instr -> match instr with
MovRegConst(_,_) | MovRegSymb(_,_) -> true |_ -> false)
| MovRegReg(_, _) ->
( fun instr -> match instr with MovRegReg(_,_) -> true | _ -> false)
| ReadMConst(_,_) ->
( fun instr -> match instr with ReadMConst(_,_) -> true | _ -> false )
| WriteMConst(_,_) ->
( fun instr -> match instr with WriteMConst(_,_) -> true | _ -> false)
| LocalAddr(_,_) ->
( fun instr -> match instr with LocalAddr(_,_) -> true | _ -> false)
| PushReg(_)->
( fun instr -> match instr with PushReg(_) -> true | _ -> false)
| PopReg(_) ->
( fun instr -> match instr with PopReg(_) -> true | _ -> false)
| ReadLocal(_,_)->
( fun instr -> match instr with ReadLocal(_,_) -> true | _ -> false)
| WriteLocal(_,_) ->
( fun instr -> match instr with WriteLocal(_,_) -> true | _ -> false)
| AdvanceStack(_)->
( fun instr -> match instr with AdvanceStack(_) -> true | _ -> false)
| RawHex(_) ->
( fun instr -> match instr with RawHex(_) -> true | _ -> false)
| Lbl(_)-> assert false
| Comment(_) -> assert false
| _ -> assert false
in
f_match
(* Make f_assign x an identity for concrete regs *)
let wrap_f_assign f =
let g r =
match r with
| C(_) -> (try f r with _ -> r)
| S(_) -> (try f r with _ -> assert false)
in
g
let apply_assignment f_assign instr =
let f = wrap_f_assign f_assign in
match instr with
| MovRegConst(r,c) -> MovRegConst(f r,c)
| MovRegSymb(r,sc) -> MovRegSymb(f r,sc)
| ReadMConst(r,ma) -> ReadMConst(f r,ma)
| WriteMConst(ma,r) -> WriteMConst(ma,f r)
| ReadLocal(off,r) -> ReadLocal(off,f r)
| WriteLocal(off,r) -> WriteLocal(off,f r)
| LocalAddr(v,r) -> LocalAddr(v,f r)
| PopReg(r) -> PopReg(f r)
| PushReg(r) -> PushReg(f r)
| OpStack(op, r) -> OpStack(op, f r)
| MovRegReg(r1,r2) -> MovRegReg(f r1,f r2)
| WriteM(r1,r2) -> WriteM(f r1,f r2)
| ReadM(r1,r2) -> ReadM(f r1,f r2)
| BinO(ro,r1,op,r2) -> BinO(f ro, f r1, op, f r2)
(*
| AdvanceStack
| RawHex
| SaveFlags
| Lbl(_)
| Comment(_)
*)
| _ -> instr
let make_cache_funs () =
let cache = ref (fun i p -> raise Not_found) in
let cache_add instr reg_set_list =
let f_match = matching_func_for_instr instr in
let new_cache i p =
if f_match i then
List.nth reg_set_list p
else
!cache i p (* FIXME ? *)
in
begin
cache := new_cache
end
in
let cache_test instr pos =
try let _ = !cache instr pos in true with Not_found -> false
in
let cache_get instr pos =
try !cache instr pos with Not_found -> assert false
in
(cache_add,cache_test,cache_get)
(* All registers used in implementations are "local".
* Use noncolliding regs for params: S(-1), S(-2) ... *)
let make_fake_instr instr =
let args = arg_dumper instr in
let f (n,f_assign) arg =
let f_new x = if x=arg then (S(-n)) else f_assign x in
(n+1, f_new)
in
let f_assert = (fun x->assert false) in
let (_, f_assign) = List.fold_left f (1, f_assert) args in
let fake_instr = apply_assignment f_assign instr in
fake_instr
(* *by_pos/by_arg are mutually recursive.
* by_pos returns possible regs for ith argument
* by_arg returns possible regs for a specific arg
* difference: if two args are equal then we need to intersect corresponding
* sets *)
let make_possible_regs_funs gadgets implement =
(* let (cache_add,cache_test,cache_get) = make_cache_funs () in *)
let rec possible_regs_by_pos gadgets implement instr pos =
let possible_regs_t0 = possible_regs_t0 gadgets in
let cache_add instr reg_set_list =
()
in
(* FIXME *)
let cache_test instr pos = false in
let cache_get instr pos = assert false in
let higher_t instr pos =
let process_impl impl arg =
let collect reg_set instr =
let regs = possible_regs_by_arg gadgets implement instr arg in
RegSet.inter reg_set regs
in
List.fold_left collect fULL_REG_SET impl
in
(* Beware: this works correctly only because higher types don't take multiple reg params *)
let fake_instr = make_fake_instr instr in
let args = arg_dumper fake_instr in
let impl = implement fake_instr in
let f acc arg =
let regs = process_impl impl arg in
regs::acc
in
let possible_for_all_args = List.fold_left f [] args in
List.rev possible_for_all_args
in
if (cache_test instr pos) then
cache_get instr pos
else
(* list of sets. i-th set contains possible regs for ith param *)
let reg_set_list =
let typ = instr_type instr in
match typ with
| T0 ->
(* get possible regs for all arguments *)
let reg_set_list = possible_regs_t0 instr in
reg_set_list
| _ -> higher_t instr pos
in
let _ = cache_add instr reg_set_list in
let total_args = number_of_args instr in
if pos > (total_args-1) then assert false
else List.nth reg_set_list pos
and
possible_regs_by_arg gadgets implement instr arg =
let positions = arg_positions instr arg in
let collect reg_set pos =
let regs = possible_regs_by_pos gadgets implement instr pos in
RegSet.inter reg_set regs
in
List.fold_left collect fULL_REG_SET positions
in
let by_arg = possible_regs_by_arg gadgets implement in
let by_pos = possible_regs_by_pos gadgets implement in
by_arg, by_pos
let mod_read_vars = function
| AdvanceStack(_)
| RawHex(_) -> [],[]
| MovRegConst(r,_)
| MovRegSymb(r,_)
| ReadMConst(r,_)
| ReadLocal(_,r)
| LocalAddr(_,r)
| PopReg(r) -> [r],[]
| WriteLocal(_,r)
| WriteMConst(_,r)
| PushReg(r)
| OpStack(_, r) -> [],[r]
| MovRegReg(r1,r2) -> [r1],[r2]
| WriteM(r1,r2) -> [],[r1;r2]
| ReadM(r1,r2) -> [r1],[r2]
| BinO(ro,r1,op,r2) -> [ro],[r1;r2]
| SaveFlags -> [C(EAX)],[]
| Lbl(_)
| Comment(_) -> [],[]
let mod_vars instr = fst (mod_read_vars instr)
let read_vars instr = snd (mod_read_vars instr)
(* Assumes SSA form.
* Overapproximated for non-SSA.
* Store first write and last read *)
let analyse_reads_writes instrs =
let reads = Hashtbl.create 8 in
let writes = Hashtbl.create 8 in
let update_hashes i instr reads writes =
let wr = mod_vars instr in
let rd = read_vars instr in
(* first write *)
let f_w acc reg =
try
let _ = Hashtbl.find writes reg in
()
with Not_found ->
Hashtbl.add writes reg i
in
(* last read *)
let f_r acc reg = Hashtbl.add reads reg i in
let _ = List.fold_left f_w () wr in
let _ = List.fold_left f_r () rd in
()
in
let f i instr =
let _ = update_hashes i instr reads writes in
i+1
in
let _ = List.fold_left f 0 instrs in
(reads, writes)
let get_kv h =
(* Hashtbl.fold provides history of bindings, but we only want the most
* recent one. *)
let seen = Hashtbl.create 8 in
let f k v acc =
try
let _ = Hashtbl.find seen k in
acc
with Not_found ->
let _ = Hashtbl.add seen k true in
(k,v)::acc
in
let l = Hashtbl.fold f h [] in
l
let inverse_hash h =
let inv = Hashtbl.create 16 in
let kv_pairs = get_kv h in
let f h (k,v) =
let cur = try Hashtbl.find h v with Not_found -> SRegSet.empty in
let cur = SRegSet.add k cur in
let _ = Hashtbl.add h v cur in
h
in
let inv = List.fold_left f inv kv_pairs in
inv
let hash_get h k empty = try Hashtbl.find h k with Not_found -> empty
let find_read_but_not_written reads writes =
let f k v acc =
try
let _ = Hashtbl.find writes k in
acc
with Not_found -> k::acc
in
let in_args = Hashtbl.fold f reads [] in
sreg_set_from_list in_args
(* liveness analysis *)
let analyse_liveness instrs =
let (reads, writes) = analyse_reads_writes instrs in
let l2rd = inverse_hash reads in
let l2wr = inverse_hash writes in
let in_args = find_read_but_not_written reads writes in
let cur = hash_get l2wr 0 SRegSet.empty in
let cur = SRegSet.union cur in_args in
let _ = Hashtbl.add l2wr 0 cur in
(* Add a set of live vars to every instruction.
* il - list of pairs (instr, live_vars)
* alive - alive vars *)
let attach instrs =
let rec aux (line_no, pairs, alive) instrs =
match instrs with
| instr::tl ->
let new_alive = hash_get l2wr line_no SRegSet.empty in
let new_dead = hash_get l2rd line_no SRegSet.empty in
let alive = SRegSet.union (SRegSet.diff alive new_dead) new_alive in
let pair = (instr, alive) in
aux (line_no+1, pair::pairs, alive) tl
| [] -> List.rev pairs
in
aux (0, [], SRegSet.empty) instrs
in
attach instrs
(* Return a hash: sreg -> set of conflicting sregs.
* Vars are in conflict, when they can't share a register (they are both alive at the
* same time).
*)
let calc_conflicts pairs =
let f h (_, alive) =
let g acc sreg =
let cur = hash_get h sreg SRegSet.empty in
let new_set = SRegSet.union cur alive in
Hashtbl.add h sreg new_set
in
let elems = SRegSet.elements alive in
let _ = List.fold_left g () elems in
h
in
let fix h (sreg, set) =
let set' = SRegSet.remove sreg set in
let _ = Hashtbl.add h sreg set' in
h
in
let tmp_hash = Hashtbl.create 16 in
let _ = List.fold_left f tmp_hash pairs in
let kv_pairs = get_kv tmp_hash in
let conflicts = Hashtbl.create 16 in
let conflicts = List.fold_left fix conflicts kv_pairs in
conflicts
let just_symbolic args = List.filter (function S(_) -> true | _ -> false) args
let just_concrete args = List.filter (function C(_) -> true | _ -> false) args
let symbolic_args instr =
let args = arg_dumper instr in
let args = just_symbolic args in
args
(* Returns a hash: sreg->set of possible concrete regs *)
let possible_regs possible_regs_by_arg instrs =
let analyse_one possible instr =
let args = symbolic_args instr in
let f h arg_reg =
let regs = possible_regs_by_arg instr arg_reg in
let cur =
try Hashtbl.find h arg_reg
with Not_found -> regs
in
let cur = RegSet.inter cur regs in
let _ = Hashtbl.add h arg_reg cur in
h
in
let possible = List.fold_left f possible args in
possible
in
let possible = Hashtbl.create 16 in
List.fold_left analyse_one possible instrs
let make_assign_regs gmetas stack_ptr frame_ptr =
let gadgets = get_gadgets gmetas in
let implement = make_implement stack_ptr frame_ptr in
let p_by_arg, p_by_pos = make_possible_regs_funs gadgets implement in
let dprintf depth f =
let pre = String.make (depth*4) ' ' in
let _ = print_string pre in
let _ = f () in
()
in
let rec assign_regs depth instrs top_preserved =
(* Make assignments only for symbolic regs *)
let collect_all_vars instrs =
let collect vars instr =
let args = symbolic_args instr in
let args_set = sreg_set_from_list args in
SRegSet.union vars args_set
in
let set = List.fold_left collect SRegSet.empty instrs in
SRegSet.elements set
in
(* Return all possible assignments of sreg->concrete reg.
* Return a list of functions sreg->reg *)
let all_assignments sregs possible conflicts =
let rec all_perms f_acc sregs =
match sregs with
| sreg::tl ->
let p_concrete_set =
try Hashtbl.find possible sreg with Not_found -> assert false
in
let p_concrete_set = common_reg_set_to_sreg_set p_concrete_set in
let conflicting = try Hashtbl.find conflicts sreg with _ -> assert false in
(* Collect conflicting regs *)
let f sreg acc =
match sreg with
| C(creg) -> SRegSet.add sreg acc
| S(_) ->
begin
try
let creg = f_acc sreg in
SRegSet.add creg acc
with _ -> acc
end
in
let used = SRegSet.fold f conflicting (SRegSet.empty) in
let p_concrete_set = SRegSet.diff p_concrete_set used in
let p_concrete_list = SRegSet.elements p_concrete_set in
let assign_one acc concrete =
let g sr = if sr=sreg then concrete else f_acc sr in
let new_perms = all_perms (g) tl in
new_perms@acc
in
List.fold_left assign_one [] p_concrete_list
| [] -> [f_acc]
in
let f_fail r =
let err = sprintf "Unable to assign to: %s" (dump_sreg r) in
failwith err
in
let perms = all_perms f_fail sregs in
perms
in
(* Apply one of the sregs assignments. Exceptions from this function are
* always an error.
* Regs in "alive" sets are also concretized. *)
let apply_assignment_to_all f_assign pairs =
(* Don't throw exceptions on concretized regs *)
let f_assign = wrap_f_assign f_assign in
let f acc (instr, alive) =
let i = apply_assignment f_assign instr in
let g x acc = SRegSet.add (f_assign x) acc in
let alive = SRegSet.fold g alive SRegSet.empty in
(i,alive)::acc
in
let pairs = List.fold_left f [] pairs in
let pairs = List.rev pairs in
pairs
in
(* Which concrete regs need to be preserved between instructions *)
let calc_preserved pairs =
let f acc (instr, alive) =
let mod_params = mod_vars instr in
let mod_params = sreg_set_from_list mod_params in
(* Instruction can't preserve a param, if it writes to it *)
let preserved = SRegSet.diff alive mod_params in
(instr, preserved)::acc
in
let pairs = List.fold_left f [] pairs in
List.rev pairs
in
let dump_preserved preserved =
let pr sreg = printf "%s;" (dump_sreg sreg) in
let sregs = SRegSet.elements preserved in
let _ = dprintf depth (fun _ -> print_string "$ top_preserved: ") in
let _ = List.map pr sregs in
dprintf depth (fun _ -> print_newline ())
in
(* Check if the assignment is possible.
* If it is, return instructions paired with gmetas *)
let satisfy perms pairs =
(* Throws Not_found if it's impossible to find a gmeta *)
let satisfy_t0 instr preserved =
let check_possible gmeta =
let GMeta(_,_,mod_regs,_) = gmeta in
let mod_regs = List.map (fun r -> C(r)) mod_regs in
let mod_regs = sreg_set_from_list mod_regs in
(*
let si = (dump_instr instr) in
let _ = dprintf depth (fun _ -> printf "@@ %s, preserved: " si) in
let _ = dump_sreg_set preserved in
let _ = printf "%s" ", mod_regs: " in
let _ = dump_sreg_set mod_regs in
let _ = dprintf depth (fun _ -> print_newline ()) in
*)
let inter = SRegSet.inter preserved mod_regs in
(* If the intersection is empty, none of the preserved regs is modified *)
SRegSet.is_empty inter
in
let possible_gmetas = try find_all_gmetas instr gmetas with Not_found -> [] in
(* let _ = dprintf depth (fun _ -> printf "possible gmetas: %d\n" (List.length possible_gmetas)) in *)
(* Throws Not_found *)
let gmeta = List.find check_possible possible_gmetas in
gmeta
in
let satisfy_t instr preserved =
let impl = implement instr in
assign_regs (depth+1) impl preserved
in
let satisfy_one (instr, preserved) top_preserved =
let _ = dprintf depth (fun _ -> printf "implementing %s\n" (dump_instr instr)) in
let preserved = SRegSet.union preserved top_preserved in
let typ = instr_type instr in
let pairs =
match typ with
| T0 ->
let gmeta = satisfy_t0 instr preserved in
[(instr, gmeta)]
| _ -> satisfy_t instr preserved
in
pairs
in
let satisfy_all c_pairs top_preserved =
let f acc (instr,preserved) =
let impl = satisfy_one (instr, preserved) top_preserved in
acc@impl
in
let impl = List.fold_left f [] c_pairs in
impl
in
(* Test all possible assignments *)
let rec aux perms =
match perms with
| f_assign::tl ->
begin
(* Concretize all regs *)
let c_pairs = apply_assignment_to_all f_assign pairs in
(* Remove unnecessary regs from 'alive' set *)
let c_pairs = calc_preserved c_pairs in
try
let impl = satisfy_all c_pairs top_preserved in
f_assign, impl
with Not_found ->
aux tl
end
| [] ->
(* No assignment is satisfiable *)
raise Not_found
in
let f_assign, impl = aux perms in
f_assign, impl
in
let dump_one_perm vars f_assign =
let f sreg = (sreg, f_assign sreg) in
let l = List.map f vars in
let pr (s,c) = dprintf depth (fun _ -> printf "%s -> %s\n" (dump_sreg s) (dump_sreg c)) in
let _ = List.map pr l in
()
in
(* IN: satisfiable assignment, (instr, gmeta) pairs *)
let dump_satisfied vars f_assign pairs =
let _ = dprintf depth (fun _ -> print_endline "%%% winner assignment:") in
let _ = dump_one_perm vars f_assign in
let _ = dprintf depth (fun _ -> print_endline "%%% paired:") in
let f (instr, gmeta) =
let _ = dprintf depth (fun _ -> printf "%s\n" (dump_instr instr)) in
()
in
let _ = List.map f pairs in
()
in
let dump vars possible conflicts perms top_preserved pairs =
let dump_possible possible =
let pr (sreg,set) =
let set = common_reg_set_to_sreg_set set in
let _ = dprintf depth (fun _ -> printf "%s in {" (dump_sreg sreg)) in
let _ = dump_sreg_set set in
let _ = dprintf depth (fun _ -> printf "%s\n" "}") in
()
in
let _ = dprintf depth (fun _ -> printf "%s\n" "$ possible") in
let kv = get_kv possible in
List.map pr kv
in
let dump_conflicts h =
let _ = dprintf depth (fun _ -> printf "%s\n" "$ conflicts") in
let kv = get_kv h in
let pr (k,v) =
let _ = dprintf depth (fun _ -> printf "%s conflicts: " (dump_sreg k)) in
let _ = dump_sreg_set v in
dprintf depth (fun _ -> print_newline ())
in
let _ = List.map pr kv in
()
in
let dump_perms perms =
let _ = dprintf depth (fun _ -> printf "%s\n" "$ perms") in
let pr perm =
let _ = dump_one_perm vars perm in
dprintf depth (fun _ -> print_endline "-")
in
let _ = List.map pr perms in
()
in
let print_pair (instr, alive) =
let _ = dprintf depth (fun _ -> Printf.printf "%s alive: " (dump_instr instr)) in
let _ = dump_sreg_set alive in
print_newline ()
in
let _ = dprintf depth (fun _ -> print_endline "--------------") in
let _ = List.map print_pair pairs in
let _ = dump_preserved top_preserved in
let _ = dump_possible possible in
let _ = dump_conflicts conflicts in
let _ = dump_perms perms in
()
in
let pairs = analyse_liveness instrs in
let conflicts = calc_conflicts pairs in
let possible = possible_regs p_by_arg instrs in
let vars = collect_all_vars instrs in
let perms = all_assignments vars possible conflicts in
let _ = dump vars possible conflicts perms top_preserved pairs in
let f_assign, s_pairs = satisfy perms pairs in
let _ = dump_satisfied vars f_assign s_pairs in
s_pairs
in
(* depth = 0 *)
assign_regs 0