mirror of
https://github.com/Nexoniarz/Finch.git
synced 2026-11-03 00:44:27 +00:00
Vector types (SIMD): f32x8, i8x32, f64x4 and the rest; --cpu native
- fNxM / iNxM / uNxM up to 512 bits, as LLVM vectors (<8 x float>): LLVM picks SSE, AVX2, AVX-512 or NEON for them - f32x8(x) in every lane, f32x8(a, ..., h), f32x8(list, i) loads, f32x8(i32x8 v) converts - + - * / and the bit operators lane by lane, with a plain number on either side counting for every lane; v[i], v[i] = x, v.len, == / != (every lane), print and str - methods: sum min max dot abs sqrt floor ceil round fma store; min/max/abs/clamp lane by lane - wide vectors (and structs holding them) are loaded and stored with align 16, what malloc and the stack give - --cpu <name> (and cpu = "..." in finch.toml): native, x86-64-v3, apple-m1, ... - debug info shows vectors; the language server completes their methods; Kate and VS Code highlight them - f32 x = -1.5 works: a minus in front of a float written in the code keeps it such a number Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Psc42moPLwP43Cmb9oZqSR
This commit is contained in:
parent
a4bdeb5712
commit
68a9493572
21 changed files with 734 additions and 18 deletions
5
tests/fail/vec_intdiv.fch
Normal file
5
tests/fail/vec_intdiv.fch
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// expect: no instruction that divides whole numbers lane by lane
|
||||
fn main() {
|
||||
a := i32x4(8)
|
||||
print(a / 2)
|
||||
}
|
||||
6
tests/fail/vec_lane_index.fch
Normal file
6
tests/fail/vec_lane_index.fch
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
// expect: index 4
|
||||
fn main() {
|
||||
v := i32x4(1)
|
||||
i := 4
|
||||
print(v[i])
|
||||
}
|
||||
4
tests/fail/vec_lanes.fch
Normal file
4
tests/fail/vec_lanes.fch
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// expect: f32x4(a, b, ...) takes 4 numbers
|
||||
fn main() {
|
||||
print(f32x4(1.0, 2.0, 3.0))
|
||||
}
|
||||
5
tests/fail/vec_less.fch
Normal file
5
tests/fail/vec_less.fch
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// expect: use min(v, w), max(v, w), or compare lanes: v[i] < w[i]
|
||||
fn main() {
|
||||
a := f32x4(1.0)
|
||||
print(a < a)
|
||||
}
|
||||
5
tests/fail/vec_load_end.fch
Normal file
5
tests/fail/vec_load_end.fch
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// expect: the 8 numbers of the vector don't all fit in the list there
|
||||
fn main() {
|
||||
[]f32 data = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
|
||||
print(f32x8(data, 2))
|
||||
}
|
||||
6
tests/fail/vec_mix.fch
Normal file
6
tests/fail/vec_mix.fch
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
// expect: can't use '+' on f32x8 and i32x8 (convert one: f32x8(...))
|
||||
fn main() {
|
||||
a := f32x8(1.0)
|
||||
b := i32x8(1)
|
||||
print(a + b)
|
||||
}
|
||||
5
tests/fail/vec_type.fch
Normal file
5
tests/fail/vec_type.fch
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// expect: f32x8(x) puts x in every lane
|
||||
fn main() {
|
||||
f32x8 v = 1.0
|
||||
print(v)
|
||||
}
|
||||
69
tests/run/vectors.fch
Normal file
69
tests/run/vectors.fch
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// Vectors: N numbers side by side, worked on all at once (SIMD)
|
||||
|
||||
struct Particle {
|
||||
f32x8 pos
|
||||
int id = 7
|
||||
}
|
||||
|
||||
fn scale(f32x8 v, f32 k) -> f32x8 {
|
||||
return v * k
|
||||
}
|
||||
|
||||
// a dot product of two lists, 8 at a time, with the rest one by one
|
||||
fn dot([]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 {
|
||||
total += a[i] * b[i]
|
||||
i += 1
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
fn main() {
|
||||
a := f32x4(1.0, 2.0, 3.0, 4.0)
|
||||
b := f32x4(0.5)
|
||||
print(a + b, a * 2.0, 10.0 - a, -a)
|
||||
print(a.sum(), a.min(), a.max(), a.dot(a), a.len)
|
||||
print((a * a).sqrt(), f32x4(1.5, -1.5, 2.5, -0.2).round(), f32x4(1.7).floor(), f32x4(1.2).ceil())
|
||||
print(abs(f32x4(-1.0, 2.0, -3.0, 4.0)), min(a, 2.5), max(a, f32x4(2.0)), clamp(a, 1.5, 3.5))
|
||||
|
||||
// lanes
|
||||
a[0] = 9.0
|
||||
print(a[0], a[3], a)
|
||||
print(a == f32x4(9.0, 2.0, 3.0, 4.0), a != a)
|
||||
|
||||
// whole numbers, bits, conversions
|
||||
n := i32x8(1, 2, 3, 4, 5, 6, 7, 8)
|
||||
print(n * 3 - 1, n << 2, n & 1, ~n, n.sum(), n.max())
|
||||
print(f32x8(n) / 2.0, i32x8(f32x8(2.9)), i16x8(n), u8x16(200).sum())
|
||||
print(abs(i32x4(-3, 3, -7, 0)), min(u8x16(5), u8x16(9)).max())
|
||||
|
||||
// from lists and back
|
||||
[]f32 data
|
||||
for i in 0..20 {
|
||||
data.push(f32(i))
|
||||
}
|
||||
v := f32x8(data, 4)
|
||||
print(v)
|
||||
(v * 10.0).store(data, 12)
|
||||
print(data)
|
||||
print(dot(data, data))
|
||||
|
||||
// in structs, arrays, functions, and str()
|
||||
p := Particle(pos: f32x8(1.0))
|
||||
p.pos = scale(p.pos, 3.0)
|
||||
p.pos[7] = 0.5
|
||||
print(p)
|
||||
[]f64x4 list
|
||||
list.push(f64x4(1.0, 2.0, 3.0, 4.0))
|
||||
list.push(list[0] * list[0])
|
||||
print(list, str(list[1]).len)
|
||||
i64x2 big = i64x2(1 << 40, -5)
|
||||
print(big + big)
|
||||
}
|
||||
15
tests/run/vectors.out
Normal file
15
tests/run/vectors.out
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
f32x4(1.5, 2.5, 3.5, 4.5) f32x4(2, 4, 6, 8) f32x4(9, 8, 7, 6) f32x4(-1, -2, -3, -4)
|
||||
10 1 4 30 4
|
||||
f32x4(1, 2, 3, 4) f32x4(2, -2, 3, -0) f32x4(1, 1, 1, 1) f32x4(2, 2, 2, 2)
|
||||
f32x4(1, 2, 3, 4) f32x4(1, 2, 2.5, 2.5) f32x4(2, 2, 3, 4) f32x4(1.5, 2, 3, 3.5)
|
||||
9 4 f32x4(9, 2, 3, 4)
|
||||
true false
|
||||
i32x8(2, 5, 8, 11, 14, 17, 20, 23) i32x8(4, 8, 12, 16, 20, 24, 28, 32) i32x8(1, 0, 1, 0, 1, 0, 1, 0) i32x8(-2, -3, -4, -5, -6, -7, -8, -9) 36 8
|
||||
f32x8(0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4) i32x8(2, 2, 2, 2, 2, 2, 2, 2) i16x8(1, 2, 3, 4, 5, 6, 7, 8) 128
|
||||
i32x4(3, 3, 7, 0) 5
|
||||
f32x8(4, 5, 6, 7, 8, 9, 10, 11)
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 40, 50, 60, 70, 80, 90, 100, 110]
|
||||
49706
|
||||
Particle(pos: f32x8(3, 3, 3, 3, 3, 3, 3, 0.5), id: 7)
|
||||
[f64x4(1, 2, 3, 4), f64x4(1, 4, 9, 16)] 18
|
||||
i64x2(2199023255552, -10)
|
||||
Loading…
Reference in a new issue