Commit eadc6e27 authored by qinsoon's avatar qinsoon

FPEXT and FPTRUNC for x86_64

parent a2b50bb1
...@@ -2241,6 +2241,28 @@ impl ASMCodeGen { ...@@ -2241,6 +2241,28 @@ impl ASMCodeGen {
) )
} }
/// emits a truncate instruction (fpreg -> fpreg)
fn internal_fp_trunc(&mut self, inst: &str, dest: Reg, src: Reg) {
let inst = inst.to_string();
trace!("emit: {} {} -> {}", inst, src, dest);
let (reg1, id1, loc1) = self.prepare_fpreg(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,
linked_hashmap!{
id2 => vec![loc2]
},
linked_hashmap!{
id1 => vec![loc1]
},
false
)
}
/// emits a store instruction to store a spilled register /// emits a store instruction to store a spilled register
fn emit_spill_store_gpr(&mut self, dest: Mem, src: Reg) { fn emit_spill_store_gpr(&mut self, dest: Mem, src: Reg) {
self.internal_mov_mem_r("mov", dest, src, true, false) self.internal_mov_mem_r("mov", dest, src, true, false)
...@@ -3508,6 +3530,15 @@ impl CodeGenerator for ASMCodeGen { ...@@ -3508,6 +3530,15 @@ impl CodeGenerator for ASMCodeGen {
self.internal_fpr_to_gpr("cvttss2si", dest, src); self.internal_fpr_to_gpr("cvttss2si", dest, src);
} }
// convert - fp trunc
fn emit_cvtsd2ss_f32_f64(&mut self, dest: Reg, src: Reg) {
self.internal_fp_trunc("cvtsd2ss", dest, src)
}
fn emit_cvtss2sd_f64_f32(&mut self, dest: Reg, src: Reg) {
self.internal_fp_trunc("cvtss2sd", dest, src)
}
// unpack low data - interleave low byte // unpack low data - interleave low byte
fn emit_punpckldq_f64_mem128(&mut self, dest: Reg, src: Mem) { fn emit_punpckldq_f64_mem128(&mut self, dest: Reg, src: Mem) {
trace!("emit: punpckldq {} {} -> {}", src, dest, dest); trace!("emit: punpckldq {} {} -> {}", src, dest, dest);
......
...@@ -302,6 +302,10 @@ pub trait CodeGenerator { ...@@ -302,6 +302,10 @@ pub trait CodeGenerator {
fn emit_cvtsi2ss_f32_r(&mut self, dest: Reg, src: Reg); fn emit_cvtsi2ss_f32_r(&mut self, dest: Reg, src: Reg);
fn emit_cvtss2si_r_f32(&mut self, dest: Reg, src: Reg); fn emit_cvtss2si_r_f32(&mut self, dest: Reg, src: Reg);
// fp trunc
fn emit_cvtsd2ss_f32_f64(&mut self, dest: Reg, src: Reg);
fn emit_cvtss2sd_f64_f32(&mut self, dest: Reg, src: Reg);
// used for unsigned int to fp conversion // used for unsigned int to fp conversion
fn emit_cvttsd2si_r_f64(&mut self, dest: Reg, src: Reg); fn emit_cvttsd2si_r_f64(&mut self, dest: Reg, src: Reg);
......
...@@ -1349,6 +1349,45 @@ impl<'a> InstructionSelection { ...@@ -1349,6 +1349,45 @@ impl<'a> InstructionSelection {
panic!("expect double or float") panic!("expect double or float")
} }
} }
op::ConvOp::FPTRUNC => {
let tmp_res = self.get_result_value(node);
assert!(
self.match_fpreg(op),
"unexpected op (expected fpreg): {}",
op
);
let tmp_op = self.emit_fpreg(op, f_content, f_context, vm);
if tmp_op.ty.is_double() && tmp_res.ty.is_float() {
self.backend.emit_cvtsd2ss_f32_f64(&tmp_res, &tmp_op);
} else {
panic!(
"FPTRUNC from {} to {} is not supported \
(only support FPTRUNC from double to float)",
tmp_op.ty,
tmp_res.ty
);
}
}
op::ConvOp::FPEXT => {
let tmp_res = self.get_result_value(node);
assert!(
self.match_fpreg(op),
"unexpected op (expected fpreg): {}",
op
);
let tmp_op = self.emit_fpreg(op, f_content, f_context, vm);
if tmp_op.ty.is_float() && tmp_res.ty.is_double() {
self.backend.emit_cvtss2sd_f64_f32(&tmp_res, &tmp_op);
} else {
panic!(
"FPEXT from {} to {} is not supported\
(only support FPEXT from float to double)",
tmp_op.ty,
tmp_res.ty
);
}
}
_ => unimplemented!() _ => unimplemented!()
} }
} }
......
...@@ -875,3 +875,113 @@ fn fp_arraysum() -> VM { ...@@ -875,3 +875,113 @@ fn fp_arraysum() -> VM {
vm vm
} }
#[test]
fn test_double_to_float() {
let lib = linkutils::aot::compile_fnc("double_to_float", &double_to_float);
unsafe {
use std::f64;
let double_to_float: libloading::Symbol<unsafe extern "C" fn(f64) -> f32> =
lib.get(b"double_to_float").unwrap();
let res = double_to_float(0f64);
println!("double_fo_float(0) = {}", res);
assert!(res == 0f32);
let res = double_to_float(1f64);
println!("double_fo_float(1) = {}", res);
assert!(res == 1f32);
let res = double_to_float(f64::MAX);
println!("double_to_float(f64::MAX) = {}", res);
assert!(res.is_infinite());
}
}
fn double_to_float() -> VM {
let vm = VM::new();
typedef! ((vm) double = mu_double);
typedef! ((vm) float = mu_float);
funcsig! ((vm) sig = (double) -> (float));
funcdecl! ((vm) <sig> double_to_float);
funcdef! ((vm) <sig> double_to_float VERSION double_to_float_v1);
// blk entry
block! ((vm, double_to_float_v1) blk_entry);
ssa! ((vm, double_to_float_v1) <double> d);
ssa! ((vm, double_to_float_v1) <float> f);
inst! ((vm, double_to_float_v1) blk_entry_fptrunc:
f = CONVOP (ConvOp::FPTRUNC) <double float> d
);
inst! ((vm, double_to_float_v1) blk_entry_ret:
RET (f)
);
define_block!((vm, double_to_float_v1) blk_entry(d) {
blk_entry_fptrunc, blk_entry_ret
});
define_func_ver!((vm) double_to_float_v1 (entry: blk_entry) {
blk_entry
});
vm
}
#[test]
fn test_float_to_double() {
let lib = linkutils::aot::compile_fnc("float_to_double", &float_to_double);
unsafe {
let float_to_double: libloading::Symbol<unsafe extern "C" fn(f32) -> f64> =
lib.get(b"float_to_double").unwrap();
let res = float_to_double(0f32);
println!("float_to_double(0) = {}", 0);
assert!(res == 0f64);
let res = float_to_double(1f32);
println!("float_to_double(1) = {}", 0);
assert!(res == 1f64);
}
}
fn float_to_double() -> VM {
let vm = VM::new();
typedef! ((vm) double = mu_double);
typedef! ((vm) float = mu_float);
funcsig! ((vm) sig = (float) -> (double));
funcdecl! ((vm) <sig> float_to_double);
funcdef! ((vm) <sig> float_to_double VERSION float_to_double_v1);
// blk entry
block! ((vm, float_to_double_v1) blk_entry);
ssa! ((vm, float_to_double_v1) <double> d);
ssa! ((vm, float_to_double_v1) <float> f);
inst! ((vm, float_to_double_v1) blk_entry_fpext:
d = CONVOP (ConvOp::FPEXT) <double float> f
);
inst! ((vm, float_to_double_v1) blk_entry_ret:
RET (d)
);
define_block!((vm, float_to_double_v1) blk_entry(f) {
blk_entry_fpext, blk_entry_ret
});
define_func_ver!((vm) float_to_double_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