|
@@ -492,14 +492,224 @@ let code_graph (f:fundecl) =
|
|
|
in
|
|
|
blocks_pos, make_block 0
|
|
|
|
|
|
-let optimize dump get_str (f:fundecl) =
|
|
|
+type rctx = {
|
|
|
+ r_root : block;
|
|
|
+ r_used_regs : int;
|
|
|
+ r_nop_count : int;
|
|
|
+ r_blocks_pos : (int, block) Hashtbl.t;
|
|
|
+ r_reg_moved : (int, (int * int)) Hashtbl.t;
|
|
|
+ r_live_bits : int array;
|
|
|
+ r_reg_map : int array;
|
|
|
+}
|
|
|
+
|
|
|
+let remap_fun ctx f dump get_str =
|
|
|
+ let aget = Array.unsafe_get in
|
|
|
+ let aset = Array.unsafe_set in
|
|
|
+ let op index = aget f.code index in
|
|
|
let nregs = Array.length f.regs in
|
|
|
+ let reg_remap = ctx.r_used_regs <> nregs in
|
|
|
+ let assigns = ref f.assigns in
|
|
|
let old_code = match dump with None -> f.code | Some _ -> Array.copy f.code in
|
|
|
+ let write str = match dump with None -> () | Some ch -> IO.nwrite ch (Bytes.unsafe_of_string (str ^ "\n")) in
|
|
|
+ let nargs = (match f.ftype with HFun (args,_) -> List.length args | _ -> assert false) in
|
|
|
+
|
|
|
+ let live_bits = ctx.r_live_bits in
|
|
|
+ let reg_map = ctx.r_reg_map in
|
|
|
+
|
|
|
+ let bit_regs = 30 in
|
|
|
+ let stride = (nregs + bit_regs - 1) / bit_regs in
|
|
|
+ let is_live r i =
|
|
|
+ let offset = r / bit_regs in
|
|
|
+ let mask = 1 lsl (r - offset * bit_regs) in
|
|
|
+ Array.unsafe_get live_bits (i * stride + offset) land mask <> 0
|
|
|
+ in
|
|
|
+
|
|
|
+ (* remap assigns *)
|
|
|
+ if ctx.r_nop_count > 0 then begin
|
|
|
+ let rec resolve_block p =
|
|
|
+ try Hashtbl.find ctx.r_blocks_pos p with Not_found -> resolve_block (p - 1)
|
|
|
+ in
|
|
|
+
|
|
|
+ let new_assigns = List.fold_left (fun acc (i,p) ->
|
|
|
+ let gmap = Hashtbl.create 0 in
|
|
|
+ (*
|
|
|
+ For a given assign at position p, that's been optimized out,
|
|
|
+ let's try to find where the last assign that maps to the same value
|
|
|
+ is, and remap the variable name to it
|
|
|
+ *)
|
|
|
+ let rec loop p =
|
|
|
+ if p < 0 || (match op p with ONop _ -> false | _ -> true) then [(i,p)] else
|
|
|
+ let reg, last_w = try Hashtbl.find ctx.r_reg_moved p with Not_found -> (-1,-1) in
|
|
|
+ if reg < 0 then [] (* ? *) else
|
|
|
+ if reg < nargs then [(i,-reg-1)] else
|
|
|
+ let b = resolve_block p in
|
|
|
+ if last_w >= b.bstart && last_w < b.bend && last_w < p then loop last_w else
|
|
|
+ let wp = try PMap.find reg b.bwrite with Not_found -> -1 in
|
|
|
+ let rec gather b =
|
|
|
+ if Hashtbl.mem gmap b.bstart then [] else begin
|
|
|
+ Hashtbl.add gmap b.bstart ();
|
|
|
+ (* lookup in all parent blocks, recursively, to fetch all last writes *)
|
|
|
+ List.fold_left (fun acc bp ->
|
|
|
+ if bp.bstart > b.bstart then acc else
|
|
|
+ try
|
|
|
+ let wp = PMap.find reg bp.bwrite in
|
|
|
+ if wp > p then assert false;
|
|
|
+ loop wp @ acc
|
|
|
+ with Not_found ->
|
|
|
+ gather bp @ acc
|
|
|
+ ) [] b.bprev;
|
|
|
+ end
|
|
|
+ in
|
|
|
+ if wp < 0 then
|
|
|
+ gather b
|
|
|
+ else if wp < p then
|
|
|
+ loop wp
|
|
|
+ else
|
|
|
+ (* lookup in writes between p-1 and block bstart *)
|
|
|
+ let rec find_w p =
|
|
|
+ if p < b.bstart then
|
|
|
+ gather b
|
|
|
+ else
|
|
|
+ let found = ref false in
|
|
|
+ opcode_fx (fun r read -> if r = reg && not read then found := true) (aget old_code p);
|
|
|
+ if !found then loop p else find_w (p - 1)
|
|
|
+ in
|
|
|
+ find_w (p - 1)
|
|
|
+ in
|
|
|
+ loop p @ acc
|
|
|
+ ) [] (Array.to_list !assigns) in
|
|
|
+ let new_assigns = List.sort (fun (_,p1) (_,p2) -> p1 - p2) (List.rev new_assigns) in
|
|
|
+ assigns := Array.of_list new_assigns;
|
|
|
+ end;
|
|
|
+
|
|
|
+ (* done *)
|
|
|
+ if dump <> None then begin
|
|
|
+ let old_assigns = Hashtbl.create 0 in
|
|
|
+ let new_assigns = Hashtbl.create 0 in
|
|
|
+ Array.iter (fun (var,pos) -> if pos >= 0 then Hashtbl.replace old_assigns pos var) f.assigns;
|
|
|
+ Array.iter (fun (var,pos) ->
|
|
|
+ if pos >= 0 then begin
|
|
|
+ let f = try Hashtbl.find new_assigns pos with Not_found -> let v = ref [] in Hashtbl.add new_assigns pos v; v in
|
|
|
+ f := var :: !f;
|
|
|
+ end
|
|
|
+ ) !assigns;
|
|
|
+ let rec loop i block =
|
|
|
+ if i = Array.length f.code then () else
|
|
|
+ let block = try
|
|
|
+ let b = Hashtbl.find ctx.r_blocks_pos i in
|
|
|
+ write (Printf.sprintf "\t----- [%s] (%X)"
|
|
|
+ (String.concat "," (List.map (fun b -> Printf.sprintf "%X" b.bstart) b.bnext))
|
|
|
+ b.bend
|
|
|
+ );
|
|
|
+ let need = String.concat "," (List.map string_of_int (ISet.elements b.bneed)) in
|
|
|
+ let wr = String.concat " " (List.rev (PMap.foldi (fun r p acc -> Printf.sprintf "%d@%X" r p :: acc) b.bwrite [])) in
|
|
|
+ write ("\t" ^ (if b.bloop then "LOOP " else "") ^ "NEED=" ^ need ^ "\tWRITE=" ^ wr);
|
|
|
+ b
|
|
|
+ with Not_found ->
|
|
|
+ block
|
|
|
+ in
|
|
|
+ let old = aget old_code i in
|
|
|
+ let op = op i in
|
|
|
+ let rec live_loop r l =
|
|
|
+ if r = nregs then List.rev l else
|
|
|
+ live_loop (r + 1) (if is_live r i then r :: l else l)
|
|
|
+ in
|
|
|
+ let live = "LIVE=" ^ String.concat "," (List.map string_of_int (live_loop 0 [])) in
|
|
|
+ let var_set = (try let v = Hashtbl.find old_assigns i in "set " ^ get_str v with Not_found -> "") in
|
|
|
+ let nvar_set = (try let v = Hashtbl.find new_assigns i in "set " ^ String.concat "," (List.map get_str !v) with Not_found -> "") in
|
|
|
+ write (Printf.sprintf "\t@%-3X %-20s %-20s %-20s %-20s %s" i (ostr string_of_int old) (if opcode_eq old op then "" else ostr string_of_int op) var_set nvar_set live);
|
|
|
+ loop (i + 1) block
|
|
|
+ in
|
|
|
+ write (Printf.sprintf "%s@%d" (fundecl_name f) f.findex);
|
|
|
+ let rec loop_arg = function
|
|
|
+ | [] -> []
|
|
|
+ | (_,p) :: _ when p >= 0 -> []
|
|
|
+ | (str,p) :: l -> (get_str str ^ ":" ^ string_of_int p) :: loop_arg l
|
|
|
+ in
|
|
|
+ write (Printf.sprintf "ARGS = %s\n" (String.concat ", " (loop_arg (Array.to_list f.assigns))));
|
|
|
+ if reg_remap then begin
|
|
|
+ for i=0 to nregs-1 do
|
|
|
+ write (Printf.sprintf "\tr%-2d %-10s%s" i (tstr f.regs.(i)) (if ctx.r_reg_map.(i) < 0 then " unused" else if ctx.r_reg_map.(i) = i then "" else Printf.sprintf " r%-2d" ctx.r_reg_map.(i)))
|
|
|
+ done;
|
|
|
+ end;
|
|
|
+ loop 0 ctx.r_root;
|
|
|
+ write "";
|
|
|
+ write "";
|
|
|
+ (match dump with None -> () | Some ch -> IO.flush ch);
|
|
|
+ end;
|
|
|
+
|
|
|
+ let code = ref f.code in
|
|
|
+ let regs = ref f.regs in
|
|
|
+ let debug = ref f.debug in
|
|
|
+
|
|
|
+ if ctx.r_nop_count > 0 || reg_remap then begin
|
|
|
+ let new_pos = Array.make (Array.length f.code) 0 in
|
|
|
+ let jumps = ref [] in
|
|
|
+ let out_pos = ref 0 in
|
|
|
+ let out_code = Array.make (Array.length f.code - ctx.r_nop_count) (ONop "") in
|
|
|
+ let new_debug = Array.make (Array.length f.code - ctx.r_nop_count) (0,0) in
|
|
|
+ Array.iteri (fun i op ->
|
|
|
+ Array.unsafe_set new_pos i !out_pos;
|
|
|
+ match op with
|
|
|
+ | ONop _ -> ()
|
|
|
+ | _ ->
|
|
|
+ (match op with
|
|
|
+ | OJTrue _ | OJFalse _ | OJNull _ | OJNotNull _ | OJSLt _ | OJSGte _ | OJSGt _ | OJSLte _ | OJNotLt _ | OJNotGte _ | OJULt _ | OJUGte _ | OJEq _ | OJNotEq _ | OJAlways _ | OSwitch _ | OTrap _ ->
|
|
|
+ jumps := i :: !jumps
|
|
|
+ | _ -> ());
|
|
|
+ let op = if reg_remap then opcode_map (fun r -> aget reg_map r) (fun r -> aget reg_map r) op else op in
|
|
|
+ aset out_code (!out_pos) op;
|
|
|
+ aset new_debug (!out_pos) (aget f.debug i);
|
|
|
+ incr out_pos
|
|
|
+ ) f.code;
|
|
|
+ List.iter (fun j ->
|
|
|
+ let pos d =
|
|
|
+ aget new_pos (j + 1 + d) - aget new_pos (j + 1)
|
|
|
+ in
|
|
|
+ let p = new_pos.(j) in
|
|
|
+ aset out_code p (match aget out_code p with
|
|
|
+ | OJTrue (r,d) -> OJTrue (r,pos d)
|
|
|
+ | OJFalse (r,d) -> OJFalse (r,pos d)
|
|
|
+ | OJNull (r,d) -> OJNull (r, pos d)
|
|
|
+ | OJNotNull (r,d) -> OJNotNull (r, pos d)
|
|
|
+ | OJSLt (a,b,d) -> OJSLt (a,b,pos d)
|
|
|
+ | OJSGte (a,b,d) -> OJSGte (a,b,pos d)
|
|
|
+ | OJSLte (a,b,d) -> OJSLte (a,b,pos d)
|
|
|
+ | OJSGt (a,b,d) -> OJSGt (a,b,pos d)
|
|
|
+ | OJULt (a,b,d) -> OJULt (a,b,pos d)
|
|
|
+ | OJUGte (a,b,d) -> OJUGte (a,b,pos d)
|
|
|
+ | OJNotLt (a,b,d) -> OJNotLt (a,b,pos d)
|
|
|
+ | OJNotGte (a,b,d) -> OJNotGte (a,b,pos d)
|
|
|
+ | OJEq (a,b,d) -> OJEq (a,b,pos d)
|
|
|
+ | OJNotEq (a,b,d) -> OJNotEq (a,b,pos d)
|
|
|
+ | OJAlways d -> OJAlways (pos d)
|
|
|
+ | OSwitch (r,cases,send) -> OSwitch (r, Array.map pos cases, pos send)
|
|
|
+ | OTrap (r,d) -> OTrap (r,pos d)
|
|
|
+ | _ -> assert false)
|
|
|
+ ) !jumps;
|
|
|
+
|
|
|
+ let assigns = !assigns in
|
|
|
+ Array.iteri (fun idx (i,p) -> if p >= 0 then aset assigns idx (i, aget new_pos p)) assigns;
|
|
|
+
|
|
|
+ code := out_code;
|
|
|
+ debug := new_debug;
|
|
|
+ if reg_remap then begin
|
|
|
+ let new_regs = Array.make ctx.r_used_regs HVoid in
|
|
|
+ for i=0 to nregs-1 do
|
|
|
+ let p = aget reg_map i in
|
|
|
+ if p >= 0 then aset new_regs p (aget f.regs i)
|
|
|
+ done;
|
|
|
+ regs := new_regs;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+ { f with code = !code; regs = !regs; debug = !debug; assigns = !assigns }
|
|
|
+
|
|
|
+let _optimize (f:fundecl) =
|
|
|
+ let nregs = Array.length f.regs in
|
|
|
let op index = f.code.(index) in
|
|
|
let set_op index op = f.code.(index) <- op in
|
|
|
let nop_count = ref 0 in
|
|
|
let set_nop index r = f.code.(index) <- (ONop r); incr nop_count in
|
|
|
- let write str = match dump with None -> () | Some ch -> IO.nwrite ch (Bytes.unsafe_of_string (str ^ "\n")) in
|
|
|
|
|
|
let blocks_pos, root = code_graph f in
|
|
|
|
|
@@ -539,7 +749,7 @@ let optimize dump get_str (f:fundecl) =
|
|
|
r.ralias <- r;
|
|
|
r
|
|
|
) in
|
|
|
-
|
|
|
+(*
|
|
|
let print_state i s =
|
|
|
let state_str s =
|
|
|
if s.ralias == s && s.rbind == [] then "" else
|
|
@@ -547,8 +757,7 @@ let optimize dump get_str (f:fundecl) =
|
|
|
in
|
|
|
write (Printf.sprintf "@%X %s" i (String.concat " " (Array.to_list (Array.map state_str s))))
|
|
|
in
|
|
|
-
|
|
|
- let dstate = false in
|
|
|
+*)
|
|
|
|
|
|
let rec propagate b =
|
|
|
let state = if b.bloop then
|
|
@@ -614,7 +823,7 @@ let optimize dump get_str (f:fundecl) =
|
|
|
in
|
|
|
if i > b.bend then () else
|
|
|
let op = op i in
|
|
|
- if dstate then print_state i state;
|
|
|
+ (* print_state i state; (* debug *) *)
|
|
|
(match op with
|
|
|
| OIncr r | ODecr r | ORef (_,r) -> unalias state.(r)
|
|
|
| OCallClosure (_,r,_) when f.regs.(r) = HDyn && (match f.regs.(state.(r).ralias.rindex) with HFun (_,rt) -> not (is_dynamic rt) | HDyn -> false | _ -> true) -> unalias state.(r) (* Issue3218.hx *)
|
|
@@ -766,187 +975,74 @@ let optimize dump get_str (f:fundecl) =
|
|
|
end else
|
|
|
reg_map.(i) <- -1;
|
|
|
done;
|
|
|
- let reg_remap = !used_regs <> nregs in
|
|
|
- let assigns = ref f.assigns in
|
|
|
-
|
|
|
- (* remap assigns *)
|
|
|
- if !nop_count > 0 then begin
|
|
|
- let rec resolve_block p =
|
|
|
- try Hashtbl.find blocks_pos p with Not_found -> resolve_block (p - 1)
|
|
|
- in
|
|
|
-
|
|
|
- let new_assigns = List.fold_left (fun acc (i,p) ->
|
|
|
- let gmap = Hashtbl.create 0 in
|
|
|
- (*
|
|
|
- For a given assign at position p, that's been optimized out,
|
|
|
- let's try to find where the last assign that maps to the same value
|
|
|
- is, and remap the variable name to it
|
|
|
- *)
|
|
|
- let rec loop p =
|
|
|
- if p < 0 || (match f.code.(p) with ONop _ -> false | _ -> true) then [(i,p)] else
|
|
|
- let reg, last_w = try Hashtbl.find reg_moved p with Not_found -> (-1,-1) in
|
|
|
- if reg < 0 then [] (* ? *) else
|
|
|
- if reg < nargs then [(i,-reg-1)] else
|
|
|
- let b = resolve_block p in
|
|
|
- if last_w >= b.bstart && last_w < b.bend && last_w < p then loop last_w else
|
|
|
- let wp = try PMap.find reg b.bwrite with Not_found -> -1 in
|
|
|
- let rec gather b =
|
|
|
- if Hashtbl.mem gmap b.bstart then [] else begin
|
|
|
- Hashtbl.add gmap b.bstart ();
|
|
|
- (* lookup in all parent blocks, recursively, to fetch all last writes *)
|
|
|
- List.fold_left (fun acc bp ->
|
|
|
- if bp.bstart > b.bstart then acc else
|
|
|
- try
|
|
|
- let wp = PMap.find reg bp.bwrite in
|
|
|
- if wp > p then assert false;
|
|
|
- loop wp @ acc
|
|
|
- with Not_found ->
|
|
|
- gather bp @ acc
|
|
|
- ) [] b.bprev;
|
|
|
- end
|
|
|
- in
|
|
|
- if wp < 0 then
|
|
|
- gather b
|
|
|
- else if wp < p then
|
|
|
- loop wp
|
|
|
- else
|
|
|
- (* lookup in writes between p-1 and block bstart *)
|
|
|
- let rec find_w p =
|
|
|
- if p < b.bstart then
|
|
|
- gather b
|
|
|
- else
|
|
|
- let found = ref false in
|
|
|
- opcode_fx (fun r read -> if r = reg && not read then found := true) old_code.(p);
|
|
|
- if !found then loop p else find_w (p - 1)
|
|
|
- in
|
|
|
- find_w (p - 1)
|
|
|
- in
|
|
|
- loop p @ acc
|
|
|
- ) [] (Array.to_list !assigns) in
|
|
|
- let new_assigns = List.sort (fun (_,p1) (_,p2) -> p1 - p2) (List.rev new_assigns) in
|
|
|
- assigns := Array.of_list new_assigns;
|
|
|
- end;
|
|
|
+ {
|
|
|
+ r_root = root;
|
|
|
+ r_blocks_pos = blocks_pos;
|
|
|
+ r_nop_count = !nop_count;
|
|
|
+ r_used_regs = !used_regs;
|
|
|
+ r_live_bits = live_bits;
|
|
|
+ r_reg_map = reg_map;
|
|
|
+ r_reg_moved = reg_moved;
|
|
|
+ }
|
|
|
|
|
|
- (* done *)
|
|
|
- if dump <> None then begin
|
|
|
- let old_assigns = Hashtbl.create 0 in
|
|
|
- let new_assigns = Hashtbl.create 0 in
|
|
|
- Array.iter (fun (var,pos) -> if pos >= 0 then Hashtbl.replace old_assigns pos var) f.assigns;
|
|
|
- Array.iter (fun (var,pos) ->
|
|
|
- if pos >= 0 then begin
|
|
|
- let f = try Hashtbl.find new_assigns pos with Not_found -> let v = ref [] in Hashtbl.add new_assigns pos v; v in
|
|
|
- f := var :: !f;
|
|
|
- end
|
|
|
- ) !assigns;
|
|
|
- let rec loop i block =
|
|
|
- if i = Array.length f.code then () else
|
|
|
- let block = try
|
|
|
- let b = Hashtbl.find blocks_pos i in
|
|
|
- write (Printf.sprintf "\t----- [%s] (%X)"
|
|
|
- (String.concat "," (List.map (fun b -> Printf.sprintf "%X" b.bstart) b.bnext))
|
|
|
- b.bend
|
|
|
- );
|
|
|
- let need = String.concat "," (List.map string_of_int (ISet.elements b.bneed)) in
|
|
|
- let wr = String.concat " " (List.rev (PMap.foldi (fun r p acc -> Printf.sprintf "%d@%X" r p :: acc) b.bwrite [])) in
|
|
|
- write ("\t" ^ (if b.bloop then "LOOP " else "") ^ "NEED=" ^ need ^ "\tWRITE=" ^ wr);
|
|
|
- b
|
|
|
- with Not_found ->
|
|
|
- block
|
|
|
- in
|
|
|
- let old = old_code.(i) in
|
|
|
- let op = op i in
|
|
|
- let rec live_loop r l =
|
|
|
- if r = nregs then List.rev l else
|
|
|
- live_loop (r + 1) (if is_live r i then r :: l else l)
|
|
|
- in
|
|
|
- let live = "LIVE=" ^ String.concat "," (List.map string_of_int (live_loop 0 [])) in
|
|
|
- let var_set = (try let v = Hashtbl.find old_assigns i in "set " ^ get_str v with Not_found -> "") in
|
|
|
- let nvar_set = (try let v = Hashtbl.find new_assigns i in "set " ^ String.concat "," (List.map get_str !v) with Not_found -> "") in
|
|
|
- write (Printf.sprintf "\t@%-3X %-20s %-20s %-20s %-20s %s" i (ostr string_of_int old) (if opcode_eq old op then "" else ostr string_of_int op) var_set nvar_set live);
|
|
|
- loop (i + 1) block
|
|
|
- in
|
|
|
- write (Printf.sprintf "%s@%d" (fundecl_name f) f.findex);
|
|
|
- let rec loop_arg = function
|
|
|
- | [] -> []
|
|
|
- | (_,p) :: _ when p >= 0 -> []
|
|
|
- | (str,p) :: l -> (get_str str ^ ":" ^ string_of_int p) :: loop_arg l
|
|
|
- in
|
|
|
- write (Printf.sprintf "ARGS = %s\n" (String.concat ", " (loop_arg (Array.to_list f.assigns))));
|
|
|
- if reg_remap then begin
|
|
|
- for i=0 to nregs-1 do
|
|
|
- write (Printf.sprintf "\tr%-2d %-10s%s" i (tstr f.regs.(i)) (if reg_map.(i) < 0 then " unused" else if reg_map.(i) = i then "" else Printf.sprintf " r%-2d" reg_map.(i)))
|
|
|
- done;
|
|
|
- end;
|
|
|
- loop 0 root;
|
|
|
- write "";
|
|
|
- write "";
|
|
|
- (match dump with None -> () | Some ch -> IO.flush ch);
|
|
|
- end;
|
|
|
-
|
|
|
- (* remap *)
|
|
|
-
|
|
|
- let code = ref f.code in
|
|
|
- let regs = ref f.regs in
|
|
|
- let debug = ref f.debug in
|
|
|
-
|
|
|
- if !nop_count > 0 || reg_remap then begin
|
|
|
- let new_pos = Array.make (Array.length f.code) 0 in
|
|
|
- let jumps = ref [] in
|
|
|
- let out_pos = ref 0 in
|
|
|
- let out_code = Array.make (Array.length f.code - !nop_count) (ONop "") in
|
|
|
- let new_debug = Array.make (Array.length f.code - !nop_count) (0,0) in
|
|
|
- Array.iteri (fun i op ->
|
|
|
- Array.unsafe_set new_pos i !out_pos;
|
|
|
- match op with
|
|
|
- | ONop _ -> ()
|
|
|
- | _ ->
|
|
|
- (match op with
|
|
|
- | OJTrue _ | OJFalse _ | OJNull _ | OJNotNull _ | OJSLt _ | OJSGte _ | OJSGt _ | OJSLte _ | OJNotLt _ | OJNotGte _ | OJULt _ | OJUGte _ | OJEq _ | OJNotEq _ | OJAlways _ | OSwitch _ | OTrap _ ->
|
|
|
- jumps := i :: !jumps
|
|
|
- | _ -> ());
|
|
|
- let op = if reg_remap then opcode_map (fun r -> reg_map.(r)) (fun r -> reg_map.(r)) op else op in
|
|
|
- out_code.(!out_pos) <- op;
|
|
|
- new_debug.(!out_pos) <- f.debug.(i);
|
|
|
- incr out_pos
|
|
|
- ) f.code;
|
|
|
- List.iter (fun j ->
|
|
|
- let pos d =
|
|
|
- new_pos.(j + 1 + d) - new_pos.(j + 1)
|
|
|
- in
|
|
|
- let p = new_pos.(j) in
|
|
|
- out_code.(p) <- (match out_code.(p) with
|
|
|
- | OJTrue (r,d) -> OJTrue (r,pos d)
|
|
|
- | OJFalse (r,d) -> OJFalse (r,pos d)
|
|
|
- | OJNull (r,d) -> OJNull (r, pos d)
|
|
|
- | OJNotNull (r,d) -> OJNotNull (r, pos d)
|
|
|
- | OJSLt (a,b,d) -> OJSLt (a,b,pos d)
|
|
|
- | OJSGte (a,b,d) -> OJSGte (a,b,pos d)
|
|
|
- | OJSLte (a,b,d) -> OJSLte (a,b,pos d)
|
|
|
- | OJSGt (a,b,d) -> OJSGt (a,b,pos d)
|
|
|
- | OJULt (a,b,d) -> OJULt (a,b,pos d)
|
|
|
- | OJUGte (a,b,d) -> OJUGte (a,b,pos d)
|
|
|
- | OJNotLt (a,b,d) -> OJNotLt (a,b,pos d)
|
|
|
- | OJNotGte (a,b,d) -> OJNotGte (a,b,pos d)
|
|
|
- | OJEq (a,b,d) -> OJEq (a,b,pos d)
|
|
|
- | OJNotEq (a,b,d) -> OJNotEq (a,b,pos d)
|
|
|
- | OJAlways d -> OJAlways (pos d)
|
|
|
- | OSwitch (r,cases,send) -> OSwitch (r, Array.map pos cases, pos send)
|
|
|
- | OTrap (r,d) -> OTrap (r,pos d)
|
|
|
- | _ -> assert false)
|
|
|
- ) !jumps;
|
|
|
-
|
|
|
- Array.iteri (fun idx (i,p) -> if p >= 0 then (!assigns).(idx) <- (i, new_pos.(p))) !assigns;
|
|
|
+type cache_elt = {
|
|
|
+ c_hfx : Type.tfunc;
|
|
|
+ c_code : opcode array;
|
|
|
+ c_rctx : rctx;
|
|
|
+ mutable c_last_used : int;
|
|
|
+}
|
|
|
|
|
|
- code := out_code;
|
|
|
- debug := new_debug;
|
|
|
- if reg_remap then begin
|
|
|
- let new_regs = Array.make !used_regs HVoid in
|
|
|
- for i=0 to nregs-1 do
|
|
|
- let p = reg_map.(i) in
|
|
|
- if p >= 0 then new_regs.(p) <- f.regs.(i)
|
|
|
- done;
|
|
|
- regs := new_regs;
|
|
|
- end;
|
|
|
- end;
|
|
|
+let opt_cache = Hashtbl.create 0
|
|
|
+let used_mark = ref 0
|
|
|
|
|
|
- { f with code = !code; regs = !regs; debug = !debug; assigns = !assigns }
|
|
|
+let optimize dump get_str (f:fundecl) hxf =
|
|
|
+ try
|
|
|
+ let c = Hashtbl.find opt_cache f.fpath in
|
|
|
+ if c.c_hfx != hxf then raise Not_found;
|
|
|
+ c.c_last_used <- !used_mark;
|
|
|
+ if Array.length f.code <> Array.length c.c_code then assert false;
|
|
|
+ let f = { f with code = Array.mapi (fun i op ->
|
|
|
+ match op, Array.unsafe_get f.code i with
|
|
|
+ (* only regs : ok ! *)
|
|
|
+ | OInt (r,_), OInt (_,idx) -> OInt (r,idx)
|
|
|
+ | OFloat (r,_), OFloat (_,idx) -> OFloat (r,idx)
|
|
|
+ | OBytes (r,_), OBytes (_,idx) -> OBytes (r,idx)
|
|
|
+ | OString (r,_), OString (_,idx) -> OString (r,idx)
|
|
|
+ | OCall0 (r,_), OCall0 (_,idx) -> OCall0 (r,idx)
|
|
|
+ | OCall1 (r,_,a), OCall1 (_,idx,_) -> OCall1 (r,idx,a)
|
|
|
+ | OCall2 (r,_,a,b), OCall2 (_,idx,_,_) -> OCall2 (r,idx,a,b)
|
|
|
+ | OCall3 (r,_,a,b,c), OCall3 (_,idx,_,_,_) -> OCall3 (r,idx,a,b,c)
|
|
|
+ | OCall4 (r,_,a,b,c,d), OCall4 (_,idx,_,_,_,_) -> OCall4 (r,idx,a,b,c,d)
|
|
|
+ | OCallN (r,_,pl), OCallN (_,idx,_) -> OCallN (r,idx,pl)
|
|
|
+ | OStaticClosure (r,_), OStaticClosure (_,idx) -> OStaticClosure (r,idx)
|
|
|
+ | OInstanceClosure (r,_,v), OInstanceClosure (_,idx,_) -> OInstanceClosure (r,idx,v)
|
|
|
+ | OGetGlobal (r,_), OGetGlobal (_,g) -> OGetGlobal (r,g)
|
|
|
+ | OSetGlobal (_,v), OSetGlobal (g,_) -> OSetGlobal (g,v)
|
|
|
+ | ODynGet (r,o,_), ODynGet (_,_,idx) -> ODynGet (r,o,idx)
|
|
|
+ | ODynSet (o,_,v), ODynSet (_,idx,_) -> ODynSet (o,idx,v)
|
|
|
+ | OType (r,_), OType (_,t) -> OType (r,t)
|
|
|
+ | (ONop _ | OMov _ | OBool _ | ONull _
|
|
|
+ | OAdd _ | OSub _ | OMul _ | OSDiv _ | OUDiv _ | OSMod _ | OUMod _ | OShl _ | OSShr _ | OUShr _ | OAnd _ | OOr _ | OXor _
|
|
|
+ | ONeg _ | ONot _ | OIncr _ | ODecr _ | OCallMethod _ | OCallThis _ | OCallClosure _ | OVirtualClosure _
|
|
|
+ | OField _ | OSetField _ | OGetThis _ | OSetThis _
|
|
|
+ | OJTrue _ | OJFalse _ | OJNull _ | OJNotNull _ | OJSLt _ | OJSGte _ | OJSGt _ | OJSLte _ | OJULt _ | OJUGte _ | OJNotLt _ | OJNotGte _ | OJEq _ | OJNotEq _ | OJAlways _
|
|
|
+ | OToDyn _ | OToSFloat _ | OToUFloat _ | OToInt _ | OSafeCast _ | OUnsafeCast _ | OToVirtual _ | OLabel _ | ORet _ | OThrow _ | ORethrow _ | OSwitch _ | ONullCheck _
|
|
|
+ | OTrap _ | OEndTrap _ | OGetUI8 _ | OGetUI16 _ | OGetMem _ | OGetArray _ | OSetUI8 _ | OSetUI16 _ | OSetMem _ | OSetArray _ | ONew _ | OArraySize _ | OGetType _
|
|
|
+ | OGetTID _ | ORef _ | OUnref _ | OSetref _ | OMakeEnum _ | OEnumAlloc _ | OEnumIndex _ | OEnumField _ | OSetEnumField _ | OAssert _ | ORefData _ | ORefOffset _)
|
|
|
+ , _ -> op
|
|
|
+ | a, b ->
|
|
|
+ prerr_endline (ostr get_str a);
|
|
|
+ prerr_endline (ostr get_str b);
|
|
|
+ assert false
|
|
|
+ ) c.c_code } in
|
|
|
+ remap_fun c.c_rctx f dump get_str
|
|
|
+ with Not_found ->
|
|
|
+ let rctx = _optimize f in
|
|
|
+ let fopt = remap_fun rctx f dump get_str in
|
|
|
+ if f.fpath <> ("","") then Hashtbl.replace opt_cache f.fpath {
|
|
|
+ c_hfx = hxf;
|
|
|
+ c_code = f.code;
|
|
|
+ c_rctx = rctx;
|
|
|
+ c_last_used = !used_mark;
|
|
|
+ };
|
|
|
+ fopt
|