Commit 4f5b2e41 authored by qinsoon's avatar qinsoon

massive refactoring. tree gen pass seems fine

parent b974c3b1
This diff is collapsed.
use ast::ir::*;
use ast::ir::Instruction_::*;
pub fn is_terminal_inst(inst: &Instruction_) -> bool {
match inst {
&BinOp(_, _, _)
| &CmpOp(_, _, _)
| &ExprCall{..}
| &Load{..}
| &Store{..}
| &CmpXchg{..}
| &AtomicRMW{..}
| &New(_)
| &AllocA(_)
| &NewHybrid(_, _)
| &AllocAHybrid(_, _)
| &NewStack(_)
| &NewThread(_, _)
| &NewThreadExn(_, _)
| &NewFrameCursor(_)
| &GetIRef(_)
| &GetFieldIRef{..}
| &GetElementIRef{..}
| &ShiftIRef{..}
| &GetVarPartIRef{..}
| &Fence(_) => false,
&Return(_)
| &ThreadExit
| &Throw(_)
| &TailCall(_)
| &Branch1(_)
| &Branch2{..}
| &Watchpoint{..}
| &WPBranch{..}
| &Call{..}
| &SwapStack{..}
| &Switch{..}
| &ExnInstruction{..} => true
}
}
pub fn is_non_terminal_inst(inst: &Instruction_) -> bool {
!is_terminal_inst(inst)
}
// FIXME: check the correctness
pub fn has_side_effect(inst: &Instruction_) -> bool {
match inst {
&BinOp(_, _, _) => false,
&CmpOp(_, _, _) => false,
&ExprCall{..} => true,
&Load{..} => true,
&Store{..} => true,
&CmpXchg{..} => true,
&AtomicRMW{..} => true,
&New(_) => true,
&AllocA(_) => true,
&NewHybrid(_, _) => true,
&AllocAHybrid(_, _) => true,
&NewStack(_) => true,
&NewThread(_, _) => true,
&NewThreadExn(_, _) => true,
&NewFrameCursor(_) => true,
&GetIRef(_) => false,
&GetFieldIRef{..} => false,
&GetElementIRef{..} => false,
&ShiftIRef{..} => false,
&GetVarPartIRef{..} => false,
&Fence(_) => true,
&Return(_) => true,
&ThreadExit => true,
&Throw(_) => true,
&TailCall(_) => true,
&Branch1(_) => true,
&Branch2{..} => true,
&Watchpoint{..} => true,
&WPBranch{..} => true,
&Call{..} => true,
&SwapStack{..} => true,
&Switch{..} => true,
&ExnInstruction{..} => true
}
}
\ No newline at end of file
pub mod types;
pub mod ir;
pub mod ir_semantics;
pub mod ptr;
pub mod op;
\ No newline at end of file
use ast::ir::*;
use ast::ptr::*;
use vm::context::VMContext;
use compiler::CompilerPass;
......@@ -13,16 +14,7 @@ impl DefUse {
}
}
impl CompilerPass for DefUse {
fn name(&self) -> &'static str {
self.name
}
#[allow(unused_variables)]
fn visit_inst(&mut self, vm_context: &VMContext, func_context: &mut FunctionContext, node: &mut TreeNode) {
match node.v {
TreeNode_::Instruction(ref inst) => {
for op in inst.list_operands() {
fn use_op(op: &P<TreeNode>, func_context: &mut FunctionContext) {
match op.v {
TreeNode_::Value(ref val) => {
match val.v {
......@@ -35,6 +27,31 @@ impl CompilerPass for DefUse {
},
_ => {} // dont worry about instruction
}
}
impl CompilerPass for DefUse {
fn name(&self) -> &'static str {
self.name
}
#[allow(unused_variables)]
fn visit_block(&mut self, vm_context: &VMContext, func_context: &mut FunctionContext, block: &mut Block) {
// if an SSA appears in keepalives, its use count increases
let ref mut keepalives = block.content.as_mut().unwrap().keepalives;
if keepalives.is_some() {
for op in keepalives.as_mut().unwrap().iter_mut() {
use_op(op, func_context);
}
}
}
#[allow(unused_variables)]
fn visit_inst(&mut self, vm_context: &VMContext, func_context: &mut FunctionContext, node: &mut TreeNode) {
// if an SSA appears in operands of instrs, its use count increases
match node.v {
TreeNode_::Instruction(ref inst) => {
for op in inst.ops.borrow().iter() {
use_op(op, func_context);
}
},
_ => panic!("expected instruction node in visit_inst()")
......
use ast::ir::*;
use ast::ir_semantics::*;
use vm::context::VMContext;
use compiler::CompilerPass;
pub struct TreeGen {
name: &'static str,
name: &'static str
}
impl TreeGen {
......@@ -10,8 +13,118 @@ impl TreeGen {
}
}
fn is_movable(expr: &Instruction_) -> bool {
!has_side_effect(expr)
}
impl CompilerPass for TreeGen {
fn name(&self) -> &'static str {
self.name
}
fn execute(&mut self, vm_context: &VMContext, func: &mut MuFunction) {
debug!("---CompilerPass {} for {}---", self.name(), func.fn_name);
for entry in func.content.as_mut().unwrap().blocks.iter_mut() {
let label : MuTag = entry.0;
let ref mut block : &mut Block = &mut entry.1;
// take its content, we will need to put it back
let mut content = block.content.take().unwrap();
let body = content.body;
let mut new_body = vec![];
trace!("check block {}", label);
trace!("");
for node in body.into_iter() {
trace!("check inst: {:?}", node);
match &node.v {
&TreeNode_::Instruction(ref inst) => {
// check if any operands can be replaced by expression
{
trace!("check if we can replace any operand with inst");
let mut ops = inst.ops.borrow_mut();
for index in 0..ops.len() {
let possible_ssa_id = ops[index].extract_ssa_id();
if possible_ssa_id.is_some() {
let entry_value = func.context.get_value_mut(possible_ssa_id.unwrap()).unwrap();
if entry_value.expr.is_some() {
// replace the node with its expr
let expr = entry_value.expr.take().unwrap();
trace!("{:?} replaced by {:?}", ops[index], expr);
ops[index] = TreeNode::new_inst(expr);
}
} else {
trace!("{:?} cant be replaced", ops[index]);
}
}
}
// check if left hand side of an assignment has a single use
trace!("check if we should fold the inst");
if inst.value.is_some() {
let left = inst.value.as_ref().unwrap();
// if left is _one_ variable that is used once
// we can put the expression as a child node to its use
if left.len() == 1 {
let lhs = func.context.get_value_mut(left[0].extract_ssa_id().unwrap()).unwrap();
if lhs.use_count.get() == 1{
if is_movable(&inst.v) {
lhs.expr = Some(inst.clone()); // FIXME: should be able to move the inst here
trace!("yes");
trace!("");
continue;
} else {
trace!("no, not movable");
}
} else {
trace!("no, use count more than 1");
}
} else {
trace!("no, yields more than 1 SSA var");
}
} else {
trace!("no, no value yielded");
}
},
_ => panic!("expected an instruction node here")
}
trace!("add {:?} back to block {}", node, label);
trace!("");
new_body.push(node);
}
content.body = new_body;
trace!("block {} has {} insts", label, content.body.len());
trace!("");
// put the content back
block.content = Some(content);
}
self.finish_function(vm_context, func);
debug!("---finish---");
}
#[allow(unused_variables)]
fn finish_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {
debug!("check depth tree for {}", func.fn_name);
for entry in func.content.as_ref().unwrap().blocks.iter() {
debug!("block {}", entry.0);
for inst in entry.1.content.as_ref().unwrap().body.iter() {
debug!("{:?}", inst);
}
}
}
}
\ No newline at end of file
......@@ -32,7 +32,7 @@ fn test_use_count() {
}
#[test]
fn test_tree_gen() {
fn test_build_tree() {
simple_logger::init_with_level(log::LogLevel::Trace).ok();
let vm_context : VMContext = factorial();
......
......@@ -6,6 +6,8 @@ use self::mu::ast::ptr::*;
use self::mu::ast::op::*;
use self::mu::vm::context::*;
use std::cell::RefCell;
#[test]
#[allow(unused_variables)]
fn test_factorial() {
......@@ -47,23 +49,26 @@ pub fn factorial() -> VMContext {
// %v48 = EQ <@int_64> %n_3 @int_64_1
let blk_0_v48 = func.new_ssa(1, "blk_0_v48", type_def_int64.clone());
let blk_0_v48_expr = Expression_::CmpOp(
CmpOp::EQ,
blk_0_n_3.clone(),
const_def_int64_1_local.clone()
);
let blk_0_inst0 = TreeNode::new_inst(Instruction::Assign{left: vec![blk_0_v48.clone()], right: blk_0_v48_expr});
let blk_0_inst0 = TreeNode::new_inst(Instruction {
value: Some(vec![blk_0_v48.clone()]),
ops: RefCell::new(vec![blk_0_n_3.clone(), const_def_int64_1_local.clone()]),
v: Instruction_::CmpOp(CmpOp::EQ, 0, 1)
});
// BRANCH2 %v48 %blk_2(@int_64_1) %blk_1(%n_3)
let blk_0_term = TreeNode::new_inst(Instruction::Branch2{
cond: blk_0_v48.clone(),
let blk_0_term = TreeNode::new_inst(Instruction{
value: None,
ops: RefCell::new(vec![blk_0_v48.clone(), const_def_int64_1_local.clone(), blk_0_n_3.clone()]),
v: Instruction_::Branch2 {
cond: 0,
true_dest: Destination {
target: "blk_2",
args: vec![DestArg::Normal(const_def_int64_1_local.clone())]
args: vec![DestArg::Normal(1)]
},
false_dest: Destination {
target: "blk_1",
args: vec![DestArg::Normal(blk_0_n_3.clone())]
args: vec![DestArg::Normal(2)]
}
}
});
......@@ -79,7 +84,11 @@ pub fn factorial() -> VMContext {
let blk_2_v53 = func.new_ssa(2, "blk_2_v53", type_def_int64.clone());
// RET %v53
let blk_2_term = TreeNode::new_inst(Instruction::Return(vec![blk_2_v53.clone()]));
let blk_2_term = TreeNode::new_inst(Instruction{
value: None,
ops: RefCell::new(vec![blk_2_v53.clone()]),
v: Instruction_::Return(vec![0])
});
let blk_2_content = BlockContent {
args: vec![blk_2_v53.clone()],
......@@ -94,21 +103,21 @@ pub fn factorial() -> VMContext {
// %v50 = SUB <@int_64> %n_3 @int_64_1
let blk_1_v50 = func.new_ssa(4, "blk_1_v50", type_def_int64.clone());
let blk_1_v50_expr = Expression_::BinOp(
BinOp::Sub,
blk_1_n_3.clone(),
const_def_int64_1_local.clone()
);
let blk_1_inst0 = TreeNode::new_inst(Instruction::Assign{left: vec![blk_1_v50.clone()], right: blk_1_v50_expr});
let blk_1_inst0 = TreeNode::new_inst(Instruction{
value: Some(vec![blk_1_v50.clone()]),
ops: RefCell::new(vec![blk_1_n_3.clone(), const_def_int64_1_local.clone()]),
v: Instruction_::BinOp(BinOp::Sub, 0, 1)
});
// %v51 = CALL <@fac_sig> @fac (%v50)
let blk_1_v51 = func.new_ssa(5, "blk_1_v51", type_def_int64.clone());
let blk_1_inst1 = TreeNode::new_inst(Instruction::Assign{
left: vec![blk_1_v51.clone()],
right: Expression_::ExprCall {
let blk_1_inst1 = TreeNode::new_inst(Instruction{
value: Some(vec![blk_1_v51.clone()]),
ops: RefCell::new(vec![func.new_ssa(6, "blk_1_fac", P(MuType::funcref(fac_sig.clone()))), blk_1_v50.clone()]),
v: Instruction_::ExprCall {
data: CallData {
func: func.new_ssa(6, "blk_1_fac", P(MuType::funcref(fac_sig.clone()))),
args: vec![blk_1_v50.clone()],
func: 0,
args: vec![1],
convention: CallConvention::Mu
},
is_abort: true
......@@ -117,22 +126,20 @@ pub fn factorial() -> VMContext {
// %v52 = MUL <@int_64> %n_3 %v51
let blk_1_v52 = func.new_ssa(7, "blk_1_v52", type_def_int64.clone());
let blk_1_v52_expr = Expression_::BinOp(
BinOp::Mul,
blk_1_n_3.clone(),
blk_1_v51.clone()
);
let blk_1_inst2 = TreeNode::new_inst(Instruction::Assign{
left: vec![blk_1_v52.clone()],
right: blk_1_v52_expr
let blk_1_inst2 = TreeNode::new_inst(Instruction{
value: Some(vec![blk_1_v52.clone()]),
ops: RefCell::new(vec![blk_1_n_3.clone(), blk_1_v51.clone()]),
v: Instruction_::BinOp(BinOp::Mul, 0, 1)
});
let blk_1_term = TreeNode::new_inst(Instruction::Branch1 (
Destination {
let blk_1_term = TreeNode::new_inst(Instruction{
value: None,
ops: RefCell::new(vec![blk_1_v52.clone()]),
v: Instruction_::Branch1(Destination {
target: "blk_2",
args: vec![DestArg::Normal(blk_1_v52.clone())]
}
));
args: vec![DestArg::Normal(0)]
})
});
let blk_1_content = BlockContent {
args: vec![blk_1_n_3.clone()],
......
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