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 types;
pub mod ir; pub mod ir;
pub mod ir_semantics;
pub mod ptr; pub mod ptr;
pub mod op; pub mod op;
\ No newline at end of file
use ast::ir::*; use ast::ir::*;
use ast::ptr::*;
use vm::context::VMContext; use vm::context::VMContext;
use compiler::CompilerPass; use compiler::CompilerPass;
...@@ -13,28 +14,44 @@ impl DefUse { ...@@ -13,28 +14,44 @@ impl DefUse {
} }
} }
fn use_op(op: &P<TreeNode>, func_context: &mut FunctionContext) {
match op.v {
TreeNode_::Value(ref val) => {
match val.v {
Value_::SSAVar(ref id) => {
let entry = func_context.values.get_mut(id).unwrap();
entry.use_count.set(entry.use_count.get() + 1);
},
_ => {} // dont worry about constants
}
},
_ => {} // dont worry about instruction
}
}
impl CompilerPass for DefUse { impl CompilerPass for DefUse {
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
self.name 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)] #[allow(unused_variables)]
fn visit_inst(&mut self, vm_context: &VMContext, func_context: &mut FunctionContext, node: &mut TreeNode) { 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 { match node.v {
TreeNode_::Instruction(ref inst) => { TreeNode_::Instruction(ref inst) => {
for op in inst.list_operands() { for op in inst.ops.borrow().iter() {
match op.v { use_op(op, func_context);
TreeNode_::Value(ref val) => {
match val.v {
Value_::SSAVar(ref id) => {
let entry = func_context.values.get_mut(id).unwrap();
entry.use_count.set(entry.use_count.get() + 1);
},
_ => {} // dont worry about constants
}
},
_ => {} // dont worry about instruction
}
} }
}, },
_ => panic!("expected instruction node in visit_inst()") _ => panic!("expected instruction node in visit_inst()")
......
use ast::ir::*;
use ast::ir_semantics::*;
use vm::context::VMContext;
use compiler::CompilerPass; use compiler::CompilerPass;
pub struct TreeGen { pub struct TreeGen {
name: &'static str, name: &'static str
} }
impl TreeGen { impl TreeGen {
...@@ -10,8 +13,118 @@ impl TreeGen { ...@@ -10,8 +13,118 @@ impl TreeGen {
} }
} }
fn is_movable(expr: &Instruction_) -> bool {
!has_side_effect(expr)
}
impl CompilerPass for TreeGen { impl CompilerPass for TreeGen {
fn name(&self) -> &'static str { fn name(&self) -> &'static str {
self.name 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() { ...@@ -32,7 +32,7 @@ fn test_use_count() {
} }
#[test] #[test]
fn test_tree_gen() { fn test_build_tree() {
simple_logger::init_with_level(log::LogLevel::Trace).ok(); simple_logger::init_with_level(log::LogLevel::Trace).ok();
let vm_context : VMContext = factorial(); let vm_context : VMContext = factorial();
......
...@@ -6,6 +6,8 @@ use self::mu::ast::ptr::*; ...@@ -6,6 +6,8 @@ use self::mu::ast::ptr::*;
use self::mu::ast::op::*; use self::mu::ast::op::*;
use self::mu::vm::context::*; use self::mu::vm::context::*;
use std::cell::RefCell;
#[test] #[test]
#[allow(unused_variables)] #[allow(unused_variables)]
fn test_factorial() { fn test_factorial() {
...@@ -47,23 +49,26 @@ pub fn factorial() -> VMContext { ...@@ -47,23 +49,26 @@ pub fn factorial() -> VMContext {
// %v48 = EQ <@int_64> %n_3 @int_64_1 // %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 = func.new_ssa(1, "blk_0_v48", type_def_int64.clone());
let blk_0_v48_expr = Expression_::CmpOp( let blk_0_inst0 = TreeNode::new_inst(Instruction {
CmpOp::EQ, value: Some(vec![blk_0_v48.clone()]),
blk_0_n_3.clone(), ops: RefCell::new(vec![blk_0_n_3.clone(), const_def_int64_1_local.clone()]),
const_def_int64_1_local.clone() v: Instruction_::CmpOp(CmpOp::EQ, 0, 1)
); });
let blk_0_inst0 = TreeNode::new_inst(Instruction::Assign{left: vec![blk_0_v48.clone()], right: blk_0_v48_expr});
// BRANCH2 %v48 %blk_2(@int_64_1) %blk_1(%n_3)
// BRANCH2 %v48 %blk_2(@int_64_1) %blk_1(%n_3) let blk_0_term = TreeNode::new_inst(Instruction{
let blk_0_term = TreeNode::new_inst(Instruction::Branch2{ value: None,
cond: blk_0_v48.clone(), ops: RefCell::new(vec![blk_0_v48.clone(), const_def_int64_1_local.clone(), blk_0_n_3.clone()]),
true_dest: Destination { v: Instruction_::Branch2 {
target: "blk_2", cond: 0,
args: vec![DestArg::Normal(const_def_int64_1_local.clone())] true_dest: Destination {
}, target: "blk_2",
false_dest: Destination { args: vec![DestArg::Normal(1)]
target: "blk_1", },
args: vec![DestArg::Normal(blk_0_n_3.clone())] false_dest: Destination {
target: "blk_1",
args: vec![DestArg::Normal(2)]
}
} }
}); });
...@@ -79,7 +84,11 @@ pub fn factorial() -> VMContext { ...@@ -79,7 +84,11 @@ pub fn factorial() -> VMContext {
let blk_2_v53 = func.new_ssa(2, "blk_2_v53", type_def_int64.clone()); let blk_2_v53 = func.new_ssa(2, "blk_2_v53", type_def_int64.clone());
// RET %v53 // 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 { let blk_2_content = BlockContent {
args: vec![blk_2_v53.clone()], args: vec![blk_2_v53.clone()],
...@@ -94,45 +103,43 @@ pub fn factorial() -> VMContext { ...@@ -94,45 +103,43 @@ pub fn factorial() -> VMContext {
// %v50 = SUB <@int_64> %n_3 @int_64_1 // %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 = func.new_ssa(4, "blk_1_v50", type_def_int64.clone());
let blk_1_v50_expr = Expression_::BinOp( let blk_1_inst0 = TreeNode::new_inst(Instruction{
BinOp::Sub, value: Some(vec![blk_1_v50.clone()]),
blk_1_n_3.clone(), ops: RefCell::new(vec![blk_1_n_3.clone(), const_def_int64_1_local.clone()]),
const_def_int64_1_local.clone() v: Instruction_::BinOp(BinOp::Sub, 0, 1)
); });
let blk_1_inst0 = TreeNode::new_inst(Instruction::Assign{left: vec![blk_1_v50.clone()], right: blk_1_v50_expr});
// %v51 = CALL <@fac_sig> @fac (%v50) // %v51 = CALL <@fac_sig> @fac (%v50)
let blk_1_v51 = func.new_ssa(5, "blk_1_v51", type_def_int64.clone()); let blk_1_v51 = func.new_ssa(5, "blk_1_v51", type_def_int64.clone());
let blk_1_inst1 = TreeNode::new_inst(Instruction::Assign{ let blk_1_inst1 = TreeNode::new_inst(Instruction{
left: vec![blk_1_v51.clone()], value: Some(vec![blk_1_v51.clone()]),
right: Expression_::ExprCall { ops: RefCell::new(vec![func.new_ssa(6, "blk_1_fac", P(MuType::funcref(fac_sig.clone()))), blk_1_v50.clone()]),
data: CallData { v: Instruction_::ExprCall {
func: func.new_ssa(6, "blk_1_fac", P(MuType::funcref(fac_sig.clone()))), data: CallData {
args: vec![blk_1_v50.clone()], func: 0,
convention: CallConvention::Mu args: vec![1],
}, convention: CallConvention::Mu
is_abort: true },
} is_abort: true
}
}); });
// %v52 = MUL <@int_64> %n_3 %v51 // %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 = func.new_ssa(7, "blk_1_v52", type_def_int64.clone());
let blk_1_v52_expr = Expression_::BinOp( let blk_1_inst2 = TreeNode::new_inst(Instruction{
BinOp::Mul, value: Some(vec![blk_1_v52.clone()]),
blk_1_n_3.clone(), ops: RefCell::new(vec![blk_1_n_3.clone(), blk_1_v51.clone()]),
blk_1_v51.clone() v: Instruction_::BinOp(BinOp::Mul, 0, 1)
);
let blk_1_inst2 = TreeNode::new_inst(Instruction::Assign{
left: vec![blk_1_v52.clone()],
right: blk_1_v52_expr
}); });
let blk_1_term = TreeNode::new_inst(Instruction::Branch1 ( let blk_1_term = TreeNode::new_inst(Instruction{
Destination { value: None,
target: "blk_2", ops: RefCell::new(vec![blk_1_v52.clone()]),
args: vec![DestArg::Normal(blk_1_v52.clone())] v: Instruction_::Branch1(Destination {
} target: "blk_2",
)); args: vec![DestArg::Normal(0)]
})
});
let blk_1_content = BlockContent { let blk_1_content = BlockContent {
args: vec![blk_1_n_3.clone()], 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