[CPU/X64] Preserve NaN bit during float->double, double->float conversion
Probably this should be moved to ppc_emit_memory level instead of being x86-64 specific Was AI used in this change: Yes
This commit is contained in:
committed by
Radosław Gliński
parent
9781a75a22
commit
9588ce244d
@@ -1113,6 +1113,8 @@ static const vec128_t xmm_consts[] = {
|
||||
/* XMMInt127 */ vec128i(0x7Fu),
|
||||
/* XMM2To32 */ vec128f(0x1.0p32f),
|
||||
/* XMMFloatInf */ vec128i(0x7f800000),
|
||||
/* XMMDoubleInf */
|
||||
vec128i(0x00000000u, 0x7FF00000u, 0x00000000u, 0x7FF00000u),
|
||||
|
||||
/* XMMIntsToBytes*/
|
||||
v128_setr_bytes(0, 4, 8, 12, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
|
||||
|
||||
@@ -151,6 +151,7 @@ enum XmmConst {
|
||||
XMMInt127,
|
||||
XMM2To32,
|
||||
XMMFloatInf,
|
||||
XMMDoubleInf,
|
||||
XMMIntsToBytes,
|
||||
XMMShortsToBytes,
|
||||
XMMLVSLTableBase,
|
||||
|
||||
@@ -386,7 +386,25 @@ struct CONVERT_F32_F64
|
||||
static void Emit(X64Emitter& e, const EmitArgType& i) {
|
||||
e.ChangeMxcsrMode(MXCSRMode::Fpu);
|
||||
// TODO(benvanik): saturation check? cvtt* (trunc?)
|
||||
e.vcvtsd2ss(i.dest, GetInputRegOrConstant(e, i.src1, e.xmm0));
|
||||
|
||||
Xbyak::Xmm src = GetInputRegOrConstant(e, i.src1, e.xmm0);
|
||||
e.vmovq(e.rax, src);
|
||||
e.vcvtsd2ss(i.dest, src);
|
||||
Xbyak::Label done;
|
||||
e.mov(e.rcx, e.rax);
|
||||
e.btr(e.rcx, 63);
|
||||
e.mov(e.rdx, e.GetXmmConstPtr(XMMDoubleInf));
|
||||
e.cmp(e.rcx, e.rdx);
|
||||
e.jbe(done); // finite or +/-inf
|
||||
|
||||
// NaN: float quiet bit (22) -> double quiet bit (51)
|
||||
e.vmovd(e.ecx, i.dest);
|
||||
e.and_(e.ecx, ~(1u << 22));
|
||||
e.shr(e.rax, 51 - 22);
|
||||
e.and_(e.eax, 1u << 22);
|
||||
e.or_(e.ecx, e.eax);
|
||||
e.vmovd(i.dest, e.ecx);
|
||||
e.L(done);
|
||||
}
|
||||
};
|
||||
struct CONVERT_F64_I64
|
||||
@@ -407,7 +425,26 @@ struct CONVERT_F64_F32
|
||||
: Sequence<CONVERT_F64_F32, I<OPCODE_CONVERT, F64Op, F32Op>> {
|
||||
static void Emit(X64Emitter& e, const EmitArgType& i) {
|
||||
e.ChangeMxcsrMode(MXCSRMode::Fpu);
|
||||
e.vcvtss2sd(i.dest, GetInputRegOrConstant(e, i.src1, e.xmm0));
|
||||
Xbyak::Xmm src = GetInputRegOrConstant(e, i.src1, e.xmm0);
|
||||
|
||||
e.vmovd(e.eax, src);
|
||||
e.vcvtss2sd(i.dest, src);
|
||||
|
||||
Xbyak::Label done;
|
||||
e.mov(e.ecx, e.eax);
|
||||
e.and_(e.ecx, e.GetXmmConstPtr(XMMAbsMaskPS));
|
||||
e.cmp(e.ecx, e.GetXmmConstPtr(XMMFloatInf));
|
||||
e.jbe(done);
|
||||
|
||||
// NaN: double quiet bit (51) -> float quiet bit (22)
|
||||
e.vmovq(e.rcx, i.dest);
|
||||
e.btr(e.rcx, 51); // clear the bit the convert forced to 1
|
||||
e.shr(e.eax, 22);
|
||||
e.and_(e.eax, 1);
|
||||
e.shl(e.rax, 51);
|
||||
e.or_(e.rcx, e.rax);
|
||||
e.vmovq(i.dest, e.rcx);
|
||||
e.L(done);
|
||||
}
|
||||
};
|
||||
EMITTER_OPCODE_TABLE(OPCODE_CONVERT, CONVERT_I32_F32, CONVERT_I32_F64,
|
||||
|
||||
Reference in New Issue
Block a user