aboutsummaryrefslogtreecommitdiffstats
path: root/scheduling/RTLpathScheduleraux.ml
diff options
context:
space:
mode:
Diffstat (limited to 'scheduling/RTLpathScheduleraux.ml')
-rw-r--r--scheduling/RTLpathScheduleraux.ml498
1 files changed, 0 insertions, 498 deletions
diff --git a/scheduling/RTLpathScheduleraux.ml b/scheduling/RTLpathScheduleraux.ml
deleted file mode 100644
index 659a8ba7..00000000
--- a/scheduling/RTLpathScheduleraux.ml
+++ /dev/null
@@ -1,498 +0,0 @@
-open DebugPrint
-open Machine
-open RTLpathLivegenaux
-open RTLpath
-open RTLpathCommon
-open RTL
-open Maps
-open Registers
-open ExpansionOracle
-open RTLcommonaux
-
-let config = Machine.config
-
-let print_superblock (sb: superblock) code =
- let insts = sb.instructions in
- let li = sb.liveins in
- let outs = sb.s_output_regs in
- begin
- debug "{ instructions = "; print_instructions (Array.to_list insts) code; debug "\n";
- debug " liveins = "; print_ptree_regset li; debug "\n";
- debug " output_regs = "; print_regset outs; debug "\n}"
- end
-
-let print_superblocks lsb code =
- let rec f = function
- | [] -> ()
- | sb :: lsb -> (print_superblock sb code; debug ",\n"; f lsb)
- in begin
- debug "[\n";
- f lsb;
- debug "]"
- end
-
-let get_superblocks code entry pm typing =
- let visited = ref (PTree.map (fun n i -> false) code) in
- let rec get_superblocks_rec pc =
- let liveins = ref (PTree.empty) in
- let rec follow pc n =
- let inst = get_some @@ PTree.get pc code in
- if (n == 0) then begin
- (match (non_predicted_successors inst) with
- | [pcout] ->
- let live = (get_some @@ PTree.get pcout pm).input_regs in
- liveins := PTree.set pc live !liveins
- | _ -> ());
- ([pc], successors_inst inst)
- end else
- let nexts_from_exit = match (non_predicted_successors inst) with
- | [pcout] ->
- let live = (get_some @@ PTree.get pcout pm).input_regs in begin
- liveins := PTree.set pc live !liveins;
- [pcout]
- end
- | [] -> []
- | _ -> failwith "Having more than one non_predicted_successor is not handled"
- in match (predicted_successor inst) with
- | None -> failwith "Incorrect path"
- | Some succ ->
- let (insts, nexts) = follow succ (n-1) in (pc :: insts, nexts_from_exit @ nexts)
- in if (get_some @@ PTree.get pc !visited) then []
- else begin
- visited := PTree.set pc true !visited;
- let pi = get_some @@ PTree.get pc pm in
- let (insts, nexts) = follow pc (Camlcoq.Nat.to_int pi.psize) in
- let superblock = { instructions = Array.of_list insts; liveins = !liveins;
- s_output_regs = pi.output_regs; typing = typing } in
- superblock :: (List.concat @@ List.map get_superblocks_rec nexts)
- end
- in let lsb = get_superblocks_rec entry in begin
- (* debug_flag := true; *)
- debug "Superblocks identified:"; print_superblocks lsb code; debug "\n";
- (* debug_flag := false; *)
- lsb
-end
-
-(** the useful one. Returns a hashtable with bindings of shape
- ** [(r,(t, n)], where [r] is a pseudo-register (Registers.reg),
- ** [t] is its class (according to [typing]), and [n] the number of
- ** times it's referenced as an argument in instructions of [seqa] ;
- ** and an arrray containg the list of regs referenced by each
- ** instruction, with a boolean to know whether it's as arg or dest *)
-let reference_counting (seqa : (instruction * Regset.t) array)
- (out_regs : Registers.Regset.t) (typing : RTLtyping.regenv) :
- (Registers.reg, int * int) Hashtbl.t *
- (Registers.reg * bool) list array =
- let retl = Hashtbl.create 42 in
- let retr = Array.make (Array.length seqa) [] in
- (* retr.(i) : (r, b) -> (r', b') -> ...
- * where b = true if seen as arg, false if seen as dest
- *)
- List.iter (fun reg ->
- Hashtbl.add retl
- reg (Machregsaux.class_of_type (typing reg), 1)
- ) (Registers.Regset.elements out_regs);
- let add_reg reg =
- match Hashtbl.find_opt retl reg with
- | Some (t, n) -> Hashtbl.add retl reg (t, n+1)
- | None -> Hashtbl.add retl reg (Machregsaux.class_of_type
- (typing reg), 1)
- in
- let map_true = List.map (fun r -> r, true) in
- Array.iteri (fun i (ins, _) ->
- match ins with
- | Iop(_,args,dest,_) | Iload(_,_,_,args,dest,_) ->
- List.iter (add_reg) args;
- retr.(i) <- (dest, false)::(map_true args)
- | Icond(_,args,_,_,_) ->
- List.iter (add_reg) args;
- retr.(i) <- map_true args
- | Istore(_,_,args,src,_) ->
- List.iter (add_reg) args;
- add_reg src;
- retr.(i) <- (src, true)::(map_true args)
- | Icall(_,fn,args,dest,_) ->
- List.iter (add_reg) args;
- retr.(i) <- (match fn with
- | Datatypes.Coq_inl reg ->
- add_reg reg;
- (dest,false)::(reg, true)::(map_true args)
- | _ -> (dest,false)::(map_true args))
-
- | Itailcall(_,fn,args) ->
- List.iter (add_reg) args;
- retr.(i) <- (match fn with
- | Datatypes.Coq_inl reg ->
- add_reg reg;
- (reg, true)::(map_true args)
- | _ -> map_true args)
- | Ibuiltin(_,args,dest,_) ->
- let rec bar = function
- | AST.BA r -> add_reg r;
- retr.(i) <- (r, true)::retr.(i)
- | AST.BA_splitlong (hi, lo) | AST.BA_addptr (hi, lo) ->
- bar hi; bar lo
- | _ -> ()
- in
- List.iter (bar) args;
- let rec bad = function
- | AST.BR r -> retr.(i) <- (r, false)::retr.(i)
- | AST.BR_splitlong (hi, lo) ->
- bad hi; bad lo
- | _ -> ()
- in
- bad dest;
- | Ijumptable (reg,_) | Ireturn (Some reg) ->
- add_reg reg;
- retr.(i) <- [reg, true]
- | _ -> ()
- ) seqa;
- (* print_string "mentions\n";
- * Array.iteri (fun i l ->
- * print_int i;
- * print_string ": [";
- * List.iter (fun (r, b) ->
- * print_int (Camlcoq.P.to_int r);
- * print_string ":";
- * print_string (if b then "a:" else "d");
- * if b then print_int (snd (Hashtbl.find retl r));
- * print_string ", "
- * ) l;
- * print_string "]\n";
- * flush stdout;
- * ) retr; *)
- retl, retr
-
-
-let get_live_regs_entry (sb : superblock) code =
- (if !Clflags.option_debug_compcert > 6
- then debug_flag := true);
- debug "getting live regs for superblock:\n";
- print_superblock sb code;
- debug "\n";
- let seqa = Array.map (fun i ->
- (match PTree.get i code with
- | Some ii -> ii
- | None -> failwith "RTLpathScheduleraux.get_live_regs_entry"
- ),
- (match PTree.get i sb.liveins with
- | Some s -> s
- | None -> Regset.empty))
- sb.instructions in
- let ret =
- Array.fold_right (fun (ins, liveins) regset_i ->
- let regset = Registers.Regset.union liveins regset_i in
- match ins with
- | Inop _ -> regset
- | Iop (_, args, dest, _)
- | Iload (_, _, _, args, dest, _) ->
- List.fold_left (fun set reg -> Registers.Regset.add reg set)
- (Registers.Regset.remove dest regset) args
- | Istore (_, _, args, src, _) ->
- List.fold_left (fun set reg -> Registers.Regset.add reg set)
- (Registers.Regset.add src regset) args
- | Icall (_, fn, args, dest, _) ->
- List.fold_left (fun set reg -> Registers.Regset.add reg set)
- ((match fn with
- | Datatypes.Coq_inl reg -> (Registers.Regset.add reg)
- | Datatypes.Coq_inr _ -> (fun x -> x))
- (Registers.Regset.remove dest regset))
- args
- | Itailcall (_, fn, args) ->
- List.fold_left (fun set reg -> Registers.Regset.add reg set)
- (match fn with
- | Datatypes.Coq_inl reg -> (Registers.Regset.add reg regset)
- | Datatypes.Coq_inr _ -> regset)
- args
- | Ibuiltin (_, args, dest, _) ->
- List.fold_left (fun set arg ->
- let rec add reg set =
- match reg with
- | AST.BA r -> Registers.Regset.add r set
- | AST.BA_splitlong (hi, lo)
- | AST.BA_addptr (hi, lo) -> add hi (add lo set)
- | _ -> set
- in add arg set)
- (let rec rem dest set =
- match dest with
- | AST.BR r -> Registers.Regset.remove r set
- | AST.BR_splitlong (hi, lo) -> rem hi (rem lo set)
- | _ -> set
- in rem dest regset)
- args
- | Icond (_, args, _, _, _) ->
- List.fold_left (fun set reg ->
- Registers.Regset.add reg set)
- regset args
- | Ijumptable (reg, _)
- | Ireturn (Some reg) ->
- Registers.Regset.add reg regset
- | _ -> regset
- ) seqa sb.s_output_regs
- in debug "live in regs: ";
- print_regset ret;
- debug "\n";
- debug_flag := false;
- ret
-
-(* TODO David *)
-let schedule_superblock sb code =
- if not !Clflags.option_fprepass
- then sb.instructions
- else
- (* let old_flag = !debug_flag in
- debug_flag := true;
- print_endline "ORIGINAL SUPERBLOCK";
- print_superblock sb code;
- debug_flag := old_flag; *)
- let nr_instr = Array.length sb.instructions in
- let trailer_length =
- match PTree.get (sb.instructions.(nr_instr-1)) code with
- | None -> 0
- | Some ii ->
- match predicted_successor ii with
- | Some _ -> 0
- | None -> 1 in
- debug "hello\n";
- let live_regs_entry = get_live_regs_entry sb code in
- let seqa =
- Array.map (fun i ->
- (match PTree.get i code with
- | Some ii -> ii
- | None -> failwith "RTLpathScheduleraux.schedule_superblock"),
- (match PTree.get i sb.liveins with
- | Some s -> s
- | None -> Regset.empty))
- (Array.sub sb.instructions 0 (nr_instr-trailer_length)) in
- match PrepassSchedulingOracle.schedule_sequence
- seqa
- live_regs_entry
- sb.typing
- (reference_counting seqa sb.s_output_regs sb.typing) with
- | None -> sb.instructions
- | Some order ->
- let ins' =
- Array.append
- (Array.map (fun i -> sb.instructions.(i)) order)
- (Array.sub sb.instructions (nr_instr-trailer_length) trailer_length) in
- (* Printf.printf "REORDERED SUPERBLOCK %d\n" (Array.length ins');
- debug_flag := true;
- print_instructions (Array.to_list ins') code;
- debug_flag := old_flag;
- flush stdout; *)
- assert ((Array.length sb.instructions) = (Array.length ins'));
- (*sb.instructions; *)
- ins';;
-
- (* stub2: reverse function *)
- (*
- let reversed = Array.of_list @@ List.rev @@ Array.to_list (sb.instructions) in
- let tmp = reversed.(0) in
- let last_index = Array.length reversed - 1 in
- begin
- reversed.(0) <- reversed.(last_index);
- reversed.(last_index) <- tmp;
- reversed
- end *)
- (* stub: identity function *)
-
-(**
- * Perform basic checks on the new order :
- * - must have the same length as the old order
- * - non basic instructions (call, tailcall, return, jumptable, non predicted CB) must not move
- *)
-let check_order code old_order new_order = begin
- assert ((Array.length old_order) == (Array.length new_order));
- let length = Array.length new_order in
- if length > 0 then
- let last_inst = Array.get old_order (length - 1) in
- let instr = get_some @@ PTree.get last_inst code in
- match predicted_successor instr with
- | None ->
- if (last_inst != Array.get new_order (length - 1)) then
- failwith "The last instruction of the superblock is not basic, but was moved"
- | _ -> ()
-end
-
-type sinst =
- (* Each middle instruction has a direct successor *)
- (* A Smid can be the last instruction of a superblock, but a Send cannot be moved *)
- | Smid of RTL.instruction * node
- | Send of RTL.instruction
-
-let rinst_to_sinst inst =
- match inst with
- | Inop n -> Smid(inst, n)
- | Iop (_,_,_,n) -> Smid(inst, n)
- | Iload (_,_,_,_,_,n) -> Smid(inst, n)
- | Istore (_,_,_,_,n) -> Smid(inst, n)
- | Icond (_,_,n1,n2,p) -> (
- match p with
- | Some true -> Smid(inst, n1)
- | Some false -> Smid(inst, n2)
- | None -> Send(inst)
- )
- | Icall _ | Ibuiltin _ | Ijumptable _ | Itailcall _ | Ireturn _ -> Send(inst)
-
-let change_predicted_successor s = function
- | Smid(i, n) -> Smid(i, s)
- | Send _ -> failwith "Called change_predicted_successor on Send. Are you trying to move a non-basic instruction in the middle of the block?"
-
-(* Forwards the successor changes into an RTL instruction *)
-let sinst_to_rinst = function
- | Smid(inst, s) -> (
- match inst with
- | Inop n -> Inop s
- | Iop (a,b,c,n) -> Iop (a,b,c,s)
- | Iload (a,b,c,d,e,n) -> Iload (a,b,c,d,e,s)
- | Istore (a,b,c,d,n) -> Istore (a,b,c,d,s)
- | Icond (a,b,n1,n2,p) -> (
- match p with
- | Some true -> Icond(a, b, s, n2, p)
- | Some false -> Icond(a, b, n1, s, p)
- | None -> failwith "Non predicted Icond as a middle instruction!"
- )
- | _ -> failwith "That instruction shouldn't be a middle instruction"
- )
- | Send i -> i
-
-let is_a_cb = function Icond _ -> true | _ -> false
-let is_a_load = function Iload _ -> true | _ -> false
-
-let find_array arr n =
- let index = ref None in
- begin
- Array.iteri (fun i n' ->
- if n = n' then
- match !index with
- | Some _ -> failwith "More than one element present"
- | None -> index := Some i
- ) arr;
- !index
- end
-
-let rec hashedset_from_list = function
- | [] -> HashedSet.PSet.empty
- | n::ln -> HashedSet.PSet.add n (hashedset_from_list ln)
-
-let hashedset_map f hs = hashedset_from_list @@ List.map f @@ HashedSet.PSet.elements hs
-
-let apply_schedule code sb new_order =
- let tc = ref code in
- let old_order = sb.instructions in
- let count_cbs order code =
- let current_cbs = ref HashedSet.PSet.empty in
- let cbs_above = ref PTree.empty in
- Array.iter (fun n ->
- let inst = get_some @@ PTree.get n code in
- if is_a_cb inst then current_cbs := HashedSet.PSet.add n !current_cbs
- else if is_a_load inst then cbs_above := PTree.set n !current_cbs !cbs_above
- ) order;
- !cbs_above
- in let fmap n =
- let index = get_some @@ find_array new_order n in
- old_order.(index)
- in begin
- check_order code old_order new_order;
- (* First pass - modify the positions, nothing else *)
- Array.iteri (fun i n' ->
- let inst' = get_some @@ PTree.get n' code in
- let iend = Array.length old_order - 1 in
- let new_inst =
- if (i == iend) then
- let final_inst_node = Array.get old_order iend in
- let sinst' = rinst_to_sinst inst' in
- match sinst' with
- (* The below assert fails if a Send is in the middle of the original superblock *)
- | Send i -> (assert (final_inst_node == n'); i)
- | Smid _ ->
- let final_inst = get_some @@ PTree.get final_inst_node code in
- match rinst_to_sinst final_inst with
- | Smid (_, s') -> sinst_to_rinst @@ change_predicted_successor s' sinst'
- | Send _ -> assert(false) (* should have failed earlier *)
- else
- sinst_to_rinst
- (* this will fail if the moved instruction is a Send *)
- @@ change_predicted_successor (Array.get old_order (i+1))
- @@ rinst_to_sinst inst'
- in tc := PTree.set (Array.get old_order i) new_inst !tc
- ) new_order;
- (* Second pass - turn the loads back into trapping when it was not needed *)
- (* 1) We remember which CBs are "above" a given load *)
- let cbs_above = count_cbs old_order code in
- (* 2) We do the same for new_order *)
- let cbs_above' = count_cbs (Array.map fmap new_order) !tc in
- (* 3) We examine each load, turn it back into trapping if cbs_above is included in cbs_above' *)
- Array.iter (fun n ->
- let n' = fmap n in
- let inst' = get_some @@ PTree.get n' !tc in
- match inst' with
- | Iload (t,a,b,c,d,s) ->
- let pset = hashedset_map fmap @@ get_some @@ PTree.get n cbs_above in
- let pset' = get_some @@ PTree.get n' cbs_above' in
- if HashedSet.PSet.is_subset pset pset' then tc := PTree.set n' (Iload (AST.TRAP,a,b,c,d,s)) !tc
- else assert !config.has_non_trapping_loads
- | _ -> ()
- ) old_order;
- !tc
- end
-
-let turn_all_loads_nontrap sb code =
- if not !config.has_non_trapping_loads then code
- else begin
- let code' = ref code in
- Array.iter (fun n ->
- let inst = get_some @@ PTree.get n code in
- match inst with
- | Iload (t,a,b,c,d,s) -> code' := PTree.set n (Iload (AST.NOTRAP,a,b,c,d,s)) !code'
- | _ -> ()
- ) sb.instructions;
- !code'
- end
-
-let rec do_schedule code pm = function
- | [] -> (code, pm)
- | sb :: lsb ->
- (*debug_flag := true;*)
- let (code_exp, pm) = expanse sb code pm in
- (*debug_flag := false;*)
- (* Trick: instead of turning loads into non trap as needed..
- * First, we turn them all into non-trap.
- * Then, we turn back those who didn't need to be turned, into TRAP again
- * This is because the scheduler (rightfully) refuses to schedule ahead of a branch
- * operations that might trap *)
- let code' = turn_all_loads_nontrap sb code_exp in
- let schedule = schedule_superblock sb code' in
- let new_code = apply_schedule code' sb schedule in
- begin
- (*debug_flag := true;*)
- if code != code_exp then (
- debug "Old Code: "; print_code code;
- debug "Exp Code: "; print_code code_exp);
- debug "\nSchedule to apply: "; print_arrayp schedule;
- debug "\nNew Code: "; print_code new_code;
- debug "\n";
- do_schedule new_code pm lsb
- end
-
-let get_ok r = match r with Errors.OK x -> x | _ -> failwith "Did not get OK"
-
-let scheduler f =
- let code = f.fn_RTL.fn_code in
- let id_ptree = PTree.map (fun n i -> n) (f.fn_path) in
- let entry = f.fn_RTL.fn_entrypoint in
- let pm = f.fn_path in
- let typing = get_ok @@ RTLtyping.type_function f.fn_RTL in
- let lsb = get_superblocks code entry pm typing in
- begin
- (* debug_flag := true; *)
- debug "Pathmap:\n"; debug "\n";
- print_path_map pm;
- debug "Superblocks:\n";
- (*print_code code; flush stdout; flush stderr;*)
- (*debug_flag := false;*)
- (*print_superblocks lsb code; debug "\n";*)
- find_last_node_reg (PTree.elements code);
- let (tc, pm) = do_schedule code pm lsb in
- (((tc, entry), pm), id_ptree)
- end