WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

Commit 97e188ad authored by qinsoon's avatar qinsoon
Browse files

implement SELECT

parent 01145b46
......@@ -8,3 +8,4 @@ Cargo.lock
*.DS_Store
*.swp
.idea
*.pyc
......@@ -221,6 +221,11 @@ pub enum Instruction_ {
false_dest: Destination,
true_prob: f32
},
Select{
cond: OpIndex,
true_val: OpIndex,
false_val: OpIndex
},
Watchpoint{ // Watchpoint NONE ResumptionData
// serves as an unconditional trap. Trap to client, and resume with ResumptionData
// Watchpoint (WPID dest) ResumptionData
......@@ -333,6 +338,9 @@ impl Instruction_ {
&Instruction_::Branch2{cond, ref true_dest, ref false_dest, ..} => {
format!("BRANCH2 {} {} {}", ops[cond], true_dest.debug_str(ops), false_dest.debug_str(ops))
},
&Instruction_::Select{cond, true_val, false_val} => {
format!("SELECT if {} then {} else {}", ops[cond], ops[true_val], ops[false_val])
}
&Instruction_::Watchpoint{id, ref disable_dest, ref resume} => {
match id {
Some(id) => {
......
......@@ -25,6 +25,7 @@ pub fn is_terminal_inst(inst: &Instruction_) -> bool {
| &GetElementIRef{..}
| &ShiftIRef{..}
| &GetVarPartIRef{..}
| &Select{..}
| &Fence(_) => false,
&Return(_)
| &ThreadExit
......@@ -78,6 +79,7 @@ pub fn has_side_effect(inst: &Instruction_) -> bool {
&TailCall(_) => true,
&Branch1(_) => true,
&Branch2{..} => true,
&Select{..} => false,
&Watchpoint{..} => true,
&WPBranch{..} => true,
&Call{..} => true,
......
......@@ -24,6 +24,7 @@ pub enum OpCode {
TailCall,
Branch1,
Branch2,
Select,
Watchpoint,
WPBranch,
Call,
......@@ -272,6 +273,7 @@ pub fn pick_op_code_for_inst(inst: &Instruction) -> OpCode {
Instruction_::TailCall(_) => OpCode::TailCall,
Instruction_::Branch1(_) => OpCode::Branch1,
Instruction_::Branch2{..} => OpCode::Branch2,
Instruction_::Select{..} => OpCode::Select,
Instruction_::Watchpoint{..} => OpCode::Watchpoint,
Instruction_::WPBranch{..} => OpCode::WPBranch,
Instruction_::Call{..} => OpCode::Call,
......
......@@ -1657,6 +1657,48 @@ impl CodeGenerator for ASMCodeGen {
mov_mem_imm!(emit_mov_mem16_imm16, "mov", 16, i16);
mov_mem_imm!(emit_mov_mem8_imm8 , "mov", 8 , i8 );
// cmov
mov_r_r!(emit_cmova_r64_r64, "cmova", 64);
mov_r_imm!(emit_cmova_r64_imm32, "cmova", 64, i32);
mov_r_mem!(emit_cmova_r64_mem64, "cmova", 64);
mov_r_r!(emit_cmovae_r64_r64, "cmovae", 64);
mov_r_imm!(emit_cmovae_r64_imm32, "cmovae", 64, i32);
mov_r_mem!(emit_cmovae_r64_mem64, "cmovae", 64);
mov_r_r!(emit_cmovb_r64_r64, "cmovb", 64);
mov_r_imm!(emit_cmovb_r64_imm32, "cmovb", 64, i32);
mov_r_mem!(emit_cmovb_r64_mem64, "cmovb", 64);
mov_r_r!(emit_cmovbe_r64_r64, "cmovbe", 64);
mov_r_imm!(emit_cmovbe_r64_imm32, "cmovbe", 64, i32);
mov_r_mem!(emit_cmovbe_r64_mem64, "cmovbe", 64);
mov_r_r!(emit_cmove_r64_r64, "cmove", 64);
mov_r_imm!(emit_cmove_r64_imm32, "cmove", 64, i32);
mov_r_mem!(emit_cmove_r64_mem64, "cmove", 64);
mov_r_r!(emit_cmovne_r64_r64, "cmovne", 64);
mov_r_imm!(emit_cmovne_r64_imm32, "cmovne", 64, i32);
mov_r_mem!(emit_cmovne_r64_mem64, "cmovne", 64);
mov_r_r!(emit_cmovg_r64_r64, "cmovg", 64);
mov_r_imm!(emit_cmovg_r64_imm32, "cmovg", 64, i32);
mov_r_mem!(emit_cmovg_r64_mem64, "cmovg", 64);
mov_r_r!(emit_cmovge_r64_r64, "cmovge", 64);
mov_r_imm!(emit_cmovge_r64_imm32, "cmovge", 64, i32);
mov_r_mem!(emit_cmovge_r64_mem64, "cmovge", 64);
mov_r_r!(emit_cmovl_r64_r64, "cmovl", 64);
mov_r_imm!(emit_cmovl_r64_imm32, "cmovl", 64, i32);
mov_r_mem!(emit_cmovl_r64_mem64, "cmovl", 64);
mov_r_r!(emit_cmovle_r64_r64, "cmovle", 64);
mov_r_imm!(emit_cmovle_r64_imm32, "cmovle", 64, i32);
mov_r_mem!(emit_cmovle_r64_mem64, "cmovle", 64);
// lea
mov_r_mem!(emit_lea_r64, "lea", 64);
......
......@@ -73,6 +73,48 @@ pub trait CodeGenerator {
fn emit_mov_mem8_r8 (&mut self, dest: Mem, src: Reg); // store
fn emit_mov_mem8_imm8 (&mut self, dest: Mem, src: i8);
// gpr conditional move
fn emit_cmova_r64_r64 (&mut self, dest: Reg, src: Reg);
fn emit_cmova_r64_imm32(&mut self, dest: Reg, src: i32);
fn emit_cmova_r64_mem64(&mut self, dest: Reg, src: Mem); // load
fn emit_cmovae_r64_r64 (&mut self, dest: Reg, src: Reg);
fn emit_cmovae_r64_imm32(&mut self, dest: Reg, src: i32);
fn emit_cmovae_r64_mem64(&mut self, dest: Reg, src: Mem); // load
fn emit_cmovb_r64_r64 (&mut self, dest: Reg, src: Reg);
fn emit_cmovb_r64_imm32(&mut self, dest: Reg, src: i32);
fn emit_cmovb_r64_mem64(&mut self, dest: Reg, src: Mem); // load
fn emit_cmovbe_r64_r64 (&mut self, dest: Reg, src: Reg);
fn emit_cmovbe_r64_imm32(&mut self, dest: Reg, src: i32);
fn emit_cmovbe_r64_mem64(&mut self, dest: Reg, src: Mem); // load
fn emit_cmove_r64_r64 (&mut self, dest: Reg, src: Reg);
fn emit_cmove_r64_imm32(&mut self, dest: Reg, src: i32);
fn emit_cmove_r64_mem64(&mut self, dest: Reg, src: Mem); // load
fn emit_cmovg_r64_r64 (&mut self, dest: Reg, src: Reg);
fn emit_cmovg_r64_imm32(&mut self, dest: Reg, src: i32);
fn emit_cmovg_r64_mem64(&mut self, dest: Reg, src: Mem); // load
fn emit_cmovge_r64_r64 (&mut self, dest: Reg, src: Reg);
fn emit_cmovge_r64_imm32(&mut self, dest: Reg, src: i32);
fn emit_cmovge_r64_mem64(&mut self, dest: Reg, src: Mem); // load
fn emit_cmovl_r64_r64 (&mut self, dest: Reg, src: Reg);
fn emit_cmovl_r64_imm32(&mut self, dest: Reg, src: i32);
fn emit_cmovl_r64_mem64(&mut self, dest: Reg, src: Mem); // load
fn emit_cmovle_r64_r64 (&mut self, dest: Reg, src: Reg);
fn emit_cmovle_r64_imm32(&mut self, dest: Reg, src: i32);
fn emit_cmovle_r64_mem64(&mut self, dest: Reg, src: Mem); // load
fn emit_cmovne_r64_r64 (&mut self, dest: Reg, src: Reg);
fn emit_cmovne_r64_imm32(&mut self, dest: Reg, src: i32);
fn emit_cmovne_r64_mem64(&mut self, dest: Reg, src: Mem); // load
// lea
fn emit_lea_r64(&mut self, dest: Reg, src: Mem);
......
......@@ -180,7 +180,84 @@ impl <'a> InstructionSelection {
unimplemented!();
}
},
Instruction_::Select{cond, true_val, false_val} => {
let ops = inst.ops.read().unwrap();
let ref cond = ops[cond];
let ref true_val = ops[true_val];
let ref false_val = ops[false_val];
if self.match_ireg(true_val) {
// moving integers/pointers
let tmp_res = self.get_result_value(node);
let tmp_true = self.emit_ireg(true_val, f_content, f_context, vm);
let tmp_false = self.emit_ireg(false_val, f_content, f_context, vm);
if self.match_cmp_res(cond) {
match self.emit_cmp_res(cond, f_content, f_context, vm) {
op::CmpOp::EQ => {
self.backend.emit_cmove_r64_r64 (&tmp_res, &tmp_true);
self.backend.emit_cmovne_r64_r64(&tmp_res, &tmp_false);
}
op::CmpOp::NE => {
self.backend.emit_cmovne_r64_r64(&tmp_res, &tmp_true);
self.backend.emit_cmove_r64_r64 (&tmp_res, &tmp_false);
}
op::CmpOp::SGE => {
self.backend.emit_cmovge_r64_r64(&tmp_res, &tmp_true);
self.backend.emit_cmovl_r64_r64 (&tmp_res, &tmp_false);
}
op::CmpOp::SGT => {
self.backend.emit_cmovg_r64_r64 (&tmp_res, &tmp_true);
self.backend.emit_cmovle_r64_r64(&tmp_res, &tmp_false);
}
op::CmpOp::SLE => {
self.backend.emit_cmovle_r64_r64(&tmp_res, &tmp_true);
self.backend.emit_cmovg_r64_r64 (&tmp_res, &tmp_false);
}
op::CmpOp::SLT => {
self.backend.emit_cmovl_r64_r64 (&tmp_res, &tmp_true);
self.backend.emit_cmovge_r64_r64(&tmp_res, &tmp_false);
}
op::CmpOp::UGE => {
self.backend.emit_cmovae_r64_r64(&tmp_res, &tmp_true);
self.backend.emit_cmovb_r64_r64 (&tmp_res, &tmp_false);
}
op::CmpOp::UGT => {
self.backend.emit_cmova_r64_r64 (&tmp_res, &tmp_true);
self.backend.emit_cmovbe_r64_r64(&tmp_res, &tmp_false);
}
op::CmpOp::ULE => {
self.backend.emit_cmovbe_r64_r64(&tmp_res, &tmp_true);
self.backend.emit_cmova_r64_r64 (&tmp_res, &tmp_false);
}
op::CmpOp::ULT => {
self.backend.emit_cmovb_r64_r64 (&tmp_res, &tmp_true);
self.backend.emit_cmovae_r64_r64(&tmp_res, &tmp_false);
}
_ => panic!("expecting CmpOp for integers")
}
} else if self.match_ireg(cond) {
let tmp_cond = self.emit_ireg(cond, f_content, f_context, vm);
// emit: cmp cond_reg 1
self.backend.emit_cmp_imm32_r64(1, &tmp_cond);
// emit: cmove tmp_true -> tmp_res
self.backend.emit_cmove_r64_r64(&tmp_res, &tmp_true);
// emit: cmovne tmp_false -> tmp_res
self.backend.emit_cmovne_r64_r64(&tmp_res, &tmp_false);
} else {
unimplemented!()
}
} else {
// moving vectors, floatingpoints
unimplemented!()
}
},
Instruction_::Branch1(ref dest) => {
let ops = inst.ops.read().unwrap();
......
......@@ -165,6 +165,30 @@ macro_rules! inst {
});
};
// CMPOP
(($vm: expr, $fv: ident) $name: ident: $value: ident = CMPOP ($op: expr) $op1: ident $op2: ident) => {
let $name = $fv.new_inst(Instruction{
hdr: MuEntityHeader::unnamed($vm.next_id()),
value: Some(vec![$value.clone_value()]),
ops: RwLock::new(vec![$op1.clone(), $op2.clone()]),
v: Instruction_::CmpOp($op, 0, 1)
});
};
// SELECT
(($vm: expr, $fv: ident) $name: ident: $value: ident = SELECT $cond: ident $op_true: ident $op_false:ident) => {
let $name = $fv.new_inst(Instruction{
hdr: MuEntityHeader::unnamed($vm.next_id()),
value: Some(vec![$value.clone_value()]),
ops: RwLock::new(vec![$cond.clone(), $op_true.clone(), $op_false.clone()]),
v: Instruction_::Select{
cond: 0,
true_val: 1,
false_val: 2
}
});
};
// BRANCH
(($vm: expr, $fv: ident) $name: ident: BRANCH $dest: ident ($($arg: ident), *)) => {
let $name = $fv.new_inst(Instruction{
......
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::vm::*;
use self::mu::testutil;
use mu::ast::types::*;
use mu::ast::ir::*;
use mu::ast::inst::*;
use mu::ast::op::*;
use mu::vm::*;
use mu::testutil;
use std::sync::RwLock;
......@@ -203,5 +202,125 @@ fn switch() -> VM {
vm.define_func_version(func_ver);
vm
}
#[test]
fn test_select_eq_zero() {
let lib = testutil::compile_fnc("select_eq_zero", &select_eq_zero);
unsafe {
let select_eq_zero : libloading::Symbol<unsafe extern fn(u64) -> u64> = lib.get(b"select_eq_zero").unwrap();
let res = select_eq_zero(0);
println!("select_eq_zero(0) = {}", res);
assert!(res == 1);
let res = select_eq_zero(1);
println!("select_eq_zero(1) = {}", res);
assert!(res == 0);
}
}
fn select_eq_zero() -> VM {
let vm = VM::new();
typedef! ((vm) int64 = mu_int(64));
typedef! ((vm) int1 = mu_int(1));
constdef!((vm) <int64> int64_0 = Constant::Int(0));
constdef!((vm) <int64> int64_1 = Constant::Int(1));
funcsig! ((vm) sig = (int64) -> (int64));
funcdecl!((vm) <sig> select_eq_zero);
funcdef! ((vm) <sig> select_eq_zero VERSION select_v1);
// blk entry
block! ((vm, select_v1) blk_entry);
ssa! ((vm, select_v1) <int64> blk_entry_n);
ssa! ((vm, select_v1) <int1> blk_entry_cond);
consta!((vm, select_v1) int64_0_local = int64_0);
consta!((vm, select_v1) int64_1_local = int64_1);
inst! ((vm, select_v1) blk_entry_inst_cmp:
blk_entry_cond = CMPOP (CmpOp::EQ) blk_entry_n int64_0_local
);
ssa! ((vm, select_v1) <int64> blk_entry_ret);
inst! ((vm, select_v1) blk_entry_inst_select:
blk_entry_ret = SELECT blk_entry_cond int64_1_local int64_0_local
);
inst! ((vm, select_v1) blk_entry_inst_ret:
RET (blk_entry_ret)
);
define_block! ((vm, select_v1) blk_entry(blk_entry_n){
blk_entry_inst_cmp, blk_entry_inst_select, blk_entry_inst_ret
});
define_func_ver!((vm) select_v1 (entry: blk_entry) {blk_entry});
vm
}
#[test]
fn test_select_sge_zero() {
let lib = testutil::compile_fnc("select_sge_zero", &select_sge_zero);
unsafe {
let select_sge_zero : libloading::Symbol<unsafe extern fn(i64) -> u64> = lib.get(b"select_sge_zero").unwrap();
let res = select_sge_zero(0);
println!("select_sge_zero(0) = {}", res);
assert!(res == 1);
let res = select_sge_zero(1);
println!("select_sge_zero(1) = {}", res);
assert!(res == 1);
let res = select_sge_zero(-1);
println!("select_sge_zero(-1) = {}", res);
assert!(res == 0);
}
}
fn select_sge_zero() -> VM {
let vm = VM::new();
typedef! ((vm) int64 = mu_int(64));
typedef! ((vm) int1 = mu_int(1));
constdef!((vm) <int64> int64_0 = Constant::Int(0));
constdef!((vm) <int64> int64_1 = Constant::Int(1));
funcsig! ((vm) sig = (int64) -> (int64));
funcdecl!((vm) <sig> select_sge_zero);
funcdef! ((vm) <sig> select_sge_zero VERSION select_v1);
// blk entry
block! ((vm, select_v1) blk_entry);
ssa! ((vm, select_v1) <int64> blk_entry_n);
ssa! ((vm, select_v1) <int1> blk_entry_cond);
consta!((vm, select_v1) int64_0_local = int64_0);
consta!((vm, select_v1) int64_1_local = int64_1);
inst! ((vm, select_v1) blk_entry_inst_cmp:
blk_entry_cond = CMPOP (CmpOp::SGE) blk_entry_n int64_0_local
);
ssa! ((vm, select_v1) <int64> blk_entry_ret);
inst! ((vm, select_v1) blk_entry_inst_select:
blk_entry_ret = SELECT blk_entry_cond int64_1_local int64_0_local
);
inst! ((vm, select_v1) blk_entry_inst_ret:
RET (blk_entry_ret)
);
define_block! ((vm, select_v1) blk_entry(blk_entry_n){
blk_entry_inst_cmp, blk_entry_inst_select, blk_entry_inst_ret
});
define_func_ver!((vm) select_v1 (entry: blk_entry) {blk_entry});
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