JIT - vctsxs: Properly saturate signed integers

This commit is contained in:
Dr. Chat
2017-03-05 17:43:56 -06:00
parent ea89a5d179
commit d5e7bc8dca
5 changed files with 102 additions and 36 deletions

View File

@@ -670,9 +670,9 @@ static const vec128_t xmm_consts[] = {
0x80000000u),
/* XMMShortMinPS */ vec128f(SHRT_MIN),
/* XMMShortMaxPS */ vec128f(SHRT_MAX),
/* XMMIntMaxPS */ vec128f(float(INT_MAX)),
/* XMMIntMin */ vec128i(INT_MIN),
/* XMMIntMax */ vec128i(INT_MAX),
/* XMMIntMaxPD */ vec128d(INT_MAX),
/* XMMInt64MaxPD */ vec128d(double(INT64_MAX)),
};
// First location to try and place constants.

View File

@@ -89,9 +89,9 @@ enum XmmConst {
XMMSignMaskF32,
XMMShortMinPS,
XMMShortMaxPS,
XMMIntMaxPS,
XMMIntMin,
XMMIntMax,
XMMIntMaxPD,
XMMInt64MaxPD,
};
// Unfortunately due to the design of xbyak we have to pass this to the ctor.

View File

@@ -1429,8 +1429,11 @@ struct CONVERT_I32_F32
: Sequence<CONVERT_I32_F32, I<OPCODE_CONVERT, I32Op, F32Op>> {
static void Emit(X64Emitter& e, const EmitArgType& i) {
// TODO(benvanik): saturation check? cvtt* (trunc?)
e.vminss(e.xmm0, i.src1, e.GetXmmConstPtr(XMMIntMaxPS));
e.vcvtss2si(i.dest, e.xmm0);
if (i.instr->flags == ROUND_TO_ZERO) {
e.vcvttss2si(i.dest, e.xmm0);
} else {
e.vcvtss2si(i.dest, e.xmm0);
}
}
};
struct CONVERT_I32_F64
@@ -1440,14 +1443,22 @@ struct CONVERT_I32_F64
// PPC saturates the value instead.
// So, we can clamp the double value to (double)0x7FFFFFFF.
e.vminsd(e.xmm0, i.src1, e.GetXmmConstPtr(XMMIntMaxPD));
e.vcvttsd2si(i.dest, e.xmm0);
if (i.instr->flags == ROUND_TO_ZERO) {
e.vcvttsd2si(i.dest, e.xmm0);
} else {
e.vcvtsd2si(i.dest, e.xmm0);
}
}
};
struct CONVERT_I64_F64
: Sequence<CONVERT_I64_F64, I<OPCODE_CONVERT, I64Op, F64Op>> {
static void Emit(X64Emitter& e, const EmitArgType& i) {
e.vminsd(e.xmm0, i.src1, e.GetXmmConstPtr(XMMInt64MaxPD));
e.vcvttsd2si(i.dest, e.xmm0);
// TODO(benvanik): saturation check? cvtt* (trunc?)
if (i.instr->flags == ROUND_TO_ZERO) {
e.vcvttsd2si(i.dest, e.xmm0);
} else {
e.vcvtsd2si(i.dest, e.xmm0);
}
}
};
struct CONVERT_F32_I32
@@ -1568,13 +1579,28 @@ struct VECTOR_CONVERT_F2I
: Sequence<VECTOR_CONVERT_F2I,
I<OPCODE_VECTOR_CONVERT_F2I, V128Op, V128Op>> {
static void Emit(X64Emitter& e, const EmitArgType& i) {
// flags = ARITHMETIC_UNSIGNED | ARITHMETIC_UNSIGNED
// TODO(benvanik): are these really the same? VC++ thinks so.
e.vcvttps2dq(i.dest, i.src1);
if (i.instr->flags & ARITHMETIC_SATURATE) {
// TODO(benvanik): check saturation.
// In theory cvt throws if it saturates.
Xmm src1 = i.src1;
// Copy src1 if necessary.
bool copy_src1 = !!(i.instr->flags & ARITHMETIC_SATURATE);
if (copy_src1 && i.dest == i.src1) {
e.vmovdqa(e.xmm1, i.src1);
src1 = e.xmm1;
}
e.vcvttps2dq(i.dest, i.src1);
if (i.instr->flags & ARITHMETIC_SATURATE &&
!(i.instr->flags & ARITHMETIC_UNSIGNED)) {
// if dest is indeterminate and i.src1 >= 0 (i.e. !(i.src1 & 0x80000000))
// i.dest = 0x7FFFFFFF
e.vpcmpeqd(e.xmm0, i.dest, e.GetXmmConstPtr(XMMIntMin));
e.vpandn(e.xmm0, src1, e.xmm0);
// (high bit of xmm0 = is ind. && i.src1 >= 0)
e.vblendvps(i.dest, i.dest, e.GetXmmConstPtr(XMMIntMax), e.xmm0);
}
// TODO(DrChat): Unsigned saturation!
}
};
EMITTER_OPCODE_TABLE(OPCODE_VECTOR_CONVERT_F2I, VECTOR_CONVERT_F2I);