Commit 97e188ad authored by qinsoon's avatar qinsoon

implement SELECT

parent 01145b46
Pipeline #129 canceled with stage
in 4 minutes and 19 seconds
......@@ -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