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

rewrite part of the register allocator

parent 332474a3
......@@ -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();
// get node
let node_mut = self.graph.node_weight_mut(node_index).unwrap();
let node_mut = self.nodes.get_mut(&reg_id).unwrap();
// increase node spill cost
node_mut.spill_cost += 1.0f32;
node_index
}
/// returns the node index for a temp
pub fn get_node(&self, reg: MuID) -> NodeIndex {
match self.nodes.get(&reg) {
Some(index) => *index,
None => panic!("do not have a node for {}", reg)
}
reg_id
}
/// returns all the nodes in the graph
pub fn nodes(&self) -> Vec<NodeIndex> {
let mut ret = vec![];
for index in self.nodes.values() {
ret.push(*index);
}
ret
pub fn nodes(&self) -> Vec<MuID> {
self.nodes.keys().map(|x| *x).collect()
}
/// returns all the moves in the graph
......@@ -122,23 +113,19 @@ impl InterferenceGraph {
}
/// adds a move edge between two nodes
fn add_move(&mut self, src: NodeIndex, dst: NodeIndex) {
fn add_move(&mut self, src: MuID, dst: MuID) {
let src = {
let temp_src = self.get_temp_of(src);
if temp_src < MACHINE_ID_END {
if is_precolored(src) {
// get the color for the machine register, e.g. rax for eax/ax/al/ah
let alias = backend::get_color_for_precolored(temp_src);
self.get_node(alias)
backend::get_color_for_precolored(src)
} else {
src
}
};
let dst = {
let temp_dst = self.get_temp_of(dst);
if temp_dst < MACHINE_ID_END {
let alias = backend::get_color_for_precolored(temp_dst);
self.get_node(alias)
if is_precolored(dst) {
backend::get_color_for_precolored(dst)
} else {
dst
}
......@@ -148,99 +135,88 @@ impl InterferenceGraph {
}
/// adds an interference edge between two nodes
pub fn add_interference_edge(&mut self, from: NodeIndex, to: NodeIndex) {
// adds edge to the internal graph
self.graph.update_edge(from, to, ());
pub fn add_edge(&mut self, u: MuID, v: MuID) {
// // adds edge to the internal graph
// self.graph.update_edge(from, to, ());
// if one of the node is machine register, we also add
// interference edge to its alias
// e.g. if we have %a - %edi interfered,
// we also add %a - %rdi interference
let from_tmp = self.graph.node_weight(from).unwrap().temp;
let to_tmp = self.graph.node_weight(to).unwrap().temp;
if from_tmp < MACHINE_ID_END || to_tmp < MACHINE_ID_END {
let from_tmp = if from_tmp < MACHINE_ID_END {
backend::get_color_for_precolored(from_tmp)
} else {
from_tmp
};
let to_tmp = if to_tmp < MACHINE_ID_END {
backend::get_color_for_precolored(to_tmp)
} else {
to_tmp
};
if !self.adj_set.contains(&(u, v)) && u != v {
self.adj_set.insert((u, v));
self.adj_set.insert((v, u));
let from_tmp_node = self.get_node(from_tmp);
let to_tmp_node = self.get_node(to_tmp);
self.graph.update_edge(from_tmp_node, to_tmp_node, ());
if !is_precolored(u) {
self.adj_list.get_mut(&u).unwrap().insert(v);
let degree = self.degree.get_mut(&u).unwrap();
*degree = *degree + 1;
}
if !is_precolored(v) {
self.adj_list.get_mut(&v).unwrap().insert(u);
let degree = self.degree.get_mut(&v).unwrap();
*degree = *degree + 1;
}
}
}
/// is two nodes interfered?
pub fn is_interfered_with(&self, node1: NodeIndex, node2: NodeIndex) -> bool {
let edge = self.graph.find_edge(node1, node2);
edge.is_some()
}
/// set color for a node
pub fn color_node(&mut self, node: NodeIndex, color: MuID) {
self.graph.node_weight_mut(node).unwrap().color = Some(color);
pub fn color_node(&mut self, reg: MuID, color: MuID) {
self.nodes.get_mut(&reg).unwrap().color = Some(color);
}
/// is a node colored yet?
pub fn is_colored(&self, node: NodeIndex) -> bool {
self.graph.node_weight(node).unwrap().color.is_some()
pub fn is_colored(&self, reg: MuID) -> bool {
self.nodes.get(&reg).unwrap().color.is_some()
}
/// gets the color of a node
pub fn get_color_of(&self, node: NodeIndex) -> Option<MuID> {
self.graph.node_weight(node).unwrap().color
pub fn get_color_of(&self, reg: MuID) -> Option<MuID> {
self.nodes.get(&reg).unwrap().color
}
/// gets the reg group of a node
pub fn get_group_of(&self, node: NodeIndex) -> backend::RegGroup {
self.graph.node_weight(node).unwrap().group
pub fn get_group_of(&self, reg: MuID) -> backend::RegGroup {
self.nodes.get(&reg).unwrap().group
}
/// gets the temporary of a node
pub fn get_temp_of(&self, node: NodeIndex) -> MuID {
self.graph.node_weight(node).unwrap().temp
pub fn get_temp_of(&self, reg: MuID) -> MuID {
self.nodes.get(&reg).unwrap().temp
}
/// gets the spill cost of a node
pub fn get_spill_cost(&self, node: NodeIndex) -> f32 {
self.graph.node_weight(node).unwrap().spill_cost
pub fn get_spill_cost(&self, reg: MuID) -> f32 {
self.nodes.get(&reg).unwrap().spill_cost
}
/// are two nodes the same node?
fn is_same_node(&self, node1: NodeIndex, node2: NodeIndex) -> bool {
node1 == node2
fn is_same_node(&self, reg1: MuID, reg2: MuID) -> bool {
reg1 == reg2
}
/// are two nodes from the same reg group?
fn is_same_group(&self, node1: NodeIndex, node2: NodeIndex) -> bool {
let node1 = self.graph.node_weight(node1).unwrap();
let node2 = self.graph.node_weight(node2).unwrap();
node1.group == node2.group
fn is_same_group(&self, reg1: MuID, reg2: MuID) -> bool {
self.get_group_of(reg1) == self.get_group_of(reg2)
}
/// are two nodes adjacent?
pub fn is_adj(&self, from: NodeIndex, to: NodeIndex) -> bool {
self.is_interfered_with(from, to)
/// gets edges from a node
pub fn get_adj_list(&self, reg: MuID) -> &LinkedHashSet<MuID> {
self.adj_list.get(&reg).unwrap()
}
/// gets edges from a node
pub fn get_edges_of(&self, node: NodeIndex) -> Vec<NodeIndex> {
self.graph.neighbors(node).collect()
pub fn is_in_adj_set(&self, u: MuID, v: MuID) -> bool {
self.adj_set.contains(&(u, v))
}
/// gets degree of a node (number of edges from the node)
pub fn get_degree_of(&self, node: NodeIndex) -> usize {
self.get_edges_of(node).len()
pub fn get_degree_of(&self, reg: MuID) -> usize {
*self.degree.get(&reg).unwrap()
}
pub fn set_degree_of(&mut self, reg: MuID, degree: usize) {
*self.degree.get_mut(&reg).unwrap() = degree;
}
/// prints current graph for debugging (via trace log)
......@@ -251,23 +227,7 @@ impl InterferenceGraph {
trace!("");
trace!("Interference Graph");
trace!("nodes:");
for id in self.nodes.keys() {
let val = context.get_value(*id).unwrap().value();
trace!("Reg {} -> {:?}", val, self.nodes.get(&id).unwrap());
}
trace!("moves:");
for mov in self.moves.iter() {
trace!("Move {:?} -> {:?}", mov.from, mov.to);
}
trace!("graph:");
trace!(
"\n\n{:?}\n",
Dot::with_config(&self.graph, &[Config::EdgeNoLabel])
);
trace!("");
trace!("not available");
}
}
......@@ -360,17 +320,17 @@ pub fn build_interference_graph_chaitin_briggs(
None
} else {
if src.len() == 1 {
let node1 = ig.get_node(src[0]);
let node2 = ig.get_node(dst[0]);
let src = src[0];
let dst = dst[0];
trace_if!(
TRACE_LIVENESS,
"add move between {} and {}",
func.context.get_temp_display(src[0]),
func.context.get_temp_display(dst[0])
func.context.get_temp_display(src),
func.context.get_temp_display(dst)
);
ig.add_move(node1, node2);
ig.add_move(src, dst);
Some(src[0])
Some(src)
} else {
None
}
......@@ -406,12 +366,10 @@ pub fn build_interference_graph_chaitin_briggs(
func.context.get_temp_display(*e)
);
if src.is_none() || (src.is_some() && *e != src.unwrap()) {
let from = ig.get_node(d);
let to = ig.get_node(*e);
let from = d;
let to = *e;
if !ig.is_same_node(from, to) && ig.is_same_group(from, to) &&
!ig.is_adj(from, to)
{
if !ig.is_same_node(from, to) && ig.is_same_group(from, to) {
if !ig.is_colored(from) {
trace_if!(
TRACE_LIVENESS,
......@@ -421,7 +379,7 @@ pub fn build_interference_graph_chaitin_briggs(
func.context.get_temp_display(d),
func.context.get_temp_display(*e)
);
ig.add_interference_edge(from, to);
ig.add_edge(from, to);
}
if !ig.is_colored(to) {
trace_if!(
......@@ -432,7 +390,7 @@ pub fn build_interference_graph_chaitin_briggs(
func.context.get_temp_display(*e),
func.context.get_temp_display(d)
);
ig.add_interference_edge(to, from);
ig.add_edge(to, from);
}
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment