[rocjitsu] Round FMA mix BF16 results to nearest even - #10913
[rocjitsu] Round FMA mix BF16 results to nearest even#10913sjain-stanford wants to merge 1 commit into
Conversation
Use the ISA-required round-to-nearest-even conversion instead of truncation for CDNA5 BF16-result FMA mix instructions. Cover both result halves and ordinary and DPP execution paths with regressions. Signed-off-by: Sambhav Jain <sambhav@alumni.stanford.edu>
✅ All Checks Passed — Ready for Review
📖 Need help? See the Policy FAQ for details on every check and how to fix failures. |
|
🎉 All checks passed! This PR is ready for review. |
There was a problem hiding this comment.
Pull request overview
This PR fixes incorrect BF16 result packing for CDNA5 v_fma_mixlo_bf16 / v_fma_mixhi_bf16 execution by switching the final FP32→BF16 narrowing step from truncation to round-to-nearest-even (RNE), aligning rocJITsu’s behavior with expected hardware semantics and preventing 1-ULP-low BF16 results in common mixed BF16/FP32 compiler output patterns.
Changes:
- Update the packed-instruction generator to use
util::f32_to_bf16_rne(result)when emitting BF16-resultFMA_MIXvariants. - Regenerate CDNA5 VOP3P execution code to apply RNE for both
mixloandmixhi, including modifier/DPP paths. - Add/strengthen regression coverage in both the generator tests and CDNA5 execution tests for tie-to-even and boundary cases.
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| emulation/rocjitsu/tests/cdna5_execution_test.cpp | Adds a targeted CDNA5 execution regression test covering RNE behavior for mixlo/mixhi across ordinary and identity-DPP encodings, including halfway/tie cases and overflow-to-inf. |
| emulation/rocjitsu/lib/rocjitsu/src/rocjitsu/isa/arch/amdgpu/generated/cdna5/vop3p_exec.cpp | Applies util::f32_to_bf16_rne for BF16-result packing in VFmaMixloBf16Vop3p and VFmaMixhiBf16Vop3p (normal + modifier/DPP paths). |
| emulation/rocjitsu/lib/python/amdisa/tests/test_packed_codegen.py | Updates generator regression expectations to require the RNE helper for both mixlo and mixhi BF16-result variants and reject truncation. |
| emulation/rocjitsu/lib/python/amdisa/codegen/execute/packed.py | Changes gen_mad_mix_bf16() BF16-result emission to use util::f32_to_bf16_rne(result) instead of util::f32_to_bf16(result). |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Provenance and context
Closes #10806.
The issue was reported by @Yu-Zhewen against rocJITsu
08ae38600aa96bc29fde7701ef2d17240d4f1945with HIP7.16.26315and thegfx1250_mi455x.jsonconfiguration. The posted 256-element harness showed thatv_fma_mixlo_bf16disagreed with round-to-nearest-even for 132 inputs and matched plain FP32-to-BF16 truncation for all 256 inputs. The FP32-result form,v_fma_mix_f32_bf16, remained correct. A follow-up established thatv_fma_mixhi_bf16was affected identically while the FP16-result form was not.I independently reproduced the result on rocJITsu
97ab4d1f880b1814f736de11453b525bed21a250with ROCm7.16.26332, then confirmed that the relevant implementation was unchanged at the currentorigin/developbase,d562788ea0a24ae91847df3073579dffc36ccd11. This affects ordinary compiler output: mixed BF16/FP32 expressions such as the multiply chain in BF16 RMSNorm can lower tov_fma_mix_f32_bf16followed byv_fma_mixlo_bf16, causing roughly half of stored BF16 results to be low by one BF16 ULP.Root cause
The fused arithmetic and input conversion are correct.
gen_mad_mix_bf16()in the authoritative packed-instruction generator computes the FP32 result withstd::fma(a, b, c), but the BF16-result branch narrows it withutil::f32_to_bf16(result).f32_to_bf16()is a deliberately truncating bit pack: it returns the upper 16 bits of the FP32 representation. Generation propagated that call into all four affected CDNA5 execution paths: ordinary and DPP forms of bothv_fma_mixlo_bf16andv_fma_mixhi_bf16. The existingutil::f32_to_bf16_rne()helper provides the required round-to-nearest-even conversion, including retained-LSB tie handling and NaN preservation.The fix is intentionally made at this result-pack site instead of changing
f32_to_bf16()globally, because other callers may rely on truncation. It also intentionally usesf32_to_bf16_rne()rather than the MODE-aware helper: packed BF16 arithmetic is not MODE-aware in rocJITsu, consistent with the existing packed BF16 overflow behavior.Implemented fix
The BF16-result branch of
gen_mad_mix_bf16()now emitsutil::f32_to_bf16_rne(result), and the checked-in CDNA5 VOP3P execution source was regenerated. This corrects both destination halves and both ordinary and DPP execution paths without changing the FP32-result path or unrelated BF16 conversions.The generator regression test now requires the RNE helper for both
mixloandmixhiand explicitly rejects the truncating helper. A CDNA5 execution regression exercises both opcodes through ordinary and identity-DPP encodings, verifies preservation of the untouched destination half, and covers:Validation
The original HIP reproducer was rebuilt with the same ROCm 7.16 toolchain and run unchanged through the fixed rocJITsu interpreter:
Before the fix, the same run produced
132 of 256 wrongand256 of 256 equal plain truncation. The post-fix result matches the expected FFM behavior, while the FP32-result control remains unchanged.Additional local validation:
emulation/rocjitsu/scripts/generate-amdisa.sh;rocjitsu_tests,rocjitsu_bin, androcjitsu_shared;test_packed_codegen.pypassed;git diff --checkpassed.A broader local sweep ran 114 tests and passed 113. The sole failure was
Gfx1250ExecutionTest.FusedOperationsHonorF16F64ModeControlsin the existing FP64 rounding-mode path; this change is confined to BF16 result packing, and all directly affected and neighboring FMA-mix tests pass.Co-authored-by: GPT-5.6 Sol codex@openai.com
🤖 Generated with Codex