To protect your data, the CISO officer has suggested users to enable GitLab 2FA as soon as possible.

Commit 970bbb22 authored by qinsoon's avatar qinsoon
Browse files

rewrite part of the register allocator

parent 332474a3
......@@ -48,27 +48,27 @@ pub struct GraphColoring<'a> {
iteration_count: usize,
/// machine registers, preassigned a color
precolored: LinkedHashSet<NodeIndex>,
precolored: LinkedHashSet<MuID>,
/// all colors available
colors: LinkedHashMap<backend::RegGroup, LinkedHashSet<MuID>>,
/// temporaries, not precolored and not yet processed
initial: Vec<NodeIndex>,
initial: Vec<MuID>,
/// list of low-degree non-move-related nodes
worklist_simplify: LinkedHashSet<NodeIndex>,
worklist_simplify: LinkedHashSet<MuID>,
/// low-degree move related nodes
worklist_freeze: LinkedHashSet<NodeIndex>,
worklist_freeze: LinkedHashSet<MuID>,
/// nodes marked for spilling during this round
worklist_spill: Vec<NodeIndex>,
worklist_spill: Vec<MuID>,
/// nodes marked for spilling during this round
spilled_nodes: Vec<NodeIndex>,
spilled_nodes: Vec<MuID>,
/// temps that have been coalesced
/// when u <- v is coalesced, v is added to this set and u put back on some work list
coalesced_nodes: LinkedHashSet<NodeIndex>,
coalesced_nodes: LinkedHashSet<MuID>,
/// nodes successfully colored
colored_nodes: Vec<NodeIndex>,
colored_nodes: Vec<MuID>,
/// stack containing temporaries removed from the graph
select_stack: Vec<NodeIndex>,
select_stack: Vec<MuID>,
/// moves that have been coalesced
coalesced_moves: LinkedHashSet<Move>,
......@@ -81,12 +81,10 @@ pub struct GraphColoring<'a> {
/// moves not yet ready for coalescing
active_moves: LinkedHashSet<Move>,
/// degree of nodes
degree: LinkedHashMap<NodeIndex, usize>,
/// a mapping from a node to the list of moves it is associated with
movelist: LinkedHashMap<NodeIndex, RefCell<Vec<Move>>>,
movelist: LinkedHashMap<MuID, LinkedHashSet<Move>>,
/// when a move (u, v) has been coalesced, and v put in coalescedNodes, then alias(v) = u
alias: LinkedHashMap<NodeIndex, NodeIndex>,
alias: LinkedHashMap<MuID, MuID>,
// for validation use
/// we need to log all registers get spilled with their spill location
......@@ -148,7 +146,6 @@ impl<'a> GraphColoring<'a> {
},
colored_nodes: Vec::new(),
initial: Vec::new(),
degree: LinkedHashMap::new(),
worklist_moves: Vec::new(),
movelist: LinkedHashMap::new(),
active_moves: LinkedHashSet::new(),
......@@ -169,12 +166,6 @@ impl<'a> GraphColoring<'a> {
coloring.regalloc()
}
/// returns formatted string for a node
fn display_node(&self, node: NodeIndex) -> String {
let id = self.ig.get_temp_of(node);
self.display_id(id)
}
/// returns formatted string for an ID
fn display_id(&self, id: MuID) -> String {
self.func.context.get_temp_display(id)
......@@ -184,8 +175,8 @@ impl<'a> GraphColoring<'a> {
fn display_move(&self, m: Move) -> String {
format!(
"Move: {} -> {}",
self.display_node(m.from),
self.display_node(m.to)
self.display_id(m.from),
self.display_id(m.to)
)
}
......@@ -200,8 +191,7 @@ impl<'a> GraphColoring<'a> {
// precolor for all machine registers
for reg in backend::all_regs().values() {
let reg_id = reg.extract_ssa_id().unwrap();
let node = self.ig.get_node(reg_id);
self.precolored.insert(node);
self.precolored.insert(reg_id);
}
// put usable registers as available colors
......@@ -215,9 +205,6 @@ impl<'a> GraphColoring<'a> {
for node in self.ig.nodes() {
if !self.ig.is_colored(node) {
self.initial.push(node);
let degree = self.ig.get_degree_of(node);
self.degree.insert(node, degree);
trace!("{} has a degree of {}", self.display_node(node), degree);
}
}
......@@ -253,7 +240,7 @@ impl<'a> GraphColoring<'a> {
if cfg!(debug_assertions) {
trace!("nodes to be spilled:");
for node in self.spilled_nodes.iter() {
trace!("{}", self.display_node(*node));
trace!("{}", *node);
}
}
......@@ -274,20 +261,39 @@ impl<'a> GraphColoring<'a> {
self
}
fn add_to_movelist(
movelist: &mut LinkedHashMap<MuID, LinkedHashSet<Move>>,
reg: MuID,
mov: Move
) {
if movelist.contains_key(&reg) {
let mut list = movelist.get_mut(&reg).unwrap();
list.insert(mov);
} else {
let mut list = LinkedHashSet::new();
list.insert(mov);
movelist.insert(reg, list);
}
}
fn get_movelist(&self, reg: MuID) -> LinkedHashSet<Move> {
if let Some(list) = self.movelist.get(&reg) {
list.clone()
} else {
LinkedHashSet::new()
}
}
fn build(&mut self) {
if COALESCING {
trace!("coalescing enabled, build move list");
let ref ig = self.ig;
let ref mut movelist = self.movelist;
for m in ig.moves().iter() {
trace!("add to movelist: {:?}", m);
self.worklist_moves.push(m.clone());
GraphColoring::movelist_mut(movelist, m.from)
.borrow_mut()
.push(m.clone());
GraphColoring::movelist_mut(movelist, m.to)
.borrow_mut()
.push(m.clone());
self.worklist_moves.push(*m);
GraphColoring::add_to_movelist(&mut self.movelist, m.from, *m);
GraphColoring::add_to_movelist(&mut self.movelist, m.to, *m);
}
} else {
trace!("coalescing disabled");
......@@ -308,30 +314,27 @@ impl<'a> GraphColoring<'a> {
} {
trace!(
"{} 's degree >= reg number limit (K), push to spill list",
self.display_node(node)
node
);
self.worklist_spill.push(node);
} else if self.is_move_related(node) {
trace!(
"{} is move related, push to freeze list",
self.display_node(node)
);
trace!("{} is move related, push to freeze list", node);
self.worklist_freeze.insert(node);
} else {
trace!(
"{} has small degree and not move related, push to simplify list",
self.display_node(node)
node
);
self.worklist_simplify.insert(node);
}
}
}
fn n_regs_for_node(&self, node: NodeIndex) -> usize {
fn n_regs_for_node(&self, node: MuID) -> usize {
backend::number_of_usable_regs_in_group(self.ig.get_group_of(node))
}
fn is_move_related(&mut self, node: NodeIndex) -> bool {
fn is_move_related(&mut self, node: MuID) -> bool {
!self.node_moves(node).is_empty()
}
......@@ -345,7 +348,7 @@ impl<'a> GraphColoring<'a> {
}
}
fn node_moves(&mut self, node: NodeIndex) -> LinkedHashSet<Move> {
fn node_moves(&mut self, node: MuID) -> LinkedHashSet<Move> {
let mut moves = LinkedHashSet::new();
// addAll(active_moves)
......@@ -359,9 +362,9 @@ impl<'a> GraphColoring<'a> {
}
let mut retained = LinkedHashSet::new();
let movelist = &GraphColoring::movelist_mut(&mut self.movelist, node).borrow();
let movelist = self.get_movelist(node);
for m in moves.iter() {
if vec_utils::find_value(movelist, *m).is_some() {
if movelist.contains(m) {
retained.insert(*m);
}
}
......@@ -369,36 +372,11 @@ impl<'a> GraphColoring<'a> {
retained
}
// avoid using &mut self as argument
// in build(), we will need to mutate on self.movelist while
// holding an immmutable reference of self(self.ig)
fn movelist_mut(
list: &mut LinkedHashMap<NodeIndex, RefCell<Vec<Move>>>,
node: NodeIndex
) -> &RefCell<Vec<Move>> {
GraphColoring::movelist_check(list, node);
unsafe { GraphColoring::movelist_nocheck(list, node) }
}
fn movelist_check(list: &mut LinkedHashMap<NodeIndex, RefCell<Vec<Move>>>, node: NodeIndex) {
if !list.contains_key(&node) {
list.insert(node, RefCell::new(Vec::new()));
}
}
// allows getting the Vec<Move> without a mutable reference of the hashmap
unsafe fn movelist_nocheck(
list: &LinkedHashMap<NodeIndex, RefCell<Vec<Move>>>,
node: NodeIndex
) -> &RefCell<Vec<Move>> {
list.get(&node).unwrap()
}
fn simplify(&mut self) {
// remove next element from worklist_simplify, we know its not empty
let node = self.worklist_simplify.pop_front().unwrap();
trace!("Simplifying {}", self.display_node(node));
trace!("Simplifying {}", node);
self.select_stack.push(node);
for m in self.adjacent(node).iter() {
......@@ -406,12 +384,12 @@ impl<'a> GraphColoring<'a> {
}
}
fn adjacent(&self, n: NodeIndex) -> LinkedHashSet<NodeIndex> {
fn adjacent(&self, n: MuID) -> LinkedHashSet<MuID> {
let mut adj = LinkedHashSet::new();
// add n's successors
for s in self.ig.get_edges_of(n) {
adj.insert(s);
for s in self.ig.get_adj_list(n).iter() {
adj.insert(*s);
}
// removeAll(select_stack)
......@@ -427,29 +405,19 @@ impl<'a> GraphColoring<'a> {
adj
}
fn degree(&self, n: NodeIndex) -> usize {
match self.degree.get(&n) {
Some(d) => *d,
None => 0
}
}
fn decrement_degree(&mut self, n: NodeIndex) {
fn decrement_degree(&mut self, n: MuID) {
if self.precolored.contains(&n) {
return;
}
trace!("decrement degree of {}", self.display_node(n));
trace!("decrement degree of {}", n);
let d = self.degree(n);
let d = self.ig.get_degree_of(n);
debug_assert!(d != 0);
self.degree.insert(n, d - 1);
self.ig.set_degree_of(n, d - 1);
if d == self.n_regs_for_node(n) {
trace!(
"{}'s degree is K, no longer need to spill it",
self.display_node(n)
);
trace!("{}'s degree is K, no longer need to spill it", n);
let mut nodes = self.adjacent(n);
nodes.insert(n);
trace!("enable moves of {:?}", nodes);
......@@ -458,22 +426,16 @@ impl<'a> GraphColoring<'a> {
vec_utils::remove_value(&mut self.worklist_spill, n);
if self.is_move_related(n) {
trace!(
"{} is move related, push to freeze list",
self.display_node(n)
);
trace!("{} is move related, push to freeze list", n);
self.worklist_freeze.insert(n);
} else {
trace!(
"{} is not move related, push to simplify list",
self.display_node(n)
);
trace!("{} is not move related, push to simplify list", n);
self.worklist_simplify.insert(n);
}
}
}
fn enable_moves(&mut self, nodes: LinkedHashSet<NodeIndex>) {
fn enable_moves(&mut self, nodes: LinkedHashSet<MuID>) {
for n in nodes.iter() {
let n = *n;
for mov in self.node_moves(n).iter() {
......@@ -501,11 +463,7 @@ impl<'a> GraphColoring<'a> {
let x = self.get_alias(m.from);
let y = self.get_alias(m.to);
trace!(
"resolve alias: from {} to {}",
self.display_node(x),
self.display_node(y)
);
trace!("resolve alias: from {} to {}", x, y);
let (u, v, precolored_u, precolored_v) = {
if self.precolored.contains(&y) {
......@@ -526,8 +484,8 @@ impl<'a> GraphColoring<'a> {
};
trace!(
"u={}, v={}, precolored_u={}, precolroed_v={}",
self.display_node(u),
self.display_node(v),
u,
v,
precolored_u,
precolored_v
);
......@@ -554,9 +512,9 @@ impl<'a> GraphColoring<'a> {
if !precolored_u {
self.add_worklist(u);
}
} else if precolored_v || self.ig.is_adj(u, v) {
} else if precolored_v || self.ig.is_in_adj_set(u, v) {
trace!("precolored_v: {}", precolored_v);
trace!("is_adj(u, v): {}", self.ig.is_adj(u, v));
trace!("is_adj(u, v): {}", self.ig.is_in_adj_set(u, v));
trace!("v is precolored or u,v is adjacent, the move is constrained");
self.constrained_moves.insert(m);
if !precolored_u {
......@@ -584,7 +542,7 @@ impl<'a> GraphColoring<'a> {
}
}
pub fn get_alias(&self, node: NodeIndex) -> NodeIndex {
pub fn get_alias(&self, node: MuID) -> MuID {
if self.coalesced_nodes.contains(&node) {
self.get_alias(*self.alias.get(&node).unwrap())
} else {
......@@ -592,18 +550,18 @@ impl<'a> GraphColoring<'a> {
}
}
fn add_worklist(&mut self, node: NodeIndex) {
if !self.is_move_related(node) && self.degree(node) < self.n_regs_for_node(node) {
fn add_worklist(&mut self, node: MuID) {
if !self.is_move_related(node) && self.ig.get_degree_of(node) < self.n_regs_for_node(node) {
self.worklist_freeze.remove(&node);
self.worklist_simplify.insert(node);
}
}
fn ok(&self, u: NodeIndex, v: NodeIndex) -> bool {
fn ok(&self, u: MuID, v: MuID) -> bool {
for t in self.adjacent(v).iter() {
let t = *t;
if !(self.degree(t) < self.n_regs_for_node(t) || self.precolored.contains(&t) ||
self.ig.is_adj(t, u))
if !(self.ig.get_degree_of(t) < self.n_regs_for_node(t) ||
self.precolored.contains(&t) || self.ig.is_in_adj_set(t, u))
{
return false;
}
......@@ -612,7 +570,7 @@ impl<'a> GraphColoring<'a> {
true
}
fn conservative(&self, u: NodeIndex, v: NodeIndex) -> bool {
fn conservative(&self, u: MuID, v: MuID) -> bool {
let adj_u = self.adjacent(u);
let adj_v = self.adjacent(v);
let nodes = {
......@@ -625,7 +583,7 @@ impl<'a> GraphColoring<'a> {
let mut k = 0;
for n in nodes.iter() {
if self.precolored.contains(n) || self.degree(*n) >= n_reg_for_group {
if self.precolored.contains(n) || self.ig.get_degree_of(*n) >= n_reg_for_group {
k += 1;
}
}
......@@ -633,7 +591,7 @@ impl<'a> GraphColoring<'a> {
k < n_reg_for_group
}
fn combine(&mut self, u: NodeIndex, v: NodeIndex) {
fn combine(&mut self, u: MuID, v: MuID) {
if self.worklist_freeze.contains(&v) {
self.worklist_freeze.remove(&v);
self.coalesced_nodes.insert(v);
......@@ -645,19 +603,12 @@ impl<'a> GraphColoring<'a> {
self.alias.insert(v, u);
{
let ref mut movelist = self.movelist;
GraphColoring::movelist_check(movelist, u);
GraphColoring::movelist_check(movelist, v);
// we checked before getting the movelist, its safe
// use nocheck version which requires only immutable references of movelist
// avoid maintaining a mutable reference of movelist alive
let movelist_u =
&mut unsafe { GraphColoring::movelist_nocheck(movelist, u) }.borrow_mut();
let movelist_v =
&mut unsafe { GraphColoring::movelist_nocheck(movelist, v) }.borrow_mut();
// movelist[u] <- movelist[u] + movelist[v]
let movelist_v = self.get_movelist(v);
// addAll()
movelist_u.extend_from_slice(movelist_v.as_slice());
for m in movelist_v.iter() {
GraphColoring::add_to_movelist(&mut self.movelist, u, *m)
}
}
let mut nodes = LinkedHashSet::new();
......@@ -670,23 +621,25 @@ impl<'a> GraphColoring<'a> {
self.decrement_degree(t);
}
if self.worklist_freeze.contains(&u) && self.degree(u) >= self.n_regs_for_node(u) {
if self.worklist_freeze.contains(&u) &&
self.ig.get_degree_of(u) >= self.n_regs_for_node(u)
{
self.worklist_freeze.remove(&u);
self.worklist_spill.push(u);
}
}
fn add_edge(&mut self, u: NodeIndex, v: NodeIndex) {
if u != v && !self.ig.is_adj(u, v) {
fn add_edge(&mut self, u: MuID, v: MuID) {
if u != v && !self.ig.is_in_adj_set(u, v) {
if !self.precolored.contains(&u) {
self.ig.add_interference_edge(u, v);
let degree_u = self.degree(u);
self.degree.insert(u, degree_u + 1);
self.ig.add_edge(u, v);
let degree_u = self.ig.get_degree_of(u);
self.ig.set_degree_of(u, degree_u + 1);
}
if !self.precolored.contains(&v) {
self.ig.add_interference_edge(v, u);
let degree_v = self.degree(v);
self.degree.insert(v, degree_v + 1);
self.ig.add_edge(v, u);
let degree_v = self.ig.get_degree_of(v);
self.ig.set_degree_of(v, degree_v + 1);
}
}
}
......@@ -694,13 +647,13 @@ impl<'a> GraphColoring<'a> {
fn freeze(&mut self) {
// it is not empty (checked before)
let node = self.worklist_freeze.pop_front().unwrap();
trace!("Freezing {}...", self.display_node(node));
trace!("Freezing {}...", node);
self.worklist_simplify.insert(node);
self.freeze_moves(node);
}
fn freeze_moves(&mut self, u: NodeIndex) {
fn freeze_moves(&mut self, u: MuID) {
for m in self.node_moves(u).iter() {
let m = *m;
let mut v = self.get_alias(m.from);
......@@ -712,7 +665,7 @@ impl<'a> GraphColoring<'a> {
self.frozen_moves.insert(m);
if !self.precolored.contains(&v) && self.node_moves(v).is_empty() &&
self.degree(v) < self.n_regs_for_node(v)
self.ig.get_degree_of(v) < self.n_regs_for_node(v)
{
self.worklist_freeze.remove(&v);
self.worklist_simplify.insert(v);
......@@ -722,7 +675,7 @@ impl<'a> GraphColoring<'a> {
fn select_spill(&mut self) {
trace!("Selecting a node to spill...");
let mut m: Option<NodeIndex> = None;
let mut m: Option<MuID> = None;
for n in self.worklist_spill.iter() {
let n = *n;
......@@ -734,8 +687,9 @@ impl<'a> GraphColoring<'a> {
!self.is_spillable(temp)
} {
m = Some(n);
} else if (self.ig.get_spill_cost(n) / (self.degree(n) as f32)) <
(self.ig.get_spill_cost(m.unwrap()) / (self.degree(m.unwrap()) as f32))
} else if (self.ig.get_spill_cost(n) / (self.ig.get_degree_of(n) as f32)) <
(self.ig.get_spill_cost(m.unwrap()) /
(self.ig.get_degree_of(m.unwrap()) as f32))
{
m = Some(n);
}
......@@ -743,7 +697,7 @@ impl<'a> GraphColoring<'a> {
// m is not none
let m = m.unwrap();
trace!("Spilling {}...", self.display_node(m));
trace!("Spilling {}...", m);
vec_utils::remove_value(&mut self.worklist_spill, m);
self.worklist_simplify.insert(m);
......@@ -754,23 +708,23 @@ impl<'a> GraphColoring<'a> {
trace!("---coloring done---");
while !self.select_stack.is_empty() {
let n = self.select_stack.pop().unwrap();
trace!("Assigning color to {}", self.display_node(n));
trace!("Assigning color to {}", n);
let mut ok_colors: LinkedHashSet<MuID> =
self.colors.get(&self.ig.get_group_of(n)).unwrap().clone();
trace!("all the colors for this temp: {:?}", ok_colors);
for w in self.ig.get_edges_of(n) {
let w_alias = self.get_alias(w);
for w in self.ig.get_adj_list(n).iter() {
let w_alias = self.get_alias(*w);
match self.ig.get_color_of(w_alias) {
None => {} // do nothing
Some(color) => {
trace!(
"color {} is used for its neighbor {:?} (aliasing to {:?})",
color,
self.display_node(w),
self.display_node(w_alias)
w,
w_alias
);
ok_colors.remove(&color);
}
......@@ -779,15 +733,11 @@ impl<'a> GraphColoring<'a> {
trace!("available colors: {:?}", ok_colors);
if ok_colors.is_empty() {
trace!("{} is a spilled node", self.display_node(n));
trace!("{} is a spilled node", n);
self.spilled_nodes.push(n);
} else {
let first_available_color = ok_colors.pop_front().unwrap();
trace!(
"Color {} as {}",
self.display_node(n),
first_available_color
);
trace!("Color {} as {}", n, first_available_color);
if !backend::is_callee_saved(first_available_color) {
trace!("Use caller saved register {}", first_available_color);
......@@ -802,12 +752,8 @@ impl<'a> GraphColoring<'a> {
let n = *n;
let alias = self.get_alias(n);
if let Some(alias_color) = self.ig.get_color_of(alias) {
trace!(
"Assign color to {} based on aliased {}",
self.display_node(n),
self.display_node(alias)
);
trace!("Color {} as {}", self.display_node(n), alias_color);
trace!("Assign color to {} based on aliased {}", n, alias);
trace!("Color {} as {}", n, alias_color);