[X64] MAX_V128/MIN_V128 Proper NaN handling.

According to console. FFC00000->FFC00000 instead of FFFFFC00 as it was previously.

Test case: 415607E8 - "Evil Queen's Castle" level
This commit is contained in:
Gliniak
2026-07-05 17:53:43 +02:00
committed by Radosław Gliński
parent 51322122a5
commit 7ff152a5a7
3 changed files with 54 additions and 6 deletions

View File

@@ -601,11 +601,18 @@ struct MAX_V128 : Sequence<MAX_V128, I<OPCODE_MAX, V128Op, V128Op, V128Op>> {
static void Emit(X64Emitter& e, const EmitArgType& i) {
e.ChangeMxcsrMode(MXCSRMode::Vmx);
// if 0 and -0, return 0! opposite of minfp
auto src1 = GetInputRegOrConstant(e, i.src1, e.xmm0);
auto src2 = GetInputRegOrConstant(e, i.src2, e.xmm1);
const Xmm src1 = GetInputRegOrConstant(e, i.src1, e.xmm0);
const Xmm src2 = GetInputRegOrConstant(e, i.src2, e.xmm1);
e.vmaxps(e.xmm2, src1, src2);
e.vmaxps(e.xmm3, src2, src1);
e.vorps(i.dest, e.xmm2, e.xmm3);
e.vandps(e.xmm2, e.xmm2, e.xmm3);
e.vcmpunordps(e.xmm3, src1, src1); // mask: vA is NaN
e.vblendvps(e.xmm3, src2, src1, e.xmm3);
e.vcmpunordps(i.dest, src1, src2); // mask: vA or vB is NaN
e.vblendvps(i.dest, e.xmm2, e.xmm3, i.dest);
}
};
EMITTER_OPCODE_TABLE(OPCODE_MAX, MAX_F32, MAX_F64, MAX_V128);
@@ -660,11 +667,18 @@ struct MIN_F64 : Sequence<MIN_F64, I<OPCODE_MIN, F64Op, F64Op, F64Op>> {
struct MIN_V128 : Sequence<MIN_V128, I<OPCODE_MIN, V128Op, V128Op, V128Op>> {
static void Emit(X64Emitter& e, const EmitArgType& i) {
e.ChangeMxcsrMode(MXCSRMode::Vmx);
auto src1 = GetInputRegOrConstant(e, i.src1, e.xmm0);
auto src2 = GetInputRegOrConstant(e, i.src2, e.xmm1);
const Xmm src1 = GetInputRegOrConstant(e, i.src1, e.xmm0);
const Xmm src2 = GetInputRegOrConstant(e, i.src2, e.xmm1);
e.vminps(e.xmm2, src1, src2);
e.vminps(e.xmm3, src2, src1);
e.vorps(i.dest, e.xmm2, e.xmm3);
e.vorps(e.xmm2, e.xmm2, e.xmm3);
e.vcmpunordps(e.xmm3, src1, src1); // mask: vA is NaN
e.vblendvps(e.xmm3, src2, src1, e.xmm3);
e.vcmpunordps(i.dest, src1, src2); // mask: vA or vB is NaN
e.vblendvps(i.dest, e.xmm2, e.xmm3, i.dest);
}
};
EMITTER_OPCODE_TABLE(OPCODE_MIN, MIN_I8, MIN_I16, MIN_I32, MIN_I64, MIN_F32,

View File

@@ -5848,3 +5848,20 @@ test_vmaxfp_650_GEN:
#_ REGISTER_OUT v2 [FFFFFF80, 0000007F, FFFEFF7F, 00010080]
#_ REGISTER_OUT v3 [FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF]
test_vmaxfp_651_GEN:
#_ REGISTER_IN v1 [FFC00000, FFC00000, FFC00000, 00000000]
#_ REGISTER_IN v2 [00000000, 00000000, 00000000, 00000000]
vmaxfp v3, v1, v2
blr
#_ REGISTER_OUT v1 [FFC00000, FFC00000, FFC00000, 00000000]
#_ REGISTER_OUT v2 [00000000, 00000000, 00000000, 00000000]
#_ REGISTER_OUT v3 [FFC00000, FFC00000, FFC00000, 00000000]
test_vmaxfp_652_GEN:
#_ REGISTER_IN v1 [7FC00000, 7FC00000, 7FC00000, 00000000]
#_ REGISTER_IN v2 [00000000, 00000000, 00000000, 00000000]
vmaxfp v3, v1, v2
blr
#_ REGISTER_OUT v1 [7FC00000, 7FC00000, 7FC00000, 00000000]
#_ REGISTER_OUT v2 [00000000, 00000000, 00000000, 00000000]
#_ REGISTER_OUT v3 [7FC00000, 7FC00000, 7FC00000, 00000000]

View File

@@ -5848,3 +5848,20 @@ test_vminfp_650_GEN:
#_ REGISTER_OUT v2 [FFFFFF80, 0000007F, FFFEFF7F, 00010080]
#_ REGISTER_OUT v3 [FFFFFFFF, FFFFFFFF, FFFFFFFF, FFFFFFFF]
test_vminfp_651_GEN:
#_ REGISTER_IN v1 [FFC00000, FFC00000, FFC00000, 00000000]
#_ REGISTER_IN v2 [477FFC00, 477FFC00, 477FFC00, 477FFC00]
vminfp v3, v1, v2
blr
#_ REGISTER_OUT v1 [FFC00000, FFC00000, FFC00000, 00000000]
#_ REGISTER_OUT v2 [477FFC00, 477FFC00, 477FFC00, 477FFC00]
#_ REGISTER_OUT v3 [FFC00000, FFC00000, FFC00000, 00000000]
test_vminfp_652_GEN:
#_ REGISTER_IN v1 [7FC00000, 7FC00000, 7FC00000, 00000000]
#_ REGISTER_IN v2 [477FFC00, 477FFC00, 477FFC00, 477FFC00]
vminfp v3, v1, v2
blr
#_ REGISTER_OUT v1 [7FC00000, 7FC00000, 7FC00000, 00000000]
#_ REGISTER_OUT v2 [477FFC00, 477FFC00, 477FFC00, 477FFC00]
#_ REGISTER_OUT v3 [7FC00000, 7FC00000, 7FC00000, 00000000]