Skip to content

Remove more fields from Reg.t #3838

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Apr 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 6 additions & 23 deletions backend/reg.ml
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ type t =
{ mutable raw_name: Raw_name.t;
stamp: int;
typ: Cmm.machtype_component;
mutable loc: location;
mutable spill: bool;
mutable spill_cost: int; }
mutable loc: location; }

and location =
Unknown
Expand All @@ -58,19 +56,14 @@ and stack_location =
type reg = t

let dummy =
{ raw_name = Raw_name.Anon; stamp = 0; typ = Int; loc = Unknown;
spill = false; spill_cost = 0;
}
{ raw_name = Raw_name.Anon; stamp = 0; typ = Int; loc = Unknown; }

let currstamp = ref 0
let reg_list = ref([] : t list)
let hw_reg_list = ref ([] : t list)

let create ty =
let r = { raw_name = Raw_name.Anon; stamp = !currstamp; typ = ty;
loc = Unknown;
spill = false;
spill_cost = 0; } in
let r = { raw_name = Raw_name.Anon; stamp = !currstamp; typ = ty; loc = Unknown; } in
reg_list := r :: !reg_list;
incr currstamp;
r
Expand All @@ -93,9 +86,7 @@ let clone r =
nr

let at_location ty loc =
let r = { raw_name = Raw_name.R; stamp = !currstamp; typ = ty; loc;
spill = false;
spill_cost = 0; } in
let r = { raw_name = Raw_name.R; stamp = !currstamp; typ = ty; loc; } in
hw_reg_list := r :: !hw_reg_list;
incr currstamp;
r
Expand All @@ -121,11 +112,7 @@ let is_unknown t =
let name t =
match Raw_name.to_string t.raw_name with
| None -> ""
| Some raw_name ->
if t.spill then
"spilled-" ^ raw_name
else
raw_name
| Some raw_name -> raw_name

let first_virtual_reg_stamp = ref (-1)

Expand Down Expand Up @@ -155,11 +142,7 @@ let all_registers() = !reg_list
let num_registers() = !currstamp

let reinit_reg r =
r.loc <- Unknown;
(* Preserve the very high spill costs introduced by the reloading pass *)
if r.spill_cost >= 100000
then r.spill_cost <- 100000
else r.spill_cost <- 0
r.loc <- Unknown

let reinit() =
List.iter reinit_reg !reg_list
Expand Down
4 changes: 1 addition & 3 deletions backend/reg.mli
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@ type t =
{ mutable raw_name: Raw_name.t; (* Name *)
stamp: int; (* Unique stamp *)
typ: Cmm.machtype_component; (* Type of contents *)
mutable loc: location; (* Actual location *)
mutable spill: bool; (* "true" to force stack allocation *)
mutable spill_cost: int; } (* Estimate of spilling cost *)
mutable loc: location; } (* Actual location *)

and location =
Unknown
Expand Down
13 changes: 5 additions & 8 deletions backend/regalloc/regalloc_gi.ml
Original file line number Diff line number Diff line change
Expand Up @@ -134,16 +134,15 @@ let rec main : round:int -> flat:bool -> State.t -> Cfg_with_infos.t -> unit =
log "main, round #%d" round;
log_cfg_with_infos cfg_with_infos);
if debug then log "updating spilling costs";
update_spill_cost cfg_with_infos ~flat ();
let costs = SpillCosts.compute cfg_with_infos ~flat () in
State.iter_introduced_temporaries state ~f:(fun (reg : Reg.t) ->
reg.Reg.spill_cost <- reg.Reg.spill_cost + 10_000);
SpillCosts.add_to_reg costs reg 10_000);
if debug
then (
log "spilling costs";
indent ();
List.iter (Reg.all_registers ()) ~f:(fun (reg : Reg.t) ->
reg.Reg.spill <- false;
log "%a: %d" Printreg.reg reg reg.spill_cost);
SpillCosts.iter costs ~f:(fun (reg : Reg.t) (cost : int) ->
log "%a: %d" Printreg.reg reg cost);
dedent ());
let hardware_registers, prio_queue =
make_hardware_registers_and_prio_queue cfg_with_infos
Expand All @@ -162,7 +161,7 @@ let rec main : round:int -> flat:bool -> State.t -> Cfg_with_infos.t -> unit =
indent ();
log "got register %a (prio=%d)" Printreg.reg reg priority);
(match
Hardware_registers.find_available hardware_registers reg interval
Hardware_registers.find_available hardware_registers costs reg interval
with
| For_assignment { hardware_reg } ->
if debug
Expand Down Expand Up @@ -211,7 +210,6 @@ let rec main : round:int -> flat:bool -> State.t -> Cfg_with_infos.t -> unit =
| Split_or_spill ->
(* CR xclerc for xclerc: we should actually try to split. *)
if debug then log "spilling %a" Printreg.reg reg;
reg.Reg.spill <- true;
spilling := (reg, interval) :: !spilling);
if debug then dedent ()
done;
Expand Down Expand Up @@ -280,7 +278,6 @@ let run : Cfg_with_infos.t -> Cfg_with_infos.t =
(match Reg.Set.elements spilling_because_unused with
| [] -> ()
| _ :: _ as spilled_nodes ->
List.iter spilled_nodes ~f:(fun reg -> reg.Reg.spill <- true);
(* note: rewrite will remove the `spilling` registers from the "spilled"
work list and set the field to unknown. *)
let (_ : bool) = rewrite state cfg_with_infos ~spilled_nodes in
Expand Down
18 changes: 10 additions & 8 deletions backend/regalloc/regalloc_gi_utils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -620,11 +620,11 @@ module Hardware_registers = struct
fun t ~of_reg ~f ~init ->
Array.fold_left t.(Proc.register_class of_reg) ~f ~init

let actual_cost (reg : Reg.t) : int =
let actual_cost (costs : SpillCosts.t) (reg : Reg.t) : int =
(* CR xclerc for xclerc: it could make sense to give a lower cost to reg
already spilled (e.g. by the split preprocessing) since they already have
a stack slot *)
reg.Reg.spill_cost
SpillCosts.for_reg costs reg

let overlap (hardware_reg : Hardware_register.t) (interval : Interval.t) :
bool =
Expand Down Expand Up @@ -668,7 +668,8 @@ module Hardware_registers = struct
else acc)
|> Option.map fst

