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 a5af3d18 authored by qinsoon's avatar qinsoon

implement switch

parent 6e44ecc6
Pipeline #108 failed with stage
in 13 minutes and 41 seconds
......@@ -192,6 +192,52 @@ impl <'a> InstructionSelection {
// jmp
self.backend.emit_jmp(target);
},
Instruction_::Switch{cond, ref default, ref branches} => {
let ops = inst.ops.read().unwrap();
let ref cond = ops[cond];
if self.match_ireg(cond) {
let tmp_cond = self.emit_ireg(cond, f_content, f_context, vm);
// emit each branch
for &(case_op_index, ref case_dest) in branches {
let ref case_op = ops[case_op_index];
// process dest
self.process_dest(&ops, case_dest, f_content, f_context, vm);
let target = f_content.get_block(case_dest.target).name().unwrap();
if self.match_iimm(case_op) {
let imm = self.node_iimm_to_i32(case_op);
// cmp case cond
self.backend.emit_cmp_imm32_r64(imm, &tmp_cond);
// je dest
self.backend.emit_je(target);
} else if self.match_ireg(case_op) {
let tmp_case_op = self.emit_ireg(case_op, f_content, f_context, vm);
// cmp case cond
self.backend.emit_cmp_r64_r64(&tmp_case_op, &tmp_cond);
// je dest
self.backend.emit_je(target);
} else {
panic!("expecting ireg cond to be either iimm or ireg: {}", cond);
}
}
// emit default
self.process_dest(&ops, default, f_content, f_context, vm);
let default_target = f_content.get_block(default.target).name().unwrap();
self.backend.emit_jmp(default_target);
} else {
panic!("expecting cond in switch to be ireg: {}", cond);
}
}
Instruction_::ExprCall{ref data, is_abort} => {
if is_abort {
......
......@@ -89,6 +89,29 @@ fn dfs(cur: MuID, stack: &mut Vec<MuID>, visited: &mut Vec<MuID>, func: &mut MuF
}
],
// switch
Switch{ref default, ref branches, ..} => {
const BRANCH_DEFAULT_PROB : f32 = 0.1;
let switch_prob = (1.0f32 - BRANCH_DEFAULT_PROB) / (branches.len() as f32);
let mut ret : Vec<BlockEdge> = branches.iter().map(|pair| BlockEdge {
target: pair.1.target,
kind: check_edge_kind(pair.1.target, stack),
is_exception: false,
probability: switch_prob
}).collect();
// default
ret.push(BlockEdge {
target: default.target,
kind: check_edge_kind(default.target, stack),
is_exception: false,
probability: BRANCH_DEFAULT_PROB
});
ret
}
// watchpoints
Watchpoint{ref id, ref disable_dest, ref resume} => {
let ref normal = resume.normal_dest;
......@@ -153,6 +176,7 @@ fn dfs(cur: MuID, stack: &mut Vec<MuID>, visited: &mut Vec<MuID>, func: &mut MuF
// call
Call{ref resume, ..}
| CCall{ref resume, ..}
| SwapStack{ref resume, ..}
| ExnInstruction{ref resume, ..} => {
let ref normal = resume.normal_dest;
......
......@@ -8,4 +8,5 @@ mod test_exception;
mod test_thread;
mod test_floatingpoint;
mod test_int;
mod test_binop;
\ No newline at end of file
mod test_binop;
mod test_controlflow;
\ No newline at end of file
extern crate mu;
extern crate log;
extern crate libloading;
use self::mu::ast::types::*;
use self::mu::ast::ir::*;
use self::mu::ast::inst::*;
use self::mu::ast::op::*;
use self::mu::vm::*;
use self::mu::testutil;
use std::sync::RwLock;
#[test]
fn test_switch() {
let lib = testutil::compile_fnc("switch", &switch);
unsafe {
let switch : libloading::Symbol<unsafe extern fn(u64) -> u64> = lib.get(b"switch").unwrap();
let res = switch(0);
println!("switch(0) = {}", res);
assert!(res == 0);
let res = switch(1);
println!("switch(1) = {}", res);
assert!(res == 1);
let res = switch(2);
println!("switch(2) = {}", res);
assert!(res == 2);
let res = switch(3);
println!("switch(3) = {}", res);
assert!(res == 99);
}
}
fn switch() -> VM {
let vm = VM::new();
// .typedef @int64 = int<64>
let type_def_int64 = vm.declare_type(vm.next_id(), MuType_::int(64));
vm.set_name(type_def_int64.as_entity(), Mu("int64"));
// .const @int64_0 <@int64> = 0
let const_int64_0 = vm.declare_const(vm.next_id(), type_def_int64.clone(), Constant::Int(0));
// .const @int64_1 <@int64> = 1
let const_int64_1 = vm.declare_const(vm.next_id(), type_def_int64.clone(), Constant::Int(1));
// .const @int64_2 <@int64> = 2
let const_int64_2 = vm.declare_const(vm.next_id(), type_def_int64.clone(), Constant::Int(2));
// .const @int64_99 <@int64> = 99
let const_int64_99 = vm.declare_const(vm.next_id(), type_def_int64.clone(), Constant::Int(99));
// .funcsig @switch_sig = (@int64) -> (@int64)
let switch_sig = vm.declare_func_sig(vm.next_id(), vec![type_def_int64.clone()], vec![type_def_int64.clone()]);
vm.set_name(switch_sig.as_entity(), Mu("switch_sig"));
// .funcdecl @switch <@switch_sig>
let func_id = vm.next_id();
let func = MuFunction::new(func_id, switch_sig.clone());
vm.set_name(func.as_entity(), Mu("switch"));
vm.declare_func(func);
// .funcdef @switch VERSION @switch_v1 <@switch_sig>
let mut func_ver = MuFunctionVersion::new(vm.next_id(), func_id, switch_sig.clone());
vm.set_name(func_ver.as_entity(), Mu("switch_v1"));
// %entry(<@int64> %a):
let mut blk_entry = Block::new(vm.next_id());
vm.set_name(blk_entry.as_entity(), Mu("entry"));
let blk_entry_a = func_ver.new_ssa(vm.next_id(), type_def_int64.clone());
vm.set_name(blk_entry_a.as_entity(), Mu("blk_entry_a"));
// SWITCH %a %blk_default (0 -> %blk_ret0, 1 -> %blk_ret1, 2 -> %blk_ret2)
let const0 = func_ver.new_constant(const_int64_0.clone());
let const1 = func_ver.new_constant(const_int64_1.clone());
let const2 = func_ver.new_constant(const_int64_2.clone());
let blk_default_id = vm.next_id();
let blk_ret0_id = vm.next_id();
let blk_ret1_id = vm.next_id();
let blk_ret2_id = vm.next_id();
let blk_entry_switch = func_ver.new_inst(Instruction {
hdr: MuEntityHeader::unnamed(vm.next_id()),
value: None,
ops: RwLock::new(vec![
blk_entry_a.clone(), // 0
const0.clone(), // 1
const1.clone(), // 2
const2.clone(), // 3
]),
v: Instruction_::Switch {
cond: 0,
default: Destination {
target: blk_default_id,
args: vec![]
},
branches: vec![
(1, Destination{target: blk_ret0_id, args: vec![]}),
(2, Destination{target: blk_ret1_id, args: vec![]}),
(3, Destination{target: blk_ret2_id, args: vec![]})
]
}
});
blk_entry.content = Some(BlockContent{
args: vec![blk_entry_a.clone_value()],
exn_arg: None,
body: vec![blk_entry_switch],
keepalives: None
});
// blk_default
let mut blk_default = Block::new(blk_default_id);
vm.set_name(blk_default.as_entity(), Mu("default"));
let const99 = func_ver.new_constant(const_int64_99.clone());
let blk_default_ret = func_ver.new_inst(Instruction {
hdr: MuEntityHeader::unnamed(vm.next_id()),
value: None,
ops: RwLock::new(vec![const99]),
v: Instruction_::Return(vec![0])
});
blk_default.content = Some(BlockContent{
args: vec![],
exn_arg: None,
body: vec![blk_default_ret],
keepalives: None
});
// blk_ret0
let mut blk_ret0 = Block::new(blk_ret0_id);
vm.set_name(blk_ret0.as_entity(), Mu("ret0"));
let blk_ret0_ret = func_ver.new_inst(Instruction {
hdr: MuEntityHeader::unnamed(vm.next_id()),
value: None,
ops: RwLock::new(vec![const0.clone()]),
v: Instruction_::Return(vec![0])
});
blk_ret0.content = Some(BlockContent{
args: vec![],
exn_arg: None,
body: vec![blk_ret0_ret],
keepalives: None
});
// blk_ret1
let mut blk_ret1 = Block::new(blk_ret1_id);
vm.set_name(blk_ret1.as_entity(), Mu("ret1"));
let blk_ret1_ret = func_ver.new_inst(Instruction {
hdr: MuEntityHeader::unnamed(vm.next_id()),
value: None,
ops: RwLock::new(vec![const1.clone()]),
v: Instruction_::Return(vec![0])
});
blk_ret1.content = Some(BlockContent{
args: vec![],
exn_arg: None,
body: vec![blk_ret1_ret],
keepalives: None
});
// blk_ret2
let mut blk_ret2 = Block::new(blk_ret2_id);
vm.set_name(blk_ret2.as_entity(), Mu("ret2"));
let blk_ret2_ret = func_ver.new_inst(Instruction {
hdr: MuEntityHeader::unnamed(vm.next_id()),
value: None,
ops: RwLock::new(vec![const2.clone()]),
v: Instruction_::Return(vec![0])
});
blk_ret2.content = Some(BlockContent{
args: vec![],
exn_arg: None,
body: vec![blk_ret2_ret],
keepalives: None
});
func_ver.define(FunctionContent{
entry: blk_entry.id(),
blocks: hashmap!{
blk_entry.id() => blk_entry,
blk_default_id => blk_default,
blk_ret0_id => blk_ret0,
blk_ret1_id => blk_ret1,
blk_ret2_id => blk_ret2
}
});
vm.define_func_version(func_ver);
vm
}
\ No newline at end of file
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