mirror of
https://github.com/Nexoniarz/Finch.git
synced 2026-11-03 00:44:27 +00:00
- 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
69 lines
1.7 KiB
Text
69 lines
1.7 KiB
Text
// Vectors (SIMD): eight f32 at once instead of one.
|
|
//
|
|
// finch run examples/simd.fch runs on any x86-64 or ARM64 processor
|
|
// finch run examples/simd.fch --cpu native uses all of this one's instructions (AVX2, AVX-512, NEON)
|
|
import time
|
|
|
|
// one number at a time
|
|
fn dot_plain([]f32 a, []f32 b) -> f32 {
|
|
f32 total = 0.0
|
|
for i in 0..a.len {
|
|
total += a[i] * b[i]
|
|
}
|
|
return total
|
|
}
|
|
|
|
// 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).muladd(f32x8(b, i), acc)
|
|
i += 8
|
|
}
|
|
total := acc.sum()
|
|
while i < a.len { // the few that are left
|
|
total += a[i] * b[i]
|
|
i += 1
|
|
}
|
|
return total
|
|
}
|
|
|
|
// brighten every color: the same work on every lane, with min keeping it below 1
|
|
fn brighten([]f32 pixels, f32 amount) {
|
|
i := 0
|
|
while i + 8 <= pixels.len {
|
|
v := min(f32x8(pixels, i) * (1.0 + amount), 1.0)
|
|
v.store(pixels, i)
|
|
i += 8
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
[]f32 a
|
|
[]f32 b
|
|
for i in 0..4_000_000 {
|
|
a.push(f32(i % 100) / 100.0)
|
|
b.push(0.5)
|
|
}
|
|
|
|
start := time.millis()
|
|
x := 0.0
|
|
for round in 0..20 {
|
|
x = float(dot_plain(a, b))
|
|
}
|
|
plain := time.millis() - start
|
|
|
|
start = time.millis()
|
|
y := 0.0
|
|
for round in 0..20 {
|
|
y = float(dot_simd(a, b))
|
|
}
|
|
simd := time.millis() - start
|
|
|
|
print("one at a time: ", str(x, 1), "in", plain, "ms")
|
|
print("eight at a time:", str(y, 1), "in", simd, "ms")
|
|
|
|
brighten(a, 0.5)
|
|
print("brightened:", a[10], a[90], a.len)
|
|
}
|