Commit 970bbb22 authored by qinsoon's avatar qinsoon

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);
self.ig.color_node(n, alias_color);
}
}
......
......@@ -20,13 +20,9 @@ use compiler::backend;
use utils::LinkedHashSet;
use utils::LinkedHashMap;
use compiler::backend::reg_alloc::graph_coloring::petgraph;
use compiler::backend::reg_alloc::graph_coloring::petgraph::Graph;
use compiler::backend::reg_alloc::graph_coloring::petgraph::graph::NodeIndex;
/// GraphNode represents a node in the interference graph.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct GraphNode {
pub struct Node {
/// temp ID (could be register)
temp: MuID,
/// assigned color
......@@ -41,8 +37,17 @@ pub struct GraphNode {
/// We need to know the moves so that we can coalesce.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Move {
pub from: NodeIndex,
pub to: NodeIndex
pub from: MuID,
pub to: MuID
}
#[inline(always)]
fn is_precolored(reg: MuID) -> bool {
if reg < MACHINE_ID_END {
true
} else {
false
}
}
/// InterferenceGraph represents the interference graph, including
......@@ -50,12 +55,11 @@ pub struct Move {
/// * all the nodes and its NodeIndex (a node is referred to by NodeIndex)
/// * all the moves
pub struct InterferenceGraph {
/// the internal graph
graph: Graph<GraphNode, (), petgraph::Undirected>,
/// a map of all nodes (from temp ID to node index)
/// node index is how nodes are referred to with pet_graph
nodes: LinkedHashMap<MuID, NodeIndex>,
/// a set of all moves
nodes: LinkedHashMap<MuID, Node>,
adj_set: LinkedHashSet<(MuID, MuID)>,
adj_list: LinkedHashMap<MuID, LinkedHashSet<MuID>>,
degree: LinkedHashMap<MuID, usize>,
moves: LinkedHashSet<Move>
}
......@@ -63,7 +67,9 @@ impl InterferenceGraph {
/// creates a new graph
fn new() -> InterferenceGraph {
InterferenceGraph {
graph: Graph::new_undirected(),
adj_set: LinkedHashSet::new(),
adj_list: LinkedHashMap::new(),
degree: LinkedHashMap::new(),
nodes: LinkedHashMap::new(),
moves: LinkedHashSet::new()
}
......@@ -71,49 +77,34 @@ impl InterferenceGraph {
/// creates a new node for a temp (if we already created a temp for the temp, returns the node)
/// This function will increase spill cost for the node by 1 each tiem it is called for the temp
fn new_node(&mut self, reg_id: MuID, context: &FunctionContext) -> NodeIndex {
fn new_node(&mut self, reg_id: MuID, context: &FunctionContext) -> MuID {
let entry = context.get_value(reg_id).unwrap();
// if it is the first time, create the node
if !self.nodes.contains_key(&reg_id) {
let node = GraphNode {
let node = Node {
temp: reg_id,
color: None,
group: backend::RegGroup::get_from_ty(entry.ty()),
spill_cost: 0.0f32
};
// add to the graph
let index = self.graph.add_node(node);
// save index
self.nodes.insert(reg_id, index);
self.nodes.insert(reg_id, node);
self.adj_list.insert(reg_id, LinkedHashSet::new());
self.degree.insert(reg_id, 0);
}
// get the node index
let node_index = *self.nodes.get(&reg_id).unwrap();