WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

To protect your data, the CISO officer has suggested users to enable 2FA as soon as possible.
Currently 2.7% of users enabled 2FA.

Commit 8669dba8 authored by qinsoon's avatar qinsoon
Browse files

[wip] liveness analysis

parent ab7dde71
...@@ -7,4 +7,5 @@ authors = [ "Your name <you@example.com>" ] ...@@ -7,4 +7,5 @@ authors = [ "Your name <you@example.com>" ]
[dependencies] [dependencies]
lazy_static = "0.1.15" lazy_static = "0.1.15"
log = "0.3.5" log = "0.3.5"
simple_logger = "0.4.0" simple_logger = "0.4.0"
\ No newline at end of file nalgebra = "0.8.2"
\ No newline at end of file
...@@ -98,7 +98,8 @@ impl FunctionContent { ...@@ -98,7 +98,8 @@ impl FunctionContent {
} }
pub fn get_entry_block_mut(&mut self) -> &mut Block { 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 { pub fn get_block(&self, tag: MuTag) -> &Block {
......
...@@ -40,12 +40,20 @@ impl MachineCode for ASMCode { ...@@ -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> { 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> { fn get_inst_reg_defines(&self, index: usize) -> &Vec<MuID> {
&self.code[index].uses &self.code[index].defines
} }
fn print(&self) { fn print(&self) {
......
...@@ -82,22 +82,22 @@ lazy_static! { ...@@ -82,22 +82,22 @@ lazy_static! {
} }
lazy_static!{ lazy_static!{
pub static ref XMM0 : P<Value> = FPR!("xmm0", 20); pub static ref XMM0 : P<Value> = FPR!("xmm0", 16);
pub static ref XMM1 : P<Value> = FPR!("xmm1", 21); pub static ref XMM1 : P<Value> = FPR!("xmm1", 17);
pub static ref XMM2 : P<Value> = FPR!("xmm2", 22); pub static ref XMM2 : P<Value> = FPR!("xmm2", 18);
pub static ref XMM3 : P<Value> = FPR!("xmm3", 23); pub static ref XMM3 : P<Value> = FPR!("xmm3", 19);
pub static ref XMM4 : P<Value> = FPR!("xmm4", 24); pub static ref XMM4 : P<Value> = FPR!("xmm4", 20);
pub static ref XMM5 : P<Value> = FPR!("xmm5", 25); pub static ref XMM5 : P<Value> = FPR!("xmm5", 21);
pub static ref XMM6 : P<Value> = FPR!("xmm6", 26); pub static ref XMM6 : P<Value> = FPR!("xmm6", 22);
pub static ref XMM7 : P<Value> = FPR!("xmm7", 27); pub static ref XMM7 : P<Value> = FPR!("xmm7", 23);
pub static ref XMM8 : P<Value> = FPR!("xmm8", 28); pub static ref XMM8 : P<Value> = FPR!("xmm8", 24);
pub static ref XMM9 : P<Value> = FPR!("xmm9", 29); pub static ref XMM9 : P<Value> = FPR!("xmm9", 25);
pub static ref XMM10 : P<Value> = FPR!("xmm10",30); pub static ref XMM10 : P<Value> = FPR!("xmm10",26);
pub static ref XMM11 : P<Value> = FPR!("xmm11",31); pub static ref XMM11 : P<Value> = FPR!("xmm11",27);
pub static ref XMM12 : P<Value> = FPR!("xmm12",32); pub static ref XMM12 : P<Value> = FPR!("xmm12",28);
pub static ref XMM13 : P<Value> = FPR!("xmm13",33); pub static ref XMM13 : P<Value> = FPR!("xmm13",29);
pub static ref XMM14 : P<Value> = FPR!("xmm14",34); pub static ref XMM14 : P<Value> = FPR!("xmm14",30);
pub static ref XMM15 : P<Value> = FPR!("xmm15",35); pub static ref XMM15 : P<Value> = FPR!("xmm15",31);
pub static ref RETURN_FPRs : [P<Value>; 2] = [ pub static ref RETURN_FPRs : [P<Value>; 2] = [
XMM0.clone(), XMM0.clone(),
...@@ -116,6 +116,54 @@ lazy_static!{ ...@@ -116,6 +116,54 @@ lazy_static!{
pub static ref CALLEE_SAVED_FPRs : [P<Value>; 0] = []; 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 { pub fn is_valid_x86_imm(op: &P<Value>) -> bool {
use std::u32; use std::u32;
match op.v { match op.v {
......
...@@ -7,4 +7,7 @@ mod x86_64; ...@@ -7,4 +7,7 @@ mod x86_64;
#[cfg(target_arch = "arm")] #[cfg(target_arch = "arm")]
#[path = "arch/arm/mod.rs"] #[path = "arch/arm/mod.rs"]
mod arm; mod arm;
\ No newline at end of file
#[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::CompiledFunction;
use vm::machine_code::MachineCode; use vm::machine_code::MachineCode;
use ast::ir::*; use ast::ir::*;
use compiler::backend::get_name_for_value as get_tag;
use std::collections::LinkedList; use std::collections::LinkedList;
use std::collections::{HashMap, HashSet};
use self::nalgebra::DMatrix;
type MatrixIndex = usize;
pub struct InterferenceGraph { pub struct InterferenceGraph {
foo: usize nodes: HashMap<MuID, MatrixIndex>,
matrix: Option<DMatrix<bool>>,
color: HashMap<MuID, MuID>,
moves: HashSet<(MuID, MuID)>
} }
impl InterferenceGraph { impl InterferenceGraph {
fn new() -> 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 // 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(); let mut ig = InterferenceGraph::new();
// FIXME: precolor nodes // move precolor nodes to later iteration of registers
// Liveness Analysis // Liveness Analysis
let n_insts = cf.mc.number_of_insts(); let n_insts = cf.mc.number_of_insts();
...@@ -36,20 +159,129 @@ pub fn build (cf: &CompiledFunction, f: &MuFunction) { ...@@ -36,20 +159,129 @@ pub fn build (cf: &CompiledFunction, f: &MuFunction) {
let ref mut in_set = live_in[i]; let ref mut in_set = live_in[i];
for reg_id in cf.mc.get_inst_reg_defines(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) { for reg_id in cf.mc.get_inst_reg_uses(i) {
ig.new_node(*reg_id); let reg_id = *reg_id;
in_set.push(*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); 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() { while !work_list.is_empty() {
let n = work_list.pop_front().unwrap(); let n = work_list.pop_front().unwrap();
let ref in_set = live_in[n];
let ref mut out_set = live_out[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 { ...@@ -28,6 +28,7 @@ impl CompilerPass for RegisterAllocation {
cf.mc.print(); 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 { ...@@ -9,7 +9,10 @@ pub trait MachineCode {
fn print(&self); fn print(&self);
fn number_of_insts(&self) -> usize; fn number_of_insts(&self) -> usize;
fn is_move(&self, index: usize) -> bool; 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_uses(&self, index: usize) -> &Vec<MuID>;
fn get_inst_reg_defines(&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