Commit edcc327f authored by qinsoon's avatar qinsoon

a pass GenMovPhi is added between TreeGen and CFA

introduced Move instruction at IR level.
Intermediate blocks will be inserted for multi-target branch
instructions
parent 61791d70
......@@ -266,7 +266,10 @@ pub enum Instruction_ {
// common inst
CommonInst_GetThreadLocal,
CommonInst_SetThreadLocal(OpIndex)
CommonInst_SetThreadLocal(OpIndex),
// internal use: mov from ops[0] to value
Move(OpIndex)
}
impl Instruction_ {
......@@ -379,8 +382,13 @@ impl Instruction_ {
&Instruction_::ExnInstruction{ref inner, ref resume} => {
format!("{} {}", inner.debug_str(ops), resume.debug_str(ops))
},
// common inst
&Instruction_::CommonInst_GetThreadLocal => format!("COMMONINST GetThreadLocal"),
&Instruction_::CommonInst_SetThreadLocal(op) => format!("COMMONINST SetThreadLocal {}", ops[op])
&Instruction_::CommonInst_SetThreadLocal(op) => format!("COMMONINST SetThreadLocal {}", ops[op]),
// move
&Instruction_::Move(from) => format!("MOVE {}", ops[from])
}
}
}
......
......@@ -28,7 +28,8 @@ pub fn is_terminal_inst(inst: &Instruction_) -> bool {
| &Select{..}
| &Fence(_)
| &CommonInst_GetThreadLocal
| &CommonInst_SetThreadLocal(_) => false,
| &CommonInst_SetThreadLocal(_)
| &Move(_) => false,
&Return(_)
| &ThreadExit
| &Throw(_)
......@@ -91,5 +92,6 @@ pub fn has_side_effect(inst: &Instruction_) -> bool {
&ExnInstruction{..} => true,
&CommonInst_GetThreadLocal => true,
&CommonInst_SetThreadLocal(_) => true,
&Move(_) => false,
}
}
......@@ -59,7 +59,9 @@ pub enum OpCode {
GetVarPartIRef,
CommonInst_GetThreadLocal,
CommonInst_SetThreadLocal
CommonInst_SetThreadLocal,
Move
}
pub fn pick_op_code_for_ssa(ty: &P<MuType>) -> OpCode {
......@@ -285,6 +287,7 @@ pub fn pick_op_code_for_inst(inst: &Instruction) -> OpCode {
Instruction_::Switch{..} => OpCode::Switch,
Instruction_::ExnInstruction{..} => OpCode::ExnInstruction,
Instruction_::CommonInst_GetThreadLocal => OpCode::CommonInst_GetThreadLocal,
Instruction_::CommonInst_SetThreadLocal(_) => OpCode::CommonInst_SetThreadLocal
Instruction_::CommonInst_SetThreadLocal(_) => OpCode::CommonInst_SetThreadLocal,
Instruction_::Move(_) => OpCode::Move,
}
}
......@@ -93,7 +93,7 @@ impl <'a> InstructionSelection {
let ref cond = ops[cond];
if self.match_cmp_res(cond) {
trace!("emit cmp_eq-branch2");
trace!("emit cmp_res-branch2");
match self.emit_cmp_res(cond, f_content, f_context, vm) {
op::CmpOp::EQ => {
if branch_if_true {
......@@ -1055,6 +1055,15 @@ impl <'a> InstructionSelection {
// store tmp_op -> [tl + USER_TLS_OFFSTE]
self.emit_store_base_offset(&tl, *thread::USER_TLS_OFFSET as i32, &tmp_op, vm);
}
Instruction_::Move(op) => {
let ops = inst.ops.read().unwrap();
let ref op = ops[op];
let tmp_res = self.get_result_value(node);
self.emit_move_node_to_value(&tmp_res, op, f_content, f_context, vm);
}
Instruction_::New(ref ty) => {
if cfg!(debug_assertions) {
......
......@@ -67,6 +67,7 @@ impl Default for CompilerPolicy {
// ir level passes
passes.push(Box::new(passes::DefUse::new()));
passes.push(Box::new(passes::TreeGen::new()));
passes.push(Box::new(passes::GenMovPhi::new()));
passes.push(Box::new(passes::ControlFlowAnalysis::new()));
passes.push(Box::new(passes::TraceGen::new()));
......
This diff is collapsed.
......@@ -5,11 +5,13 @@ mod def_use;
mod tree_gen;
mod control_flow;
mod trace_gen;
mod gen_mov_phi;
pub use compiler::passes::def_use::DefUse;
pub use compiler::passes::tree_gen::TreeGen;
pub use compiler::passes::control_flow::ControlFlowAnalysis;
pub use compiler::passes::trace_gen::TraceGen;
pub use compiler::passes::gen_mov_phi::GenMovPhi;
use std::any::Any;
......
......@@ -14,11 +14,13 @@ mod test_api;
mod common {
use std::fmt;
#[allow(dead_code)]
pub fn assert_vector_ordered <T: fmt::Debug> (left: &Vec<T>, right: &Vec<T>) {
assert_debug_str(left, right);
}
#[allow(dead_code)]
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();
......@@ -27,7 +29,8 @@ mod common {
assert_debug_str(left_clone, right_clone);
}
#[allow(dead_code)]
pub fn assert_debug_str<T: fmt::Debug, U: fmt::Debug> (left: T, right: U) {
assert_eq!(format!("{:?}", left), format!("{:?}", right))
}
......
......@@ -54,6 +54,59 @@ fn test_build_tree() {
compiler.compile(&mut func_ver);
}
// consider one intermediate block
fn is_successor(from_id: MuID, to_id: MuID, content: &FunctionContent) -> bool {
let blk_from = content.get_block(from_id);
for outedge in blk_from.control_flow.succs.iter() {
if outedge.target == to_id {
return true;
}
let intermediate_block = content.get_block(outedge.target);
for int_outedge in intermediate_block.control_flow.succs.iter() {
if int_outedge.target == to_id {
return true;
}
}
}
return false;
}
fn has_successor(id: MuID, content: &FunctionContent) -> bool {
let blk = content.get_block(id);
!blk.control_flow.succs.is_empty()
}
fn is_predecessor(from_id: MuID, to_id: MuID, content: &FunctionContent) -> bool {
let blk_from = content.get_block(from_id);
for pred in blk_from.control_flow.preds.iter() {
if *pred == to_id {
return true;
}
let intermediate_block = content.get_block(*pred);
for int_pred in intermediate_block.control_flow.preds.iter() {
if *int_pred == to_id {
return true;
}
}
}
return false;
}
fn has_predecessor(id: MuID, content: &FunctionContent) -> bool {
let blk = content.get_block(id);
!blk.control_flow.preds.is_empty()
}
#[test]
fn test_cfa_factorial() {
VM::start_logging_trace();
......@@ -62,6 +115,7 @@ fn test_cfa_factorial() {
let compiler = Compiler::new(CompilerPolicy::new(vec![
Box::new(passes::DefUse::new()),
Box::new(passes::TreeGen::new()),
Box::new(passes::GenMovPhi::new()),
Box::new(passes::ControlFlowAnalysis::new())
]), vm.clone());
......@@ -75,23 +129,28 @@ fn test_cfa_factorial() {
// assert cfa
let content = func_ver.content.as_ref().unwrap();
// blk_0: preds=[], succs=[blk_2, blk_1]
let (blk_0_id, blk_1_id, blk_2_id) = (vm.id_of("blk_0"), vm.id_of("blk_1"), vm.id_of("blk_2"));
let blk_0 = content.get_block(blk_0_id);
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_id, blk_1_id]);
// blk_0: preds=[], succs=[blk_2, blk_1] - however there will be intermediate block
// check blk_0 predecessor
assert!(!has_predecessor(blk_0_id, content));
// check blk_0 successor
assert!(is_successor(blk_0_id, blk_1_id, content));
assert!(is_successor(blk_0_id, blk_2_id, content));
// blk_2: preds=[blk_0, blk_1], succs=[]
let blk_2 = content.get_block(blk_2_id);
assert_vector_no_order(&blk_2.control_flow.preds, &vec![blk_0_id, blk_1_id]);
assert_vector_no_order(&block_edges_into_vec(&blk_2.control_flow.succs), &vec![]);
// check blk_2 predecessor
assert!(is_predecessor(blk_2_id, blk_0_id, content));
assert!(is_predecessor(blk_2_id, blk_1_id, content));
// check blk_2 successor
assert!(!has_successor(blk_2_id, content));
// blk_1: preds=[blk_0], succs=[blk_2]
let blk_1 = content.get_block(blk_1_id);
assert_vector_no_order(&blk_1.control_flow.preds, &vec![blk_0_id]);
assert_vector_no_order(&block_edges_into_vec(&blk_1.control_flow.succs), &vec![blk_2_id]);
// check blk_1 predecessor
assert!(is_predecessor(blk_1_id, blk_0_id, content));
// check blk_1 successor
assert!(is_successor(blk_1_id, blk_2_id, content));
}
#[test]
......@@ -102,6 +161,7 @@ fn test_cfa_sum() {
let compiler = Compiler::new(CompilerPolicy::new(vec![
Box::new(passes::DefUse::new()),
Box::new(passes::TreeGen::new()),
Box::new(passes::GenMovPhi::new()),
Box::new(passes::ControlFlowAnalysis::new())
]), vm.clone());
......@@ -116,32 +176,46 @@ fn test_cfa_sum() {
// assert cfa
let content = func_ver.content.as_ref().unwrap();
let entry_id = vm.id_of("entry");
let head_id = vm.id_of("head");
let ret_id = vm.id_of("ret");
let entry = vm.id_of("entry");
let head = vm.id_of("head");
let ret = vm.id_of("ret");
// entry: preds=[], succs=[head]
let entry = content.get_block(entry_id);
assert_vector_no_order(&entry.control_flow.preds, &vec![]);
assert_vector_no_order(&block_edges_into_vec(&entry.control_flow.succs), &vec![head_id]);
assert!(!has_predecessor(entry, content));
assert!(is_successor(entry, head, content));
// head: preds=[entry, head], succs=[head, ret]
let head = content.get_block(head_id);
assert_vector_no_order(&head.control_flow.preds, &vec![entry_id, head_id]);
assert_vector_no_order(&block_edges_into_vec(&head.control_flow.succs), &vec![ret_id, head_id]);
assert!(is_predecessor(head, entry, content));
assert!(is_predecessor(head, head, content));
assert!(is_successor(head, head, content));
assert!(is_successor(head, ret, content));
// ret: preds=[head], succs=[]
let ret = content.get_block(ret_id);
assert_vector_no_order(&ret.control_flow.preds, &vec![head_id]);
assert_vector_no_order(&block_edges_into_vec(&ret.control_flow.succs), &vec![]);
assert!(is_predecessor(ret, head, content));
assert!(!has_successor(ret, content));
}
fn block_edges_into_vec(edges: &Vec<BlockEdge>) -> Vec<MuID> {
let mut ret = vec![];
for edge in edges {
ret.push(edge.target);
// as long as expected appears in correct order in actual, it is correct
fn match_trace(actual: &Vec<MuID>, expected: &Vec<MuID>) -> bool {
assert!(actual.len() >= expected.len());
debug!("matching trace:");
debug!("actual: {:?}", actual);
debug!("expected: {:?}", expected);
let mut expected_cursor = 0;
for i in actual {
if *i == expected[expected_cursor] {
expected_cursor += 1;
if expected_cursor == expected.len() {
return true;
}
}
}
ret
return false;
}
#[test]
......@@ -152,6 +226,7 @@ fn test_trace_factorial() {
let compiler = Compiler::new(CompilerPolicy::new(vec![
Box::new(passes::DefUse::new()),
Box::new(passes::TreeGen::new()),
Box::new(passes::GenMovPhi::new()),
Box::new(passes::ControlFlowAnalysis::new()),
Box::new(passes::TraceGen::new())
]), vm.clone());
......@@ -163,8 +238,11 @@ fn test_trace_factorial() {
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);
assert_vector_ordered(func_ver.block_trace.as_ref().unwrap(), &vec![vm.id_of("blk_0"), vm.id_of("blk_1"), vm.id_of("blk_2")]);
assert!(match_trace(
func_ver.block_trace.as_ref().unwrap(),
&vec![vm.id_of("blk_0"), vm.id_of("blk_1"), vm.id_of("blk_2")]
));
}
#[test]
......@@ -175,6 +253,7 @@ fn test_trace_sum() {
let compiler = Compiler::new(CompilerPolicy::new(vec![
Box::new(passes::DefUse::new()),
Box::new(passes::TreeGen::new()),
Box::new(passes::GenMovPhi::new()),
Box::new(passes::ControlFlowAnalysis::new()),
Box::new(passes::TraceGen::new())
]), vm.clone());
......@@ -186,6 +265,9 @@ fn test_trace_sum() {
let mut func_ver = func_vers.get(&func.cur_ver.unwrap()).unwrap().write().unwrap();
compiler.compile(&mut func_ver);
assert_vector_ordered(func_ver.block_trace.as_ref().unwrap(), &vec![vm.id_of("entry"), vm.id_of("head"), vm.id_of("ret")]);
assert!(match_trace(
func_ver.block_trace.as_ref().unwrap(),
&vec![vm.id_of("entry"), vm.id_of("head"), vm.id_of("ret")]
));
}
......@@ -104,14 +104,14 @@ pub fn sum() -> VM {
v: Instruction_::BinOp(BinOp::Add, 0, 1)
});
// %cond = UGT %i %n
// %cond = UGE %i %n
let blk_head_cond = func_ver.new_ssa(vm.next_id(), type_def_int1.clone());
vm.set_name(blk_head_cond.as_entity(), "blk_head_cond".to_string());
let blk_head_inst2 = func_ver.new_inst(Instruction {
hdr: MuEntityHeader::unnamed(vm.next_id()),
value: Some(vec![blk_head_cond.clone_value()]),
ops: RwLock::new(vec![blk_head_i.clone(), blk_head_n.clone()]),
v: Instruction_::CmpOp(CmpOp::UGT, 0, 1)
v: Instruction_::CmpOp(CmpOp::UGE, 0, 1)
});
// BRANCH2 %cond %ret(%s2) %head(%n %s2 %i2)
......
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