Commit 3f035045 authored by qinsoon's avatar qinsoon

implement binop_with_status

parent 0e158574
......@@ -92,6 +92,8 @@ pub enum Instruction_ {
// expressions
BinOp(BinOp, OpIndex, OpIndex),
BinOpWithStatus(BinOp, BinOpStatus, OpIndex, OpIndex),
CmpOp(CmpOp, OpIndex, OpIndex),
ConvOp{
operation: ConvOp,
......@@ -282,6 +284,9 @@ impl Instruction_ {
fn debug_str(&self, ops: &Vec<P<TreeNode>>) -> String {
match self {
&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_::ConvOp{operation, ref from_ty, ref to_ty, operand} => {
format!("{:?} {} {} {}", operation, from_ty, to_ty, ops[operand])
......@@ -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)]
pub enum MemoryOrder {
NotAtomic,
......
......@@ -4,6 +4,7 @@ use inst::Instruction_::*;
pub fn is_terminal_inst(inst: &Instruction_) -> bool {
match inst {
&BinOp(_, _, _)
| &BinOpWithStatus(_, _, _, _)
| &CmpOp(_, _, _)
| &ConvOp{..}
| &ExprCall{..}
......@@ -56,6 +57,7 @@ pub fn is_non_terminal_inst(inst: &Instruction_) -> bool {
pub fn has_side_effect(inst: &Instruction_) -> bool {
match inst {
&BinOp(_, _, _) => false,
&BinOpWithStatus(_, _, _, _) => false,
&CmpOp(_, _, _) => false,
&ConvOp{..} => false,
&ExprCall{..} => true,
......
......@@ -36,6 +36,7 @@ pub enum OpCode {
// expression
Binary(BinOp),
BinaryWithStatus(BinOp),
Comparison(CmpOp),
Conversion(ConvOp),
AtomicRMW(AtomicRMWOp),
......@@ -253,6 +254,7 @@ pub fn is_int_cmp(op: CmpOp) -> bool {
pub fn pick_op_code_for_inst(inst: &Instruction) -> OpCode {
match inst.v {
Instruction_::BinOp(op, _, _) => OpCode::Binary(op),
Instruction_::BinOpWithStatus(op, _, _, _) => OpCode::BinaryWithStatus(op),
Instruction_::CmpOp(op, _, _) => OpCode::Comparison(op),
Instruction_::ConvOp{operation, ..} => OpCode::Conversion(operation),
Instruction_::AtomicRMW{op, ..} => OpCode::AtomicRMW(op),
......
......@@ -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
// binop op1, op2 (op2 is destination)
......
......@@ -48,6 +48,12 @@ pub trait CodeGenerator {
fn emit_movs_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
fn emit_cmova_r_r (&mut self, dest: Reg, src: Reg);
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -480,6 +480,7 @@ pub fn estimate_insts_for_ir(inst: &Instruction) -> usize {
match inst.v {
// simple
BinOp(_, _, _) => 1,
BinOpWithStatus(_, _, _, _) => 2,
CmpOp(_, _, _) => 1,
ConvOp{..} => 0,
......
......@@ -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>) {
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) {
......
......@@ -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
(($vm: expr, $fv: ident) $name: ident: $value: ident = CMPOP ($op: expr) $op1: ident $op2: ident) => {
let $name = $fv.new_inst(Instruction{
......
......@@ -353,3 +353,314 @@ fn lshr() -> 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