25.5BF16 II: The Five Instructions

Part III Linux boot: optional Vol. I (Unprivileged) pp. 139–144 · ~2 min read

Five instructions total — two scalar converts, two vector converts, one widening FMA. The encoding trick: the 2-bit fmt field is full (S/D/H/Q), so BF16 identifies itself through new rs2/vs1 sub-field codes inside the existing convert encodings.

The BF16 instruction set
EncodingSemantics & flags
fcvt.bf16.s rd, rs1 (Zfbfmin)OP-FP, funct5 01000 (FCVT), fmt=H, rs2-field = 01000Narrowing FP32 → BF16, rounds per rm. Flags: Overflow, Underflow, Inexact, Invalid.
fcvt.s.bf16 rd, rs1 (Zfbfmin)OP-FP, fmt=S, rs2-field = 00110Widening BF16 → FP32 — EXACT: shift left 16, zero-fill, NaN-box. Only Invalid (sNaN input).
vfncvtbf16.f.f.w vd, vs2, vm (Zvfbfmin)OP-V VFUNARY0 (funct6 010010), vs1-code 11101, OPFVVVector FP32 → BF16 per frm; SEW must be 16 (else reserved). EEW: vs2=32 in, vd=16 out.
vfwcvtbf16.f.f.v vd, vs2, vm (Zvfbfmin)VFUNARY0, vs1-code 01101Vector BF16 → FP32, exact.
vfwmaccbf16.vv / .vf (Zvfbfwma)OP-V funct6 111011, OPFVV / OPFVFBF16 × BF16 with the UNROUNDED product added to the FP32 accumulator in vd; single rounding per frm. .vf reads the scalar BF16 from an f-register (NaN-box checked). All four flags possible.
Dotted-underlined cells have explanations — click one.

The FMA’s fused-ness comes cheap: an 8×8-bit significand product needs at most 16 bits, which FP32’s 24-bit significand holds exactly — so the instruction is precisely equivalent to the documented expansion (vfwcvtbf16 both operands, then vfmacc; or fcvt.s.bf16 + vfwcvtbf16 + vfmacc.vf for the scalar form). No extra internal precision required.

Hardware Designer Notes

If you build one BF16 thing, build vfwmaccbf16: it is the inner loop of every transformer inference kernel, and its datapath is your existing FP32 FMA with an 8×8 front end. The converts alone (Zfbfmin/Zvfbfmin) are days of work; budget the FMA verification against your FP32 suite with truncated stimulus.

Minimal Linux-boot hart MUST

  • Decode the new rs2/vs1 sub-field codes exactly; neighboring convert encodings remain their old selves and SEW≠16 vector forms are reserved
  • For vfwmaccbf16: feed the 16-bit exact product into the existing FP32 FMA datapath — no rounding between multiply and add
  • NaN-box-check the .vf scalar operand like any other vector-scalar FP read

MAY simplify / trap-and-emulate

  • Share the FP32→BF16 narrower with your FP32 rounder (it is a 16-bit-shorter tail of the same logic)
  • Implement Zvfbfwma as double-pumped BF16 lanes over the FP32 accumulators — the area math that makes BF16 worthwhile

Check yourself — BF16 instructions

1.Why can FCVT.S.BF16 never be inexact, while FCVT.BF16.S can raise Overflow/Underflow/Inexact?

2.What makes vfwmaccbf16 'fused', and what's it equivalent to?

3.How do the BF16 converts squeeze into the OP-FP encoding without a new fmt code?

3 questions