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 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