Floats as written, never fused; fma and muladd; f32/f64 bits, f16 and bf16

- a * b + c is two roundings on every processor and --cpu: the IR has no fast-math flags, and clang
  compiles it with -ffp-contract=on (checked in the assembly: never fused, also with FMA hardware)
- fma(a, b, c) / v.fma(b, c): one rounding, always (llvm.fma)
- muladd(a, b, c) / v.muladd(b, c): the fastest way here (llvm.fmuladd), what v.fma was before
- f32_bits / f32_from_bits / f64_bits / f64_from_bits: bitcasts, also of vectors
- f16_to_f32 / f32_to_f16 (LLVM half), bf16_to_f32 / f32_to_bf16 (integer ops, ties to even, NaN kept)
- docs (en, pl): what is guaranteed about floats, the new built-ins

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Psc42moPLwP43Cmb9oZqSR
This commit is contained in:
Claude 2026-11-01 15:25:40 +00:00
commit 0ceaaa27c4
No known key found for this signature in database
13 changed files with 373 additions and 22 deletions

View file

@ -13,12 +13,12 @@ fn dot_plain([]f32 a, []f32 b) -> f32 {
return total
}
// eight at a time: f32x8(list, i) takes list[i] ... list[i+7], fma multiplies and adds in one step
// eight at a time: f32x8(list, i) takes list[i] ... list[i+7]; muladd multiplies and adds, in one step where it can
fn dot_simd([]f32 a, []f32 b) -> f32 {
acc := f32x8(0.0)
i := 0
while i + 8 <= a.len {
acc = f32x8(a, i).fma(f32x8(b, i), acc)
acc = f32x8(a, i).muladd(f32x8(b, i), acc)
i += 8
}
total := acc.sum()