Commit 8aa0b809 authored by qinsoon's avatar qinsoon

fmul, fadd, frem, sitofp, fptosi

parent 3fce5a32
Pipeline #190 failed with stage
in 24 minutes and 23 seconds
......@@ -2640,6 +2640,52 @@ impl CodeGenerator for ASMCodeGen {
fn emit_mulsd_f64_mem64(&mut self, dest: Reg, src: Mem) {
self.internal_fp_binop_def_r_mem("mulsd", dest, src);
}
fn emit_cvtsi2sd_f64_r (&mut self, dest: Reg, src: Reg) {
let len = check_op_len(src);
let inst = "cvtsi2sd".to_string() + &op_postfix(len);
trace!("emit: {} {} -> {}", inst, src, dest);
let (reg1, id1, loc1) = self.prepare_reg (src, inst.len() + 1);
let (reg2, id2, loc2) = self.prepare_fpreg(dest, inst.len() + 1 + reg1.len() + 1);
let asm = format!("{} {},{}", inst, reg1, reg2);
self.add_asm_inst(
asm,
hashmap!{
id2 => vec![loc2]
},
hashmap!{
id1 => vec![loc1]
},
false
)
}
fn emit_cvtsd2si_r_f64 (&mut self, dest: Reg, src: Reg) {
let len = check_op_len(dest);
let inst = "cvtsd2si".to_string() + &op_postfix(len);
trace!("emit: {} {} -> {}", inst, src, dest);
let (reg1, id1, loc1) = self.prepare_fpreg(src, inst.len() + 1);
let (reg2, id2, loc2) = self.prepare_reg (dest, inst.len() + 1 + reg1.len() + 1);
let asm = format!("{} {},{}", inst, reg1, reg2);
self.add_asm_inst(
asm,
hashmap!{
id2 => vec![loc2]
},
hashmap!{
id1 => vec![loc1]
},
false
)
}
}
fn create_emit_directory(vm: &VM) {
......
......@@ -180,4 +180,8 @@ pub trait CodeGenerator {
// fp comparison
fn emit_comisd_f64_f64 (&mut self, op1: Reg, op2: Reg);
fn emit_ucomisd_f64_f64 (&mut self, op1: Reg, op2: 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);
}
\ No newline at end of file
......@@ -1011,8 +1011,21 @@ impl <'a> InstructionSelection {
panic!("unexpected fdiv: {}", node)
}
}
_ => unimplemented!()
op::BinOp::FRem => {
if self.match_fpreg(&ops[op1]) && self.match_fpreg(&ops[op2]) {
trace!("emit frem-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_tmp = self.get_result_value(node);
self.emit_runtime_entry(&entrypoints::FREM, vec![reg_op1.clone(), reg_op2.clone()], Some(vec![reg_tmp.clone()]), Some(node), f_content, f_context, vm);
} else {
panic!("unexpected fdiv: {}", node)
}
}
}
}
......@@ -1094,6 +1107,26 @@ impl <'a> InstructionSelection {
panic!("unexpected op (expect ireg): {}", op)
}
}
op::ConvOp::SITOFP => {
let tmp_res = self.get_result_value(node);
if self.match_ireg(op) {
let tmp_op = self.emit_ireg(op, f_content, f_context, vm);
self.backend.emit_cvtsi2sd_f64_r(&tmp_res, &tmp_op);
} else {
panic!("unexpected op (expected ireg): {}", op)
}
}
op::ConvOp::FPTOSI => {
let tmp_res = self.get_result_value(node);
if self.match_fpreg(op) {
let tmp_op = self.emit_fpreg(op, f_content, f_context, vm);
self.backend.emit_cvtsd2si_r_f64(&tmp_res, &tmp_op);
} else {
panic!("unexpected op (expected fpreg): {}", op)
}
}
_ => unimplemented!()
}
......@@ -2499,7 +2532,7 @@ impl <'a> InstructionSelection {
tmp_fp
}
Value_::Constant(Constant::Float(val)) => {
Value_::Constant(Constant::Float(_)) => {
unimplemented!()
},
_ => panic!("expected fpreg")
......@@ -2895,17 +2928,28 @@ impl <'a> InstructionSelection {
if !types::is_fp(dst_ty) && types::is_scalar(dst_ty) {
if self.match_iimm(src) {
let src_imm = self.node_iimm_to_i32(src);
self.backend.emit_mov_r_imm(dest, src_imm);
if dest.is_int_reg() {
self.backend.emit_mov_r_imm(dest, src_imm);
} else if dest.is_mem() {
self.backend.emit_mov_mem_imm(dest, src_imm);
} else {
panic!("unexpected dest: {}", dest);
}
} else if self.match_ireg(src) {
let src_reg = self.emit_ireg(src, f_content, f_context, vm);
self.backend.emit_mov_r_r(dest, &src_reg);
self.emit_move_value_to_value(dest, &src_reg);
} else {
panic!("expected an int type op");
panic!("expected src: {}", src);
}
} else if types::is_fp(dst_ty) && types::is_scalar(dst_ty) {
if self.match_fpreg(src) {
let src_reg = self.emit_fpreg(src, f_content, f_context, vm);
self.emit_move_value_to_value(dest, &src_reg)
} else {
panic!("unexpected fp src: {}", src);
}
} else if !types::is_fp(dst_ty) && types::is_scalar(dst_ty) {
unimplemented!()
} else {
panic!("unexpected type for move");
unimplemented!()
}
}
......
......@@ -73,4 +73,15 @@ lazy_static! {
aot: ValueLocation::Relocatable(RegGroup::GPR, String::from("muentry_throw_exception")),
jit: RwLock::new(None),
};
// impl/decl: math.rs
pub static ref FREM : RuntimeEntrypoint = RuntimeEntrypoint {
sig: P(MuFuncSig{
hdr: MuEntityHeader::unnamed(ir::new_internal_id()),
ret_tys: vec![DOUBLE_TYPE.clone()],
arg_tys: vec![DOUBLE_TYPE.clone(), DOUBLE_TYPE.clone()]
}),
aot: ValueLocation::Relocatable(RegGroup::GPR, String::from("muentry_frem")),
jit: RwLock::new(None)
};
}
\ No newline at end of file
#[no_mangle]
#[allow(unreachable_code)]
pub extern fn muentry_frem(a: f64, b: f64) -> f64 {
use std::ops::Rem;
a.rem(b)
}
\ No newline at end of file
......@@ -14,6 +14,7 @@ use std::sync::Arc;
pub extern crate gc as mm;
pub mod thread;
pub mod math;
pub mod entrypoints;
#[cfg(target_arch = "x86_64")]
......
......@@ -3,6 +3,10 @@ macro_rules! typedef {
let $name = $vm.declare_type($vm.next_id(), MuType_::int($len));
$vm.set_name($name.as_entity(), Mu(stringify!($name)));
};
(($vm: expr) $name: ident = mu_double) => {
let $name = $vm.declare_type($vm.next_id(), MuType_::double());
$vm.set_name($name.as_entity(), Mu(stringify!($name)));
};
(($vm: expr) $name: ident = mu_ref($ty: ident)) => {
let $name = $vm.declare_type($vm.next_id(), MuType_::muref($ty.clone()));
$vm.set_name($name.as_entity(), Mu(stringify!($name)));
......
......@@ -8,6 +8,7 @@ use self::mu::ast::inst::*;
use self::mu::ast::op::*;
use self::mu::vm::*;
use self::mu::compiler::*;
use self::mu::testutil;
use std::sync::RwLock;
use std::sync::Arc;
......@@ -110,5 +111,162 @@ fn fp_add() -> VM {
vm.define_func_version(func_ver);
vm
}
#[test]
fn test_fp_ogt_branch() {
let lib = testutil::compile_fnc("fp_ogt_branch", &fp_ogt_branch);
unsafe {
let fp_ogt : libloading::Symbol<unsafe extern fn(f64, f64) -> u32> = lib.get(b"fp_ogt_branch").unwrap();
let res = fp_ogt(-1f64, 0f64);
println!("fp_ogt(-1, 0) = {}", res);
assert!(res == 0);
let res = fp_ogt(0f64, -1f64);
println!("fp_ogt(0, -1) = {}", res);
assert!(res == 1);
let res = fp_ogt(-1f64, -1f64);
println!("fp_ogt(-1, -1) = {}", res);
assert!(res == 0);
let res = fp_ogt(-1f64, -2f64);
println!("fp_ogt(-1, -2) = {}", res);
assert!(res == 1);
let res = fp_ogt(-2f64, -1f64);
println!("fp_ogt(-2, -1) = {}", res);
assert!(res == 0);
let res = fp_ogt(1f64, 2f64);
println!("fp_ogt(1, 2) = {}", res);
assert!(res == 0);
let res = fp_ogt(2f64, 1f64);
println!("fp_ogt(2, 1) = {}", res);
assert!(res == 1);
}
}
fn fp_ogt_branch() -> VM {
let vm = VM::new();
typedef! ((vm) double = mu_double);
typedef! ((vm) int32 = mu_int(32));
typedef! ((vm) int1 = mu_int(1));
constdef! ((vm) <int32> int32_0 = Constant::Int(0));
constdef! ((vm) <int32> int32_1 = Constant::Int(1));
funcsig! ((vm) sig = (double, double) -> (int32));
funcdecl! ((vm) <sig> fp_ogt_branch);
funcdef! ((vm) <sig> fp_ogt_branch VERSION fp_ogt_branch_v1);
// blk entry
block! ((vm, fp_ogt_branch_v1) blk_entry);
ssa! ((vm, fp_ogt_branch_v1) <double> a);
ssa! ((vm, fp_ogt_branch_v1) <double> b);
ssa! ((vm, fp_ogt_branch_v1) <int1> cond);
inst! ((vm, fp_ogt_branch_v1) blk_entry_cmp:
cond = CMPOP (CmpOp::FOGT) a b
);
block! ((vm, fp_ogt_branch_v1) blk_ret1);
consta! ((vm, fp_ogt_branch_v1) int32_1_local = int32_1);
block! ((vm, fp_ogt_branch_v1) blk_ret0);
consta! ((vm, fp_ogt_branch_v1) int32_0_local = int32_0);
inst! ((vm, fp_ogt_branch_v1) blk_entry_branch:
BRANCH2 (cond, int32_1_local, int32_0_local)
IF (OP 0)
THEN blk_ret1 (vec![1]) WITH 0.6f32,
ELSE blk_ret0 (vec![2])
);
define_block! ((vm, fp_ogt_branch_v1) blk_entry(a, b){
blk_entry_cmp, blk_entry_branch
});
// blk_ret1
ssa! ((vm, fp_ogt_branch_v1) <int32> blk_ret1_res);
inst! ((vm, fp_ogt_branch_v1) blk_ret1_inst:
RET (blk_ret1_res)
);
define_block! ((vm, fp_ogt_branch_v1) blk_ret1(blk_ret1_res){
blk_ret1_inst
});
// blk_ret0
ssa! ((vm, fp_ogt_branch_v1) <int32> blk_ret0_res);
inst! ((vm, fp_ogt_branch_v1) blk_ret0_inst:
RET (blk_ret0_res)
);
define_block! ((vm, fp_ogt_branch_v1) blk_ret0(blk_ret0_res){
blk_ret0_inst
});
define_func_ver!((vm) fp_ogt_branch_v1 (entry: blk_entry) {
blk_entry, blk_ret1, blk_ret0
});
vm
}
#[test]
fn test_sitofp() {
let lib = testutil::compile_fnc("sitofp", &sitofp);
unsafe {
let sitofp : libloading::Symbol<unsafe extern fn(i64) -> f64> = lib.get(b"sitofp").unwrap();
let res = sitofp(-1i64);
println!("sitofp(-1) = {}", res);
assert!(res == -1f64);
let res = sitofp(0i64);
println!("sitofp(0) = {}", res);
assert!(res == 0f64);
let res = sitofp(1i64);
println!("sitofp(1) = {}", res);
assert!(res == 1f64);
}
}
fn sitofp() -> VM {
let vm = VM::new();
typedef! ((vm) int64 = mu_int(64));
typedef! ((vm) double = mu_double);
funcsig! ((vm) sig = (int64) -> (double));
funcdecl! ((vm) <sig> sitofp);
funcdef! ((vm) <sig> sitofp VERSION sitofp_v1);
// blk entry
block! ((vm, sitofp_v1) blk_entry);
ssa! ((vm, sitofp_v1) <int64> x);
ssa! ((vm, sitofp_v1) <double> res);
inst! ((vm, sitofp_v1) blk_entry_conv:
res = CONVOP (ConvOp::SITOFP) <int64 double> x
);
inst! ((vm, sitofp_v1) blk_entry_ret:
RET (res)
);
define_block!((vm, sitofp_v1) blk_entry(x){
blk_entry_conv, blk_entry_ret
});
define_func_ver!((vm) sitofp_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