Fix F32Min for all cases including NaNs.

This commit is contained in:
Nick Lewycky 2019-10-11 17:51:29 -07:00
parent 8b937afc1f
commit 963148fdce
2 changed files with 102 additions and 0 deletions

View File

@ -2823,6 +2823,7 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
&mut self.machine,
&mut self.value_stack,
|a, src1, src2, dst| {
/*
// TODO: we don't have access to 'machine' here.
//let tmp1 = self.machine.acquire_temp_gpr().unwrap();
//let tmp2 = self.machine.acquire_temp_gpr().unwrap();
@ -2897,6 +2898,75 @@ impl FunctionCodeGenerator<CodegenError> for X64FunctionCode {
a.emit_vminss(src1, src2, dst);
// TODO: we don't have access to 'machine' here.
//if release_tmp_xmm { self.machine.release_temp_xmm(tmp_xmm) }
*/
let tmp_xmm1 = /*if dst != src1 && XMMOrMemory::XMM(dst) != src2
{
dst
} else {
// TODO: we don't have access to 'machine' here.
//(self.machine.acquire_temp_xmm().unwrap(), true)
if src1 == XMM::XMM0 {
if src2 == XMMOrMemory::XMM(XMM::XMM1) {
XMM::XMM2
} else {
XMM::XMM1
}
} else {
XMM::XMM0
}
};*/ XMM::XMM6;
let tmp_xmm2 = XMM::XMM7; // TODO: pick value safely.
let tmp_xmm3 = XMM::XMM5; // TODO: pick value safely.
/*
let src2 = match src2 {
XMMOrMemory::XMM(x) => x,
XMMOrMemory::Memory(_, _) => panic!(),
};
a.emit_vminss(src1, XMMOrMemory::XMM(src2), src2);
a.emit_vcmpunordss(src1, XMMOrMemory::XMM(src1), tmp_xmm);
a.emit_vblendvps(src1, src2, XMMOrMemory::XMM(src1), tmp_xmm);
a.emit_vcmpordss(src1, XMMOrMemory::XMM(src1), src2);
let canonical_nan_base = GPR::RDX;
static CANONICAL_NAN: u128 = 0x7FC0_0000;
a.emit_mov(Size::S64, Location::Imm64((&CANONICAL_NAN as *const u128) as u64), Location::GPR(canonical_nan_base));
a.emit_mov(Size::S64, Location::Memory(canonical_nan_base, 0), Location::XMM(tmp_xmm));
a.emit_vblendvps(src1, tmp_xmm, XMMOrMemory::XMM(src1), src2);
a.emit_mov(Size::S64, Location::XMM(src2), Location::XMM(dst));
*/
static NEG_ZERO: u128 = 0x8000_0000;
static CANONICAL_NAN: u128 = 0x7FC0_0000;
let loc2 = match src2 {
XMMOrMemory::XMM(x) => Location::XMM(x),
XMMOrMemory::Memory(base, disp) => Location::Memory(base, disp),
};
let spare_base = GPR::RDX;
//a.emit_ud2();
a.emit_mov(Size::S32, Location::XMM(src1), Location::GPR(GPR::RAX));
a.emit_mov(Size::S32, loc2, Location::GPR(GPR::RDX));
a.emit_cmp(Size::S32, Location::GPR(GPR::RDX), Location::GPR(GPR::RAX));
let src2 = match src2 {
XMMOrMemory::XMM(x) => x,
XMMOrMemory::Memory(_, _) => panic!(),
};
a.emit_vminss(src1, XMMOrMemory::XMM(src2), tmp_xmm1);
let label1 = a.get_label();
let label2 = a.get_label();
a.emit_jmp(Condition::NotEqual, label1);
a.emit_vmovaps(XMMOrMemory::XMM(tmp_xmm1), XMMOrMemory::XMM(tmp_xmm2));
a.emit_jmp(Condition::None, label2);
a.emit_label(label1);
// load float -0.0
a.emit_mov(Size::S64, Location::Imm64((&NEG_ZERO as *const u128) as u64), Location::GPR(spare_base));
a.emit_mov(Size::S64, Location::Memory(spare_base, 0), Location::XMM(tmp_xmm2));
a.emit_label(label2);
a.emit_vcmpeqss(src1, XMMOrMemory::XMM(src2), tmp_xmm3);
a.emit_vblendvps(tmp_xmm3, XMMOrMemory::XMM(tmp_xmm2), tmp_xmm1, tmp_xmm1);
a.emit_vcmpunordss(src1, XMMOrMemory::XMM(src2), src1);
// load float canonical nan
a.emit_mov(Size::S64, Location::Imm64((&CANONICAL_NAN as *const u128) as u64), Location::GPR(spare_base));
a.emit_mov(Size::S64, Location::Memory(spare_base, 0), Location::XMM(src2));
a.emit_vblendvps(src1, XMMOrMemory::XMM(src2), tmp_xmm1, src1);
a.emit_vmovaps(XMMOrMemory::XMM(src1), XMMOrMemory::XMM(dst));
},
),
Operator::F32Eq => Self::emit_fp_cmpop_avx(

View File

@ -107,6 +107,8 @@ pub trait Emitter {
fn emit_cmovae_gpr_32(&mut self, src: GPR, dst: GPR);
fn emit_cmovae_gpr_64(&mut self, src: GPR, dst: GPR);
fn emit_vmovaps(&mut self, src: XMMOrMemory, dst: XMMOrMemory);
fn emit_vaddss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM);
fn emit_vaddsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM);
fn emit_vsubss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM);
@ -138,6 +140,12 @@ pub trait Emitter {
fn emit_vcmpgess(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM);
fn emit_vcmpgesd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM);
fn emit_vcmpunordss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM);
fn emit_vcmpunordsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM);
fn emit_vcmpordss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM);
fn emit_vcmpordsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM);
fn emit_vsqrtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM);
fn emit_vsqrtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM);
@ -166,6 +174,8 @@ pub trait Emitter {
fn emit_vcvtsi2sd_32(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM);
fn emit_vcvtsi2sd_64(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM);
fn emit_vblendvps(&mut self, src1: XMM, src2: XMMOrMemory, mask: XMM, dst: XMM);
fn emit_test_gpr_64(&mut self, reg: GPR);
fn emit_ud2(&mut self);
@ -951,6 +961,15 @@ impl Emitter for Assembler {
dynasm!(self ; cmovae Rq(dst as u8), Rq(src as u8));
}
fn emit_vmovaps(&mut self, src: XMMOrMemory, dst: XMMOrMemory) {
match (src, dst) {
(XMMOrMemory::XMM(src), XMMOrMemory::XMM(dst)) => dynasm!(self ; movaps Rx(dst as u8), Rx(src as u8)),
(XMMOrMemory::Memory(base, disp), XMMOrMemory::XMM(dst)) => dynasm!(self ; movaps Rx(dst as u8), [Rq(base as u8) + disp]),
(XMMOrMemory::XMM(src), XMMOrMemory::Memory(base, disp)) => dynasm!(self ; movaps [Rq(base as u8) + disp], Rx(src as u8)),
_ => panic!("singlepass can't emit VMOVAPS {:?} {:?}", src, dst),
};
}
avx_fn!(vaddss, emit_vaddss);
avx_fn!(vaddsd, emit_vaddsd);
@ -987,6 +1006,12 @@ impl Emitter for Assembler {
avx_fn!(vcmpgess, emit_vcmpgess);
avx_fn!(vcmpgesd, emit_vcmpgesd);
avx_fn!(vcmpunordss, emit_vcmpunordss);
avx_fn!(vcmpunordsd, emit_vcmpunordsd);
avx_fn!(vcmpordss, emit_vcmpordss);
avx_fn!(vcmpordsd, emit_vcmpordsd);
avx_fn!(vsqrtss, emit_vsqrtss);
avx_fn!(vsqrtsd, emit_vsqrtsd);
@ -1007,6 +1032,13 @@ impl Emitter for Assembler {
avx_i2f_64_fn!(vcvtsi2ss, emit_vcvtsi2ss_64);
avx_i2f_64_fn!(vcvtsi2sd, emit_vcvtsi2sd_64);
fn emit_vblendvps(&mut self, src1: XMM, src2: XMMOrMemory, mask: XMM, dst: XMM) {
match src2 {
XMMOrMemory::XMM(src2) => dynasm!(self ; vblendvps Rx(dst as u8), Rx(mask as u8), Rx(src2 as u8), Rx(src1 as u8)),
XMMOrMemory::Memory(base, disp) => dynasm!(self ; vblendvps Rx(dst as u8), Rx(mask as u8), [Rq(base as u8) + disp], Rx(src1 as u8)),
}
}
fn emit_ucomiss(&mut self, src: XMMOrMemory, dst: XMM) {
match src {
XMMOrMemory::XMM(x) => dynasm!(self ; ucomiss Rx(dst as u8), Rx(x as u8)),