Commit deab5cac authored by qinsoon's avatar qinsoon

fix the bug of wrong code sequence emitted for mul

parent 06f9d9a0
......@@ -2672,6 +2672,12 @@ impl<'a> InstructionSelection {
1 | 2 | 4 | 8 => {
trace!("emit mul");
// we need to emit both operands first, then move one into RAX
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(),
4 => x86_64::EAX.clone(),
......@@ -2679,38 +2685,10 @@ impl<'a> InstructionSelection {
1 => x86_64::AL.clone(),
_ => unimplemented!()
};
if self.match_iimm(op1) {
let imm_op1 = self.node_iimm_to_i32(op1);
self.backend.emit_mov_r_imm(&mreg_op1, imm_op1);
} else if self.match_mem(op1) {
let mem_op1 = self.emit_mem(op1, vm);
self.backend.emit_mov_r_mem(&mreg_op1, &mem_op1);
} else if self.match_ireg(op1) {
let reg_op1 = self.emit_ireg(op1, f_content, f_context, vm);
self.backend.emit_mov_r_r(&mreg_op1, &reg_op1);
} else {
panic!("unexpected op1 for node {:?}", node)
}
self.backend.emit_mov_r_r(&mreg_op1, &tmp_op1);
// mul op2
if self.match_iimm(op2) {
let imm_op2 = self.node_iimm_to_i32(op2);
// put imm in a temporary
// here we use result reg as temporary
self.backend.emit_mov_r_imm(&res_tmp, imm_op2);
self.backend.emit_mul_r(&res_tmp);
} else if self.match_mem(op2) {
let mem_op2 = self.emit_mem(op2, vm);
self.backend.emit_mul_mem(&mem_op2);
} else if self.match_ireg(op2) {
let reg_op2 = self.emit_ireg(op2, f_content, f_context, vm);
self.backend.emit_mul_r(&reg_op2);
} else {
panic!("unexpected op2 for node {:?}", node)
}
self.backend.emit_mul_r(&tmp_op2);
// mov rax -> result
let res_size = vm.get_backend_type_size(res_tmp.ty.id());
......
......@@ -650,3 +650,125 @@ fn add_int64_nzc() -> VM {
vm
}
#[test]
fn test_nest_mul_simple() {
VM::start_logging_trace();
let lib = linkutils::aot::compile_fnc("nest_mul_simple", &nest_mul_simple);
unsafe {
let nest_mul_simple: libloading::Symbol<unsafe extern "C" fn(u64, u64, u64) -> u64> =
lib.get(b"nest_mul_simple").unwrap();
let res = nest_mul_simple(2, 3, 4);
println!("mul(2, 3, 4) = {}", res);
assert_eq!(res, 24);
}
}
fn nest_mul_simple() -> VM {
let vm = VM::new();
typedef! ((vm) int64 = mu_int(64));
funcsig! ((vm) sig = (int64, int64, int64) -> (int64));
funcdecl! ((vm) <sig> nest_mul_simple);
funcdef! ((vm) <sig> nest_mul_simple VERSION nest_mul_simple_v1);
// %entry(%x, %y, %z)
block! ((vm, nest_mul_simple_v1) blk_entry);
ssa! ((vm, nest_mul_simple_v1) <int64> x);
ssa! ((vm, nest_mul_simple_v1) <int64> y);
ssa! ((vm, nest_mul_simple_v1) <int64> z);
// %a = MUL %x %y
ssa! ((vm, nest_mul_simple_v1) <int64> a);
inst! ((vm, nest_mul_simple_v1) blk_entry_mul1:
a = BINOP (BinOp::Mul) x y
);
// %b = MUL %a %z
ssa! ((vm, nest_mul_simple_v1) <int64> b);
inst! ((vm, nest_mul_simple_v1) blk_entry_mul2:
b = BINOP (BinOp::Mul) a z
);
// RET b
inst! ((vm, nest_mul_simple_v1) blk_entry_ret:
RET (b)
);
define_block!((vm, nest_mul_simple_v1) blk_entry(x, y, z) {
blk_entry_mul1,
blk_entry_mul2,
blk_entry_ret
});
define_func_ver!((vm) nest_mul_simple_v1(entry: blk_entry) {
blk_entry
});
vm
}
#[test]
fn test_nest_mul_times_10() {
VM::start_logging_trace();
let lib = linkutils::aot::compile_fnc("nest_mul_times_10", &nest_mul_times_10);
unsafe {
let nest_mul: libloading::Symbol<unsafe extern "C" fn(u64, u64) -> u64> =
lib.get(b"nest_mul_times_10").unwrap();
let res = nest_mul(2, 3);
println!("mul(2, 3) x 10 = {}", res);
assert_eq!(res, 60);
}
}
fn nest_mul_times_10() -> VM {
let vm = VM::new();
typedef! ((vm) int64 = mu_int(64));
constdef! ((vm) <int64> int64_10 = Constant::Int(10));
funcsig! ((vm) sig = (int64, int64) -> (int64));
funcdecl! ((vm) <sig> nest_mul_times_10);
funcdef! ((vm) <sig> nest_mul_times_10 VERSION nest_mul_times_10_v1);
// %entry(%x, %y)
block! ((vm, nest_mul_times_10_v1) blk_entry);
ssa! ((vm, nest_mul_times_10_v1) <int64> x);
ssa! ((vm, nest_mul_times_10_v1) <int64> y);
consta! ((vm, nest_mul_times_10_v1) int64_10_local = int64_10);
// %a = MUL %x %y
ssa! ((vm, nest_mul_times_10_v1) <int64> a);
inst! ((vm, nest_mul_times_10_v1) blk_entry_mul1:
a = BINOP (BinOp::Mul) x y
);
// %b = MUL 10 %a
ssa! ((vm, nest_mul_times_10_v1) <int64> b);
inst! ((vm, nest_mul_times_10_v1) blk_entry_mul2:
b = BINOP (BinOp::Mul) int64_10_local a
);
// RET b
inst! ((vm, nest_mul_times_10_v1) blk_entry_ret:
RET (b)
);
define_block!((vm, nest_mul_times_10_v1) blk_entry(x, y) {
blk_entry_mul1,
blk_entry_mul2,
blk_entry_ret
});
define_func_ver!((vm) nest_mul_times_10_v1(entry: blk_entry) {
blk_entry
});
vm
}
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