Commit 8dfa2bff authored by qinsoon's avatar qinsoon

trace gen: layout blocks before instruction selection

parent 629e1960
......@@ -20,12 +20,14 @@ pub struct MuFunction {
pub fn_name: MuTag,
pub sig: P<MuFuncSig>,
pub content: Option<FunctionContent>,
pub context: FunctionContext
pub context: FunctionContext,
pub block_trace: Option<Vec<MuTag>> // only available after Trace Generation Pass
}
impl MuFunction {
pub fn new(fn_name: MuTag, sig: P<MuFuncSig>) -> MuFunction {
MuFunction{fn_name: fn_name, sig: sig, content: None, context: FunctionContext::new()}
MuFunction{fn_name: fn_name, sig: sig, content: None, context: FunctionContext::new(), block_trace: None}
}
pub fn define(&mut self, content: FunctionContent) {
......@@ -133,6 +135,26 @@ pub struct ControlFlow {
pub succs : Vec<BlockEdge>
}
impl ControlFlow {
pub fn get_hottest_succ(&self) -> Option<MuTag> {
if self.succs.len() == 0 {
None
} else {
let mut hot_blk = self.succs[0].target;
let mut hot_prob = self.succs[0].probability;
for edge in self.succs.iter() {
if edge.probability > hot_prob {
hot_blk = edge.target;
hot_prob = edge.probability;
}
}
Some(hot_blk)
}
}
}
impl fmt::Display for ControlFlow {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "preds: [{}], ", vector_as_str(&self.preds)).unwrap();
......
mod def_use;
mod tree_gen;
mod control_flow;
mod trace_gen;
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
pub use compiler::passes::control_flow::ControlFlowAnalysis;
pub use compiler::passes::trace_gen::TraceGen;
\ No newline at end of file
use ast::ir::*;
use vm::context::VMContext;
use compiler::CompilerPass;
pub struct TraceGen {
name: &'static str
}
impl TraceGen {
pub fn new() -> TraceGen {
TraceGen{name: "Trace Generation"}
}
}
impl CompilerPass for TraceGen {
fn name(&self) -> &'static str {
self.name
}
fn visit_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {
// we put the high probability edge into a hot trace, and others into cold paths
// and traverse cold_path later
let trace = {
let mut trace : Vec<MuTag> = vec![];
let mut work_stack : Vec<MuTag> = vec![];
let entry = func.content.as_ref().unwrap().entry;
work_stack.push(entry);
while !work_stack.is_empty() {
let cur = work_stack.pop().unwrap();
let cur_block = func.content.as_ref().unwrap().get_block(&cur);
trace!("check block {}", cur);
trace!("add {:?} to trace", cur);
trace.push(cur);
let hot_edge = {
match cur_block.control_flow.get_hottest_succ() {
Some(tag) => tag,
None => continue
}
};
// push cold paths (that are not in the trace and not in the work_stack) to work_stack
let mut cold_edges = cur_block.control_flow.succs.clone();
cold_edges.retain(|x| !x.target.eq(hot_edge) && !trace.contains(&x.target) &&!work_stack.contains(&x.target));
let mut cold_edge_tags = cold_edges.iter().map(|x| x.target).collect::<Vec<MuTag>>();
trace!("push cold edges {:?} to work stack", cold_edge_tags);
work_stack.append(&mut cold_edge_tags);
// if hot edge is not in the trace, push it
if !trace.contains(&hot_edge) && !work_stack.contains(&hot_edge) {
trace!("push hot edge {:?} to work stack", hot_edge);
work_stack.push(hot_edge);
} else {
trace!("hot edge {:?} already in trace, ignore", hot_edge);
}
trace!("");
}
trace
};
func.block_trace = Some(trace);
}
fn finish_function(&mut self, vm_context: &VMContext, func: &mut MuFunction) {
debug!("trace for {}", func.fn_name);
debug!("{:?}", func.block_trace.as_ref().unwrap());
}
}
\ No newline at end of file
......@@ -5,13 +5,19 @@ mod test_compiler;
mod common {
use std::fmt;
pub fn assert_str_vector (left: &Vec<&str>, right: &Vec<&str>) {
left.clone().sort();
right.clone().sort();
pub fn assert_vector_ordered <T: fmt::Debug> (left: &Vec<T>, right: &Vec<T>) {
assert_debug_str(left, right);
}
pub fn assert_vector_no_order <T: Ord + fmt::Debug + Clone> (left: &Vec<T>, right: &Vec<T>) {
let mut left_clone = left.clone();
left_clone.sort();
let mut right_clone = right.clone();
right_clone.sort();
assert_debug_str(left_clone, right_clone);
}
pub fn assert_debug_str<T: fmt::Debug, U: fmt::Debug> (left: T, right: U) {
assert_eq!(format!("{:?}", left), format!("{:?}", right))
}
......
......@@ -73,18 +73,18 @@ fn test_cfa_factorial() {
// blk_0: preds=[], succs=[blk_2, blk_1]
let blk_0 = content.get_block("blk_0");
assert_str_vector(&blk_0.control_flow.preds, &vec![]);
assert_str_vector(&block_edges_into_vec(&blk_0.control_flow.succs), &vec!["blk_2", "blk_1"]);
assert_vector_no_order(&blk_0.control_flow.preds, &vec![]);
assert_vector_no_order(&block_edges_into_vec(&blk_0.control_flow.succs), &vec!["blk_2", "blk_1"]);
// blk_2: preds=[blk_0, blk_1], succs=[]
let blk_2 = content.get_block("blk_2");
assert_str_vector(&blk_2.control_flow.preds, &vec!["blk_0", "blk_1"]);
assert_str_vector(&block_edges_into_vec(&blk_2.control_flow.succs), &vec![]);
assert_vector_no_order(&blk_2.control_flow.preds, &vec!["blk_0", "blk_1"]);
assert_vector_no_order(&block_edges_into_vec(&blk_2.control_flow.succs), &vec![]);
// blk_1: preds=[blk_0], succs=[blk_2]
let blk_1 = content.get_block("blk_1");
assert_str_vector(&blk_1.control_flow.preds, &vec!["blk_0"]);
assert_str_vector(&block_edges_into_vec(&blk_1.control_flow.succs), &vec!["blk_2"]);
assert_vector_no_order(&blk_1.control_flow.preds, &vec!["blk_0"]);
assert_vector_no_order(&block_edges_into_vec(&blk_1.control_flow.succs), &vec!["blk_2"]);
}
#[test]
......@@ -109,18 +109,18 @@ fn test_cfa_sum() {
// entry: preds=[], succs=[head]
let entry = content.get_block("entry");
assert_str_vector(&entry.control_flow.preds, &vec![]);
assert_str_vector(&block_edges_into_vec(&entry.control_flow.succs), &vec!["head"]);
assert_vector_no_order(&entry.control_flow.preds, &vec![]);
assert_vector_no_order(&block_edges_into_vec(&entry.control_flow.succs), &vec!["head"]);
// head: preds=[entry, head], succs=[head, ret]
let head = content.get_block("head");
assert_str_vector(&head.control_flow.preds, &vec!["entry", "head"]);
assert_str_vector(&block_edges_into_vec(&head.control_flow.succs), &vec!["ret", "head"]);
assert_vector_no_order(&head.control_flow.preds, &vec!["entry", "head"]);
assert_vector_no_order(&block_edges_into_vec(&head.control_flow.succs), &vec!["ret", "head"]);
// ret: preds=[head], succs=[]
let ret = content.get_block("ret");
assert_str_vector(&ret.control_flow.preds, &vec!["head"]);
assert_str_vector(&block_edges_into_vec(&ret.control_flow.succs), &vec![]);
assert_vector_no_order(&ret.control_flow.preds, &vec!["head"]);
assert_vector_no_order(&block_edges_into_vec(&ret.control_flow.succs), &vec![]);
}
fn block_edges_into_vec(edges: &Vec<BlockEdge>) -> Vec<&str> {
......@@ -129,4 +129,46 @@ fn block_edges_into_vec(edges: &Vec<BlockEdge>) -> Vec<&str> {
ret.push(edge.target);
}
ret
}
#[test]
fn test_trace_factorial() {
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()),
Box::new(passes::TraceGen::new())
]));
let mut factorial_func = {
vm_context.get_func("fac").unwrap().borrow_mut()
};
compiler.compile(&vm_context, &mut factorial_func);
assert_vector_ordered(factorial_func.block_trace.as_ref().unwrap(), &vec!["blk_0", "blk_1", "blk_2"]);
}
#[test]
fn test_trace_sum() {
simple_logger::init_with_level(log::LogLevel::Trace).ok();
let vm_context : VMContext = sum();
let compiler = Compiler::new(CompilerPolicy::new(vec![
Box::new(passes::DefUse::new()),
Box::new(passes::TreeGen::new()),
Box::new(passes::ControlFlowAnalysis::new()),
Box::new(passes::TraceGen::new())
]));
let mut sum_func = {
vm_context.get_func("sum").unwrap().borrow_mut()
};
compiler.compile(&vm_context, &mut sum_func);
assert_vector_ordered(sum_func.block_trace.as_ref().unwrap(), &vec!["entry", "head", "ret"]);
}
\ No newline at end of file
......@@ -208,7 +208,7 @@ pub fn factorial() -> VMContext {
target: "blk_1",
args: vec![DestArg::Normal(2)]
},
true_prob: 0.5f32
true_prob: 0.3f32
}
});
......
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