[x64] Fix AVX-512 VECTOR_DENORMFLUSH merge-masking & FpRangeSign values

Copy src1 into dest before the masked vrangeps so that unmasked lanes
(normal/inf/NaN values) are preserved via merge-masking. Previously,
when the register allocator assigned different physical registers for
dest and src1, unmasked lanes would retain stale values from dest.

Tested with Intel SDE and AVX-512 cpu to verify.

Also shift unused FpRangeSign constants into bits [3:2] of the vrangeps
immediate, matching the Intel encoding. Only one used in the code was 0
so it was already correct by accident but using the others in the future
would produce incorrect results.
This commit is contained in:
Herman S.
2026-03-21 14:15:58 +09:00
parent 9621400ef6
commit bc37068f90
3 changed files with 47 additions and 5 deletions

View File

@@ -43,3 +43,44 @@ TEST_CASE("VECTOR_DENORMFLUSH_F32", "[instr]") {
REQUIRE(result == vec128f(-FLT_MIN));
});
}
// Test VECTOR_DENORMFLUSH with register pressure: input is kept
// alive past the denormflush, forcing dest and src into different
// physical registers. Verifies correct passthrough of normal values
// and preservation of the original input.
TEST_CASE("VECTOR_DENORMFLUSH_F32_REGPRESSURE", "[instr]") {
TestFunction test([](HIRBuilder& b) {
auto input = LoadVR(b, 4);
StoreVR(b, 3, b.VectorDenormFlush(input));
StoreVR(b, 5, input); // keep input alive past denormflush
b.Return();
});
// Mix of denormal and normal elements:
// [0] 0x007FFFFF = positive denormal -> should flush to +0.0
// [1] 0x3F800000 = 1.0f (normal) -> should pass through
// [2] 0x807FFFFF = negative denormal -> should flush to -0.0
// [3] 0x40000000 = 2.0f (normal) -> should pass through
test.Run(
[](PPCContext* ctx) {
ctx->v[4] = vec128i(0x007FFFFF, 0x3F800000, 0x807FFFFF, 0x40000000);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result ==
vec128i(0x00000000, 0x3F800000, 0x80000000, 0x40000000));
// Original input must also be preserved
REQUIRE(ctx->v[5] ==
vec128i(0x007FFFFF, 0x3F800000, 0x807FFFFF, 0x40000000));
});
// All normal values - with the bug, ALL lanes would be corrupted
// since k1 would be all-zero and merge-masking preserves dest, not src1
test.Run(
[](PPCContext* ctx) {
ctx->v[4] = vec128i(0x3F800000, 0x40000000, 0x40400000, 0x40800000);
},
[](PPCContext* ctx) {
auto result = ctx->v[3];
REQUIRE(result ==
vec128i(0x3F800000, 0x40000000, 0x40400000, 0x40800000));
});
}