Commit 3f035045 authored by qinsoon's avatar qinsoon

implement binop_with_status

parent 0e158574
...@@ -92,6 +92,8 @@ pub enum Instruction_ { ...@@ -92,6 +92,8 @@ pub enum Instruction_ {
// expressions // expressions
BinOp(BinOp, OpIndex, OpIndex), BinOp(BinOp, OpIndex, OpIndex),
BinOpWithStatus(BinOp, BinOpStatus, OpIndex, OpIndex),
CmpOp(CmpOp, OpIndex, OpIndex), CmpOp(CmpOp, OpIndex, OpIndex),
ConvOp{ ConvOp{
operation: ConvOp, operation: ConvOp,
...@@ -282,6 +284,9 @@ impl Instruction_ { ...@@ -282,6 +284,9 @@ impl Instruction_ {
fn debug_str(&self, ops: &Vec<P<TreeNode>>) -> String { fn debug_str(&self, ops: &Vec<P<TreeNode>>) -> String {
match self { match self {
&Instruction_::BinOp(op, op1, op2) => format!("{:?} {} {}", op, ops[op1], ops[op2]), &Instruction_::BinOp(op, op1, op2) => format!("{:?} {} {}", op, ops[op1], ops[op2]),
&Instruction_::BinOpWithStatus(op, status, op1, op2) => {
format!("{:?} {:?} {} {}", op, status, ops[op1], ops[op2])
}
&Instruction_::CmpOp(op, op1, op2) => format!("{:?} {} {}", op, ops[op1], ops[op2]), &Instruction_::CmpOp(op, op1, op2) => format!("{:?} {} {}", op, ops[op1], ops[op2]),
&Instruction_::ConvOp{operation, ref from_ty, ref to_ty, operand} => { &Instruction_::ConvOp{operation, ref from_ty, ref to_ty, operand} => {
format!("{:?} {} {} {}", operation, from_ty, to_ty, ops[operand]) format!("{:?} {} {} {}", operation, from_ty, to_ty, ops[operand])
...@@ -402,6 +407,50 @@ impl Instruction_ { ...@@ -402,6 +407,50 @@ impl Instruction_ {
} }
} }
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
pub struct BinOpStatus {
pub flag_n: bool,
pub flag_z: bool,
pub flag_c: bool,
pub flag_v: bool
}
impl BinOpStatus {
pub fn n() -> BinOpStatus {
BinOpStatus {flag_n: true, flag_z: false, flag_c: false, flag_v: false}
}
pub fn z() -> BinOpStatus {
BinOpStatus {flag_n: false, flag_z: true, flag_c: false, flag_v: false}
}
pub fn c() -> BinOpStatus {
BinOpStatus {flag_n: false, flag_z: false, flag_c: true, flag_v: false}
}
pub fn v() -> BinOpStatus {
BinOpStatus {flag_n: false, flag_z: false, flag_c: false, flag_v: true}
}
}
impl fmt::Debug for BinOpStatus {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.flag_n {
write!(f, "#N").unwrap();
}
if self.flag_z {
write!(f, "#Z").unwrap();
}
if self.flag_c {
write!(f, "#C").unwrap();
}
if self.flag_v {
write!(f, "#V").unwrap();
}
Ok(())
}
}
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum MemoryOrder { pub enum MemoryOrder {
NotAtomic, NotAtomic,
......
...@@ -3,7 +3,8 @@ use inst::Instruction_::*; ...@@ -3,7 +3,8 @@ use inst::Instruction_::*;
pub fn is_terminal_inst(inst: &Instruction_) -> bool { pub fn is_terminal_inst(inst: &Instruction_) -> bool {
match inst { match inst {
&BinOp(_, _, _) &BinOp(_, _, _)
| &BinOpWithStatus(_, _, _, _)
| &CmpOp(_, _, _) | &CmpOp(_, _, _)
| &ConvOp{..} | &ConvOp{..}
| &ExprCall{..} | &ExprCall{..}
...@@ -56,6 +57,7 @@ pub fn is_non_terminal_inst(inst: &Instruction_) -> bool { ...@@ -56,6 +57,7 @@ pub fn is_non_terminal_inst(inst: &Instruction_) -> bool {
pub fn has_side_effect(inst: &Instruction_) -> bool { pub fn has_side_effect(inst: &Instruction_) -> bool {
match inst { match inst {
&BinOp(_, _, _) => false, &BinOp(_, _, _) => false,
&BinOpWithStatus(_, _, _, _) => false,
&CmpOp(_, _, _) => false, &CmpOp(_, _, _) => false,
&ConvOp{..} => false, &ConvOp{..} => false,
&ExprCall{..} => true, &ExprCall{..} => true,
......
...@@ -36,6 +36,7 @@ pub enum OpCode { ...@@ -36,6 +36,7 @@ pub enum OpCode {
// expression // expression
Binary(BinOp), Binary(BinOp),
BinaryWithStatus(BinOp),
Comparison(CmpOp), Comparison(CmpOp),
Conversion(ConvOp), Conversion(ConvOp),
AtomicRMW(AtomicRMWOp), AtomicRMW(AtomicRMWOp),
...@@ -253,6 +254,7 @@ pub fn is_int_cmp(op: CmpOp) -> bool { ...@@ -253,6 +254,7 @@ pub fn is_int_cmp(op: CmpOp) -> bool {
pub fn pick_op_code_for_inst(inst: &Instruction) -> OpCode { pub fn pick_op_code_for_inst(inst: &Instruction) -> OpCode {
match inst.v { match inst.v {
Instruction_::BinOp(op, _, _) => OpCode::Binary(op), Instruction_::BinOp(op, _, _) => OpCode::Binary(op),
Instruction_::BinOpWithStatus(op, _, _, _) => OpCode::BinaryWithStatus(op),
Instruction_::CmpOp(op, _, _) => OpCode::Comparison(op), Instruction_::CmpOp(op, _, _) => OpCode::Comparison(op),
Instruction_::ConvOp{operation, ..} => OpCode::Conversion(operation), Instruction_::ConvOp{operation, ..} => OpCode::Conversion(operation),
Instruction_::AtomicRMW{op, ..} => OpCode::AtomicRMW(op), Instruction_::AtomicRMW{op, ..} => OpCode::AtomicRMW(op),
......
...@@ -1891,6 +1891,75 @@ impl CodeGenerator for ASMCodeGen { ...@@ -1891,6 +1891,75 @@ impl CodeGenerator for ASMCodeGen {
) )
} }
// set byte
fn emit_sets_r8(&mut self, dest: Reg) {
trace!("emit: sets {}", dest);
let (reg, id, loc) = self.prepare_reg(dest, 4 + 1);
let asm = format!("sets {}", reg);
self.add_asm_inst(
asm,
linked_hashmap!{
id => vec![loc]
},
linked_hashmap!{},
false
)
}
fn emit_setz_r8(&mut self, dest: Reg) {
trace!("emit: setz {}", dest);
let (reg, id, loc) = self.prepare_reg(dest, 4 + 1);
let asm = format!("setz {}", reg);
self.add_asm_inst(
asm,
linked_hashmap!{
id => vec![loc]
},
linked_hashmap!{},
false
)
}
fn emit_seto_r8(&mut self, dest: Reg) {
trace!("emit: seto {}", dest);
let (reg, id, loc) = self.prepare_reg(dest, 4 + 1);
let asm = format!("seto {}", reg);
self.add_asm_inst(
asm,
linked_hashmap!{
id => vec![loc]
},
linked_hashmap!{},
false
)
}
fn emit_setb_r8(&mut self, dest: Reg) {
trace!("emit: setb {}", dest);
let (reg, id, loc) = self.prepare_reg(dest, 4 + 1);
let asm = format!("setb {}", reg);
self.add_asm_inst(
asm,
linked_hashmap!{
id => vec![loc]
},
linked_hashmap!{},
false
)
}
// cmov src -> dest // cmov src -> dest
// binop op1, op2 (op2 is destination) // binop op1, op2 (op2 is destination)
......
...@@ -48,6 +48,12 @@ pub trait CodeGenerator { ...@@ -48,6 +48,12 @@ pub trait CodeGenerator {
fn emit_movs_r_r (&mut self, dest: Reg, src: Reg); fn emit_movs_r_r (&mut self, dest: Reg, src: Reg);
fn emit_movz_r_r (&mut self, dest: Reg, src: Reg); fn emit_movz_r_r (&mut self, dest: Reg, src: Reg);
// set byte
fn emit_sets_r8 (&mut self, dest: Reg);
fn emit_setz_r8 (&mut self, dest: Reg);
fn emit_seto_r8 (&mut self, dest: Reg);
fn emit_setb_r8 (&mut self, dest: Reg);
// gpr conditional move // gpr conditional move
fn emit_cmova_r_r (&mut self, dest: Reg, src: Reg); fn emit_cmova_r_r (&mut self, dest: Reg, src: Reg);
......
...@@ -480,6 +480,7 @@ pub fn estimate_insts_for_ir(inst: &Instruction) -> usize { ...@@ -480,6 +480,7 @@ pub fn estimate_insts_for_ir(inst: &Instruction) -> usize {
match inst.v { match inst.v {
// simple // simple
BinOp(_, _, _) => 1, BinOp(_, _, _) => 1,
BinOpWithStatus(_, _, _, _) => 2,
CmpOp(_, _, _) => 1, CmpOp(_, _, _) => 1,
ConvOp{..} => 0, ConvOp{..} => 0,
......
...@@ -308,7 +308,11 @@ impl MuIRBuilder { ...@@ -308,7 +308,11 @@ impl MuIRBuilder {
} }
pub fn new_binop_with_status(&mut self, id: MuID, result_id: MuID, status_result_ids: Vec<MuID>, optr: CMuBinOptr, status_flags: CMuBinOpStatus, ty: MuID, opnd1: MuID, opnd2: MuID, exc_clause: Option<MuID>) { pub fn new_binop_with_status(&mut self, id: MuID, result_id: MuID, status_result_ids: Vec<MuID>, optr: CMuBinOptr, status_flags: CMuBinOpStatus, ty: MuID, opnd1: MuID, opnd2: MuID, exc_clause: Option<MuID>) {
panic!("Not implemented") self.add_inst(id, NodeInst::NodeBinOp {
id: id, result_id: result_id, status_result_ids: status_result_ids,
optr: optr, flags: status_flags, ty: ty, opnd1: opnd1, opnd2: opnd2,
exc_clause: exc_clause
})
} }
pub fn new_cmp(&mut self, id: MuID, result_id: MuID, optr: CMuCmpOptr, ty: MuID, opnd1: MuID, opnd2: MuID) { pub fn new_cmp(&mut self, id: MuID, result_id: MuID, optr: CMuCmpOptr, ty: MuID, opnd1: MuID, opnd2: MuID) {
......
...@@ -247,6 +247,16 @@ macro_rules! inst { ...@@ -247,6 +247,16 @@ macro_rules! inst {
}); });
}; };
// BINOP with status
(($vm: expr, $fv: ident) $name: ident: $value: ident, $($flag: ident), * = BINOP_STATUS ($op: expr) ($flags: expr) $op1: ident $op2: ident) => {
let $name = $fv.new_inst(Instruction{
hdr: MuEntityHeader::unnamed($vm.next_id()),
value: Some(vec![$value.clone_value(), $($flag.clone_value()), *]),
ops: RwLock::new(vec![$op1.clone(), $op2.clone()]),
v: Instruction_::BinOpWithStatus($op, $flags, 0, 1)
});
};
// CMPOP // CMPOP
(($vm: expr, $fv: ident) $name: ident: $value: ident = CMPOP ($op: expr) $op1: ident $op2: ident) => { (($vm: expr, $fv: ident) $name: ident: $value: ident = CMPOP ($op: expr) $op1: ident $op2: ident) => {
let $name = $fv.new_inst(Instruction{ let $name = $fv.new_inst(Instruction{
......
...@@ -353,3 +353,314 @@ fn lshr() -> VM { ...@@ -353,3 +353,314 @@ fn lshr() -> VM {
vm vm
} }
#[test]
fn test_add_int64_n() {
let lib = testutil::compile_fnc("add_int64_n", &add_int64_n);
unsafe {
let add_int64_n : libloading::Symbol<unsafe extern fn(i64, i64) -> u8> = lib.get(b"add_int64_n").unwrap();
let flag = add_int64_n(1, 1);
println!("add_int64_n(1, 1), #N = {}", flag);
assert!(flag == 0);
let flag = add_int64_n(1, -2);
println!("add_int64_n(1, -2), #N = {}", flag);
assert!(flag == 1);
let flag = add_int64_n(1, -1);
println!("add_int64_n(1, -1), #N = {}", flag);
assert!(flag == 0);
let flag = add_int64_n(-1, -1);
println!("add_int64_n(-1, -1), #N = {}", flag);
assert!(flag == 1);
}
}
fn add_int64_n() -> VM {
let vm = VM::new();
typedef! ((vm) int64 = mu_int(64));
typedef! ((vm) int1 = mu_int(1));
funcsig! ((vm) sig = (int64, int64) -> (int1));
funcdecl! ((vm) <sig> add_int64_n);
funcdef! ((vm) <sig> add_int64_n VERSION add_int64_n_v1);
block! ((vm, add_int64_n_v1) blk_entry);
ssa! ((vm, add_int64_n_v1) <int64> a);
ssa! ((vm, add_int64_n_v1) <int64> b);
// (sum, flag_n) = Add #N %a %b
ssa! ((vm, add_int64_n_v1) <int64> sum);
ssa! ((vm, add_int64_n_v1) <int1> flag_n);
inst! ((vm, add_int64_n_v1) blk_entry_add:
sum, flag_n = BINOP_STATUS (BinOp::Add) (BinOpStatus::n()) a b
);
inst! ((vm, add_int64_n_v1) blk_entry_ret:
RET (flag_n)
);
define_block! ((vm, add_int64_n_v1) blk_entry(a, b) {
blk_entry_add, blk_entry_ret
});
define_func_ver!((vm) add_int64_n_v1 (entry: blk_entry) {blk_entry});
vm
}
#[test]
fn test_add_int64_z() {
let lib = testutil::compile_fnc("add_int64_z", &add_int64_z);
unsafe {
let add_int64_z : libloading::Symbol<unsafe extern fn(i64, i64) -> u8> = lib.get(b"add_int64_z").unwrap();
let flag = add_int64_z(1, 1);
println!("add_int64_z(1, 1), #Z = {}", flag);
assert!(flag == 0);
let flag = add_int64_z(1, -2);
println!("add_int64_z(1, -2), #Z = {}", flag);
assert!(flag == 0);
let flag = add_int64_z(1, -1);
println!("add_int64_z(1, -1), #Z = {}", flag);
assert!(flag == 1);
}
}
fn add_int64_z() -> VM {
let vm = VM::new();
typedef! ((vm) int64 = mu_int(64));
typedef! ((vm) int1 = mu_int(1));
funcsig! ((vm) sig = (int64, int64) -> (int1));
funcdecl! ((vm) <sig> add_int64_z);
funcdef! ((vm) <sig> add_int64_z VERSION add_int64_z_v1);
block! ((vm, add_int64_z_v1) blk_entry);
ssa! ((vm, add_int64_z_v1) <int64> a);
ssa! ((vm, add_int64_z_v1) <int64> b);
// (sum, flag_n) = Add #N %a %b
ssa! ((vm, add_int64_z_v1) <int64> sum);
ssa! ((vm, add_int64_z_v1) <int1> flag_z);
inst! ((vm, add_int64_z_v1) blk_entry_add:
sum, flag_z = BINOP_STATUS (BinOp::Add) (BinOpStatus::z()) a b
);
inst! ((vm, add_int64_z_v1) blk_entry_ret:
RET (flag_z)
);
define_block! ((vm, add_int64_z_v1) blk_entry(a, b) {
blk_entry_add, blk_entry_ret
});
define_func_ver!((vm) add_int64_z_v1 (entry: blk_entry) {blk_entry});
vm
}
#[test]
fn test_add_int64_c() {
use std::u64;
let lib = testutil::compile_fnc("add_int64_c", &add_int64_c);
unsafe {
let add_int64_c : libloading::Symbol<unsafe extern fn(u64, u64) -> u8> = lib.get(b"add_int64_c").unwrap();
let flag = add_int64_c(u64::MAX, 1);
println!("add_int64_c(u64::MAX, 1), #C = {}", flag);
assert!(flag == 1);
let flag = add_int64_c(u64::MAX, 0);
println!("add_int64_c(i64::MAX, 0), #C = {}", flag);
assert!(flag == 0);
}
}
fn add_int64_c() -> VM {
let vm = VM::new();
typedef! ((vm) int64 = mu_int(64));
typedef! ((vm) int1 = mu_int(1));
funcsig! ((vm) sig = (int64, int64) -> (int1));
funcdecl! ((vm) <sig> add_int64_c);
funcdef! ((vm) <sig> add_int64_c VERSION add_int64_c_v1);
block! ((vm, add_int64_c_v1) blk_entry);
ssa! ((vm, add_int64_c_v1) <int64> a);
ssa! ((vm, add_int64_c_v1) <int64> b);
// (sum, flag_n) = Add #N %a %b
ssa! ((vm, add_int64_c_v1) <int64> sum);
ssa! ((vm, add_int64_c_v1) <int1> flag_c);
inst! ((vm, add_int64_c_v1) blk_entry_add:
sum, flag_c = BINOP_STATUS (BinOp::Add) (BinOpStatus::c()) a b
);
inst! ((vm, add_int64_c_v1) blk_entry_ret:
RET (flag_c)
);
define_block! ((vm, add_int64_c_v1) blk_entry(a, b) {
blk_entry_add, blk_entry_ret
});
define_func_ver!((vm) add_int64_c_v1 (entry: blk_entry) {blk_entry});
vm
}
#[test]
fn test_add_int64_v() {
use std::i64;
let lib = testutil::compile_fnc("add_int64_v", &add_int64_v);
unsafe {
let add_int64_v : libloading::Symbol<unsafe extern fn(i64, i64) -> u8> = lib.get(b"add_int64_v").unwrap();
let flag = add_int64_v(i64::MAX, 1);
println!("add_int64_v(i64::MAX, 1), #V = {}", flag);
assert!(flag == 1);
let flag = add_int64_v(i64::MAX, 0);
println!("add_int64_v(i64::MAX, 0), #V = {}", flag);
assert!(flag == 0);
let flag = add_int64_v(i64::MIN, 0);
println!("add_int64_v(i64::MIN, 0), #V = {}", flag);
assert!(flag == 0);
let flag = add_int64_v(i64::MIN, -1);
println!("add_int64_v(i64::MIN, -1), #V = {}", flag);
assert!(flag == 1);
}
}
fn add_int64_v() -> VM {
let vm = VM::new();
typedef! ((vm) int64 = mu_int(64));
typedef! ((vm) int1 = mu_int(1));
funcsig! ((vm) sig = (int64, int64) -> (int1));
funcdecl! ((vm) <sig> add_int64_v);
funcdef! ((vm) <sig> add_int64_v VERSION add_int64_v_v1);
block! ((vm, add_int64_v_v1) blk_entry);
ssa! ((vm, add_int64_v_v1) <int64> a);
ssa! ((vm, add_int64_v_v1) <int64> b);
// (sum, flag_n) = Add #N %a %b
ssa! ((vm, add_int64_v_v1) <int64> sum);
ssa! ((vm, add_int64_v_v1) <int1> flag_v);
inst! ((vm, add_int64_v_v1) blk_entry_add:
sum, flag_v = BINOP_STATUS (BinOp::Add) (BinOpStatus::v()) a b
);
inst! ((vm, add_int64_v_v1) blk_entry_ret:
RET (flag_v)
);
define_block! ((vm, add_int64_v_v1) blk_entry(a, b) {
blk_entry_add, blk_entry_ret
});
define_func_ver!((vm) add_int64_v_v1 (entry: blk_entry) {blk_entry});
vm
}
#[test]
fn test_add_int64_nzc() {
use std::u64;
let lib = testutil::compile_fnc("add_int64_nzc", &add_int64_nzc);
unsafe {
let add_int64_nzc : libloading::Symbol<unsafe extern fn(u64, u64) -> u8> = lib.get(b"add_int64_nzc").unwrap();
let flag = add_int64_nzc(u64::MAX, 1);
println!("add_int64_nzc(u64::MAX, 1), #C = {:b}", flag);
assert!(flag == 0b110);
let flag = add_int64_nzc(u64::MAX, 0);
println!("add_int64_nzc(u64::MAX, 0), #C = {:b}", flag);
assert!(flag == 0b001);
}
}
fn add_int64_nzc() -> VM {
let vm = VM::new();
typedef! ((vm) int64 = mu_int(64));
typedef! ((vm) int8 = mu_int(8));
typedef! ((vm) int1 = mu_int(1));
constdef! ((vm) <int8> int8_1 = Constant::Int(1));
constdef! ((vm) <int8> int8_2 = Constant::Int(2));
constdef! ((vm) <int8> int8_3 = Constant::Int(3));
funcsig! ((vm) sig = (int64, int64) -> (int1));
funcdecl! ((vm) <sig> add_int64_nzc);
funcdef! ((vm) <sig> add_int64_nzc VERSION add_int64_nzc_v1);
block! ((vm, add_int64_nzc_v1) blk_entry);
ssa! ((vm, add_int64_nzc_v1) <int64> a);
ssa! ((vm, add_int64_nzc_v1) <int64> b);
// (sum, flag_n) = Add #N %a %b
ssa! ((vm, add_int64_nzc_v1) <int64> sum);
ssa! ((vm, add_int64_nzc_v1) <int1> flag_n);
ssa! ((vm, add_int64_nzc_v1) <int1> flag_z);
ssa! ((vm, add_int64_nzc_v1) <int1> flag_c);
inst! ((vm, add_int64_nzc_v1) blk_entry_add:
sum, flag_n, flag_z, flag_c = BINOP_STATUS (BinOp::Add) (BinOpStatus{flag_n: true, flag_z: true, flag_c: true, flag_v: false}) a b
);
ssa! ((vm, add_int64_nzc_v1) <int8> shift_z);
consta! ((vm, add_int64_nzc_v1) int8_1_local = int8_1);
inst! ((vm, add_int64_nzc_v1) blk_entry_shift_z:
shift_z = BINOP (BinOp::Shl) flag_z int8_1_local
);
ssa! ((vm, add_int64_nzc_v1) <int8> ret);
inst! ((vm, add_int64_nzc_v1) blk_entry_add_ret1:
ret = BINOP (BinOp::Add) flag_n shift_z
);
ssa! ((vm, add_int64_nzc_v1) <int8> shift_c);
consta! ((vm, add_int64_nzc_v1) int8_2_local = int8_2);
inst! ((vm, add_int64_nzc_v1) blk_entry_shift_c:
shift_c = BINOP (BinOp::Shl) flag_c int8_2_local
);
ssa! ((vm, add_int64_nzc_v1) <int8> ret2);
inst! ((vm, add_int64_nzc_v1) blk_entry_add_ret2:
ret2 = BINOP (BinOp::Add) ret shift_c
);
inst! ((vm, add_int64_nzc_v1) blk_entry_ret:
RET (ret2)
);
define_block! ((vm, add_int64_nzc_v1) blk_entry(a, b) {
blk_entry_add, blk_entry_shift_z, blk_entry_add_ret1, blk_entry_shift_c, blk_entry_add_ret2, blk_entry_ret
});
define_func_ver!((vm) add_int64_nzc_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