GitLab will be upgraded on June 2nd 2020 at 2.00 pm (AEDT) to 3.00 pm (AEDT) due to Critical Security Patch Availability. During the update, GitLab and Mattermost services will not be available. If you have any concerns with this, please talk to local Gitlab admin team.

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,
......
......@@ -3,7 +3,8 @@ use inst::Instruction_::*;
pub fn is_terminal_inst(inst: &Instruction_) -> bool {
match inst {
&BinOp(_, _, _)
&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);
......
......@@ -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