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 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,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 {
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.list_operands() {
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
}
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});
// 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(),
true_dest: Destination {
target: "blk_2",
args: vec![DestArg::Normal(const_def_int64_1_local.clone())]
},
false_dest: Destination {
target: "blk_1",
args: vec![DestArg::Normal(blk_0_n_3.clone())]
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{
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(1)]
},
false_dest: Destination {
target: "blk_1",
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,45 +103,43 @@ 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 {
data: CallData {
func: func.new_ssa(6, "blk_1_fac", P(MuType::funcref(fac_sig.clone()))),
args: vec![blk_1_v50.clone()],
convention: CallConvention::Mu
},
is_abort: true
}
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: 0,
args: vec![1],
convention: CallConvention::Mu
},
is_abort: true
}
});
// %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 {
target: "blk_2",
args: vec![DestArg::Normal(blk_1_v52.clone())]
}
));
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(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