Commit 8669dba8 authored by qinsoon's avatar qinsoon

[wip] liveness analysis

parent ab7dde71
......@@ -7,4 +7,5 @@ authors = [ "Your name <you@example.com>" ]
[dependencies]
lazy_static = "0.1.15"
log = "0.3.5"
simple_logger = "0.4.0"
\ No newline at end of file
simple_logger = "0.4.0"
nalgebra = "0.8.2"
\ No newline at end of file
......@@ -98,7 +98,8 @@ impl FunctionContent {
}
pub fn get_entry_block_mut(&mut self) -> &mut Block {
self.get_block_mut(self.entry)
let entry = self.entry;
self.get_block_mut(entry)
}
pub fn get_block(&self, tag: MuTag) -> &Block {
......
......@@ -40,12 +40,20 @@ impl MachineCode for ASMCode {
}
}
fn get_succs(&self, index: usize) -> &Vec<usize> {
&self.succs[index]
}
fn get_preds(&self, index: usize) -> &Vec<usize> {
&self.preds[index]
}
fn get_inst_reg_uses(&self, index: usize) -> &Vec<MuID> {
&self.code[index].defines
&self.code[index].uses
}
fn get_inst_reg_defines(&self, index: usize) -> &Vec<MuID> {
&self.code[index].uses
&self.code[index].defines
}
fn print(&self) {
......
......@@ -82,22 +82,22 @@ lazy_static! {
}
lazy_static!{
pub static ref XMM0 : P<Value> = FPR!("xmm0", 20);
pub static ref XMM1 : P<Value> = FPR!("xmm1", 21);
pub static ref XMM2 : P<Value> = FPR!("xmm2", 22);
pub static ref XMM3 : P<Value> = FPR!("xmm3", 23);
pub static ref XMM4 : P<Value> = FPR!("xmm4", 24);
pub static ref XMM5 : P<Value> = FPR!("xmm5", 25);
pub static ref XMM6 : P<Value> = FPR!("xmm6", 26);
pub static ref XMM7 : P<Value> = FPR!("xmm7", 27);
pub static ref XMM8 : P<Value> = FPR!("xmm8", 28);
pub static ref XMM9 : P<Value> = FPR!("xmm9", 29);
pub static ref XMM10 : P<Value> = FPR!("xmm10",30);
pub static ref XMM11 : P<Value> = FPR!("xmm11",31);
pub static ref XMM12 : P<Value> = FPR!("xmm12",32);
pub static ref XMM13 : P<Value> = FPR!("xmm13",33);
pub static ref XMM14 : P<Value> = FPR!("xmm14",34);
pub static ref XMM15 : P<Value> = FPR!("xmm15",35);
pub static ref XMM0 : P<Value> = FPR!("xmm0", 16);
pub static ref XMM1 : P<Value> = FPR!("xmm1", 17);
pub static ref XMM2 : P<Value> = FPR!("xmm2", 18);
pub static ref XMM3 : P<Value> = FPR!("xmm3", 19);
pub static ref XMM4 : P<Value> = FPR!("xmm4", 20);
pub static ref XMM5 : P<Value> = FPR!("xmm5", 21);
pub static ref XMM6 : P<Value> = FPR!("xmm6", 22);
pub static ref XMM7 : P<Value> = FPR!("xmm7", 23);
pub static ref XMM8 : P<Value> = FPR!("xmm8", 24);
pub static ref XMM9 : P<Value> = FPR!("xmm9", 25);
pub static ref XMM10 : P<Value> = FPR!("xmm10",26);
pub static ref XMM11 : P<Value> = FPR!("xmm11",27);
pub static ref XMM12 : P<Value> = FPR!("xmm12",28);
pub static ref XMM13 : P<Value> = FPR!("xmm13",29);
pub static ref XMM14 : P<Value> = FPR!("xmm14",30);
pub static ref XMM15 : P<Value> = FPR!("xmm15",31);
pub static ref RETURN_FPRs : [P<Value>; 2] = [
XMM0.clone(),
......@@ -116,6 +116,54 @@ lazy_static!{
pub static ref CALLEE_SAVED_FPRs : [P<Value>; 0] = [];
}
lazy_static! {
pub static ref ALL_MACHINE_REGs : Vec<P<Value>> = vec![
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(),
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 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 is_valid_x86_imm(op: &P<Value>) -> bool {
use std::u32;
match op.v {
......
......@@ -7,4 +7,7 @@ mod x86_64;
#[cfg(target_arch = "arm")]
#[path = "arch/arm/mod.rs"]
mod arm;
\ No newline at end of file
mod arm;
#[cfg(target_arch = "x86_64")]
pub use compiler::backend::x86_64::get_name_for_value;
\ No newline at end of file
extern crate nalgebra;
use vm::machine_code::CompiledFunction;
use vm::machine_code::MachineCode;
use ast::ir::*;
use compiler::backend::get_name_for_value as get_tag;
use std::collections::LinkedList;
use std::collections::{HashMap, HashSet};
use self::nalgebra::DMatrix;
type MatrixIndex = usize;
pub struct InterferenceGraph {
foo: usize
nodes: HashMap<MuID, MatrixIndex>,
matrix: Option<DMatrix<bool>>,
color: HashMap<MuID, MuID>,
moves: HashSet<(MuID, MuID)>
}
impl InterferenceGraph {
fn new() -> InterferenceGraph {
InterferenceGraph {foo: 0}
InterferenceGraph {
nodes: HashMap::new(),
matrix: None,
color: HashMap::new(),
moves: HashSet::new()
}
}
fn new_node(&mut self, node: MuID) -> MatrixIndex {
if !self.nodes.contains_key(&node) {
let index = self.nodes.len();
self.nodes.insert(node, index);
index
} else {
* self.nodes.get(&node).unwrap()
}
}
fn get_node(&self, node: MuID) -> MatrixIndex {
match self.nodes.get(&node) {
Some(index) => *index,
None => panic!("do not have a node for {}", node)
}
}
fn init_graph(&mut self) {
let len = self.nodes.len();
self.matrix = Some(DMatrix::from_element(len, len, false));
}
fn add_move(&mut self, src: MuID, dst: MuID) {
self.moves.insert((src, dst));
}
fn new_node(&mut self, node: MuID) {
fn add_interference_edge(&mut self, from: MuID, to: MuID) {
let from_ix = self.get_node(from);
let to_ix = self.get_node(to);
self.matrix.as_mut().unwrap()[(from_ix, to_ix)] = true;
}
fn color_node(&mut self, node: MuID, color: MuID) {
self.color.insert(node, color);
}
fn node_has_color(&self, node: MuID) -> bool {
self.color.contains_key(&node)
}
fn is_same_node(&self, node1: MuID, node2: MuID) -> bool {
let ix1 = self.get_node(node1);
let ix2 = self.get_node(node2);
ix1 == ix2
}
fn is_adj(&self, from: MuID, to: MuID) -> bool {
let from_ix = self.get_node(from);
let to_ix = self.get_node(to);
self.matrix.as_ref().unwrap()[(from_ix, to_ix)]
}
pub fn print_with(&self, func: &MuFunction) {
let ref context = func.context;
println!("");
println!("Interference Graph");
println!("nodes:");
for (n, ix) in self.nodes.iter() {
println!("Node {} -> Index {}", get_tag(*n, context), ix);
}
println!("color:");
for (n, c) in self.color.iter() {
println!("Node {} -> Color {}", get_tag(*n, context), get_tag(*c, context));
}
println!("moves:");
for mov in self.moves.iter() {
println!("Move {} -> {}", get_tag(mov.0, context), get_tag(mov.1, context));
}
println!("graph:");
{
let idx_to_node_id = {
let mut ret : HashMap<MatrixIndex, MuID> = HashMap::new();
for node_id in self.nodes.keys() {
ret.insert(*self.nodes.get(node_id).unwrap(), *node_id);
}
ret
};
let matrix = self.matrix.as_ref().unwrap();
for i in 0..matrix.ncols() {
for j in 0..matrix.nrows() {
if matrix[(i, j)] {
let from_node = idx_to_node_id.get(&i).unwrap();
let to_node = idx_to_node_id.get(&j).unwrap();
println!("{} -> {}", get_tag(*from_node, context), get_tag(*to_node, context));
}
}
}
}
println!("");
}
}
fn is_machine_reg(node: MuID) -> bool {
if node < RESERVED_NODE_IDS_FOR_MACHINE {
true
} else {
false
}
}
// from tony's code src/RegAlloc/Liveness.java
pub fn build (cf: &CompiledFunction, f: &MuFunction) {
pub fn build (cf: &CompiledFunction, f: &MuFunction) -> InterferenceGraph {
let mut ig = InterferenceGraph::new();
// FIXME: precolor nodes
// move precolor nodes to later iteration of registers
// Liveness Analysis
let n_insts = cf.mc.number_of_insts();
......@@ -36,20 +159,129 @@ pub fn build (cf: &CompiledFunction, f: &MuFunction) {
let ref mut in_set = live_in[i];
for reg_id in cf.mc.get_inst_reg_defines(i) {
ig.new_node(*reg_id);
let reg_id = *reg_id;
ig.new_node(reg_id);
// precolor
if is_machine_reg(reg_id) {
ig.color_node(reg_id, reg_id);
}
}
for reg_id in cf.mc.get_inst_reg_uses(i) {
ig.new_node(*reg_id);
in_set.push(*reg_id);
let reg_id = *reg_id;
ig.new_node(reg_id);
in_set.push(reg_id);
// precolor
if is_machine_reg(reg_id) {
ig.color_node(reg_id, reg_id);
}
}
work_list.push_front(i);
}
// all nodes has been added, we init graph (create adjacency matrix)
ig.init_graph();
// compute liveIn and liveOut iteratively
while !work_list.is_empty() {
let n = work_list.pop_front().unwrap();
let ref in_set = live_in[n];
let ref mut out_set = live_out[n];
// out = union(in[succ]) for all succs
for succ in cf.mc.get_succs(n) {
add_all(out_set, &live_in[*succ]);
}
// in = use(i.e. live_in) + (out - def)
let mut diff = out_set.clone();
for def in cf.mc.get_inst_reg_defines(n) {
remove_value(&mut diff, *def);
}
if !diff.is_empty() {
let ref mut in_set = live_in[n];
if add_all(in_set, &diff) {
for p in cf.mc.get_preds(n) {
work_list.push_front(*p);
}
}
}
}
// build interference graph
for n in 0..n_insts {
let ref mut live = live_out[n];
let src : Option<MuID> = {
if cf.mc.is_move(n) {
let src = cf.mc.get_inst_reg_uses(n);
let dst = cf.mc.get_inst_reg_defines(n);
debug_assert!(src.len() == 1);
debug_assert!(dst.len() == 1);
ig.add_move(src[0], dst[0]);
Some(src[0])
} else {
None
}
};
for d in cf.mc.get_inst_reg_defines(n) {
for t in live.iter() {
if src.is_none() || (src.is_some() && *t != src.unwrap()) {
let from = *d;
let to = *t;
if !ig.is_same_node(from, to) && !ig.is_adj(from, to) {
if !ig.node_has_color(from) {
ig.add_interference_edge(from, to);
}
if !ig.node_has_color(to) {
ig.add_interference_edge(to, from);
}
}
}
}
}
for d in cf.mc.get_inst_reg_defines(n) {
remove_value(live, *d);
}
for u in cf.mc.get_inst_reg_uses(n) {
live.push(*u);
}
}
ig
}
use std::fmt;
fn add_all<T: Copy + PartialEq> (vec: &mut Vec<T>, vec2: &Vec<T>) -> bool {
let mut is_changed = false;
for i in vec2.iter() {
if !vec.contains(i) {
vec.push(*i);
is_changed = true;
}
}
is_changed
}
fn remove_value<T: Ord + fmt::Debug + fmt::Display> (vec: &mut Vec<T>, val: T) {
match vec.binary_search(&val) {
Ok(index) => {vec.remove(index);},
Err(_) => {} // do nothing
}
}
\ No newline at end of file
}
\ No newline at end of file
......@@ -28,6 +28,7 @@ impl CompilerPass for RegisterAllocation {
cf.mc.print();
// liveness::build(&mut cf, func);
let liveness = liveness::build(&mut cf, func);
liveness.print_with(func);
}
}
\ No newline at end of file
......@@ -9,7 +9,10 @@ pub trait MachineCode {
fn print(&self);
fn number_of_insts(&self) -> usize;
fn is_move(&self, index: usize) -> bool;
fn get_succs(&self, index: usize) -> &Vec<usize>;
fn get_preds(&self, index: usize) -> &Vec<usize>;
fn get_inst_reg_uses(&self, index: usize) -> &Vec<MuID>;
fn get_inst_reg_defines(&self, index: usize) -> &Vec<MuID>;
......
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