Repository navigation
test(shader): cover half expansion bit patterns - #1505
Conversation
klosixgaming-arch
left a comment
There was a problem hiding this comment.
Excellent focused regression test for the half expansion bit pattern preservation. The 20 fixed vectors cover all the important edge cases (signed zeros, subnormals, normal boundary, infinities, quiet NaNs with various payloads). Running across multiple wave sizes and compute targets is thorough.
The documentation of the native GPU probe results in the PR description is very helpful for understanding the real-world impact of this fix. Ready to merge once #1463 is merged.
klosixgaming-arch
left a comment
There was a problem hiding this comment.
Good addition to the test suite. This comprehensive Vulkan execution test for half expansion operations verifies correct handling of various edge cases including denormals, infinities, and NaNs.
Strengths:
- Comprehensive test coverage with 20 different input vectors covering various edge cases
- Tests both wave sizes (32 and 64) and different compute targets
- Clear error messages that identify the specific failure condition (wave size, lane, input value, expected vs actual)
- Good use of existing Vulkan test infrastructure
Technical notes:
- The approach of testing multiple wave sizes ensures compatibility across different GPU architectures
- Proper handling of both low and high half expansion as well as BYTE_0/BYTE_1 ldexp operations
- Test properly verifies all four output components for each input vector
This will improve confidence in the shader recompiler's half-precision floating point handling. Ready to merge.
|
Checked: builds and passes on lavapipe; the 20 vectors match The test also passes without #1463 on lavapipe, so we can't see it fail here; its value is on NVIDIA and AMD Windows drivers, which we can't run. @oneandonlydean could you run |
|
Windows run on two more GPUs: Windows 11, WinLibs GCC 15.2.0 r7, Release, merged onto
AI-assisted (Claude Code); I ran this on my machine. |
|
Checked on lavapipe with #1463 on main: |
What
Depends on #1463. Add a focused execution regression for the payload-preserving half expansion contract introduced there. This PR contains only
HalfExpansion.cpp; it does not duplicate the production fix.The test sends runtime buffer values through the public
Recompileinterface and the normal Vulkan driver, then compares four raw result words per lane:v_cvt_f32_f16on the low half and on a shifted high half.v_ldexp_f16with SDWABYTE_0andBYTE_1, exponent zero. The result must remain the selected half subnormal even when the unselected bits encode a NaN.Twenty fixed vectors cover both signed zeros, subnormals, the normal boundary, finite values, infinities, quiet NaN sign/payload, and the
0xfff0fff0source reported in #1463. Three runs request guest wave32, guest wave64 with the default target, and guest wave64 withComputeTarget(32): 640 exact result comparisons. Quiet NaNs are checked by bits; the checked-in test does not assert signaling-NaN instruction behavior.The existing CMake execution-test glob registers this automatically. No production code, dependencies, coverage counters, or investigation files are added.
Tested
3069680b709d783355e381f582a3ce5320099075(currentmainwhen refreshed).EmitF16BitsToF32from fix(shader): convert f16 bits to f32 without UnpackHalf2x16 #1463 head58f596ee894d5d0d326a379032950ff4170c6964applied locally: 7/7 focused CTest tests passed, 0 skipped. They cover the new fixture, Float16Misc, Float16Modifiers, Float16Rounding, Float16ResultModifiers, SdwaFloatSelectors and SdwaLdexpF16.ANYPS5_REQUIRE_VULKAN=1and shader caching disabled. The new fixture also passed before the dependency on the earlier6e037e98base: lavapipe does not reproduce the native NVIDIA NaN failure.llvm-mcindependently assembled the embedded shader for bothgfx1013andgfx1030; both exactly match all 14 fixture dwords, SHA-256184d3b5e2cb9b9a534b47dd4107e2bb28d0bc2e77fc3283acd854c5e2a52bf07.spirv-val --target-env vulkan1.1.Focused suite reproduction after applying #1463 to this branch:
The native GPU probe below exercises the actual shared SPIR-V emitter with runtime SSBO inputs, independently of the guest-shader integration fixture. It checks all 65,536 raw half patterns plus 20 packed inputs, with four selections each: 262,224 comparisons per device. Its signaling-NaN cases check the helper's raw-bit contract only; they do not establish guest floating-point mode behavior.
The NVIDIA baseline includes 1,034 quiet-NaN mismatches, 1,022 signaling-NaN raw-contract mismatches, and zero finite/infinity mismatches. The retained integration test uses quiet NaNs only. The baseline module was exported at
6e037e98; the widening helper is unchanged in the refreshed3069680bmain base. The corrected module was freshly exported from the refreshed base with the #1463 helper.Two representative native probe captures, showing the low/high FP32 words:
7e01fe017fffffff 7fffffffffc02000 7fc02000fff0fff07fffffff 7ffffffffffe0000 fffe00007e01fe01ffc02000 7fc02000ffc02000 7fc02000fff0fff0fffe0000 fffe0000fffe0000 fffe0000Capture metadata
{ "captured": "2026-10-08", "native_rdna2_or_ps5_execution": false, "baseline_spirv_sha256": "cd065e5c5d762135dbf7a6a896d94273492cdf95d0308ecfee01c2ceb6a9523d", "corrected_spirv_sha256": "58fcc7085782a3643ff25d298c10b7b490bdd7e7e1b37426c447be8b4bf42418", "guest_shader_fixture_sha256": "7cf2b22a7c60abd2a70268a19fbc376ba4eba6245563d917a69f387ed61030af", "devices": [ { "device": "NVIDIA GeForce RTX 4070 Laptop GPU", "vendor_id": 4318, "device_id": 10272, "driver_version": 2585198592, "inputs": 65556, "comparisons": 262224, "mismatch_count": 0 }, { "device": "AMD Radeon 780M Graphics", "vendor_id": 4098, "device_id": 6400, "driver_version": 8389003, "inputs": 65556, "comparisons": 262224, "mismatch_count": 0 } ] }One-off native probe sources and reproduction
These sources are supporting investigation artifacts, included here rather than tracked in the repository. Save the three files below in
build-contribution/shader-gap-research/under the checkout under test. Configure a Linux GCC/Ninja build atbuild-contribution/half-expansion-main-buildand buildagc_driver_half_expansion_testsfirst. Runpython3 build-contribution/shader-gap-research/build_half_evidence.pyin that Linux environment to export the real emitter's SPIR-V. The exporter uses the same CMake compiler definitions, include paths and shader archive.For the Windows GPU execution used here, install the Python binding beside the scripts:
Repeat the build/export with #1463 applied, then run with
--label after(asserts no mismatches) and--label negative --negative-control(asserts exactly the injected mismatch). Use--device 1for the second adapter.--label beforerecords mismatches without failing so a driver that already preserves the bits can also supply a baseline. JSON results include the actual adapter identity, driver number, SPIR-V hash, category counts and all 20 packed rows.The raw expansion matrix includes signaling encodings without treating this as an instruction-level signaling-NaN or MODE oracle. The integration fixture's SDWA cases additionally execute the half-precision ldexp/round-trip path; this standalone probe directly checks widening of the selected bytes.
export_half_evidence.cppbuild_half_evidence.pyrun_half_evidence.pyThe expectation for finite expansion was calculated independently with Python's IEEE half unpack / float pack. Quiet NaN goldens preserve the source sign and shift the payload into the FP32 mantissa, matching #1463's contract. A useful external reference is the published native gfx1035 interpolation result, where half
fe01survives the reported interpolation asfe01. That is supporting arithmetic evidence, not a direct native execution of this new conversion fixture. The AMD SDWA failure described in #1463 motivates the packed-byte cases.Limits: the local GPUs are an NVIDIA RTX 4070 Laptop GPU and an AMD Radeon 780M (RDNA3). No new RDNA2 or PS5 execution was performed. This PR adds zero instruction coverage percentage and does not settle PS5 SPI interpolation or per-shader MODE semantics. It remains draft pending #1463.
Checklist
main; the existing implementation is fix(shader): convert f16 bits to f32 without UnpackHalf2x16 #1463, and this PR adds a separate regression test