Commit aeaa960c authored by qinsoon's avatar qinsoon

control flow analysis before inst sel. need more tests

parent f66a2348
This diff is collapsed.
This diff is collapsed.
use ast::ir::*;
use ast::ir::Instruction_::*;
use ast::inst::*;
use ast::inst::Instruction_::*;
pub fn is_terminal_inst(inst: &Instruction_) -> bool {
match inst {
......
#[macro_use]
pub mod inst;
pub mod types;
pub mod ir;
pub mod ir_semantics;
......
use std::fmt;
use ast::ptr::P;
use ast::ir::*;
use common::vector_as_str;
use std::fmt;
use std::collections::HashMap;
use std::sync::RwLock;
......@@ -67,7 +68,7 @@ impl fmt::Display for MuType_ {
&MuType_::WeakRef(ref ty) => write!(f, "weakref<{}>", ty),
&MuType_::UPtr(ref ty) => write!(f, "uptr<{}>", ty),
&MuType_::Array(ref ty, size) => write!(f, "array<{} {}>", ty, size),
&MuType_::Hybrid(ref fix_tys, ref var_ty) => write!(f, "hybrid<[{}] {}>", type_vector_str(fix_tys), var_ty),
&MuType_::Hybrid(ref fix_tys, ref var_ty) => write!(f, "hybrid<[{}] {}>", vector_as_str(fix_tys), var_ty),
&MuType_::Void => write!(f, "void"),
&MuType_::ThreadRef => write!(f, "threadref"),
&MuType_::StackRef => write!(f, "stackref"),
......@@ -301,17 +302,6 @@ pub struct MuFuncSig {
impl fmt::Display for MuFuncSig {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}] -> [{}]", type_vector_str(&self.ret_tys), type_vector_str(&self.arg_tys))
}
}
fn type_vector_str(vec: &Vec<P<MuType>>) -> String {
let mut ret = String::new();
for i in 0..vec.len() {
ret.push_str(fmt::format(format_args!("{}", vec[i])).as_str());
if i != vec.len() - 1 {
ret.push_str(", ");
}
write!(f, "[{}] -> [{}]", vector_as_str(&self.ret_tys), vector_as_str(&self.arg_tys))
}
ret
}
\ No newline at end of file
use std::fmt;
macro_rules! select_value {
($cond: expr, $res1 : expr, $res2 : expr) => {
if $cond {
$res1
} else {
$res2
}
}
}
pub fn vector_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
}
\ No newline at end of file
......@@ -30,6 +30,7 @@ impl CompilerPolicy {
let mut passes : Vec<Box<CompilerPass>> = vec![];
passes.push(Box::new(passes::DefUse::new()));
passes.push(Box::new(passes::TreeGen::new()));
passes.push(Box::new(passes::ControlFlowAnalysis::new()));
CompilerPolicy{passes: passes}
}
......@@ -46,33 +47,35 @@ pub trait CompilerPass {
fn execute(&mut self, vm_context: &VMContext, func: &mut MuFunction) {
debug!("---CompilerPass {} for {}---", self.name(), func.fn_name);
self.start_function(vm_context, func);
self.visit_function(vm_context, func);
self.finish_function(vm_context, func);
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;
debug!("---finish---");
}
fn visit_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {
for (label, ref mut block) in func.content.as_mut().unwrap().blocks.iter_mut() {
debug!("block: {}", label);
self.start_block(vm_context, &mut func.context, block);
self.visit_block(vm_context, &mut func.context, block);
self.finish_block(vm_context, &mut func.context, block);
}
}
fn visit_block(&mut self, vm_context: &VMContext, func_context: &mut FunctionContext, block: &mut Block) {
for inst in block.content.as_mut().unwrap().body.iter_mut() {
debug!("{}", inst);
self.visit_inst(vm_context, &mut func.context, inst);
self.visit_inst(vm_context, func_context, inst);
}
self.finish_block(vm_context, &mut func.context, block);
}
self.finish_function(vm_context, func);
debug!("---finish---");
}
fn visit_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {}
fn start_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {}
fn finish_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {}
fn visit_block(&mut self, vm_context: &VMContext, func_context: &mut FunctionContext, block: &mut Block) {}
fn start_block(&mut self, vm_context: &VMContext, func_context: &mut FunctionContext, block: &mut Block) {}
fn finish_block(&mut self, vm_context: &VMContext, func_context: &mut FunctionContext, block: &mut Block) {}
fn visit_inst(&mut self, vm_context: &VMContext, func_context: &mut FunctionContext, node: &mut TreeNode) {}
......
use ast::ir::*;
use ast::inst::Instruction_::*;
use vm::context::VMContext;
use compiler::CompilerPass;
pub struct ControlFlowAnalysis {
name: &'static str
}
impl ControlFlowAnalysis {
pub fn new() -> ControlFlowAnalysis {
ControlFlowAnalysis{name: "Control Flow Analysis"}
}
}
fn check_edge_kind(target: MuTag, stack: &Vec<MuTag>) -> EdgeKind {
if stack.contains(&target) {
EdgeKind::Backward
} else {
EdgeKind::Forward
}
}
fn new_edge(cur: MuTag, edge: BlockEdge, func: &mut MuFunction) {
// add current block to target's predecessors
{
let target = func.content.as_mut().unwrap().get_block_mut(edge.target).unwrap();
target.control_flow.preds.push(cur);
}
// add target as current block's successors
{
let cur = func.content.as_mut().unwrap().get_block_mut(cur).unwrap();
cur.control_flow.succs.push(edge);
}
}
const WATCHPOINT_DISABLED_CHANCE : f32 = 0.9f32;
const NORMAL_RESUME_CHANCE : f32 = 0.6f32;
const EXN_RESUME_CHANCE : f32 = 1f32 - NORMAL_RESUME_CHANCE;
fn dfs(cur: MuTag, stack: &mut Vec<MuTag>, visited: &mut Vec<MuTag>, func: &mut MuFunction) {
stack.push(cur);
visited.push(cur);
// find all the successors for current block, and push them to the stack
let out_edges : Vec<BlockEdge> = {
let cur = func.content.as_mut().unwrap().get_block_mut(cur).unwrap();
let ref body = cur.content.as_ref().unwrap().body;
let last_inst = body.last().unwrap();
match last_inst.v {
TreeNode_::Instruction(ref inst) => {
match inst.v {
// unconditional branch, definitely branch to the target
Branch1(ref dest) => vec![BlockEdge{
target: dest.target,
kind: check_edge_kind(dest.target, stack),
is_exception: false,
probability: 1.0f32
}],
// conditional branch
Branch2{ref true_dest, ref false_dest, true_prob, ..} => vec![
BlockEdge{
target: true_dest.target,
kind: check_edge_kind(true_dest.target, stack),
is_exception: false,
probability: true_prob
},
BlockEdge{
target: false_dest.target,
kind: check_edge_kind(false_dest.target, stack),
is_exception: false,
probability: 1.0f32 - true_prob
}
],
// watchpoints
Watchpoint{ref id, ref disable_dest, ref resume} => {
let ref normal = resume.normal_dest;
let ref exn = resume.exn_dest;
if id.is_none() {
// unconditional trap
vec![
BlockEdge{
target: normal.target,
kind: check_edge_kind(normal.target, stack),
is_exception: false,
probability: 1.0f32 * NORMAL_RESUME_CHANCE
},
BlockEdge{
target: exn.target,
kind: check_edge_kind(exn.target, stack),
is_exception: true,
probability: 1.0f32 * EXN_RESUME_CHANCE
}
]
} else {
// watchpoint. jump to disable_dest when disabled. otherwise trap
vec![
BlockEdge{
target: disable_dest.as_ref().unwrap().target,
kind: check_edge_kind(disable_dest.as_ref().unwrap().target, stack),
is_exception: false,
probability: WATCHPOINT_DISABLED_CHANCE
},
BlockEdge{
target: normal.target,
kind: check_edge_kind(normal.target, stack),
is_exception: false,
probability: (1.0f32 - WATCHPOINT_DISABLED_CHANCE) * NORMAL_RESUME_CHANCE
},
BlockEdge{
target: exn.target,
kind: check_edge_kind(exn.target, stack),
is_exception: true,
probability: (1.0f32 - WATCHPOINT_DISABLED_CHANCE) * EXN_RESUME_CHANCE
}
]
}
},
// wpbranch
WPBranch{ref disable_dest, ref enable_dest, ..} => vec![
BlockEdge{
target: disable_dest.target,
kind: check_edge_kind(disable_dest.target, stack),
is_exception: false,
probability: WATCHPOINT_DISABLED_CHANCE
},
BlockEdge{
target: enable_dest.target,
kind: check_edge_kind(enable_dest.target, stack),
is_exception: false,
probability: 1.0f32 - WATCHPOINT_DISABLED_CHANCE
}
],
// call
Call{ref resume, ..}
| SwapStack{ref resume, ..}
| ExnInstruction{ref resume, ..} => {
let ref normal = resume.normal_dest;
let ref exn = resume.exn_dest;
vec![
BlockEdge{
target: normal.target,
kind: check_edge_kind(normal.target, stack),
is_exception: false,
probability: 1.0f32 * NORMAL_RESUME_CHANCE
},
BlockEdge{
target: exn.target,
kind: check_edge_kind(exn.target, stack),
is_exception: true,
probability: 1.0f32 * EXN_RESUME_CHANCE
}
]
},
_ => vec![]
}
},
_ => panic!("expected an instruction")
}
};
for edge in out_edges {
new_edge(cur, edge, func);
}
stack.pop();
}
impl CompilerPass for ControlFlowAnalysis {
fn name(&self) -> &'static str {
self.name
}
#[allow(unused_variables)]
fn visit_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {
let mut stack : Vec<MuTag> = vec![];
let mut visited : Vec<MuTag> = vec![];
dfs(func.content.as_ref().unwrap().entry, &mut stack, &mut visited, func);
}
#[allow(unused_variables)]
fn finish_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {
debug!("check control flow for {}", func.fn_name);
for entry in func.content.as_ref().unwrap().blocks.iter() {
debug!("block {}", entry.0);
debug!("{}", entry.1.control_flow);
}
}
}
\ No newline at end of file
......@@ -35,7 +35,7 @@ impl CompilerPass for DefUse {
}
#[allow(unused_variables)]
fn visit_block(&mut self, vm_context: &VMContext, func_context: &mut FunctionContext, block: &mut Block) {
fn start_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() {
......
mod def_use;
mod tree_gen;
mod control_flow;
pub use compiler::passes::def_use::DefUse;
pub use compiler::passes::tree_gen::TreeGen;
pub use compiler::passes::control_flow::ControlFlowAnalysis;
\ No newline at end of file
use ast::ir::*;
use ast::inst::*;
use ast::ir_semantics::*;
use vm::context::VMContext;
use compiler::CompilerPass;
......@@ -25,10 +27,7 @@ impl CompilerPass for TreeGen {
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;
for (label, ref mut block) in func.content.as_mut().unwrap().blocks.iter_mut() {
// take its content, we will need to put it back
let mut content = block.content.take().unwrap();
let body = content.body;
......
......@@ -3,6 +3,9 @@ extern crate lazy_static;
#[macro_use]
extern crate log;
#[macro_use]
mod common;
pub mod ast;
pub mod vm;
pub mod compiler;
......
mod test_tree_gen;
\ No newline at end of file
mod test_pre_instsel;
\ No newline at end of file
......@@ -47,3 +47,21 @@ fn test_build_tree() {
compiler.compile(&vm_context, &mut factorial_func);
}
#[test]
fn test_cfa() {
simple_logger::init_with_level(log::LogLevel::Trace).ok();
let vm_context : VMContext = factorial();
let compiler = Compiler::new(CompilerPolicy::new(vec![
Box::new(passes::DefUse::new()),
Box::new(passes::TreeGen::new()),
Box::new(passes::ControlFlowAnalysis::new())
]));
let mut factorial_func = {
vm_context.get_func("fac").unwrap().borrow_mut()
};
compiler.compile(&vm_context, &mut factorial_func);
}
\ No newline at end of file
......@@ -2,11 +2,13 @@ extern crate mu;
use self::mu::ast::types::*;
use self::mu::ast::ir::*;
use self::mu::ast::inst::*;
use self::mu::ast::ptr::*;
use self::mu::ast::op::*;
use self::mu::vm::context::*;
use std::cell::RefCell;
use std::collections::HashMap;
#[test]
#[allow(unused_variables)]
......@@ -68,7 +70,8 @@ pub fn factorial() -> VMContext {
false_dest: Destination {
target: "blk_1",
args: vec![DestArg::Normal(2)]
}
},
true_prob: 0.5f32
}
});
......@@ -151,12 +154,14 @@ pub fn factorial() -> VMContext {
// wrap into a function
func.define(FunctionContent{
entry: "blk_0",
blocks: vec![
("blk_0", blk_0),
("blk_1", blk_1),
("blk_2", blk_2)
]}
);
blocks: {
let mut blocks = HashMap::new();
blocks.insert("blk_0", blk_0);
blocks.insert("blk_1", blk_1);
blocks.insert("blk_2", blk_2);
blocks
}
});
vm.declare_func(func);
......
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