GitLab will continue to be upgraded from 11.4.5-ce.0 on November 25th 2019 at 4.00pm (AEDT) to 5.00pm (AEDT) due to Critical Security Patch Availability. During the update, GitLab and Mattermost services will not be available.

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