let find_evictable (t : t) (reg : Reg.t) (interval : Interval.t) : available =
let find_evictable (t : t) (costs : SpillCosts.t) (reg : Reg.t)
(interval : Interval.t) : available =
let eviction =
fold_class t ~of_reg:reg ~init:None ~f:(fun acc hardware_reg ->
if debug
Expand Down Expand Up @@ -705,7 +706,8 @@ module Hardware_registers = struct
(acc_cost, acc_evictable)
{ Hardware_register.pseudo_reg; interval = _; evictable }
->
acc_cost + actual_cost pseudo_reg, acc_evictable && evictable)
( acc_cost + actual_cost costs pseudo_reg,
acc_evictable && evictable ))
in
if debug then dedent ();
if not evictable
Expand All @@ -714,7 +716,7 @@ module Hardware_registers = struct
let evict_cost =
match acc with None -> max_int | Some (_, _, c) -> c
in
if cost < evict_cost && cost < actual_cost reg
if cost < evict_cost && cost < actual_cost costs reg
then (
if debug
then
Expand All @@ -729,8 +731,8 @@ module Hardware_registers = struct
For_eviction { hardware_reg; evicted_regs }
| None -> Split_or_spill

let find_available : t -> Reg.t -> Interval.t -> available =
fun t reg interval ->
let find_available : t -> SpillCosts.t -> Reg.t -> Interval.t -> available =
fun t costs reg interval ->
let with_no_overlap =
let heuristic =
match Lazy.force Selection_heuristics.value with
Expand All @@ -756,5 +758,5 @@ module Hardware_registers = struct
| Some hardware_reg -> For_assignment { hardware_reg }
| None ->
if debug then log "trying to find an evictable register";
find_evictable t reg interval
find_evictable t costs reg interval
end
2 changes: 1 addition & 1 deletion backend/regalloc/regalloc_gi_utils.mli
Original file line number Diff line number Diff line change
Expand Up @@ -190,5 +190,5 @@ module Hardware_registers : sig

val of_reg : t -> Reg.t -> Hardware_register.t option

val find_available : t -> Reg.t -> Interval.t -> available
val find_available : t -> SpillCosts.t -> Reg.t -> Interval.t -> available
end
46 changes: 28 additions & 18 deletions backend/regalloc/regalloc_irc.ml
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,9 @@ let freeze : State.t -> unit =
State.add_simplify_work_list state reg;
freeze_moves state reg

let select_spilling_register_using_heuristics : State.t -> Reg.t =
fun state ->
let select_spilling_register_using_heuristics : State.t -> SpillCosts.t -> Reg.t
=
fun state costs ->
match Lazy.force Spilling_heuristics.value with
| Set_choose -> (
(* This is the "heuristics" from the IRC paper: pick any candidate, just try
Expand All @@ -280,8 +281,9 @@ let select_spilling_register_using_heuristics : State.t -> Reg.t =
let weighted_cost (reg : Reg.t) =
if debug
then
log "register %a has spill cost %d" Printreg.reg reg reg.Reg.spill_cost;
(float reg.Reg.spill_cost /. float (State.degree state reg))
log "register %a has spill cost %d" Printreg.reg reg
(SpillCosts.for_reg costs reg);
(float (SpillCosts.for_reg costs reg) /. float (State.degree state reg))
(* note: while this magic constant is questionable, it is key to not favor
the introduced temporaries which, by construct, have very few
occurrences. *)
Expand All @@ -300,13 +302,13 @@ let select_spilling_register_using_heuristics : State.t -> Reg.t =
else acc)
|> fst)

let select_spill : State.t -> unit =
fun state ->
let select_spill : State.t -> SpillCosts.t -> unit =
fun state costs ->
if debug
then (
log "select_spill";
indent ());
let reg = select_spilling_register_using_heuristics state in
let reg = select_spilling_register_using_heuristics state costs in
if debug
then
log "chose %a using heuristics %S" Printreg.reg reg
Expand Down Expand Up @@ -461,7 +463,7 @@ let rec main : round:int -> State.t -> Cfg_with_infos.t -> unit =
make_work_list state;
State.invariant state;
if debug then log_work_list_desc "before loop";
let spill_cost_is_up_to_date = ref false in
let spill_costs = ref (None : SpillCosts.t option) in
let continue = ref true in
while !continue do
if not (State.is_empty_simplify_work_list state)
Expand All @@ -471,16 +473,24 @@ let rec main : round:int -> State.t -> Cfg_with_infos.t -> unit =
else if not (State.is_empty_freeze_work_list state)
then freeze state
else if not (State.is_empty_spill_work_list state)
then (
if not !spill_cost_is_up_to_date
then (
(match Lazy.force Spilling_heuristics.value with
| Set_choose ->
(* note: `spill_cost` will not be used by the heuristics *) ()
| Flat_uses -> update_spill_cost cfg_with_infos ~flat:true ()
| Hierarchical_uses -> update_spill_cost cfg_with_infos ~flat:false ());
spill_cost_is_up_to_date := true);
select_spill state)
then
let costs =
match !spill_costs with
| Some costs -> costs
| None ->
let costs =
match Lazy.force Spilling_heuristics.value with
| Set_choose ->
(* note: `spill_cost` will not be used by the heuristics *)
SpillCosts.empty ()
| Flat_uses -> SpillCosts.compute cfg_with_infos ~flat:true ()
| Hierarchical_uses ->
SpillCosts.compute cfg_with_infos ~flat:false ()
in
spill_costs := Some costs;
costs
in
select_spill state costs
else continue := false;
if debug then log_work_list_desc "end of loop";
State.invariant state
Expand Down
10 changes: 3 additions & 7 deletions backend/regalloc/regalloc_ls.ml
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@ let allocate_stack_slot : Reg.t -> spilling_reg =
fun reg ->
indent ();
log "spilling register %a" Printreg.reg reg;
reg.spill <- true;
dedent ();
Spilling reg

Expand All @@ -119,9 +118,8 @@ exception No_free_register
let allocate_free_register : State.t -> Interval.t -> spilling_reg =
fun state interval ->
let reg = interval.reg in
match reg.loc, reg.spill with
| Unknown, true -> allocate_stack_slot reg
| Unknown, _ -> (
match reg.loc with
| Unknown -> (
let reg_class = Proc.register_class reg in
let intervals = State.active state ~reg_class in
let first_available = Proc.first_available_register.(reg_class) in
Expand Down Expand Up @@ -161,7 +159,6 @@ let allocate_free_register : State.t -> Interval.t -> spilling_reg =
else if available.(idx)
then (
reg.loc <- Reg (first_available + idx);
reg.spill <- false;
Interval.DLL.insert_sorted intervals.active_dll interval;
if debug
then (
Expand All @@ -172,7 +169,7 @@ let allocate_free_register : State.t -> Interval.t -> spilling_reg =
else assign (succ idx)
in
assign 0)
| (Reg _ | Stack _), _ -> Not_spilling
| Reg _ | Stack _ -> Not_spilling

let allocate_blocked_register : State.t -> Interval.t -> spilling_reg =
fun state interval ->
Expand Down Expand Up @@ -282,7 +279,6 @@ let run : Cfg_with_infos.t -> Cfg_with_infos.t =
(match Reg.Set.elements spilling_because_unused with
| [] -> ()
| _ :: _ as spilled_nodes ->
List.iter spilled_nodes ~f:(fun reg -> reg.Reg.spill <- true);
rewrite state cfg_with_infos ~spilled_nodes ~block_temporaries:false;
Cfg_with_infos.invalidate_liveness cfg_with_infos);
main ~round:1 state cfg_with_infos;
Expand Down
Loading