Commit 59365600 authored by qinsoon's avatar qinsoon

[wip] pass var liveness from IR to backend

parent d502ed4d
......@@ -3,6 +3,7 @@ use ast::ptr::*;
use ast::types::*;
use ast::op::*;
use utils::vec_utils::as_str as vector_as_str;
use utils::vec_utils;
use std::fmt;
use std::cell::RefCell;
......@@ -364,6 +365,16 @@ impl Destination {
ret
}
pub fn get_arguments(&self, ops: &Vec<P<TreeNode>>) -> Vec<P<Value>> {
vec_utils::map(&self.args,
|x| {
match x {
&DestArg::Normal(i) => ops[i].clone_value(),
&DestArg::Freshbound(_) => unimplemented!()
}
})
}
}
#[derive(Clone, Debug)]
......
......@@ -3,6 +3,7 @@ use ast::types::*;
use ast::inst::*;
use ast::op::*;
use utils::vec_utils::as_str as vector_as_str;
use utils::vec_utils;
use std::collections::HashMap;
use std::fmt;
......@@ -236,6 +237,77 @@ pub struct BlockContent {
pub keepalives: Option<Vec<P<Value>>>
}
impl BlockContent {
pub fn get_out_arguments(&self) -> Vec<P<Value>> {
let n_insts = self.body.len();
let ref last_inst = self.body[n_insts - 1];
let mut ret : Vec<P<Value>> = vec![];
match last_inst.v {
TreeNode_::Instruction(ref inst) => {
let ops = inst.ops.borrow();
match inst.v {
Instruction_::Return(_)
| Instruction_::ThreadExit
| Instruction_::Throw(_)
| Instruction_::TailCall(_) => {
// they do not have explicit liveouts
}
Instruction_::Branch1(ref dest) => {
let mut live_outs = dest.get_arguments(&ops);
vec_utils::append_unique(&mut ret, &mut live_outs);
}
Instruction_::Branch2{ref true_dest, ref false_dest, ..} => {
let mut live_outs = true_dest.get_arguments(&ops);
live_outs.append(&mut false_dest.get_arguments(&ops));
vec_utils::append_unique(&mut ret, &mut live_outs);
}
Instruction_::Watchpoint{ref disable_dest, ref resume, ..} => {
let mut live_outs = vec![];
if disable_dest.is_some() {
live_outs.append(&mut disable_dest.as_ref().unwrap().get_arguments(&ops));
}
live_outs.append(&mut resume.normal_dest.get_arguments(&ops));
live_outs.append(&mut resume.exn_dest.get_arguments(&ops));
vec_utils::append_unique(&mut ret, &mut live_outs);
}
Instruction_::WPBranch{ref disable_dest, ref enable_dest, ..} => {
let mut live_outs = vec![];
live_outs.append(&mut disable_dest.get_arguments(&ops));
live_outs.append(&mut enable_dest.get_arguments(&ops));
vec_utils::append_unique(&mut ret, &mut live_outs);
}
Instruction_::Call{ref resume, ..}
| Instruction_::SwapStack{ref resume, ..}
| Instruction_::ExnInstruction{ref resume, ..} => {
let mut live_outs = vec![];
live_outs.append(&mut resume.normal_dest.get_arguments(&ops));
live_outs.append(&mut resume.exn_dest.get_arguments(&ops));
vec_utils::append_unique(&mut ret, &mut live_outs);
}
Instruction_::Switch{ref default, ref branches, ..} => {
let mut live_outs = vec![];
live_outs.append(&mut default.get_arguments(&ops));
for &(_, ref dest) in branches {
live_outs.append(&mut dest.get_arguments(&ops));
}
vec_utils::append_unique(&mut ret, &mut live_outs);
}
_ => panic!("didn't expect last inst as {:?}", inst)
}
},
_ => panic!("expect last treenode of block is a inst")
}
ret
}
}
#[derive(Debug, Clone)]
/// always use with P<TreeNode>
pub struct TreeNode {
......@@ -269,7 +341,14 @@ impl TreeNode {
pub fn clone_value(&self) -> P<Value> {
match self.v {
TreeNode_::Value(ref val) => val.clone(),
_ => panic!("expecting a value")
TreeNode_::Instruction(ref inst) => {
info!("expecting a value, but we found an inst. Instead we use its first value");
let vals = inst.value.as_ref().unwrap();
if vals.len() != 1 {
panic!("we expect an inst with 1 value, but found multiple or zero (it should not be here - folded as a child)");
}
vals[0].clone()
}
}
}
......@@ -309,7 +388,7 @@ pub enum TreeNode_ {
}
/// always use with P<Value>
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub struct Value {
pub tag: MuTag,
pub ty: P<MuType>,
......@@ -377,7 +456,7 @@ impl fmt::Display for Value {
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub enum Value_ {
SSAVar(MuID),
Constant(Constant)
......@@ -409,7 +488,7 @@ impl fmt::Display for SSAVarEntry {
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub enum Constant {
Int(usize),
Float(f32),
......
......@@ -28,7 +28,10 @@ struct ASMCode {
idx_to_blk: HashMap<usize, MuTag>,
blk_to_idx: HashMap<MuTag, usize>,
cond_branches: HashMap<usize, MuTag>,
branches: HashMap<usize, MuTag>
branches: HashMap<usize, MuTag>,
block_livein: HashMap<MuTag, Vec<MuID>>,
block_liveout: HashMap<MuTag, Vec<MuID>>
}
impl MachineCode for ASMCode {
......@@ -421,7 +424,10 @@ impl CodeGenerator for ASMCodeGen {
idx_to_blk: HashMap::new(),
blk_to_idx: HashMap::new(),
cond_branches: HashMap::new(),
branches: HashMap::new()
branches: HashMap::new(),
block_livein: HashMap::new(),
block_liveout: HashMap::new()
}));
// to link with C sources via gcc
......@@ -460,6 +466,45 @@ impl CodeGenerator for ASMCodeGen {
self.add_asm_block_label(label, block_name);
}
fn set_block_livein(&mut self, block_name: MuTag, live_in: &Vec<P<Value>>) {
let cur = self.cur_mut();
let mut res = {
if !cur.block_livein.contains_key(&block_name) {
cur.block_livein.insert(block_name, vec![]);
} else {
panic!("seems we are inserting livein to block {} twice", block_name);
}
cur.block_livein.get_mut(&block_name).unwrap()
};
for value in live_in {
res.push(value.extract_ssa_id().unwrap());
}
}
fn set_block_liveout(&mut self, block_name: MuTag, live_out: &Vec<P<Value>>) {
let cur = self.cur_mut();
let mut res = {
if !cur.block_liveout.contains_key(&block_name) {
cur.block_liveout.insert(block_name, vec![]);
} else {
panic!("seems we are inserting livein to block {} twice", block_name);
}
cur.block_liveout.get_mut(&block_name).unwrap()
};
for value in live_out {
match value.extract_ssa_id() {
Some(id) => res.push(id),
None => {}
}
}
}
fn emit_cmp_r64_r64(&mut self, op1: &P<Value>, op2: &P<Value>) {
trace!("emit: cmp {} {}", op1, op2);
......
......@@ -11,6 +11,8 @@ pub trait CodeGenerator {
fn print_cur_code(&self);
fn start_block(&mut self, block_name: MuTag);
fn set_block_livein(&mut self, block_name: MuTag, live_in: &Vec<P<Value>>);
fn set_block_liveout(&mut self, block_name: MuTag, live_out: &Vec<P<Value>>);
fn emit_cmp_r64_r64(&mut self, op1: &P<Value>, op2: &P<Value>);
fn emit_cmp_r64_imm32(&mut self, op1: &P<Value>, op2: u32);
......
......@@ -681,6 +681,13 @@ impl CompilerPass for InstructionSelection {
self.backend.start_block(block.label);
let block_content = block.content.as_ref().unwrap();
// live in is args of the block
self.backend.set_block_livein(block.label, &block_content.args);
// live out is the union of all branch args of this block
let live_out = block_content.get_out_arguments();
self.backend.set_block_liveout(block.label, &live_out);
for inst in block_content.body.iter() {
self.instruction_select(inst, func);
......
......@@ -18,18 +18,18 @@ macro_rules! select_value {
// They are not included in the standard libarary.
// (because they are likely inefficient?)
pub mod vec_utils {
use std::fmt;
pub fn as_str<T: fmt::Display>(vec: &Vec<T>) -> String {
let mut ret = String::new();
for i in 0..vec.len() {
ret.push_str(format!("{}", vec[i]).as_str());
if i != vec.len() - 1 {
ret.push_str(", ");
}
}
ret
}
use std::fmt;
pub fn as_str<T: fmt::Display>(vec: &Vec<T>) -> String {
let mut ret = String::new();
for i in 0..vec.len() {
ret.push_str(format!("{}", vec[i]).as_str());
if i != vec.len() - 1 {
ret.push_str(", ");
}
}
ret
}
pub fn add_all<T: Copy + PartialEq> (vec: &mut Vec<T>, vec2: &Vec<T>) -> bool {
let mut is_changed = false;
......@@ -43,6 +43,19 @@ pub mod vec_utils {
is_changed
}
pub fn add_unique<T: PartialEq> (vec: &mut Vec<T>, val: T) {
if !vec.contains(&val) {
vec.push(val);
}
}
pub fn append_unique<T: PartialEq> (vec: &mut Vec<T>, vec2: &mut Vec<T>) {
while !vec2.is_empty() {
let val = vec2.pop().unwrap();
add_unique(vec, val);
}
}
pub fn find_value<T: PartialEq> (vec: &Vec<T>, val: T) -> Option<usize> {
for i in 0..vec.len() {
......@@ -60,6 +73,17 @@ pub mod vec_utils {
None => {} // do nothing
}
}
pub fn map<T, Q, F> (vec: &Vec<T>, map_func: F) -> Vec<Q>
where F : Fn(&T) -> Q {
let mut ret = vec![];
for t in vec {
ret.push(map_func(t));
}
ret
}
}
pub mod string_utils {
......
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