Commit 9f41288e authored by Yi Lin's avatar Yi Lin

Merge branch 'x86-const-pattern' into 'develop'

X86 const pattern

See merge request !37
parents 42e7c338 ac9c4fb5
......@@ -1608,8 +1608,8 @@ impl ASMCodeGen {
self.cur.take().unwrap()
}
/// emits an instruction (use 1 reg, define none)
fn internal_uniop_def_r(&mut self, inst: &str, op: &P<Value>) {
/// emits an instruction (use 0 reg, define 1)
fn internal_uniop_def_nouse_r(&mut self, inst: &str, op: &P<Value>) {
trace!("emit: {} {}", inst, op);
let (reg, id, loc) = self.prepare_reg(op, inst.len() + 1);
......@@ -1626,6 +1626,26 @@ impl ASMCodeGen {
)
}
/// emits an instruction (use 1 reg, define 1 reg)
fn internal_uniop_def_r(&mut self, inst: &str, op: &P<Value>) {
trace!("emit: {} {}", inst, op);
let (reg, id, loc) = self.prepare_reg(op, inst.len() + 1);
let asm = format!("{} {}", inst, reg);
self.add_asm_inst(
asm,
linked_hashmap!{
id => vec![loc.clone()]
},
linked_hashmap!{
id => vec![loc]
},
false
)
}
/// emits an instruction (use 2 regs, define none)
fn internal_binop_no_def_r_r(&mut self, inst: &str, op1: &P<Value>, op2: &P<Value>) {
let len = check_op_len(op1);
......@@ -2608,46 +2628,46 @@ impl CodeGenerator for ASMCodeGen {
// set byte
fn emit_sets_r8(&mut self, dest: Reg) {
self.internal_uniop_def_r("sets", dest)
self.internal_uniop_def_nouse_r("sets", dest)
}
fn emit_setz_r8(&mut self, dest: Reg) {
self.internal_uniop_def_r("setz", dest)
self.internal_uniop_def_nouse_r("setz", dest)
}
fn emit_seto_r8(&mut self, dest: Reg) {
self.internal_uniop_def_r("seto", dest)
self.internal_uniop_def_nouse_r("seto", dest)
}
fn emit_setb_r8(&mut self, dest: Reg) {
self.internal_uniop_def_r("setb", dest)
self.internal_uniop_def_nouse_r("setb", dest)
}
fn emit_seta_r(&mut self, dest: Reg) {
self.internal_uniop_def_r("seta", dest)
self.internal_uniop_def_nouse_r("seta", dest)
}
fn emit_setae_r(&mut self, dest: Reg) {
self.internal_uniop_def_r("setae", dest)
self.internal_uniop_def_nouse_r("setae", dest)
}
fn emit_setb_r(&mut self, dest: Reg) {
self.internal_uniop_def_r("setb", dest)
self.internal_uniop_def_nouse_r("setb", dest)
}
fn emit_setbe_r(&mut self, dest: Reg) {
self.internal_uniop_def_r("setbe", dest)
self.internal_uniop_def_nouse_r("setbe", dest)
}
fn emit_sete_r(&mut self, dest: Reg) {
self.internal_uniop_def_r("sete", dest)
self.internal_uniop_def_nouse_r("sete", dest)
}
fn emit_setg_r(&mut self, dest: Reg) {
self.internal_uniop_def_r("setg", dest)
self.internal_uniop_def_nouse_r("setg", dest)
}
fn emit_setge_r(&mut self, dest: Reg) {
self.internal_uniop_def_r("setge", dest)
self.internal_uniop_def_nouse_r("setge", dest)
}
fn emit_setl_r(&mut self, dest: Reg) {
self.internal_uniop_def_r("setl", dest)
self.internal_uniop_def_nouse_r("setl", dest)
}
fn emit_setle_r(&mut self, dest: Reg) {
self.internal_uniop_def_r("setle", dest)
self.internal_uniop_def_nouse_r("setle", dest)
}
fn emit_setne_r(&mut self, dest: Reg) {
self.internal_uniop_def_r("setne", dest)
self.internal_uniop_def_nouse_r("setne", dest)
}
// cmov src -> dest
......@@ -2824,6 +2844,20 @@ impl CodeGenerator for ASMCodeGen {
self.internal_binop_def_r_imm("sbb", dest, src)
}
// inc and dec
fn emit_inc_r(&mut self, dest: Reg) {
self.internal_uniop_def_r("inc", dest)
}
fn emit_inc_mem(&mut self, dest: Mem) {
unimplemented!()
}
fn emit_dec_r(&mut self, dest: Reg) {
self.internal_uniop_def_r("dec", dest)
}
fn emit_dec_mem(&mut self, dest: Mem) {
unimplemented!()
}
fn emit_mul_r(&mut self, src: &P<Value>) {
let len = check_op_len(src);
......@@ -3526,6 +3560,14 @@ impl CodeGenerator for ASMCodeGen {
self.internal_fp_binop_no_def_r_r("ucomiss", op1, op2);
}
// bitwise - float
fn emit_xorps_f32_f32(&mut self, dest: Reg, src: Reg) {
self.internal_fp_binop_def_r_r("xorps", &dest, &src)
}
fn emit_xorpd_f64_f64(&mut self, dest: Reg, src: Reg) {
self.internal_fp_binop_def_r_r("xorpd", &dest, &src)
}
// add - double
fn emit_addsd_f64_f64(&mut self, dest: &P<Value>, src: &P<Value>) {
......
......@@ -178,6 +178,12 @@ pub trait CodeGenerator {
fn emit_sbb_r_mem(&mut self, dest: Reg, src: Mem);
fn emit_sbb_r_imm(&mut self, dest: Reg, src: i32);
// inc and dec
fn emit_inc_r(&mut self, dest: Reg);
fn emit_inc_mem(&mut self, dest: Mem);
fn emit_dec_r(&mut self, dest: Reg);
fn emit_dec_mem(&mut self, dest: Mem);
// multiply
fn emit_mul_r(&mut self, src: Reg);
fn emit_mul_mem(&mut self, src: Mem);
......@@ -320,6 +326,10 @@ pub trait CodeGenerator {
fn emit_comiss_f32_f32(&mut self, op1: Reg, op2: Reg);
fn emit_ucomiss_f32_f32(&mut self, op1: Reg, op2: Reg);
// fp bitwise
fn emit_xorps_f32_f32(&mut self, dest: Reg, src: Reg);
fn emit_xorpd_f64_f64(&mut self, dest: Reg, src: Reg);
// fp conversion
fn emit_cvtsi2sd_f64_r(&mut self, dest: Reg, src: Reg);
fn emit_cvtsd2si_r_f64(&mut self, dest: Reg, src: Reg);
......@@ -332,7 +342,6 @@ pub trait CodeGenerator {
fn emit_cvtss2sd_f64_f32(&mut self, dest: Reg, src: Reg);
// used for unsigned int to fp conversion
fn emit_cvttsd2si_r_f64(&mut self, dest: Reg, src: Reg);
fn emit_cvttss2si_r_f32(&mut self, dest: Reg, src: Reg);
......
......@@ -2384,8 +2384,57 @@ impl<'a> InstructionSelection {
})
}
/// emits code for binary operations (no status flags)
/// emits code for binary operations
fn emit_binop(
&mut self,
node: &TreeNode,
inst: &Instruction,
op: BinOp,
mut op1: OpIndex,
mut op2: OpIndex,
f_content: &FunctionContent,
f_context: &mut FunctionContext,
vm: &VM
) {
let ref ops = inst.ops;
{
// symmetric operators, we want to make sure that if any of the operands
// will be treated specially, it is going to be op2.
// so we check op1, if it is special, we swap them
let ref node_op1 = ops[op1];
let mut swap_operands = || {
let t = op1;
op1 = op2;
op2 = t;
};
match op {
op::BinOp::Add | op::BinOp::And | op::BinOp::Or | op::BinOp::Xor |
op::BinOp::Mul => {
if self.match_iconst_zero(node_op1) || self.match_iconst_one(node_op1) ||
self.match_iimm(node_op1) ||
self.match_mem(node_op1)
{
swap_operands();
}
}
op::BinOp::FAdd | op::BinOp::FMul => {
if self.match_fconst_zero(node_op1) || self.match_mem(node_op1) {
swap_operands();
}
}
_ => {}
}
}
self.emit_binop_internal(node, inst, op, op1, op2, f_content, f_context, vm)
}
/// emits code for binary operations with the assumption that op2 may be special
fn emit_binop_internal(
&mut self,
node: &TreeNode,
inst: &Instruction,
......@@ -2399,44 +2448,64 @@ impl<'a> InstructionSelection {
let ref ops = inst.ops;
let res_tmp = self.get_result_value(node);
let ref op1 = ops[op1];
let ref op2 = ops[op2];
match op {
op::BinOp::Add => {
if self.match_ireg(&ops[op1]) && self.match_iimm(&ops[op2]) {
if self.match_ireg(op1) && self.match_iconst_zero(op2) {
// add zero is nop
trace!("emit add-ireg-0");
self.emit_move_node_to_value(&res_tmp, op1, f_content, f_context, vm);
} else if self.match_ireg(op1) && self.match_iconst_one(op2) {
// add one is increment
trace!("emit add-ireg-1");
let reg_op1 = self.emit_ireg(op1, f_content, f_context, vm);
self.backend.emit_mov_r_r(&res_tmp, &reg_op1);
self.backend.emit_inc_r(&res_tmp);
} else if self.match_ireg(op1) && self.match_iimm(op2) {
trace!("emit add-ireg-imm");
let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
let reg_op2 = self.node_iimm_to_i32(&ops[op2]);
let reg_op1 = self.emit_ireg(op1, f_content, f_context, vm);
let reg_op2 = self.node_iimm_to_i32(op2);
// mov op1, res
self.backend.emit_mov_r_r(&res_tmp, &reg_op1);
// add op2, res
self.backend.emit_add_r_imm(&res_tmp, reg_op2);
} else if self.match_ireg(&ops[op1]) && self.match_mem(&ops[op2]) {
} else if self.match_ireg(op1) && self.match_mem(op2) {
trace!("emit add-ireg-mem");
let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
let reg_op2 = self.emit_mem(&ops[op2], vm);
let reg_op1 = self.emit_ireg(op1, f_content, f_context, vm);
let reg_op2 = self.emit_mem(op2, vm);
// mov op1, res
self.backend.emit_mov_r_r(&res_tmp, &reg_op1);
// add op2 res
self.backend.emit_add_r_mem(&res_tmp, &reg_op2);
} else if self.match_ireg(&ops[op1]) && self.match_ireg(&ops[op2]) {
} else if self.match_ireg(op1) && self.match_ireg(op2) {
trace!("emit add-ireg-ireg");
let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
let reg_op2 = self.emit_ireg(&ops[op2], f_content, f_context, vm);
let reg_op1 = self.emit_ireg(op1, f_content, f_context, vm);
let reg_op2 = self.emit_ireg(op2, f_content, f_context, vm);
// mov op1, res
self.backend.emit_mov_r_r(&res_tmp, &reg_op1);
// add op2 res
self.backend.emit_add_r_r(&res_tmp, &reg_op2);
} else if self.match_ireg_ex(&ops[op1]) && self.match_ireg_ex(&ops[op2]) {
} else if self.match_ireg_ex(op1) && self.match_iconst_zero(op2) {
// add one is nop
trace!("emit add-iregex-0");
self.emit_move_node_to_value(&res_tmp, op1, f_content, f_context, vm);
} else if self.match_ireg_ex(op1) && self.match_ireg_ex(op2) {
trace!("emit add-iregex-iregex");
let (op1_l, op1_h) = self.emit_ireg_ex(&ops[op1], f_content, f_context, vm);
let (op2_l, op2_h) = self.emit_ireg_ex(&ops[op2], f_content, f_context, vm);
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);
// make result split
// mov op1 to res
......@@ -2454,41 +2523,59 @@ impl<'a> InstructionSelection {
}
}
op::BinOp::Sub => {
if self.match_ireg(&ops[op1]) && self.match_iimm(&ops[op2]) {
if self.match_ireg(op1) && self.match_iconst_zero(op2) {
// sub zero is nop
trace!("emit sub-ireg-0");
self.emit_move_node_to_value(&res_tmp, op1, f_content, f_context, vm);
} else if self.match_ireg(op1) && self.match_iconst_one(op2) {
// sub one is decrement
trace!("emit sub-ireg-1");
let reg_op1 = self.emit_ireg(op1, f_content, f_context, vm);
self.backend.emit_mov_r_r(&res_tmp, &reg_op1);
self.backend.emit_dec_r(&res_tmp);
} else if self.match_ireg(op1) && self.match_iimm(op2) {
trace!("emit sub-ireg-imm");
let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
let imm_op2 = self.node_iimm_to_i32(&ops[op2]);
let reg_op1 = self.emit_ireg(op1, f_content, f_context, vm);
let imm_op2 = self.node_iimm_to_i32(op2);
// mov op1, res
self.backend.emit_mov_r_r(&res_tmp, &reg_op1);
// sub op2, res
self.backend.emit_sub_r_imm(&res_tmp, imm_op2);
} else if self.match_ireg(&ops[op1]) && self.match_mem(&ops[op2]) {
} else if self.match_ireg(op1) && self.match_mem(op2) {
trace!("emit sub-ireg-mem");
let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
let mem_op2 = self.emit_mem(&ops[op2], vm);
let reg_op1 = self.emit_ireg(op1, f_content, f_context, vm);
let mem_op2 = self.emit_mem(op2, vm);
// mov op1, res
self.backend.emit_mov_r_r(&res_tmp, &reg_op1);
// sub op2 res
self.backend.emit_sub_r_mem(&res_tmp, &mem_op2);
} else if self.match_ireg(&ops[op1]) && self.match_ireg(&ops[op2]) {
} else if self.match_ireg(op1) && self.match_ireg(op2) {
trace!("emit sub-ireg-ireg");
let reg_op1 = self.emit_ireg(&ops[op1], f_content, f_context, vm);
let reg_op2 = self.emit_ireg(&ops[op2], f_content, f_context, vm);
let reg_op1 = self.emit_ireg(op1, f_content, f_context, vm);
let reg_op2 = self.emit_ireg(op2, f_content, f_context, vm);
// mov op1, res
self.backend.emit_mov_r_r(&res_tmp, &reg_op1);
// add op2 res
self.backend.emit_sub_r_r(&res_tmp, &reg_op2);
} else if self.match_ireg_ex(&ops[op1]) && self.match_ireg_ex(&ops[op2]) {
} else if self.match_ireg_ex(op1) && self.match_iconst_zero(op2) {
// sub zero is nop
trace!("emit sub-iregex-0");
self.emit_move_node_to_value(&res_tmp, op1, f_content, f_context, vm);
} else if self.match_ireg_ex(op1) && self.match_ireg_ex(op2) {
trace!("emit sub-iregex-iregex");
let (op1_l, op1_h) = self.emit_ireg_ex(&ops[op1], f_content, f_context, vm);
let (op2_l, op2_h) = self.emit_ireg_ex(&ops[op2], f_content, f_context, vm);
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);
// make result split
// mov op1 to res
......@@ -2506,10 +2593,12 @@ impl<'a> InstructionSelection {
}
}
op::BinOp::And => {
let op1 = &ops[op1];
let op2 = &ops[op2];
if self.match_ireg(op1) && self.match_iconst_zero(op2) {
// and with zero is setting result as zero
trace!("emit and-ireg-0");
if self.match_ireg(op1) && self.match_iimm(op2) {
self.emit_clear_value(&res_tmp, f_context, vm);
} else if self.match_ireg(op1) && self.match_iimm(op2) {
trace!("emit and-ireg-iimm");
let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
......@@ -2539,6 +2628,11 @@ impl<'a> InstructionSelection {
self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
// and op2, res -> res
self.backend.emit_and_r_r(&res_tmp, &tmp_op2);
} else if self.match_ireg_ex(op1) && self.match_iconst_zero(op2) {
// and with zero is setting result as zero
trace!("emit and-iregex-0");
self.emit_clear_value(&res_tmp, f_context, vm);
} else if self.match_ireg_ex(op1) && self.match_ireg_ex(op2) {
trace!("emit and-iregex-iregex");
......@@ -2561,9 +2655,12 @@ impl<'a> InstructionSelection {
}
}
op::BinOp::Or => {
let op1 = &ops[op1];
let op2 = &ops[op2];
if self.match_ireg(op1) && self.match_iconst_zero(op2) {
// or zero is nop
trace!("emit or-ireg-0");
self.emit_move_node_to_value(&res_tmp, op1, f_content, f_context, vm);
}
if self.match_ireg(op1) && self.match_iimm(op2) {
trace!("emit or-ireg-iimm");
......@@ -2594,6 +2691,10 @@ impl<'a> InstructionSelection {
self.backend.emit_mov_r_r(&res_tmp, &tmp_op1);
// Or op2, res -> res
self.backend.emit_or_r_r(&res_tmp, &tmp_op2);
} else if self.match_ireg(op1) && self.match_iconst_zero(op2) {
trace!("emit or-iregex-zero");
self.emit_move_node_to_value(&res_tmp, op1, f_content, f_context, vm);
} else if self.match_ireg_ex(op1) && self.match_ireg_ex(op2) {
trace!("emit or-iregex-iregex");
......@@ -2616,9 +2717,6 @@ impl<'a> InstructionSelection {
}
}
op::BinOp::Xor => {
let op1 = &ops[op1];
let op2 = &ops[op2];
if self.match_ireg(op1) && self.match_iimm(op2) {
trace!("emit xor-ireg-iimm");
......@@ -2671,10 +2769,25 @@ impl<'a> InstructionSelection {
}
}
op::BinOp::Mul => {
// special cases
if self.match_ireg(op1) && self.match_iconst_zero(op2) {
// MUL with zero is zero
trace!("emit mul-ireg-0");
self.emit_clear_value(&res_tmp, f_context, vm);
} else if self.match_ireg(op1) && self.match_iconst_one(op2) {
// MUL with one is the original value
trace!("emit mul-ireg-1");
self.emit_move_node_to_value(&res_tmp, op1, f_content, f_context, vm);
} else if self.match_ireg_ex(op1) && self.match_iconst_zero(op2) {
// MUL with zero is zero
trace!("emit mul-iregex-0");
self.emit_clear_value(&res_tmp, f_context, vm);
} else if self.match_ireg_ex(op1) && self.match_iconst_one(op2) {
// MUL with one is the original value
trace!("emit mul-iregex-1");
self.emit_move_node_to_value(&res_tmp, op1, f_content, f_context, vm);
} else {
// mov op1 -> rax
let op1 = &ops[op1];
let op2 = &ops[op2];
let op_size = vm.get_backend_type_size(op1.as_value().ty.id());
match op_size {
......@@ -2685,7 +2798,6 @@ impl<'a> InstructionSelection {
let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
let tmp_op2 = self.emit_ireg(op2, f_content, f_context, vm);
// move op1 -> RAX
let mreg_op1 = match op_size {
8 => x86_64::RAX.clone(),
......@@ -2770,10 +2882,8 @@ impl<'a> InstructionSelection {
_ => panic!("unsupported int size: {}", op_size)
}
}
}
op::BinOp::Udiv => {
let op1 = &ops[op1];
let op2 = &ops[op2];
let op_size = vm.get_backend_type_size(op1.as_value().ty.id());
match op_size {
......@@ -2812,9 +2922,6 @@ impl<'a> InstructionSelection {
}
}
op::BinOp::Sdiv => {
let op1 = &ops[op1];
let op2 = &ops[op2];
let op_size = vm.get_backend_type_size(op1.as_value().ty.id());
match op_size {
......@@ -2849,9 +2956,6 @@ impl<'a> InstructionSelection {
}
}
op::BinOp::Urem => {
let op1 = &ops[op1];
let op2 = &ops[op2];
let op_size = vm.get_backend_type_size(op1.as_value().ty.id());
match op_size {
......@@ -2886,9 +2990,6 @@ impl<'a> InstructionSelection {
}
}
op::BinOp::Srem => {
let op1 = &ops[op1];
let op2 = &ops[op2];
let op_size = vm.get_backend_type_size(op1.as_value().ty.id());
match op_size {
......@@ -2924,10 +3025,11 @@ impl<'a> InstructionSelection {
}
op::BinOp::Shl => {
let op1 = &ops[op1];
let op2 = &ops[op2];
if self.match_ireg(op1) && self.match_iconst_zero(op2) {
trace!("emit shl-ireg-0");
if self.match_ireg(op1) && self.match_iimm(op2) {
self.emit_move_node_to_value(&res_tmp, op1, f_content, f_context, vm);
} else 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);
......@@ -2953,6 +3055,10 @@ impl<'a> InstructionSelection {
// shl result, cl -> result
self.backend.emit_shl_r_cl(&res_tmp);
} else if self.match_ireg_ex(op1) && self.match_iconst_zero(op2) {
trace!("emit shl-iregex-0");
self.emit_move_node_to_value(&res_tmp, op1, f_content, f_context, vm);
} else if self.match_ireg_ex(op1) && self.match_ireg_ex(op2) {
trace!("emit shl-iregex-iregex");
......@@ -2997,10 +3103,10 @@ impl<'a> InstructionSelection {
}
}
op::BinOp::Lshr => {
let op1 = &ops[op1];
let op2 = &ops[op2];
if self.match_ireg(op1) && self.match_iimm(op2) {
if self.match_ireg(op1) && self.match_iconst_zero(op2) {
trace!("emit lshr-ireg-0");
self.emit_move_node_to_value(&res_tmp, op1, f_content, f_context, vm);
} else if self.match_ireg(op1) && self.match_iimm(op2) {
trace!("emit lshr-ireg-iimm");
let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
......@@ -3026,6 +3132,9 @@ impl<'a> InstructionSelection {
// lshr result, cl -> result
self.backend.emit_shr_r_cl(&res_tmp);
} else if self.match_ireg(op1) && self.match_iconst_zero(op2) {
trace!("emit lshr-iregex-0");
self.emit_move_node_to_value(&res_tmp, op1, f_content, f_context, vm);
} else if self.match_ireg_ex(op1) && self.match_ireg_ex(op2) {
trace!("emit lshr-iregex-iregex");
......@@ -3070,10 +3179,10 @@ impl<'a> InstructionSelection {
}
}
op::BinOp::Ashr => {
let op1 = &ops[op1];
let op2 = &ops[op2];
if self.match_ireg(op1) && self.match_iimm(op2) {
if self.match_ireg(op1) && self.match_iconst_zero(op2) {
trace!("emit ashr-ireg-0");
self.emit_move_node_to_value(&res_tmp, op1, f_content, f_context, vm);
} else if self.match_ireg(op1) && self.match_iimm(op2) {
trace!("emit ashr-ireg-iimm");
let tmp_op1 = self.emit_ireg(op1, f_content, f_context, vm);
......@@ -3099,6 +3208,9 @@ impl<'a> InstructionSelection {
// sar result, cl -> result
self.backend.emit_sar_r_cl(&res_tmp);
} else if self.match_ireg_ex(op1) && self.match_iconst_zero(op2) {
trace!("emit ashr-iregex-0");
self.emit_move_node_to_value(&res_tmp, op1, f_content, f_context, vm);
} else if self.match_ireg_ex(op1) && self.match_ireg_ex(op2) {
trace!("emit ashr-iregex-iregex");
......@@ -3150,11 +3262,14 @@ impl<'a> InstructionSelection {
// floating point
op::BinOp::FAdd => {
if self.match_fpreg(&ops[op1]) && self.match_mem(&ops[op2]) {
if self.match_fpreg(op1) && self.match_fconst_zero(op2) {
trace!("emit add-fpreg-0");
self.emit_move_node_to_value(&res_tmp, op1, f_content, f_context, vm);
} else if self.match_fpreg(op1) && self.match_mem(op2) {
trace!("emit add-fpreg-mem");
let reg_op1 = self.emit_fpreg(&ops[op1], f_content, f_context, vm);
let mem_op2 = self.emit_mem(&ops[op2], vm);
let reg_op1 = self.emit_fpreg(op1, f_content, f_context, vm);
let mem_op2 = self.emit_mem(op2, vm);
match reg_op1.ty.v {
MuType_::Double => {
......@@ -3172,11 +3287,11 @@ impl<'a> InstructionSelection {
_ => panic!("expect double or float")
}
} else if self.match_fpreg(&ops[op1]) && self.match_fpreg(&ops[op2]) {
} else if self.match_fpreg(op1) && self.match_fpreg(op2) {
trace!("emit add-fpreg-fpreg");
let reg_op1 = self.emit_fpreg(&ops[op1], f_content, f_context, vm);
let reg_op2 = self.emit_fpreg(&ops[op2], f_content, f_context, vm);
let reg_op1 = self.emit_fpreg(op1, f_content, f_context, vm);
let reg_op2 = self.emit_fpreg(op2, f_content, f_context, vm);
match reg_op1.ty.v {
MuType_::Double => {
......@@ -3199,11 +3314,14 @@ impl<'a> InstructionSelection {
}
op::BinOp::FSub => {
if self.match_fpreg(&ops[op1]) && self.match_mem(&ops[op2]) {
if self.match_fpreg(op1) && self.match_fconst_zero(op2) {
trace!("emit sub-fpreg-0");
self.emit_move_node_to_value(&res_tmp, op1, f_content, f_context, vm);
} else if self.match_fpreg(op1) && self.match_mem(op2) {
trace!("emit sub-fpreg-mem");
let reg_op1 = self.emit_fpreg(&ops[op1], f_content, f_context, vm);
let mem_op2 = self.emit_mem(&ops[op2], vm);
let reg_op1 = self.emit_fpreg(op1, f_content, f_context, vm);
let mem_op2 = self.emit_mem(op2, vm);
match reg_op1.ty.v {
MuType_::Double => {
......@@ -3220,11 +3338,11 @@ impl<'a> InstructionSelection {
}
_ => panic!("expect double or float")
}
} else if self.match_fpreg(&ops[op1]) && self.match_fpreg(&ops[op2]) {
} else if self.match_fpreg(op1) && self.match_fpreg(op2) {
trace!("emit sub-fpreg-fpreg");
let reg_op1 = self.emit_fpreg(&ops[op1], f_content, f_context, vm);
let reg_op2 = self.emit_fpreg(&ops[op2], f_content, f_context, vm);
let reg_op1 = self.emit_fpreg(op1, f_content, f_context, vm);
let reg_op2 = self.emit_fpreg(op2, f_content, f_context, vm);
match reg_op1.ty.v {
MuType_::Double => {
......@@ -3247,11 +3365,14 @@ impl<'a> InstructionSelection {
}
op::BinOp::FMul => {
if self.match_fpreg(&ops[op1]) && self.match_mem(&ops[op2]) {
if self.match_fpreg(op1) && self.match_fconst_zero(op2) {
trace!("emit mul-fpreg-0");
self.emit_clear_value(&res_tmp, f_context, vm);
} else if self.match_fpreg(op1) && self.match_mem(op2) {
trace!("emit mul-fpreg-mem");
let reg_op1 = self.emit_fpreg(&ops[op1], f_content, f_context, vm);
let mem_op2 = self.emit_mem(&ops[op2], vm);
let reg_op1 = self.emit_fpreg(op1, f_content, f_context, vm);
let mem_op2 = self.emit_mem(op2, vm);
match reg_op1.ty.v {
MuType_::Double => {
......@@ -3268,11 +3389,11 @@ impl<'a> InstructionSelection {
}
_ => panic!("expect double or float")
}
} else if self.match_fpreg(&ops[op1]) && self.match_fpreg(&ops[op2]) {
} else if self.match_fpreg(op1) && self.match_fpreg(op2) {
trace!("emit mul-fpreg-fpreg");
let reg_op1 = self.emit_fpreg(&ops[op1], f_content, f_context, vm);
let reg_op2 = self.emit_fpreg(&ops[op2], f_content, f_context, vm);
let reg_op1 = self.emit_fpreg(op1, f_content, f_context, vm);