Implement Zfbfmin BF16 converts - #1879
Open
davidharrishmc wants to merge 3 commits into
Open
davidharrishmc wants to merge 3 commits into
davidharrishmc wants to merge 3 commits into
Conversation
davidharrishmc
force-pushed
the
dh/zfbfmin
branch
from
September 16, 2026 14:07
83a0cb7 to
ea09a5b
Compare
davidharrishmc
marked this pull request as draft
September 16, 2026 16:57
Contributor
Author
|
Still in review. Do not yet merge. |
davidharrishmc
force-pushed
the
dh/zfbfmin
branch
2 times, most recently
from
September 17, 2026 05:20
c07fe5a to
9cc241f
Compare
Add fcvt.bf16.s and fcvt.s.bf16. BF16 shares single's exponent field and bias and differs only in fraction width, so both run down the existing single precision convert path: a BF16 source is widened before the unpacker, and a Bf16Dst flag swaps the fraction width where the rounder and the result packing need it. The exponent datapath and the flag logic are untouched, and a BF16 result is the top half of the single precision one, so packing it is a rebox rather than a format of its own. Undo the leading zero shift when converting a subnormal source to a subnormal result. Only a same precision convert reaches that combination, since narrowing flushes such a source to zero and widening normalizes it, so this was unreachable until BF16 gave single an equal exponent range. Enabled on rv32gc and rv64gc, including their imperas.ic. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
davidharrishmc
force-pushed
the
dh/zfbfmin
branch
from
September 17, 2026 05:28
9cc241f to
c571ebb
Compare
davidharrishmc
marked this pull request as ready for review
September 17, 2026 05:34
Contributor
Author
|
Ready for review. |
Per review, fold the BF16 cases into ResNegNF, NormSticky, FpGuard, FpLsbRes, FpRound and RoundAdd rather than overriding them at the point of use, so CvtResUf, Sticky, Guard/LsbRes/Round and the final rounding add read one signal each and a second consumer of any of them would get BF16 without a new override. The sticky bit is the one value a BF16 result cannot take from a format arm, since the sticky ranges are nested and a fifth fraction width moves every boundary. Parameterize the specialcase widths in terms of S_LEN and BF16_NF, and drop the ZFBFMIN_SUPPORTED generates: Bf16Dst is already gated on the parameter, so the muxes optimize away on their own. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
Author
|
Simplifications added thanks to @kparry4 |
Zfbfmin's loads, stores and moves are Zfh's flh, fsh, fmv.x.h and fmv.h.x, so a config with Zfbfmin but no Zfh cannot get a BF16 value into a register. Assert Zfh rather than F, and turn Zfbfmin off in the derivatives that turn Zfh off, which otherwise inherited it from rv64gc and rv32gc. Decode Bf16SrcD and Bf16DstD with the rest of the instruction instead of re-deriving the opcode, funct7 and rs2 separately, so they respect the STATUS_FS and supported format and rounding mode checks that gate the rest of the control word. fcvt.s.bf16 shares fcvt.s.(d/q/h)'s control word, so it folds into that branch. Drop Bf16SrcM, which nothing read, and widen the BF16 source in one assign rather than a generate block. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the two Zfbfmin scalar instructions,
fcvt.bf16.sandfcvt.s.bf16, and enables the extension onrv32gcandrv64gc.Approach
BF16 shares single precision's sign bit, 8-bit exponent field and bias, differing only in fraction width (7 vs 23). Both converts therefore run down the existing single precision convert path —
fcvtfeeding the postprocessor — rather than becoming a format of their own:{bf16, 16'b0}is bit-identical to the single value), sounpackinputis untouched.Bf16Dstflag swaps the fraction width where the rounder needs it.specialcasepacks it with a rebox rather than seven per-field overrides.Fmt/OutFmtstay at single throughout, which is what keeps this cheap: the exponent datapath,flags.svand the overflow/underflow thresholds are all correct with no changes at all.Cost
118 insertions, 32 deletions across 20 files. What is added:
round.sv(24+/5−) — guard/round/LSB, sticky andRoundAdd, each folded into the signal where it is defined, so the hand-unrolled per-format logic is untouched and every consumer reads one signal. Load-bearing: without rounding at 7 bits the rebox would be a truncation.specialcase.sv(27+/11−) — the single precision result reboxed to BF16 on the way out, plus the underflow result, whose single precision LSB the rebox would otherwise drop.cvtshiftcalc.sv(6+/1−) — the underflow threshold, -7 for BF16 against -23 for single.unpack.sv(11+/1−) — one mux widening a BF16 source.fcvt.sv(10+/3−) — one extra input to an adder that already sums three terms.No new wide muxes on the result path and no added logic depth:
Guardis format-mux to BF16-mux to CvtToInt-mux either way, andRoundAddis mux-then-adder either way. This is a gate-level argument, not a synthesis result.Each BF16 case sits with the signal it belongs to rather than at the point of use:
ResNegNF,NormSticky,FpGuard,FpLsbRes,FpRoundandRoundAddeach feed aDst-prefixed signal that accounts for BF16, soCvtResUf,Sticky,Guard/LsbRes/Roundand the final rounding add are unchanged from master and a future second consumer of any of those signals gets BF16 for free. The sticky bit is the one value that cannot come from a format arm: those ranges are nested, so a fifth fraction width moves every boundary in eachFPSIZES/XLENPOSvariant.Subnormal convert fix
Routing these through
fcvtexposed a latent bug in shared logic, fixed here in the same commit.When a subnormal source produces a subnormal result,
LeadingZerosnormalizes the significand butShiftAmt = NF-1+Cenever undoes it, so the fraction lands mis-aligned. Concretely for single0x007fffff: the unpackedManhas hidden bit 0,LeadingZerosis 1,Ceis 0, and shifting by 51 leaves the zero hidden bit at the top ofMf, so the fraction reads back as0x3F8000instead of0x7F0000.That combination is only reachable for a same precision convert — narrowing flushes a subnormal source to zero (a subnormal double is ~2^-1022, far below single's 2^-149 minimum) and widening turns one into a normal — and
fctrlrejectsRs2D[1:0] != 2'b00. BF16 against single is the first case with equal exponent ranges, which is why this has lain dormant.The fix adds
LeadingZerosback intoShiftAmton the subnormal branch. No condition is needed:LeadingZerosis already zero for a normal source, since the leading zero count runs on the mantissa including the hidden bit.Encodings
From binutils' own test (
gas/testsuite/gas/riscv/zfbfmin.d), confirmed by assembling and disassembling:fcvt.bf16.sfcvt.s.bf16Testing
riscv-arch-test against Sail-generated signatures on the RTL. The wider runs are what cover the shared
ShiftAmtchange, exercising the existing F/D/Zfh/Zfa converts:Verilator lint clean on
rv64gc,rv32gcandrv32i— no errors, no new warnings.Requires the companion riscv-arch-test change enabling Zfbfmin on the cvw configs (riscv/riscv-arch-test#2379).
🤖 Generated with Claude Code