// 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], fma multiplies and adds in one step 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) 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) }