GitLab will be upgraded on June 2nd 2020 at 2.00 pm (AEDT) to 3.00 pm (AEDT) due to Critical Security Patch Availability. During the update, GitLab and Mattermost services will not be available. If you have any concerns with this, please talk to local Gitlab admin team.

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