GitLab will continue to be upgraded from 11.4.5-ce.0 on November 25th 2019 at 4.00pm (AEDT) to 5.00pm (AEDT) due to Critical Security Patch Availability. During the update, GitLab and Mattermost services will not be available.

Commit 98157fa0 authored by qinsoon's avatar qinsoon

shl int128

parent 20b2d04e
......@@ -1555,6 +1555,43 @@ impl ASMCodeGen {
)
}
fn internal_triop_def_r_r_mr(&mut self, inst: &str, dest: Reg, src1: Reg, src2: Reg) {
let len = check_op_len(dest);
let inst = inst.to_string() + &op_postfix(len);
trace!("emit: {} {}, {}, {} -> {}", inst, dest, src1, src2, dest);
let mreg = self.prepare_machine_reg(src2);
let mreg_name = src2.name().unwrap();
let (reg1, id1, loc1) = self.prepare_reg(src1, inst.len() + 1 + 1 + mreg_name.len() + 1);
let (reg2, id2, loc2) = self.prepare_reg(dest, inst.len() + 1 + 1 + mreg_name.len() + 1 + reg1.len() + 1);
let asm = format!("{} %{},{},{}", inst, mreg_name, reg1, reg2);
self.add_asm_inst(
asm,
linked_hashmap!{
id2 => vec![loc2.clone()]
},
{
if id1 == id2 {
linked_hashmap! {
id1 => vec![loc1, loc2],
mreg => vec![]
}
} else {
linked_hashmap! {
id1 => vec![loc1],
id2 => vec![loc2],
mreg => vec![]
}
}
},
false
)
}
fn internal_mov_r64_imm64(&mut self, inst: &str, dest: &P<Value>, src: i64) {
let inst = inst.to_string() + &op_postfix(64);
trace!("emit: {} {} -> {}", inst, src, dest);
......@@ -2161,6 +2198,10 @@ impl CodeGenerator for ASMCodeGen {
self.internal_binop_no_def_r_r("test", op1, op2)
}
fn emit_test_imm_r(&mut self, op1: i32, op2: Reg) {
self.internal_binop_no_def_imm_r("test", op1, op2)
}
// mov
fn emit_mov_r64_imm64 (&mut self, dest: &P<Value>, src: i64) {
......@@ -2743,6 +2784,10 @@ impl CodeGenerator for ASMCodeGen {
self.internal_binop_def_r_imm("shl", dest, src as i32)
}
fn emit_shld_r_r_cl (&mut self, dest: Reg, src: Reg) {
self.internal_triop_def_r_r_mr("shld", dest, src, &x86_64::CL);
}
fn emit_shr_r_cl (&mut self, dest: &P<Value>) {
self.internal_binop_def_r_mr("shr", dest, &x86_64::CL)
}
......@@ -2751,6 +2796,10 @@ impl CodeGenerator for ASMCodeGen {
self.internal_binop_def_r_imm("shr", dest, src as i32)
}
fn emit_shrd_r_r_cl (&mut self, dest: Reg, src: Reg) {
self.internal_triop_def_r_r_mr("shrd", dest, src, &x86_64::CL);
}
fn emit_sar_r_cl (&mut self, dest: &P<Value>) {
self.internal_binop_def_r_mr("sar", dest, &x86_64::CL)
}
......
......@@ -39,7 +39,8 @@ pub trait CodeGenerator {
fn emit_cmp_imm_r(&mut self, op1: i32, op2: Reg);
fn emit_cmp_mem_r(&mut self, op1: Reg, op2: Reg);
fn emit_test_r_r (&mut self, op1: Reg, op2: Reg);
fn emit_test_r_r (&mut self, op1: Reg, op2: Reg);
fn emit_test_imm_r(&mut self, op1: i32, op2: Reg);
// gpr move
......@@ -166,9 +167,13 @@ pub trait CodeGenerator {
fn emit_shl_r_cl (&mut self, dest: Reg);
fn emit_shl_r_imm8 (&mut self, dest: Reg, src: i8);
fn emit_shld_r_r_cl (&mut self, dest: Reg, src: Reg);
fn emit_shr_r_cl (&mut self, dest: &P<Value>);
fn emit_shr_r_imm8 (&mut self, dest: &P<Value>, src: i8);
fn emit_shrd_r_r_cl (&mut self, dest: Reg, src: Reg);
fn emit_sar_r_cl (&mut self, dest: &P<Value>);
fn emit_sar_r_imm8 (&mut self, dest: &P<Value>, src: i8);
......@@ -177,15 +182,15 @@ pub trait CodeGenerator {
fn emit_cwd(&mut self); // sign extend ax to dx:ax
fn emit_jmp(&mut self, dest: MuName);
fn emit_je(&mut self, dest: MuName);
fn emit_je (&mut self, dest: MuName);
fn emit_jne(&mut self, dest: MuName);
fn emit_ja(&mut self, dest: MuName);
fn emit_ja (&mut self, dest: MuName);
fn emit_jae(&mut self, dest: MuName);
fn emit_jb(&mut self, dest: MuName);
fn emit_jb (&mut self, dest: MuName);
fn emit_jbe(&mut self, dest: MuName);
fn emit_jg(&mut self, dest: MuName);
fn emit_jg (&mut self, dest: MuName);
fn emit_jge(&mut self, dest: MuName);
fn emit_jl(&mut self, dest: MuName);
fn emit_jl (&mut self, dest: MuName);
fn emit_jle(&mut self, dest: MuName);
fn emit_js(&mut self, dest: MuName);
......
......@@ -1896,35 +1896,71 @@ impl <'a> InstructionSelection {
let op1 = &ops[op1];
let op2 = &ops[op2];
if self.match_mem(op1) {
unimplemented!()
} else if self.match_ireg(op1) {
if self.match_ireg(op1) && self.match_iimm(op2) {
trace!("emit shl-ireg-iimm");
let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
let imm_op2 = self.node_iimm_to_i32(op2);
if self.match_iimm(op2) {
let imm_op2 = self.node_iimm_to_i32(op2) as i8;
// mov op1 -> res
self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
// mov op1 -> result
self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
// shl result, op2 -> result
self.backend.emit_shl_r_imm8(&res_tmp, imm_op2 as i8);
} else if self.match_ireg(op1) && self.match_ireg(op2) {
trace!("emit shl-ireg-ireg");
// shl result, op2 -> result
self.backend.emit_shl_r_imm8(&res_tmp, imm_op2);
} else if self.match_ireg(op2) {
let tmp_op2 = self.emit_ireg(op2, f_content, f_context, vm);
let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
let tmp_op2 = self.emit_ireg(op2, f_content, f_context, vm);
// mov op2 -> cl
self.backend.emit_mov_r_r(&x86_64::CL, &tmp_op2);
// mov op2 -> cl
self.backend.emit_mov_r_r(&x86_64::CL, unsafe {&tmp_op2.as_type(UINT8_TYPE.clone())});
// mov op1 -> result
self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
// mov op1 -> result
self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
// shl result, cl -> result
self.backend.emit_shl_r_cl(&res_tmp);
} else {
panic!("unexpected op2 (not ireg not iimm): {}", op2);
}
// shl result, cl -> result
self.backend.emit_shl_r_cl(&res_tmp);
} else if self.match_ireg_ex(op1) && self.match_ireg_ex(op2) {
trace!("emit shl-iregex-iregex");
let (op1_l, op1_h) = self.emit_ireg_ex(op1, f_content, f_context, vm);
let (op2_l, op2_h) = self.emit_ireg_ex(op2, f_content, f_context, vm);
let (res_l, res_h) = self.split_int128(&res_tmp, f_context, vm);
// mov op2_l -> ecx (we do not care higher bits)
self.backend.emit_mov_r_r(&x86_64::ECX, unsafe {&op2_l.as_type(UINT32_TYPE.clone())});
// mov op1_h -> t1
let t1 = self.make_temporary(f_context, UINT64_TYPE.clone(), vm);
self.backend.emit_mov_r_r(&t1, &op1_h);
// shld op1_l, t1, cl -> t1
self.backend.emit_shld_r_r_cl(&t1, &op1_l);
// mov op1_l -> t2
let t2 = self.make_temporary(f_context, UINT64_TYPE.clone(), vm);
self.backend.emit_mov_r_r(&t2, &op1_l);
// shl t2, cl -> t2
self.backend.emit_shl_r_cl(&t2);
// clear res_l
self.backend.emit_mov_r_imm(&res_l, 0);
// test 64, cl
self.backend.emit_test_imm_r(64i32, &x86_64::CL);
// cmovne t2 -> t1
self.backend.emit_cmovne_r_r(&t1, &t2);
// cmove t2 -> res_l
self.backend.emit_cmove_r_r(&res_l, &t2);
// mov t1 -> res_h
self.backend.emit_mov_r_r(&res_h, &t1);
} else {
panic!("unexpected op1 (not ireg not mem): {}", op1);
unimplemented!()
}
},
op::BinOp::Lshr => {
......
......@@ -168,5 +168,56 @@ fn udiv_u128() -> VM {
define_func_ver!((vm) udiv_u128_v1 (entry: blk_entry) {blk_entry});
vm
}
#[test]
fn test_shl_u128() {
let lib = testutil::compile_fnc("shl_u128", &shl_u128);
unsafe {
use self::extprim::u128::u128;
let shl_u128 : libloading::Symbol<unsafe extern fn(u64, u64, u64, u64) -> (u64, u64)> = lib.get(b"shl_u128").unwrap();
let res = shl_u128(1, 0, 64, 0);
println!("shl_u128(1, 64) = {:?}", res);
assert!(res == (0, 1));
let res = shl_u128(1, 1, 64, 0);
println!("shl_u128(1, 64) = {:?}", res);
assert!(res == (0, 1));
}
}
fn shl_u128() -> VM {
let vm = VM::new();
typedef! ((vm) u128 = mu_int(128));
funcsig! ((vm) sig = (u128, u128) -> (u128));
funcdecl! ((vm) <sig> shl_u128);
funcdef! ((vm) <sig> shl_u128 VERSION shl_u128_v1);
block! ((vm, shl_u128_v1) blk_entry);
ssa! ((vm, shl_u128_v1) <u128> a);
ssa! ((vm, shl_u128_v1) <u128> b);
// sum = Add %a %b
ssa! ((vm, shl_u128_v1) <u128> sum);
inst! ((vm, shl_u128_v1) blk_entry_shl_u128:
sum = BINOP (BinOp::Shl) a b
);
inst! ((vm, shl_u128_v1) blk_entry_ret:
RET (sum)
);
define_block! ((vm, shl_u128_v1) blk_entry(a, b) {
blk_entry_shl_u128, blk_entry_ret
});
define_func_ver!((vm) shl_u128_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