Commit 19c5b2c0 authored by qinsoon's avatar qinsoon

[wip] backbone of graph coloring

parent d570c55c
......@@ -12,6 +12,7 @@ pub use compiler::backend::x86_64::asm_backend::ASMCodeGen;
use ast::ptr::P;
use ast::ir::*;
use ast::types::*;
use compiler::backend::RegGroup;
macro_rules! GPR {
($name: expr, $id: expr) => {
......@@ -79,6 +80,25 @@ lazy_static! {
R14.clone(),
R15.clone()
];
pub static ref ALL_GPRs : [P<Value>; 16] = [
RAX.clone(),
RCX.clone(),
RDX.clone(),
RBX.clone(),
RSP.clone(),
RBP.clone(),
RSI.clone(),
RDI.clone(),
R8.clone(),
R9.clone(),
R10.clone(),
R11.clone(),
R12.clone(),
R13.clone(),
R14.clone(),
R15.clone()
];
}
lazy_static!{
......@@ -114,6 +134,25 @@ lazy_static!{
];
pub static ref CALLEE_SAVED_FPRs : [P<Value>; 0] = [];
pub static ref ALL_FPRs : [P<Value>; 16] = [
XMM0.clone(),
XMM1.clone(),
XMM2.clone(),
XMM3.clone(),
XMM4.clone(),
XMM5.clone(),
XMM6.clone(),
XMM7.clone(),
XMM8.clone(),
XMM9.clone(),
XMM10.clone(),
XMM11.clone(),
XMM12.clone(),
XMM13.clone(),
XMM14.clone(),
XMM15.clone(),
];
}
pub const GPR_COUNT : usize = 16;
......@@ -156,17 +195,39 @@ lazy_static! {
];
}
pub fn get_name_for_value(id: MuID, func_context: &FunctionContext) -> &'static str {
if id < RESERVED_NODE_IDS_FOR_MACHINE {
ALL_MACHINE_REGs[id].tag
} else {
match func_context.get_value(id) {
Some(ref v) => v.tag,
None => panic!("cannot find tag for node id={}", id)
}
pub fn init_machine_regs_for_func (func_context: &mut FunctionContext) {
use std::cell::Cell;
for reg in ALL_MACHINE_REGs.iter() {
let reg_id = reg.extract_ssa_id().unwrap();
let entry = SSAVarEntry {
id: reg_id,
tag: reg.tag,
ty: reg.ty.clone(),
use_count: Cell::new(0),
expr: None
};
func_context.value_tags.insert(reg.tag, reg_id);
func_context.values.insert(reg_id, entry);
}
}
pub fn number_of_regs_in_group(group: RegGroup) -> usize {
match group {
RegGroup::GPR => ALL_GPRs.len(),
RegGroup::FPR => ALL_FPRs.len()
}
}
pub fn number_of_all_regs() -> usize {
ALL_MACHINE_REGs.len()
}
pub fn all_regs() -> &'static Vec<P<Value>> {
&ALL_MACHINE_REGs
}
pub fn is_valid_x86_imm(op: &P<Value>) -> bool {
use std::u32;
match op.v {
......
pub mod inst_sel;
pub mod reg_alloc;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum RegGroup {GPR, FPR}
#[cfg(target_arch = "x86_64")]
#[path = "arch/x86_64/mod.rs"]
mod x86_64;
#[cfg(target_arch = "arm")]
#[path = "arch/arm/mod.rs"]
mod arm;
#[cfg(target_arch = "x86_64")]
pub use compiler::backend::x86_64::get_name_for_value;
pub use compiler::backend::x86_64::init_machine_regs_for_func;
#[cfg(target_arch = "x86_64")]
pub use compiler::backend::x86_64::GPR_COUNT;
pub use compiler::backend::x86_64::number_of_regs_in_group;
#[cfg(target_arch = "x86_64")]
pub use compiler::backend::x86_64::FPR_COUNT;
pub use compiler::backend::x86_64::number_of_all_regs;
#[cfg(target_arch = "x86_64")]
pub use compiler::backend::x86_64::all_regs;
#[cfg(target_arch = "arm")]
#[path = "arch/arm/mod.rs"]
mod arm;
#[cfg(target_arch = "arm")]
pub use compiler::backend::arm::GPR_COUNT;
......
use compiler::backend::reg_alloc::liveness::InterferenceGraph;
use ast::ir::MuID;
use compiler::backend::reg_alloc::liveness::InterferenceGraph;
use compiler::backend::reg_alloc::liveness::{Node, Move};
use vm::machine_code::CompiledFunction;
use compiler::backend::GPR_COUNT;
use compiler::backend;
use compiler::backend::reg_alloc::liveness::find_value;
use std::collections::LinkedList;
use std::collections::HashSet;
use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
const COALESCING : AtomicBool = ATOMIC_BOOL_INIT;
pub struct GraphColoring <'a> {
ig: InterferenceGraph,
cur_cf: &'a CompiledFunction,
K: usize
precolored: HashSet<Node>,
colors: HashSet<MuID>,
initial: LinkedList<Node>,
degree: HashMap<Node, usize>,
worklist_moves: LinkedList<Move>,
movelist: HashMap<Node, Vec<Move>>,
active_moves: HashSet<Move>,
worklist_spill: LinkedList<Node>,
worklist_freeze: HashSet<Node>,
worklist_simplify: HashSet<Node>
}
impl <'a> GraphColoring <'a> {
......@@ -14,13 +37,151 @@ impl <'a> GraphColoring <'a> {
let mut coloring = GraphColoring {
ig: ig,
cur_cf: cf,
K: 0
precolored: HashSet::new(),
colors: HashSet::new(),
initial: LinkedList::new(),
degree: HashMap::new(),
worklist_moves: LinkedList::new(),
movelist: HashMap::new(),
active_moves: HashSet::new(),
worklist_spill: LinkedList::new(),
worklist_freeze: HashSet::new(),
worklist_simplify: HashSet::new()
};
coloring.init();
}
fn init (&mut self) {
self.K = GPR_COUNT;
COALESCING.store(true, Ordering::Relaxed);
for reg in backend::all_regs().iter() {
let reg_id = reg.extract_ssa_id().unwrap();
let node = self.ig.get_node(reg_id);
self.precolored.insert(node);
self.colors.insert(reg_id);
}
for node in self.ig.nodes() {
if !self.ig.is_colored(node) {
self.initial.push_back(node);
self.degree.insert(node, self.ig.outdegree_of(node));
}
}
self.build();
self.make_work_list();
while {
if !self.worklist_simplify.is_empty() {
self.simplify();
} else if !self.worklist_moves.is_empty() {
self.coalesce();
} else if !self.worklist_freeze.is_empty() {
self.freeze();
} else if !self.worklist_spill.is_empty() {
self.select_spill();
}
! (self.worklist_simplify.is_empty()
&& self.worklist_moves.is_empty()
&& self.worklist_freeze.is_empty()
&& self.worklist_spill.is_empty())
} {}
self.assign_colors();
}
fn simplify(&mut self) {
unimplemented!()
}
fn coalesce(&mut self) {
unimplemented!()
}
fn freeze(&mut self) {
unimplemented!()
}
fn select_spill(&mut self) {
unimplemented!()
}
fn assign_colors(&mut self) {
unimplemented!()
}
fn build(&mut self) {
if COALESCING.load(Ordering::Relaxed) {
let ref ig = self.ig;
let ref mut movelist = self.movelist;
for m in ig.moves() {
self.worklist_moves.push_back(m.clone());
GraphColoring::movelist_mut(movelist, m.from).push(m.clone());
GraphColoring::movelist_mut(movelist, m.to).push(m.clone());
}
}
}
fn make_work_list(&mut self) {
while !self.initial.is_empty() {
let node = self.initial.pop_front().unwrap();
if {
// condition: degree >= K
let degree = self.ig.degree_of(node);
let n_regs = backend::number_of_regs_in_group(self.ig.get_group_of(node));
degree >= n_regs
} {
self.worklist_spill.push_back(node);
} else if self.is_move_related(node) {
self.worklist_freeze.insert(node);
} else {
self.worklist_simplify.insert(node);
}
}
}
fn is_move_related(&mut self, node: Node) -> bool {
!self.node_moves(node).is_empty()
}
fn node_moves(&mut self, node: Node) -> HashSet<Move> {
let mut moves = HashSet::new();
// addAll(active_moves)
for m in self.active_moves.iter() {
moves.insert(m.clone());
}
// addAll(worklist_moves)
for m in self.worklist_moves.iter() {
moves.insert(m.clone());
}
let mut retained = HashSet::new();
let movelist = GraphColoring::movelist_mut(&mut self.movelist, node);
for m in moves.iter() {
if find_value(movelist, *m).is_some() {
retained.insert(*m);
}
}
retained
}
fn movelist_mut(list: &mut HashMap<Node, Vec<Move>>, node: Node) -> &mut Vec<Move> {
if !list.contains_key(&node) {
list.insert(node, Vec::new());
}
list.get_mut(&node).unwrap()
}
}
\ No newline at end of file
This diff is collapsed.
#![allow(dead_code)]
use compiler::CompilerPass;
use ast::ir::*;
use vm::context::VMContext;
use compiler::backend::init_machine_regs_for_func;
mod liveness;
mod coloring;
......@@ -29,7 +33,10 @@ impl CompilerPass for RegisterAllocation {
cf.mc.print();
let liveness = liveness::build(&mut cf);
// initialize machine registers for the function context
init_machine_regs_for_func(&mut func.context);
let liveness = liveness::build(&mut cf, func);
liveness.print();
coloring::GraphColoring::start(&mut cf, liveness);
......
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