From 0bf66740dfdd8bd9b8eaa47b73467ff1407edd2e Mon Sep 17 00:00:00 2001
From: Claude
Date: Sun, 1 Nov 2026 13:57:28 +0000
Subject: [PATCH] Compiler and docs on every system: macOS Intel in CI,
releases made by CI, docs for vectors and --cpu
- CI: macOS on Apple Silicon and Intel (macos-15, macos-15-intel); a tag v* attaches every package
(Linux x64/ARM64, macOS ARM64/x64, Windows x64, the VS Code extension) to its release
- vectors: fma is llvm.fmuladd (llvm.fma was a libm call per lane without FMA hardware: 3.5x slower)
- examples/simd.fch: a dot product eight at a time, timed against the plain loop
- README and the English guides: installing on Linux, macOS and Windows; vectors (SIMD); --cpu;
-g is DWARF on Windows too (lldb from llvm-mingw); no more mention of the C++ compiler
- comments left from the C++ compiler (src/target.cpp, src/codegen.cpp, "never frees") brought up to date
Co-Authored-By: Claude Opus 5.5
Claude-Session: https://claude.ai/code/session_01Psc42moPLwP43Cmb9oZqSR
---
.github/workflows/ci.yml | 43 +++++++--
README.md | 35 +++++---
README.pl.md | 175 ++++++++++++++++++++-----------------
bootstrap/README.md | 19 ++--
docs/en/cheatsheet.md | 26 +++++-
docs/en/for-beginners.md | 7 +-
docs/en/for-engineers.md | 79 ++++++++++++-----
docs/en/for-technicians.md | 146 +++++++++++++++++++++++++++----
examples/simd.fch | 69 +++++++++++++++
runtime/finch_rt.c | 2 +-
src/cimport.fch | 7 +-
src/docs.fch | 2 +-
src/gen.fch | 18 ++--
src/main.fch | 5 +-
src/platform.fch | 1 -
15 files changed, 463 insertions(+), 171 deletions(-)
create mode 100644 examples/simd.fch
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1c85d92..f173eb8 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,8 +1,8 @@
name: CI
# The compiler is written in Finch. It is built from bootstrap/.ll, its own LLVM IR (see bootstrap/README.md),
-# then from itself. Seeds: Linux x86-64 and ARM64 (tested here), Windows x86-64 (tested under Wine, and here),
-# macOS ARM64 and x86-64 (made with Apple's headers; only checked as IR until the macos job below passes).
+# then from itself, and tested, on every system it runs on: Linux x86-64 and ARM64, macOS ARM64 and x86-64, Windows x86-64.
+# A tag v* also makes the release: every package below is attached to it.
on:
push:
@@ -75,7 +75,14 @@ jobs:
fi
macos:
- runs-on: macos-15
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - { os: macos-15, arch: arm64 }
+ - { os: macos-15-intel, arch: x64 }
+ name: macos-${{ matrix.arch }}
+ runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Install LLVM 21 (libclang)
@@ -92,11 +99,11 @@ jobs:
- name: Package
run: |
mkdir -p dist/finch && cp build/finch README.md LICENSE dist/finch/ && cp -r runtime std examples dist/finch/
- tar -czf finch-macos-arm64.tar.gz -C dist finch
+ tar -czf finch-macos-${{ matrix.arch }}.tar.gz -C dist finch
- uses: actions/upload-artifact@v4
with:
- name: finch-macos-arm64
- path: finch-macos-arm64.tar.gz
+ name: finch-macos-${{ matrix.arch }}
+ path: finch-macos-${{ matrix.arch }}.tar.gz
windows:
runs-on: windows-2022
@@ -154,3 +161,27 @@ jobs:
with:
name: finch-vscode
path: editors/vscode/finch-lang.vsix
+
+ release:
+ if: startsWith(github.ref, 'refs/tags/v')
+ needs: [linux, cross, macos, windows, vscode]
+ runs-on: ubuntu-24.04
+ permissions:
+ contents: write
+ steps:
+ - uses: actions/download-artifact@v4
+ with:
+ path: dist
+ merge-multiple: true
+ - name: Attach the packages to the release (made if it isn't there yet)
+ uses: softprops/action-gh-release@v2
+ with:
+ name: Finch ${{ github.ref_name }}
+ generate_release_notes: true
+ files: |
+ dist/finch-linux-x64.tar.gz
+ dist/finch-linux-arm64.tar.gz
+ dist/finch-macos-arm64.tar.gz
+ dist/finch-macos-x64.tar.gz
+ dist/finch-windows-x64.zip
+ dist/finch-lang.vsix
diff --git a/README.md b/README.md
index 7f62239..938d072 100644
--- a/README.md
+++ b/README.md
@@ -40,6 +40,8 @@ fn main() {
Operator precedence that does not bite (`x & 1 == 0` means what it says).
- **Practical.** Maps, methods, errors as values (`int(s) or 0`, `try read_file(p)`), modules, any C
library, and a language server for your editor. Runs on Linux, macOS and Windows, on x86-64 and ARM64.
+- **SIMD built in.** `f32x8`, `i8x32`, `f64x4`: numbers side by side, added and multiplied all at once. LLVM turns them
+ into SSE, AVX2, AVX-512 or NEON instructions, so one piece of code is fast on a desktop, a laptop and ARM.
- **Errors that talk like a person:**
```
game.fch:3:13: error: 'y' must be i32, but this is int (use i32(...) to convert)
@@ -48,13 +50,17 @@ fn main() {
```
- **Any C library, directly.** `import "raylib.h"` + `link "raylib"`, and you can call it, structs by value
and callbacks included. Headers are read by libclang, so there is nothing to declare by hand.
-- **Written in itself.** The compiler is Finch code, and nothing else: `src/*.fch`, about 8.6k lines. It is built from a
- seed (its own LLVM IR, `bootstrap/`) and then from itself, and the two come out identical. Its first version, in C++,
- is kept on the `before-bootstrap` branch.
+- **Written in itself.** The compiler is Finch code, and nothing else: `src/*.fch`, about 12k lines. It is built from a
+ seed (its own LLVM IR, `bootstrap/`) and then from itself, and the two come out identical.
## Quick start
-**Building it** (Linux x86-64 or ARM64; needs `clang` and libclang, LLVM 21):
+**Ready builds** for Linux (x64, ARM64), macOS (Apple Silicon, Intel) and Windows (x64) are in the
+[releases](https://github.com/Nexoniarz/Finch/releases). Unpack one and keep `runtime/` and `std/` next to `finch`. What
+each system needs besides is in the [technicians' guide](docs/en/for-technicians.md#2-installing): clang and libclang
+from LLVM 21 on Linux, `brew install llvm@21` on a Mac, llvm-mingw on Windows.
+
+**Building it yourself** (on Linux, macOS, or Windows with Git Bash; needs `clang` and libclang, LLVM 21):
```sh
git clone https://github.com/Nexoniarz/Finch.git
@@ -64,13 +70,12 @@ bootstrap/build.sh # the compiler is build/finch: built from th
./build/finch run examples/hello.fch
./build/finch build examples/tour.fch -o tour && ./tour
-tests/run.sh # every program, every refusal, -g, a shared library, the language server
+tests/run.sh # every program, every expected error, -g, a shared library, the language server
```
-Ready builds of the compiler are in the [releases](https://github.com/Nexoniarz/Finch/releases) (Linux x64 and ARM64:
-unpack, keep `runtime/` and `std/` next to `finch`). **Programs for Windows, ARM64 and macOS** are built from Linux with
-`--target windows|arm64|macos` (see the [guide](docs/en/for-technicians.md#3-the-finch-command)); the compiler itself does not run on
-macOS or Windows yet (it needs a seed made with that system's headers: see [bootstrap/README.md](bootstrap/README.md)).
+The same `bootstrap/build.sh` works on a Mac (with Homebrew's `llvm@21`) and on Windows (with llvm-mingw): see
+[bootstrap/README.md](bootstrap/README.md). Programs for another system are built with `--target windows|linux|arm64|macos`
+(see the [guide](docs/en/for-technicians.md#building-for-another-system)).
Editors: **Kate** (`editors/kate/install.sh`), **VS Code** (the `finch-lang` `.vsix` from the release), or any
editor with LSP support (`finch lsp`).
@@ -91,13 +96,14 @@ Pick the guide that fits you:
| | |
|---|---|
| Variables | `x := 5` (inferred) or `int x = 5`; `const W = 640` |
-| Types | `int` `float` `bool` `char` `str`, sized `i8`…`i64` `u8`…`u64` `f32` `f64`, arrays `[]T`, maps `map[K]V`, pointers `ptr[T]` |
+| Types | `int` `float` `bool` `char` `str`, sized `i8`…`i64` `u8`…`u64` `f32` `f64`, arrays `[]T`, maps `map[K]V`, pointers `ptr[T]`, vectors `f32x8` `i8x32`… |
| Functions | `fn add(int a, int b) -> int { return a + b }` |
| Structs | `struct Point { … }` with one field per line (`int x`, `int y = 0`); create with `Point(1, 2)` or `Point(x: 1)` |
| Methods | `fn Point.move(int dx) { self.x += dx }` → `p.move(3)` |
| Arrays | `nums := [1, 2, 3]`, `nums.push(4)`, `nums[0]`, `nums.len`, `for i, n in nums { }` |
| Maps | `ages := ["ann": 31]`, `ages["bob"] = 25`, `ages.has("cy")`, `counts[w] += 1`, `for k, v in ages { }` |
| Errors | `fn parse(str s) -> int! { … return error("bad") }` → `parse(s) or 0`, `parse(s) or { … }`, `try parse(s)` |
+| Vectors (SIMD) | `v := f32x8(list, i)`, `v * 2.0 + w`, `v.sum()`, `v.dot(w)`, `min(v, 1.0)`, `v.store(list, i)`, `v[3]` |
| Text | `"hp \(hp)"`, `"a" + "b"`, `str(42)`, `int("42")`, `s.split(",")`, `s.upper()`, `s[0]` |
| Control | `if` / `else if` / `else` (also as a value), `while`, `for i in 0..10`, `break`, `continue`, `defer` |
| Memory | automatic for arrays, text and structs; `new(...)` / `free(...)` for your own heap structures |
@@ -108,7 +114,7 @@ Pick the guide that fits you:
| Tests | `test "name" { assert(x == 3) }` next to the code, run with `finch test` |
| C interop | `import "stdio.h"`, `link "glfw"`, `link "mine.c"` / `"glue.cpp"`, unions, `#define`s (also `(Color){…}`), `addr(fn)` for callbacks |
| I/O | `print(...)`, `input("? ")`, `read_file`, `write_file`, `shell` |
-| Tools | `finch run/build/test/fmt/ir/lsp`, `finch.toml` for a project, a build cache, `--target windows/arm64/macos/android`, `-g` for gdb/lldb, `-O0`, the chain of calls on runtime errors |
+| Tools | `finch run/build/test/fmt/ir/lsp`, `finch.toml` for a project, a build cache, `--target windows/arm64/macos/android`, `--cpu native`, `-g` for gdb/lldb, `-O0`, the chain of calls on runtime errors |
## Examples
@@ -122,6 +128,7 @@ Pick the guide that fits you:
| [`examples/structs.fch`](examples/structs.fch) | structs, arrays of structs, a linked list with `new`/`free` |
| [`examples/types.fch`](examples/types.fch) | sized numbers and pointers |
| [`examples/c_import.fch`](examples/c_import.fch) | `printf`, `math.h`, `malloc`/`free`, `stderr` |
+| [`examples/simd.fch`](examples/simd.fch) | vectors: a dot product eight numbers at a time, and the time it saves |
| [`examples/window.fch`](examples/window.fch) | a GLFW + OpenGL window |
| [`examples/opengl.fch`](examples/opengl.fch) | modern OpenGL 3.3: shaders, buffers, a spinning triangle |
| [`examples/vulkan.fch`](examples/vulkan.fch) | Vulkan: list the GPUs, their memory and queues, create a device |
@@ -151,14 +158,16 @@ Pick the guide that fits you:
- [x] A standard library in Finch: `json`, `path`, `time`, `proc`, `fs`
- [x] `const`, `if` as a value, `"\(x)"` in text, `"""` text, C unions and `#define` expressions
- [x] `test` blocks and `finch test`, `finch fmt`, `finch.toml`, a build cache, the chain of calls on runtime errors
-- [x] Threads (`import thread`) and atomics; C++ files; `--target android` (compiles; NDK linking and devices untried)
+- [x] Threads (`import thread`) and atomics; C++ files; `--target android`
+- [x] The compiler on every system it builds for: Linux, macOS (Apple Silicon and Intel), Windows; releases made by CI
+- [x] Vector types (`f32x8`, `i8x32`, …) for SIMD, and `--cpu native`
## Layout
```
src/ the compiler, in Finch: lexer, parser, AST, code generation (to LLVM IR as text), C import (libclang) and
the C calling conventions, the language server, the driver
-std/ the standard library, in Finch: json, path, time, proc, fs
+std/ the standard library, in Finch: json, path, time, proc, fs, thread
runtime/ the small C runtime linked into every program
bootstrap/ build.sh and the seeds: the compiler's own LLVM IR, one per system
examples/ example programs
diff --git a/README.pl.md b/README.pl.md
index 52b438d..098f317 100644
--- a/README.pl.md
+++ b/README.pl.md
@@ -5,8 +5,8 @@
-**Mały, zwinny, skuteczny.** Język programowania na LLVM ze składnią podobną do C,
-na tyle prosty, że nauczysz się go w godzinę, i tak szybki jak C.
+**Mały, szybki, celny.** Język programowania oparty na LLVM, ze składnią w stylu C. Nauczysz się go w godzinę,
+a programy działają tak szybko jak w C.
> 🇬🇧 [English version](README.md)
@@ -19,7 +19,7 @@ fn przeciwprostokatna(float a, float b) -> float {
fn main() {
imie := "Finch"
- print("Cześć od", imie, "!")
+ print("Cześć, tu", imie, "!")
for i in 1..4 {
print(i, "→", przeciwprostokatna(float(i), 1.0))
@@ -29,51 +29,58 @@ fn main() {
## Dlaczego Finch
-- **Prosty.** Bez średników, bez plików nagłówkowych, bez preprocesora. Każdą rzecz robi się na jeden sposób.
-- **Szybki.** Kompiluje się przez potok `-O2` z LLVM do kodu natywnego, bez garbage collectora.
- Rekurencyjne `fib(40)` trwa ok. 0,19 s (`clang -O2` na tym samym kodzie C: ok. 0,23 s), a kod na tablicach
- z kontrolą zakresu dorównuje C.
-- **Pamięć bez bólu.** Listy, teksty i struktury są wartościami: przypisanie kopiuje, a koniec bloku je zwalnia.
- Nie ma `free`, o którym można zapomnieć, nie ma użycia po zwolnieniu, a każdy test jest czysty pod valgrindem.
-- **Bezpieczniejszy niż C tam, gdzie to tanie.** Nie ma cichego zwężania typów ani mieszania liczb ze znakiem
- i bez znaku. Indeks poza zakresem, dzielenie przez zero i null zatrzymują program czytelnym błędem, zamiast
- powodować niezdefiniowane zachowanie. Priorytety operatorów nie gryzą (`x & 1 == 0` znaczy to, co widać).
-- **Praktyczny.** Mapy, metody, błędy jako wartości (`int(s) or 0`, `try read_file(p)`), moduły, każda
- biblioteka C i serwer języka dla twojego edytora. Działa na Linuksie, macOS i Windowsie, na x86-64 i ARM64.
-- **Błędy mówią po ludzku:**
+- **Prosty.** Nie ma średników, plików nagłówkowych ani preprocesora. Na każdą rzecz jest jeden sposób.
+- **Szybki.** Kod przechodzi przez optymalizacje LLVM (`-O2`) i staje się zwykłym programem, bez garbage collectora.
+ Rekurencyjne `fib(40)` liczy się ok. 0,19 s (ten sam kod w C z `clang -O2`: ok. 0,23 s), a pętle po tablicach
+ ze sprawdzaniem zakresu są tak samo szybkie jak w C.
+- **Pamięć bez kłopotów.** Listy, teksty i struktury są wartościami: przypisanie robi kopię, a koniec bloku sprząta.
+ Nie ma `free`, o którym da się zapomnieć, ani odwołań do zwolnionej pamięci. Valgrind nie znajduje błędów w żadnym teście.
+- **Bezpieczniejszy niż C tam, gdzie nic to nie kosztuje.** Liczby nie zmieniają po cichu typu, a liczb ze znakiem
+ i bez znaku nie da się przypadkiem pomieszać. Indeks poza tablicą, dzielenie przez zero czy `null` kończą program
+ jasnym komunikatem, a nie niezdefiniowanym zachowaniem. Kolejność działań jest taka, jakiej się spodziewasz
+ (`x & 1 == 0` znaczy dokładnie to, co widać).
+- **Praktyczny.** Mapy, metody, błędy jako wartości (`int(s) or 0`, `try read_file(p)`), moduły, dowolna biblioteka C
+ i serwer języka dla edytora. Działa na Linuksie, macOS i Windowsie, na procesorach x86-64 i ARM64.
+- **SIMD w języku.** `f32x8`, `i8x32`, `f64x4`: kilka liczb obok siebie, dodawanych i mnożonych naraz. LLVM zamienia je
+ na instrukcje SSE, AVX2, AVX-512 albo NEON, więc ten sam kod jest szybki na komputerze stacjonarnym, laptopie i ARM-ie.
+- **Komunikaty, które da się zrozumieć:**
```
gra.fch:3:13: error: 'y' must be i32, but this is int (use i32(...) to convert)
3 | i32 y = x
| ^
```
-- **Każda biblioteka C, bezpośrednio.** Piszesz `import "raylib.h"` i `link "raylib"`, i możesz z niej korzystać,
- także ze struktur przekazywanych przez wartość i z callbacków. Nagłówki czyta libclang, więc nie trzeba niczego deklarować ręcznie.
-- **Napisany w sobie.** Kompilator to kod w Finchu i nic więcej: `src/*.fch`, ok. 8,6 tys. linii. Buduje się go z ziarna
- (własny kod LLVM IR, `bootstrap/`), potem z samego siebie, a oba wyniki są identyczne. Pierwsza wersja, w C++,
- jest w gałęzi `before-bootstrap`.
+- **Biblioteki C bez pośredników.** Wystarczy `import "raylib.h"` i `link "raylib"`, żeby z niej korzystać, łącznie
+ ze strukturami przekazywanymi przez wartość i funkcjami zwrotnymi. Nagłówki czyta libclang, więc niczego nie trzeba
+ deklarować ręcznie.
+- **Napisany w samym sobie.** Kompilator to wyłącznie kod w Finchu: `src/*.fch`, ok. 12 tys. linii. Buduje się go
+ z pliku startowego (jego własnego kodu LLVM IR, w `bootstrap/`), a potem jeszcze raz nim samym. Oba wyniki są identyczne.
-## Szybki start
+## Na start
-**Budowanie** (Linux x86-64 lub ARM64; potrzebny `clang` i libclang, LLVM 21):
+**Gotowe kompilatory** na Linuksa (x64, ARM64), macOS (Apple Silicon, Intel) i Windowsa (x64) znajdziesz w
+[wydaniach](https://github.com/Nexoniarz/Finch/releases). Rozpakuj archiwum i trzymaj katalogi `runtime/` i `std/` obok
+pliku `finch`. Co jeszcze trzeba doinstalować, opisuje [przewodnik dla techników](docs/pl/dla-technikow.md#2-instalacja):
+na Linuksie clang i libclang z LLVM 21, na Macu `brew install llvm@21`, na Windowsie llvm-mingw.
+
+**Samodzielne budowanie** (na Linuksie, macOS albo Windowsie w Git Bash; potrzebne są `clang` i libclang z LLVM 21):
```sh
git clone https://github.com/Nexoniarz/Finch.git
cd Finch
-nix-shell # albo zainstaluj samodzielnie clang + libclang (LLVM 21) + pkg-config
-bootstrap/build.sh # kompilator to build/finch: z ziarna, potem z samego siebie
+nix-shell # albo zainstaluj clang, libclang (LLVM 21) i pkg-config po swojemu
+bootstrap/build.sh # gotowy kompilator to build/finch
./build/finch run examples/hello.fch
./build/finch build examples/tour.fch -o tour && ./tour
-tests/run.sh # każdy program, każda odmowa, -g, biblioteka współdzielona, serwer języka
+tests/run.sh # wszystkie programy testowe, oczekiwane błędy, -g, biblioteka współdzielona, serwer języka
```
-Gotowe kompilatory są w [wydaniach](https://github.com/Nexoniarz/Finch/releases) (Linux x64 i ARM64: rozpakuj, zostaw
-`runtime/` i `std/` obok `finch`). **Programy dla Windowsa, ARM64 i macOS** buduje się z Linuksa przez
-`--target windows|arm64|macos`; sam kompilator nie działa jeszcze na macOS ani Windowsie (potrzebuje ziarna
-zrobionego z nagłówkami tego systemu: patrz [bootstrap/README.md](bootstrap/README.md)).
+Ten sam `bootstrap/build.sh` działa na Macu (z `llvm@21` z Homebrew) i na Windowsie (z llvm-mingw); szczegóły są w
+[bootstrap/README.md](bootstrap/README.md). Program na inny system zbudujesz opcją `--target windows|linux|arm64|macos`
+(zob. [przewodnik](docs/pl/dla-technikow.md#budowanie-na-inny-system)).
-Edytory: **Kate** (`editors/kate/install.sh`), **VS Code** (plik `.vsix` `finch-lang` z wydania) albo dowolny
-edytor z obsługą LSP (`finch lsp`).
+Edytory: **Kate** (`editors/kate/install.sh`), **VS Code** (plik `.vsix` `finch-lang` z wydania) albo każdy edytor,
+który obsługuje LSP (`finch lsp`).
## Dokumentacja
@@ -81,90 +88,94 @@ Wybierz przewodnik dla siebie:
| Przewodnik | Dla kogo | Polski | English |
|---|---|---|---|
-| **Początkujący** | Nigdy nie programowałeś: uczniowie, seniorzy, ciekawscy | [dla-poczatkujacych.md](docs/pl/dla-poczatkujacych.md) | [for-beginners.md](docs/en/for-beginners.md) |
-| **Technicy** | Znasz komputery, programowanie jest nowe: instalacja, cały język, biblioteki C, problemy | [dla-technikow.md](docs/pl/dla-technikow.md) | [for-technicians.md](docs/en/for-technicians.md) |
-| **Inżynierowie** | Wszystko: lekser, gramatyka, AST, reguły typów, tłumaczenie na IR, import przez libclang, ABI, wnętrze | [dla-inzynierow.md](docs/pl/dla-inzynierow.md) | [for-engineers.md](docs/en/for-engineers.md) |
-| **Ściąga** | Każda funkcja, metoda, operator i polecenie na jednej stronie | [sciaga.md](docs/pl/sciaga.md) | [cheatsheet.md](docs/en/cheatsheet.md) |
+| **Dla początkujących** | Dla tych, którzy nigdy nie programowali: uczniów, seniorów, ciekawych świata | [dla-poczatkujacych.md](docs/pl/dla-poczatkujacych.md) | [for-beginners.md](docs/en/for-beginners.md) |
+| **Dla techników** | Znasz komputery, ale programowanie jest dla ciebie nowe: instalacja, cały język, biblioteki C, rozwiązywanie problemów | [dla-technikow.md](docs/pl/dla-technikow.md) | [for-technicians.md](docs/en/for-technicians.md) |
+| **Dla inżynierów** | Wszystko: lekser, gramatyka, AST, reguły typów, generowanie IR, import przez libclang, ABI, budowa kompilatora | [dla-inzynierow.md](docs/pl/dla-inzynierow.md) | [for-engineers.md](docs/en/for-engineers.md) |
+| **Ściąga** | Wszystkie funkcje, metody, operatory i polecenia na jednej stronie | [sciaga.md](docs/pl/sciaga.md) | [cheatsheet.md](docs/en/cheatsheet.md) |
## Język w pigułce
| | |
|---|---|
-| Zmienne | `x := 5` (typ zgadnięty) albo `int x = 5`; `const W = 640` |
-| Typy | `int` `float` `bool` `char` `str`, z rozmiarem `i8`…`i64` `u8`…`u64` `f32` `f64`, tablice `[]T`, mapy `map[K]V`, wskaźniki `ptr[T]` |
-| Funkcje | `fn add(int a, int b) -> int { return a + b }` |
-| Struktury | `struct Punkt { … }` z jednym polem na linijkę (`int x`, `int y = 0`); tworzenie przez `Punkt(1, 2)` albo `Punkt(x: 1)` |
+| Zmienne | `x := 5` (typ wynika z wartości) albo `int x = 5`; `const W = 640` |
+| Typy | `int` `float` `bool` `char` `str`, o podanym rozmiarze: `i8`…`i64` `u8`…`u64` `f32` `f64`, tablice `[]T`, mapy `map[K]V`, wskaźniki `ptr[T]`, wektory `f32x8` `i8x32`… |
+| Funkcje | `fn dodaj(int a, int b) -> int { return a + b }` |
+| Struktury | `struct Punkt { … }`, jedno pole w linii (`int x`, `int y = 0`); tworzy się je przez `Punkt(1, 2)` albo `Punkt(x: 1)` |
| Metody | `fn Punkt.przesun(int dx) { self.x += dx }` → `p.przesun(3)` |
| Tablice | `liczby := [1, 2, 3]`, `liczby.push(4)`, `liczby[0]`, `liczby.len`, `for i, n in liczby { }` |
-| Mapy | `wiek := ["ania": 31]`, `wiek["bob"] = 25`, `wiek.has("cy")`, `ile[s] += 1`, `for k, v in wiek { }` |
-| Błędy | `fn parsuj(str s) -> int! { … return error("zły") }` → `parsuj(s) or 0`, `parsuj(s) or { … }`, `try parsuj(s)` |
-| Tekst | `"hp \(hp)"`, `"a" + "b"`, `str(42)`, `int("42")`, `s.split(",")`, `s.upper()`, `s[0]` |
-| Sterowanie | `if` / `else if` / `else` (też jako wartość), `while`, `for i in 0..10`, `break`, `continue`, `defer` |
-| Pamięć | automatyczna dla tablic, tekstów i struktur; `new(...)` / `free(...)` dla własnych struktur na stercie |
-| Enumy, match | `enum Kolor { Czerwony, Zielony }`, `match k { Czerwony -> ... else -> ... }` (także jako wartość) |
-| Generyki | `fn max[T](T a, T b) -> T`, `struct Stos[T]`, `Stos[int]()` |
+| Mapy | `wiek := ["ania": 31]`, `wiek["bob"] = 25`, `wiek.has("cyryl")`, `ile[slowo] += 1`, `for k, v in wiek { }` |
+| Błędy | `fn parsuj(str s) -> int! { … return error("zła liczba") }` → `parsuj(s) or 0`, `parsuj(s) or { … }`, `try parsuj(s)` |
+| Wektory (SIMD) | `v := f32x8(lista, i)`, `v * 2.0 + w`, `v.sum()`, `v.dot(w)`, `min(v, 1.0)`, `v.store(lista, i)`, `v[3]` |
+| Tekst | `"hp: \(hp)"`, `"a" + "b"`, `str(42)`, `int("42")`, `s.split(",")`, `s.upper()`, `s[0]` |
+| Sterowanie | `if` / `else if` / `else` (również jako wartość), `while`, `for i in 0..10`, `break`, `continue`, `defer` |
+| Pamięć | tablice, teksty i struktury zwalniają się same; `new(...)` / `free(...)` dla własnych struktur na stercie |
+| Enumy i `match` | `enum Kolor { Czerwony, Zielony }`, `match k { Czerwony -> ... else -> ... }` (również jako wartość) |
+| Typy generyczne | `fn max[T](T a, T b) -> T`, `struct Stos[T]`, `Stos[int]()` |
| Moduły | `import ksztalty` → `ksztalty.pole(p)`, `import ui/button as btn`; biblioteka standardowa: `json`, `path`, `time`, `proc`, `fs`, `thread` |
| Wątki | `thread.spawn(addr(praca), addr(dane))`, `t.join()`, `thread.mutex()`, `atomic_add(addr(n), 1)` |
-| Testy | `test "nazwa" { assert(x == 3) }` obok kodu, uruchamiane przez `finch test` |
-| Współpraca z C | `import "stdio.h"`, `link "glfw"`, `link "moje.c"` / `"glue.cpp"`, unie, `#define` (też `(Color){…}`), `addr(fn)` dla callbacków |
-| Wejście/wyjście | `print(...)`, `input("? ")`, `read_file`, `write_file`, `shell` |
-| Narzędzia | `finch run/build/test/fmt/ir/lsp`, `finch.toml` dla projektu, cache budowania, `--target windows/arm64/macos/android`, `-g` dla gdb/lldb, `-O0`, łańcuch wywołań przy błędach w czasie działania |
+| Testy | `test "nazwa" { assert(x == 3) }` tuż obok kodu, uruchamiane przez `finch test` |
+| Współpraca z C | `import "stdio.h"`, `link "glfw"`, `link "moje.c"` / `"glue.cpp"`, unie, `#define` (także `(Color){…}`), `addr(fn)` jako funkcja zwrotna |
+| Wejście i wyjście | `print(...)`, `input("? ")`, `read_file`, `write_file`, `shell` |
+| Narzędzia | `finch run/build/test/fmt/ir/lsp`, `finch.toml` dla projektu, pamięć podręczna kompilacji, `--target windows/arm64/macos/android`, `--cpu native`, `-g` dla gdb i lldb, `-O0`, ścieżka wywołań przy błędzie w trakcie działania |
## Przykłady
-| Plik | Pokazuje |
+| Plik | Co pokazuje |
|---|---|
-| [`examples/hello.fch`](examples/hello.fch) | najmniejszy program |
+| [`examples/hello.fch`](examples/hello.fch) | najkrótszy program |
| [`examples/tour.fch`](examples/tour.fch) | zmienne, funkcje, warunki, pętle |
-| [`examples/guess.fch`](examples/guess.fch) | gra w zgadywanie: wejście, pętle, `rand` z C |
+| [`examples/guess.fch`](examples/guess.fch) | gra w zgadywanie liczby: wczytywanie, pętle, `rand` z C |
| [`examples/todo.fch`](examples/todo.fch) | struktury, tablice, teksty i pliki |
| [`examples/wordcount.fch`](examples/wordcount.fch) | mapy, metody i błędy jako wartości: najczęstsze słowa w pliku |
-| [`examples/structs.fch`](examples/structs.fch) | struktury, tablice struktur, lista wiązana z `new`/`free` |
-| [`examples/types.fch`](examples/types.fch) | liczby z rozmiarem i wskaźniki |
+| [`examples/structs.fch`](examples/structs.fch) | struktury, tablice struktur, lista jednokierunkowa z `new`/`free` |
+| [`examples/types.fch`](examples/types.fch) | liczby o podanym rozmiarze i wskaźniki |
| [`examples/c_import.fch`](examples/c_import.fch) | `printf`, `math.h`, `malloc`/`free`, `stderr` |
-| [`examples/window.fch`](examples/window.fch) | okno GLFW + OpenGL |
+| [`examples/simd.fch`](examples/simd.fch) | wektory: iloczyn skalarny liczony po osiem liczb naraz i zysk na czasie |
+| [`examples/window.fch`](examples/window.fch) | okno GLFW z OpenGL |
| [`examples/opengl.fch`](examples/opengl.fch) | nowoczesny OpenGL 3.3: shadery, bufory, obracający się trójkąt |
-| [`examples/vulkan.fch`](examples/vulkan.fch) | Vulkan: lista kart graficznych, ich pamięć i kolejki, tworzenie urządzenia |
-| [`examples/raylib.fch`](examples/raylib.fch) | raylib ze strukturami C przez wartość |
-| [`examples/llvm.fch`](examples/llvm.fch) | Finch budujący LLVM IR przez API LLVM-C |
-| [`src/`](src/) | kompilator napisany w Finchu (ziarno do jego zbudowania jest w [`bootstrap/`](bootstrap/)) |
+| [`examples/vulkan.fch`](examples/vulkan.fch) | Vulkan: lista kart graficznych z ich pamięcią i kolejkami, utworzenie urządzenia |
+| [`examples/raylib.fch`](examples/raylib.fch) | raylib i struktury C przekazywane przez wartość |
+| [`examples/llvm.fch`](examples/llvm.fch) | Finch, który buduje LLVM IR przez API LLVM-C |
+| [`src/`](src/) | kompilator napisany w Finchu (plik startowy do jego zbudowania leży w [`bootstrap/`](bootstrap/)) |
## Plan rozwoju
- [x] Lekser, parser, generowanie kodu LLVM, optymalizacja O2
-- [x] Typy, w tym liczby z rozmiarem, wskaźniki, konwersje; funkcje; `if`/`while`/`for`
-- [x] Czytelne błędy kompilacji; kontrole w czasie działania (dzielenie, null, zakres)
-- [x] Operatory bitowe z rozsądnymi priorytetami
-- [x] Nagłówki C przez libclang; `link` z pkg-config; porady przy błędach linkowania
-- [x] `struct`, także struktury C przez wartość (ABI System V) i callbacki
-- [x] Tablice z `.len`, kontrolą zakresu i metodami; `for x in lista`
-- [x] Pamięć: zwalnianie na końcu bloku, `defer`, `new`/`free`
+- [x] Typy, w tym liczby o podanym rozmiarze, wskaźniki i konwersje; funkcje; `if`/`while`/`for`
+- [x] Czytelne błędy kompilacji; sprawdzanie w trakcie działania (dzielenie, `null`, zakres tablicy)
+- [x] Operatory bitowe z rozsądną kolejnością działań
+- [x] Nagłówki C przez libclang; `link` z pkg-config; podpowiedzi przy błędach linkera
+- [x] `struct`, w tym struktury C przekazywane przez wartość (ABI System V) i funkcje zwrotne
+- [x] Tablice z `.len`, sprawdzaniem zakresu i metodami; `for x in lista`
+- [x] Pamięć: wartości zwalniane na końcu bloku, `defer`, `new`/`free`
- [x] Teksty: `+`, `.len`, indeksowanie, metody, `str(x)`, `int(s)`; `input()`; pliki
- [x] Moduły Fincha (`import nazwa`)
- [x] Informacje dla debuggera (`-g`)
-- [x] Bootstrap: kompilator Fincha napisany w Finchu, który buduje sam siebie
+- [x] Bootstrap: kompilator Fincha napisany w Finchu, który kompiluje sam siebie
- [x] Windows: `finch.exe`, programy `.exe`, ABI Microsoft x64; budowanie na Windowsa z Linuksa (`--target windows`)
-- [x] Serwer języka (`finch lsp`) i rozszerzenie VS Code
+- [x] Serwer języka (`finch lsp`) i rozszerzenie do VS Code
- [x] macOS i ARM64 (Linux i Apple Silicon) z ich konwencjami wywołań C; obsługa Kate
-- [x] Metody w strukturach, mapy, błędy jako wartości (`!`, `or`, `try`)
+- [x] Metody struktur, mapy, błędy jako wartości (`!`, `or`, `try`)
- [x] Typy generyczne (`fn max[T]`, `struct Stos[T]`), `match`, enumy
- [x] Biblioteka standardowa w Finchu: `json`, `path`, `time`, `proc`, `fs`
-- [x] `const`, `if` jako wartość, `"\(x)"` w tekście, tekst `"""`, unie C i wyrażenia `#define`
-- [x] Bloki `test` i `finch test`, `finch fmt`, `finch.toml`, cache budowania, łańcuch wywołań przy błędach
-- [x] Wątki (`import thread`) i operacje atomowe; pliki C++; `--target android` (kompiluje się; linkowanie z NDK i urządzenia niesprawdzone)
+- [x] `const`, `if` jako wartość, `"\(x)"` w tekście, tekst `"""`, unie C i wyrażenia w `#define`
+- [x] Bloki `test` i `finch test`, `finch fmt`, `finch.toml`, pamięć podręczna kompilacji, ścieżka wywołań przy błędach
+- [x] Wątki (`import thread`) i operacje atomowe; pliki C++; `--target android`
+- [x] Kompilator na każdym systemie, na który buduje: Linux, macOS (Apple Silicon i Intel), Windows; wydania robi CI
+- [x] Typy wektorowe (`f32x8`, `i8x32`, …) dla SIMD i `--cpu native`
-## Struktura
+## Co gdzie leży
```
-src/ kompilator, w Finchu: lekser, parser, AST, generowanie kodu (do LLVM IR jako tekst), import C (libclang)
- i konwencje wywołań C, serwer języka, sterownik
-std/ biblioteka standardowa, w Finchu: json, path, time, proc, fs
-runtime/ mały runtime w C dołączany do każdego programu
-bootstrap/ build.sh i ziarna: własny LLVM IR kompilatora, po jednym na system
+src/ kompilator w Finchu: lekser, parser, AST, generowanie kodu (LLVM IR jako tekst), import C (libclang)
+ i konwencje wywołań C, serwer języka, polecenie finch
+std/ biblioteka standardowa w Finchu: json, path, time, proc, fs, thread
+runtime/ mały runtime w C, dołączany do każdego programu
+bootstrap/ build.sh i pliki startowe: własny LLVM IR kompilatora, osobno dla każdego systemu
examples/ przykładowe programy
-editors/ rozszerzenie VS Code, podświetlanie i konfiguracja LSP dla Kate
-tests/ run/ new/ (wzorcowe wyjście), fail/ new/fail/ (oczekiwane błędy), run.sh, cross.sh, shared.sh, lsp_test.py
-docs/ przewodniki en/ i pl/ dla trzech grup odbiorców
+editors/ rozszerzenie do VS Code, podświetlanie składni i konfiguracja LSP dla Kate
+tests/ run/ new/ (wzorcowe wyniki), fail/ new/fail/ (oczekiwane błędy), run.sh, cross.sh, shared.sh, lsp_test.py
+docs/ przewodniki po angielsku (en/) i po polsku (pl/) dla trzech grup czytelników
```
## Licencja
diff --git a/bootstrap/README.md b/bootstrap/README.md
index f4825d8..3ea5dbe 100644
--- a/bootstrap/README.md
+++ b/bootstrap/README.md
@@ -3,12 +3,16 @@
Finch's compiler is written in Finch. To build it you need something that already runs Finch: the **seed**, which is
the compiler's own LLVM IR, one file per system:
-| File | System | Checked |
+| File | System | Built and tested in CI on |
|---|---|---|
-| `linux-x86_64.ll` | Linux x86-64 | built and tested here and in CI |
-| `linux-aarch64.ll` | Linux ARM64 | made with the ARM64 cross compiler; CI builds and tests it on an ARM64 runner |
-| `windows-x86_64.ll` | Windows x86-64 (MinGW: llvm-mingw's clang + libclang.dll) | built and run under Wine: it compiles itself, and every test program runs |
-| `macos-arm64.ll`, `macos-x86_64.ll` | macOS | made on Linux with the macOS 11.3 SDK; checked as IR only (nobody has run them yet) |
+| `linux-x86_64.ll` | Linux x86-64 | ubuntu-24.04 |
+| `linux-aarch64.ll` | Linux ARM64 | ubuntu-24.04-arm |
+| `macos-arm64.ll` | macOS, Apple Silicon | macos-15 |
+| `macos-x86_64.ll` | macOS, Intel | macos-15-intel |
+| `windows-x86_64.ll` | Windows x86-64 (MinGW: llvm-mingw's clang + libclang.dll) | windows-2022 |
+
+Each CI job builds the compiler from its seed, then from itself, runs every test, and packs the result; a tag `v*` attaches
+the packages to the release.
`bootstrap/build.sh` compiles the seed with `clang` (and the runtime, and libclang) into `build/finch0`; `finch0` builds
`src/` into `finch1`; `finch1` builds `src/` again into `build/finch`; the two must make the same IR, or the script stops.
@@ -41,5 +45,6 @@ official LLVM for Windows); `bootstrap/winbuild.sh` turns it into `finch.exe` fo
`bootstrap/build.sh` does the same from Git Bash: put llvm-mingw's `bin` in PATH and set `FINCH_LIBCLANG` (the path of
`libclang.dll`), `FINCH_LLVM_INCLUDE` (its `include` folder) and `FINCH_LDFLAGS=-L`.
-macOS: the seeds were made with the macOS 11.3 SDK; `brew install llvm@21` gives clang and libclang; the CI job sets
-`FINCH_CLANG`, `FINCH_LIBCLANG` and `FINCH_LLVM_INCLUDE`. If the macOS build fails, that job is where it shows first.
+macOS: the seeds were made with the macOS 11.3 SDK. `brew install llvm@21`
+gives clang and libclang; set `FINCH_CLANG`, `FINCH_LIBCLANG` and `FINCH_LLVM_INCLUDE` as the CI job does (the
+[technicians' guide](../docs/en/for-technicians.md#option-b-build-it-yourself) has the lines).
diff --git a/docs/en/cheatsheet.md b/docs/en/cheatsheet.md
index d27262c..615856d 100644
--- a/docs/en/cheatsheet.md
+++ b/docs/en/cheatsheet.md
@@ -21,8 +21,9 @@ Everything in Finch on one page. For explanations, see the [guides](../../README
| `finch version` | version |
| `-l lib` | link a C library (like `link "lib"`) |
| `--target windows` / `linux` / `arm64` / `macos` / `android` / triple | build for another system (`android`: the NDK's clang from `ANDROID_NDK_HOME`, usually with `--shared`) |
-| `-g` | debug info (gdb, lldb, Visual Studio) |
+| `-g` | debug info (gdb, lldb) |
| `-O0` | no optimizations |
+| `--cpu native` / `x86-64-v3` / `apple-m1` … | use every instruction of that processor (AVX2, AVX-512, NEON); the program then needs one like it |
| `--trace` / `--no-trace` | runtime errors show the chain of calls; on for `run`, `test`, `-g`, `-O0`, off for a plain `build` (it costs speed) |
Environment: `FINCH_PATH` (folders with modules), `FINCH_CC` (the C compiler that links), `FINCH_CXX` (for `.cpp` files).
@@ -39,6 +40,7 @@ links = ["SDL3", "native/glue.cpp"] # libraries and your own .c / .cpp / .o / .a
libdirs = ["vendor/SDL3/lib"]
cflags = ["-DFAST"] # for your .c / .cpp files
ldflags = ["-Wl,-rpath,."]
+cpu = "native" # the same as --cpu native
[target.windows] # only when building for that system (also linux, macos, android, linux-arm64)
links = ["ws2_32"]
@@ -96,6 +98,7 @@ One statement per line, no semicolons, `{` on the same line, no brackets around
| `[]T` | array: `[1, 2, 3]`, `[]str names` |
| `map[K]V` | map: `["a": 1]`, `map[str]int counts`, `[:]` |
| `ptr[T]`, `ptr` | pointer, untyped pointer |
+| `f32x8`, `i8x32`, `f64x4`, `u16x16` … | vector: N numbers worked on at once (SIMD), see below |
| `Name` / `module.Name` | a struct |
Escapes: `\n \t \r \0 \\ \" \'`.
@@ -240,6 +243,27 @@ Fallible built-ins: `int(s)`, `float(s)`, `read_file`, `write_file`, `delete_fil
---
+## Vectors `f32x8` (SIMD)
+
+Types: `f32x4/8/16`, `f64x2/4/8`, `i8x16/32/64`, `i16x8/16/32`, `i32x4/8/16`, `i64x2/4/8`, and `u…` the same; at most 512 bits.
+
+| Code | Gives |
+|---|---|
+| `f32x8(x)` | `x` in every lane |
+| `f32x8(a, b, …, h)` | one number per lane |
+| `f32x8(list, i)` | `list[i]` … `list[i+7]` (a `[]f32` or `ptr[f32]`) |
+| `f32x8(v)` | an 8-lane vector converted lane by lane (`f32x8(ints)`, `i32x8(floats)`) |
+| `v + w`, `v * 2.0`, `-v` | lane by lane; a plain number counts for every lane (`/` only on floats) |
+| `& \| ^ << >> ~` | lane by lane, whole-number lanes |
+| `v == w`, `v != w` | bool: every lane equal / not |
+| `v[i]`, `v[i] = x`, `v.len` | a lane; the number of lanes |
+| `min(v, w)`, `max`, `abs(v)`, `clamp(v, lo, hi)` | lane by lane |
+| `v.sum()`, `v.min()`, `v.max()`, `v.dot(w)` | one number from all the lanes |
+| `v.sqrt()`, `v.floor()`, `v.ceil()`, `v.round()`, `v.fma(b, c)` | every lane (float lanes; `fma` = `v * b + c`) |
+| `v.store(list, i)` | lanes into `list[i]` … |
+
+---
+
## Text `str`
| Code | Gives |
diff --git a/docs/en/for-beginners.md b/docs/en/for-beginners.md
index fd3bedc..935e0b6 100644
--- a/docs/en/for-beginners.md
+++ b/docs/en/for-beginners.md
@@ -53,8 +53,9 @@ The computer reads your program from top to bottom, line by line.
## 2. Getting Finch ready
-Finch runs on **Linux** computers. If a teacher, parent or friend has already set it up
-for you, skip to the next section.
+Finch runs on **Linux**, **macOS** and **Windows** computers. If a teacher, parent or friend has already set it up
+for you, skip to the next section. (On a Mac or on Windows, ask someone to follow the
+[guide for technicians](for-technicians.md#2-installing): it has a ready-made Finch for both.)
Otherwise, open the **Terminal** program (a window where you type commands) and type
these lines one by one, pressing **Enter** after each:
@@ -76,7 +77,7 @@ To check it works, type:
./build/finch version
```
-You should see something like `Finch 2.5.0`.
+You should see something like `Finch 2.6.0`.
---
diff --git a/docs/en/for-engineers.md b/docs/en/for-engineers.md
index 56ce0a9..e018e5a 100644
--- a/docs/en/for-engineers.md
+++ b/docs/en/for-engineers.md
@@ -1,13 +1,11 @@
# Finch for Engineers
-**The internals of Finch 2.5, whose compiler is written in Finch.** How source becomes tokens, an AST and LLVM IR *as text*,
+**The internals of Finch 2.6, whose compiler is written in Finch.** How source becomes tokens, an AST and LLVM IR *as text*,
which `clang` compiles and links with a small C runtime; how C headers are read with libclang from Finch itself and how
the C calling conventions are reproduced by hand; the type and ownership rules; how the compiler builds itself from a
seed; and the language server.
Assumed: you can read Finch (see the [technicians' guide](for-technicians.md)) and have at least seen LLVM IR.
-The compiler's first version, in C++ on LLVM's C++ API, is kept on the `before-bootstrap` branch; this guide describes
-the Finch one.
> 🇵🇱 Polska wersja: [dla-inzynierow.md](../pl/dla-inzynierow.md)
@@ -34,7 +32,7 @@ the Finch one.
## 1. Architecture
The compiler has no LLVM library inside it. It writes LLVM IR as **text** and lets `clang` do optimisation, code
-generation and linking. That is what makes it small (about 8k lines) and what lets it be written in Finch itself.
+generation and linking. That is what makes it small (about 12k lines) and what lets it be written in Finch itself.
```
main.fch ─► loader ── lex ── parse ──► Program (+ every imported module, recursively)
@@ -60,7 +58,7 @@ Design decisions that shape the rest:
Finch type (a string kind: `int`, `f32`, `str`, `array`, `map`, `struct`, `enum`, `named`…) and flags.
- **Let clang do the work.** Locals are `alloca`s promoted by `mem2reg`. Optimisation is clang's `-O2` (or `-O0` with `-g`).
- **Values, not references.** Arrays, strings and structs have value semantics; ownership is decided at compile time (§8).
-- **A tiny C runtime** (`runtime/finch_rt.c`, ~760 lines) does what is tedious in IR: strings, array growth, maps, input,
+- **A small C runtime** (`runtime/finch_rt.c`, ~1150 lines) does what is tedious in IR: strings, array growth, maps, input,
files, panics. It is compiled once and cached in `~/.cache/finch`.
---
@@ -70,17 +68,17 @@ Design decisions that shape the rest:
| File | Lines | Responsibility |
|---|---|---|
| `src/lexer.fch` | 470 | Tokens, positions, `"""` text, `"\(x)"` turned into `("…" + str(x) + "…")` tokens |
-| `src/ast.fch` | 120 | One `Node` struct with a `kind` string, children, type names, positions (`line`, `endLine`) |
+| `src/ast.fch` | 170 | One `Node` struct with a `kind` string, children, type names, positions (`line`, `endLine`) |
| `src/parser.fch` | 910 | Recursive descent: declarations, statements, expressions, generics (`[T]`), `enum`, `match`, `export`, `link`, `const`, `test "…" { }` |
-| `src/gen.fch` | 6450 | Type check + IR: structs, functions, methods, scopes and drops, statements, expressions, built-ins, maps, errors as values, generics (monomorphisation), enums and `match`, `-g` debug metadata, the `index` mode |
+| `src/gen.fch` | 7030 | Type check + IR: structs, functions, methods, scopes and drops, statements, expressions, built-ins, maps, errors as values, generics (monomorphisation), enums and `match`, vectors (SIMD), `-g` debug metadata, the `index` mode |
| `src/cimport.fch` | 790 | libclang: functions, structs and unions (fields, offsets, padding), enums, constants, globals, macros (also struct-valued) |
-| `src/platform.fch` | 90 | `Target`: triple, data layout, C compiler, signedness of `char` per system |
-| `src/linker.fch` | 430 | The cache (runtime, program object, C/C++ files), libraries (`link`, pkg-config), link-error advice |
-| `src/main.fch` | 515 | Driver: CLI, loader with module lookup and overlays, `build/run/test/fmt/ir/index/lsp` |
+| `src/platform.fch` | 120 | `Target`: triple, data layout, C compiler, signedness of `char` per system |
+| `src/linker.fch` | 480 | The cache (runtime, program object, C/C++ files), libraries (`link`, pkg-config), link-error advice |
+| `src/main.fch` | 530 | Driver: CLI, loader with module lookup and overlays, `build/run/test/fmt/ir/index/lsp` |
| `src/manifest.fch` | 240 | `finch.toml`: a small TOML reader, per-target lists |
| `src/fmt.fch` | 225 | `finch fmt` and LSP formatting |
-| `src/lsp.fch` | 910 | The language server (§11) |
-| `src/docs.fch` | 110 | One description of the built-ins, shared by hover and completion |
+| `src/lsp.fch` | 950 | The language server (§11) |
+| `src/docs.fch` | 140 | One description of the built-ins, shared by hover and completion |
| `std/*.fch` | 1040 | `json`, `path`, `time` (+`_windows`), `proc` (+`_windows`), `fs`, `thread` |
| `runtime/finch_rt.c` | 1150 | The C runtime: text, arrays, maps, files, float printing, fs, threads, the test runner, the call chain |
| `bootstrap/` | | `build.sh`, `install.sh`, the seeds (§10) |
@@ -168,6 +166,9 @@ offset 0, and a field is read through memory. They can't be passed by value to C
`ir` prints the IR; `index` prints the records the language server uses (§11); `--shared` makes a shared library of the
`export fn`s.
+`--cpu ` (or `cpu` in `finch.toml`) adds `-march=` on x86-64 or `-mcpu=` on ARM64 to the clang that
+compiles the IR (not the runtime); it is part of the cache key.
+
`--target windows|linux|arm64|macos|android|` changes the triple and data layout, the C `char` signedness, the ABI rules
above, the OS variant of modules (`name_windows.fch`), and the C compiler: `FINCH_CC` or `clang --target=…`. Linking
asks `pkg-config` for flags for `link "lib"`; when the linker fails the output is analysed and the likely missing
@@ -225,6 +226,7 @@ statement, so their shape (and the `"""` dedent) is kept.
| `map[K]V` | `{ ptr, i64, i64, i64, ptr, i64 }` (entries, len, used, cap, index, icap; see src/gen.fch) |
| `ptr`, `ptr[T]`, `null` | `ptr` (opaque) |
| `[N]T` | `[N x T]` |
+| `f32x8`, `i8x32`, … | `<8 x float>`, `<32 x i8>` (§7, Vectors) |
| Finch struct | named struct type, natural layout |
| a method's `self` | `ptr` (the first parameter) |
| the result of `-> T!` | `{ i1 ok, T value, str error }` (`i8` in place of `T` for `-> !`) |
@@ -235,11 +237,16 @@ Signedness lives only in the Finch type and selects `sdiv/udiv`, `ashr/lshr`, `i
### Values
-```cpp
-struct Value_ { Value *v; FType type; bool literal; bool fresh; };
+```c
+struct Val {
+ str v // the IR operand: %t12, 42, @.str.3, zeroinitializer
+ ast.Type ty
+ bool fresh
+ bool lit
+}
```
-- **`literal`**: a number written in the code or an imported C constant. It may become any integer type
+- **`lit`**: a number written in the code or an imported C constant. It may become any integer type
it fits (`fits()`), or `f32`. It survives unary minus and literal-only arithmetic that folds to a
constant; explicit conversions clear it (`u8(250)` is a typed constant, so `u8(250) + 10` wraps to 4).
- **`fresh`**: an owning value (str/array/owning struct) that nobody holds yet: the result of a call,
@@ -281,6 +288,38 @@ Pointers/null: `icmp eq/ne ptr` only. `str`: `finch_str_eq` (length + `memcmp`)
`finch_str_cmp` for ordering. Floats: `oeq olt ole ogt oge` and `une` for `!=`. Integers/char by
signedness (char unsigned). Bool: equality only. Arrays/structs: error.
+### Vectors
+
+`ast.vecType(name)` recognises `x` (lanes `i8`…`u64`, `f32`, `f64`; N = 2…64; at most 512 bits) and gives
+`Type(kind: "vec", elem: [lane], count: N)`, which is an LLVM vector ``. The parser takes such a name wherever a
+type goes; a call `f32x8(…)` goes to `vecMake()`.
+
+| Finch | IR |
+|---|---|
+| `f32x8(x)` | `insertelement` into lane 0 + `shufflevector … zeroinitializer` (a splat) |
+| `f32x8(a, …, h)` | a chain of `insertelement` |
+| `f32x8(list, i)` | bounds check of `i … i+7`, then `load <8 x float>, ptr …, align 4` (the lane's alignment) |
+| `f32x8(i32x8 v)` | `sitofp`, `fptosi`, `sext`, `trunc`… on the whole vector |
+| `v + w`, `v * 2.0` | `fadd`/`add`… on vectors; a scalar operand is coerced to the lane type, then splatted |
+| `v[i]` | a place: `getelementptr , ptr %v, i64 i` after a bounds check; or `extractelement` on a temporary |
+| `v == w` | `fcmp oeq`/`icmp eq` → `` → `llvm.vector.reduce.and` |
+| `min`, `max`, `abs` | `llvm.minnum`/`maxnum`, `llvm.smin`/`umin`…, `llvm.fabs`/`llvm.abs` |
+| `v.sum()`, `.min()`, `.max()` | `llvm.vector.reduce.fadd` (with `reassoc`), `.add`, `.fmin`, `.smin`… |
+| `v.sqrt()`, `.floor()`, `.ceil()`, `.round()` | the `llvm.*` intrinsic of that name |
+| `v.fma(b, c)` | `llvm.fmuladd` (fused where the target has FMA; `llvm.fma` would be a libm call per lane without it) |
+| `v.store(list, i)` | bounds check, `store <8 x float> …, align 4` |
+
+Integer `/` and `%` are refused: neither x86 nor ARM has a lane-wise integer divide, and LLVM would scalarise it.
+Ordering comparisons are refused because their result would be a mask, which has no Finch type.
+
+**Alignment.** LLVM gives `<8 x float>` an ABI alignment of 32 (its size), but `malloc` and Finch's `alloca … align 16`
+promise only 16. `llty()` records every vector wider than 16 bytes in `g.wide`, and `resolveStructBody` records a struct
+that holds one; `load()` and `store()` add `, align 16` for those types. Without it LLVM may emit `vmovaps` on a 16-byte
+aligned address and crash.
+
+**Which instructions** is clang's choice: `--cpu ` adds `-march=` (x86-64) or `-mcpu=` (ARM64) to the
+IR's compile, so the same IR becomes SSE2, AVX2 + FMA, AVX-512 or NEON code. Lanes wider than the registers are split.
+
---
---
@@ -428,8 +467,9 @@ and stops unless `finch1` and `finch` produce byte-identical IR (a fixpoint: the
whatever built it). `bootstrap/build.sh seed` rewrites the seed from the current compiler; do it whenever the compiler's
own source starts to use a feature the committed seed lacks.
-A seed is per system because the C calling convention for the libclang calls is baked into it (§5).
-Linux x86-64 and Linux ARM64 have seeds. macOS and Windows would need seeds made with Apple's and Microsoft's headers.
+A seed is per system because the C calling convention for the libclang calls is baked into it (§5). There are seeds
+for Linux x86-64 and ARM64, macOS ARM64 and x86-64 (made with Apple's SDK headers), and Windows x86-64 (made with
+llvm-mingw's headers). CI builds the compiler from each one on that system and runs the tests there.
---
@@ -518,13 +558,10 @@ evaluated twice and temporaries are never pointed to.
## 13. Known limitations
-- The compiler runs on Linux x86-64 and ARM64 only (no seed for macOS or Windows yet). Programs can be built for all three.
-- macOS output is only checked as IR; Windows and ARM64 are run under Wine and qemu in CI.
- One error per run, no recovery.
- `-g` debug info is best with `-O0`.
-- The driver uses `sh` utilities (`rm`, `mkdir`), so it needs a POSIX shell.
- Generics are monomorphised (code size grows with instantiations); there are no trait bounds, a wrong use is an error
inside the instantiated body.
- A failed test's owned memory is not freed (the test runner `longjmp`s out of it).
-- `--target android` is checked to the object file only; linking needs the NDK and has not been run on a device.
+- Vectors have no lane masks (`v < w`), shuffles or integer division.
diff --git a/docs/en/for-technicians.md b/docs/en/for-technicians.md
index 9e41283..712dea1 100644
--- a/docs/en/for-technicians.md
+++ b/docs/en/for-technicians.md
@@ -41,6 +41,7 @@ compiler works inside. For that, see the [guide for engineers](for-engineers.md)
28. [A project: finch.toml](#28-a-project-finchtoml)
29. [Threads](#29-threads)
30. [C++, Rust and Android](#30-c-rust-and-android)
+31. [Vectors (SIMD)](#31-vectors-simd)
---
@@ -67,19 +68,24 @@ messages that tell you how to fix the problem.
## 2. Installing
-The Finch compiler is written in Finch (see the [engineers' guide](for-engineers.md)). It runs on **Linux**
-(x86-64 and ARM64) and builds programs for **Linux, Windows and macOS**. It needs **clang 21** and **libclang**
-(LLVM 21) to read C headers and to compile its output.
+The Finch compiler is written in Finch (see the [engineers' guide](for-engineers.md)). It runs on **Linux** (x86-64 and
+ARM64), **macOS** (Apple Silicon and Intel) and **Windows** (x86-64), and builds programs for all of them. On every
+system it needs **clang** (it compiles each program with it) and **libclang** from LLVM 21 (it reads C headers with it).
-The compiler does not run on macOS or Windows yet; it needs a seed made with that system's headers
-([bootstrap/README.md](../../bootstrap/README.md) says why). Until then, build your Windows and macOS programs from Linux
-with `--target` (below), or use the older C++ compiler from the `before-bootstrap` branch.
+### Option A: a ready build
-### Option A: a ready build (Linux)
+Download the archive for your system from the [releases](https://github.com/Nexoniarz/Finch/releases) and unpack it.
+Keep `runtime/` and `std/` next to the `finch` file (or install it, below).
-Download `finch-linux-x64.tar.gz` or `finch-linux-arm64.tar.gz` from the
-[releases](https://github.com/Nexoniarz/Finch/releases) and unpack it. Keep `runtime/` and `std/` next to the `finch` file
-(or install it, below). You also need `clang` 21 and its libclang library:
+| System | Archive | Also install |
+|---|---|---|
+| Linux x86-64 | `finch-linux-x64.tar.gz` | clang 21 and libclang (table below) |
+| Linux ARM64 (Raspberry Pi 4/5, Graviton…) | `finch-linux-arm64.tar.gz` | the same |
+| macOS, Apple Silicon | `finch-macos-arm64.tar.gz` | `xcode-select --install` (clang and the system headers), `brew install llvm@21` (libclang) |
+| macOS, Intel | `finch-macos-x64.tar.gz` | the same |
+| Windows x64 | `finch-windows-x64.zip` (`finch.exe` with `libclang.dll`) | [llvm-mingw](https://github.com/mstorsjo/llvm-mingw/releases) (the `ucrt-x86_64` zip): unpack it and put its `bin` folder on your PATH |
+
+On Linux:
| Distribution | Packages |
|---|---|
@@ -88,12 +94,15 @@ Download `finch-linux-x64.tar.gz` or `finch-linux-arm64.tar.gz` from the
| Arch | `clang pkgconf` |
| Nix | `nix-shell` in the repository gives all of it |
+On Windows, llvm-mingw gives Finch `clang`, the C headers and the linker in one folder; Windows programs built with it
+need nothing else to run. Keep `libclang.dll` next to `finch.exe`.
+
### Option B: build it yourself
```sh
git clone https://github.com/Nexoniarz/Finch.git
cd Finch
-nix-shell # clang, libclang, pkg-config (or install them with your distribution)
+nix-shell # Linux: clang, libclang, pkg-config (or install them with your distribution)
bootstrap/build.sh # build/finch
./build/finch version
```
@@ -102,6 +111,26 @@ bootstrap/build.sh # build/finch
`src/` with it, builds `src/` again with the result and checks the two are identical. If libclang isn't where the linker
looks, tell it: `FINCH_LIBCLANG="-L/usr/lib/llvm-21/lib -lclang-21" bootstrap/build.sh`.
+On a Mac, with Homebrew's LLVM:
+
+```sh
+brew install llvm@21
+export FINCH_CLANG="$(brew --prefix llvm@21)/bin/clang"
+export FINCH_LIBCLANG="-L$(brew --prefix llvm@21)/lib -lclang"
+export FINCH_LLVM_INCLUDE="$(brew --prefix llvm@21)/include"
+bootstrap/build.sh
+```
+
+On Windows, in Git Bash, with llvm-mingw on the PATH and the official LLVM for Windows (for `libclang.dll` and its headers)
+unpacked to `C:/llvm`:
+
+```sh
+export FINCH_LIBCLANG="C:/llvm/bin/libclang.dll"
+export FINCH_LLVM_INCLUDE="C:/llvm/include"
+export FINCH_LDFLAGS="-LC:/llvm/bin"
+bootstrap/build.sh # build/finch.exe, with libclang.dll copied next to it
+```
+
### Building for another system
`--target` builds a program for another system. Finch needs that system's C compiler to link:
@@ -151,7 +180,9 @@ options:
-l link a C library, same as link "lib" in the file
-I look for C headers there too
--target build for another system: windows, linux, arm64, macos, android, or an LLVM triple
- -g add debug info (for gdb / lldb / Visual Studio)
+ --cpu use every instruction of a processor: native (this one), x86-64-v3 (AVX2),
+ x86-64-v4 (AVX-512), apple-m1, ... (section 31)
+ -g add debug info (for gdb and lldb)
-O0 skip optimizations
--trace runtime errors show the chain of calls (on anyway for run, test, -g and -O0)
--no-trace they don't (a plain finch build doesn't: keeping the chain makes calls slower)
@@ -946,8 +977,7 @@ gdb ./game
```
`-g` adds debug info (lines, functions, variables, struct fields). `-O0` keeps every variable
-visible; without it the optimizer may remove some. On Windows, `-g` writes CodeView, which the
-Visual Studio debugger and WinDbg read.
+visible; without it the optimizer may remove some. On Windows the debug info is DWARF as well: use the `lldb` that comes with llvm-mingw, or gdb.
---
@@ -959,10 +989,11 @@ Visual Studio debugger and WinDbg read.
| `… come from "x.h", but its library isn't linked` | Add `link "name"` at the top of the file. |
| `the library 'x' wasn't found` | Not installed, or a wrong name. On Nix, add it to `shell.nix` and run inside `nix-shell`. |
| `the C function 'f' can't be used from Finch yet` | It uses a union, bit fields or another unsupported type by value. Look for a variant that takes pointers. |
+| `--cpu native`: the program stops with `Illegal instruction` on another computer | It was built for the processor that built it. Build without `--cpu`, or with an older one (`x86-64-v2`). |
| `can't find the module 'x'` | Put `x.fch` next to the importing file, or set `FINCH_PATH`. |
| `couldn't build the Finch runtime` | No working C compiler. Install gcc or clang, or set `CC`. |
| A library is not found when the program starts | It was linked from a folder the system doesn't search. Run inside the same `nix-shell`, or install it system-wide. |
-| Windows: `finch` can't link (`LNK…` errors about `libcmt`, `kernel32`) | Install Visual Studio Build Tools with *Desktop development with C++*. |
+| Windows: `no C compiler found to link with ('clang')` | Put llvm-mingw's `bin` folder on your PATH (section 2). |
| Windows: `finch.exe` doesn't start (missing `libclang.dll`) | Keep `libclang.dll` next to `finch.exe`. |
| macOS: `finch` doesn't start (`Library not loaded: …libLLVM…`) | `brew install llvm@21`. |
| macOS: `can't find the C header 'stdio.h'` | Install the command line tools: `xcode-select --install`. |
@@ -1134,7 +1165,7 @@ Not there yet:
- Interfaces.
- Unicode-aware text: `.len`, `s[i]` and `upper()` work on bytes / ASCII.
- Checks that stop two threads from changing the same array at once (use a mutex).
-- Windows on ARM64, 32-bit systems, WebAssembly. `--target android` makes code for Android, but linking with the NDK and running on a device are untried.
+- Windows on ARM64, 32-bit systems, WebAssembly.
### Warnings about big copies
@@ -1193,6 +1224,7 @@ links = ["SDL3", "native/glue.cpp"] # libraries, and your own .c / .cpp / .o /
libdirs = ["vendor/SDL3/lib"] # folders with libraries
cflags = ["-DFAST"] # for your .c / .cpp files
ldflags = ["-Wl,-rpath,$ORIGIN"] # for the linker
+cpu = "native" # the same as --cpu native (section 31)
[target.windows] # added only when building for Windows
links = ["ws2_32"]
@@ -1292,6 +1324,82 @@ Write the header (`float path_len(float x, float y);`, or let `cbindgen` write i
**Android**: `finch build game.fch --target android --shared` makes `libgame.so` for 64-bit ARM Android (API 24 and
up) with the NDK's clang, found through `ANDROID_NDK_HOME` (or `FINCH_CC`). Load it from an app, for example through
-SDL3's Android project (the library's `SDL_main` is an `export fn`). This is new and only partly checked: Finch's
-output compiles for Android (thread-local data goes through the emulated TLS older Android needs), but linking with the
-NDK and running on a device have not been tried yet.
+SDL3's Android project (the library's `SDL_main` is an `export fn`). Thread-local data goes through the emulated TLS
+that older Android versions need.
+
+---
+
+## 31. Vectors (SIMD)
+
+A processor can add or multiply several numbers with one instruction: 4 floats at once with SSE, 8 with AVX2, 16 with
+AVX-512, 4 with ARM's NEON. That is SIMD (single instruction, multiple data), and it is how image filters, audio, physics
+and neural networks get their speed. In Finch it is a type: **`f32x8` is 8 `f32` side by side**.
+
+```c
+a := f32x4(1.0, 2.0, 3.0, 4.0)
+b := f32x4(0.5) // 0.5 in every lane
+print(a + b) // f32x4(1.5, 2.5, 3.5, 4.5)
+print(a * 2.0) // a plain number counts for every lane: f32x4(2, 4, 6, 8)
+print(a.sum(), a[2], a.len) // 10 3 4
+```
+
+**The types** are a number type, `x`, and how many lanes: `f32x4` `f32x8` `f32x16`, `f64x2` `f64x4` `f64x8`,
+`i8x16` `i8x32` `i8x64`, `i16x8` `i16x16`, `i32x4` `i32x8` `i32x16`, `i64x2` `i64x4`, and the same with `u` (unsigned).
+2 to 64 lanes, at most 512 bits in all. A vector is a plain value like an `int`: it goes into variables, struct fields,
+arrays, maps and function parameters, and `print` and `str` show it.
+
+**Making one:**
+
+| | |
+|---|---|
+| `f32x8(x)` | `x` in every lane |
+| `f32x8(a, b, c, d, e, f, g, h)` | one number per lane |
+| `f32x8(list, i)` | `list[i]` … `list[i+7]` from a `[]f32` (or through a `ptr[f32]`); stops the program if they aren't all in the list |
+| `f32x8(v)` | another 8-lane vector converted lane by lane: `f32x8(ints)`, `i32x8(floats)` (cuts the fractions), `i16x8(i32s)` |
+
+**Working with it:**
+
+| | |
+|---|---|
+| `+ - * /` | lane by lane (`/` on floats only: x86 and ARM can't divide whole numbers lane by lane) |
+| `& \| ^ << >> ~` | lane by lane, on whole-number lanes |
+| `-v` | every lane negated |
+| `v == w`, `v != w` | `true` if every lane is equal / if any differs |
+| `v[i]`, `v[i] = x`, `v.len` | one lane; the number of lanes |
+| `min(v, w)`, `max(v, w)`, `abs(v)`, `clamp(v, lo, hi)` | lane by lane; `lo`, `hi` and `w` can be plain numbers |
+| `v.sum()`, `v.min()`, `v.max()` | all the lanes made into one number |
+| `v.dot(w)` | `(v * w).sum()` |
+| `v.sqrt()`, `v.floor()`, `v.ceil()`, `v.round()` | every lane (float lanes) |
+| `v.fma(b, c)` | `v * b + c`, as one instruction where the processor has one |
+| `v.store(list, i)` | writes the lanes to `list[i]` … (or through a `ptr`) |
+
+`<` and the other comparisons would give an answer per lane, so they aren't there; use `min`, `max` or `v[i] < w[i]`.
+
+**A real loop.** The usual shape: as many whole vectors as fit, then the rest one by one.
+
+```c
+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
+}
+```
+
+`examples/simd.fch` times this against the plain loop.
+
+**Which instructions.** By default a program runs on every processor of its system (on x86-64 that means SSE2, so an
+`f32x8` is done as two halves). `--cpu native` (or `cpu = "native"` in `finch.toml`) lets LLVM use everything the processor
+that builds it has: AVX2 and FMA, AVX-512, or NEON's newer parts on ARM. Such a program needs a processor like that one to
+run. To pick a level instead: `--cpu x86-64-v3` (AVX2, most PCs since 2015), `--cpu x86-64-v4` (AVX-512), `--cpu apple-m1`.
+
+Lanes wider than the processor's registers are split by LLVM, and the same code builds for x86-64 and ARM64 alike.
+`v.sum()` on float lanes adds them in whatever order is fastest, so the last digits can differ from adding them one by one.
diff --git a/examples/simd.fch b/examples/simd.fch
new file mode 100644
index 0000000..691227f
--- /dev/null
+++ b/examples/simd.fch
@@ -0,0 +1,69 @@
+// 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)
+}
diff --git a/runtime/finch_rt.c b/runtime/finch_rt.c
index ab806a3..e9a63fb 100644
--- a/runtime/finch_rt.c
+++ b/runtime/finch_rt.c
@@ -2,7 +2,7 @@
// It is embedded in the compiler, compiled once into a cache folder, and linked
// statically into every Finch program. Everything here is plain C with no state.
//
-// Layout shared with the compiler (src/codegen.cpp):
+// Layout shared with the compiler (src/gen.fch):
// str = { char *ptr; int64 len; int64 cap } ptr is always NUL-terminated
// cap > 0 : heap memory owned by the value (cap bytes allocated)
// cap == 0 : a string literal, valid forever, never written to
diff --git a/src/cimport.fch b/src/cimport.fch
index 8d1701f..5d8fa14 100644
--- a/src/cimport.fch
+++ b/src/cimport.fch
@@ -1,10 +1,9 @@
// C headers, read through libclang, written in Finch.
//
// What `import "stdio.h"` teaches the compiler: the C functions, the constants (enum values and
-// plain #define numbers), the extern variables (stdout) and the structs. The same job as
-// src/cimport.cpp, done by calling libclang's C API through Finch's own C import -- which is
-// what makes this the part that closes the bootstrap: to compile this file the self-hosted
-// compiler has to read libclang's headers with this very code.
+// plain #define numbers), the extern variables (stdout) and the structs. It calls libclang's C API
+// through Finch's own C import -- so to compile this file, the compiler reads libclang's headers
+// with this very code.
//
// C structs by value appear in types as the named type `module "C"`.
import ast
diff --git a/src/docs.fch b/src/docs.fch
index 04dc13e..271660a 100644
--- a/src/docs.fch
+++ b/src/docs.fch
@@ -107,7 +107,7 @@ fn vecMethods() -> []Doc {
doc("ceil", "ceil() -> V", "Every lane rounded up (f32/f64 lanes)."),
doc("round", "round() -> V", "Every lane rounded to the nearest whole number, halves away from 0 (f32/f64 lanes)."),
doc("abs", "abs() -> V", "Every lane without its minus sign."),
- doc("fma", "fma(V b, V c) -> V", "v * b + c in one step, with one rounding (f32/f64 lanes)."),
+ doc("fma", "fma(V b, V c) -> V", "v * b + c, as one instruction where the processor has one (f32/f64 lanes)."),
doc("store", "store([]T list, int i)", "Writes the lanes into list[i], list[i+1], ... (or through a ptr[T]).")
]
}
diff --git a/src/gen.fch b/src/gen.fch
index 7aba27c..d3b3eb3 100644
--- a/src/gen.fch
+++ b/src/gen.fch
@@ -1,8 +1,7 @@
// Type checking and LLVM IR generation (as text), written in Finch.
//
-// The output is a .ll file that clang turns into a program, linked with the same
-// C runtime the main compiler uses. This compiler copies values like the main one
-// (so programs behave the same) but never frees them: it is the bootstrap compiler.
+// The output is a .ll file that clang turns into a program, linked with Finch's C runtime
+// (runtime/finch_rt.c). Values are copied when assigned and freed when their block ends.
import ast
import docs
import cimport
@@ -477,7 +476,7 @@ fn T(str kind) -> ast.Type {
return ast.simple(kind)
}
-// `int` is i64 and `float` is f64, as in the C++ compiler: the everyday names
+// `int` is i64 and `float` is f64: the everyday names
// for the two default sizes, and the only way they are ever written back.
fn isSigned(ast.Type t) -> bool {
k := t.kind
@@ -4642,11 +4641,12 @@ fn convert(ptr[Gen] g, ast.Node c, ast.Type to) -> Val {
return v
}
-// ---------- the C calling convention for structs passed by value (System V x86-64) ----------
+// ---------- the C calling convention for structs passed by value ----------
//
-// A struct of up to 16 bytes travels in registers, one INTEGER or SSE class per eightbyte;
+// System V x86-64: a struct of up to 16 bytes travels in registers, one INTEGER or SSE class per eightbyte;
// bigger ones are copied to the stack (byval) and returned through a hidden pointer (sret).
-// Other targets (Windows, ARM64) have their own rules and are not done here yet.
+// ARM64 (AAPCS64, and Apple's variant) and Windows x64 have their own rules: classifyArm64, and the
+// windows branch of classify.
struct Abi {
str kind // "direct", "expand" (in registers: `parts`) or "memory"
@@ -6992,7 +6992,9 @@ fn vecMethod(ptr[Gen] g, ast.Node m, Val v) -> Val {
need(g, m, 2)
b := asVec(g, expr(g, m.kids[1]), vt, "fma", m.kids[1])
c := asVec(g, expr(g, m.kids[2]), vt, "fma", m.kids[2])
- return Val(v: vecIntrinsic(g, lt, "fma", vt, [lt, lt, lt], [v.v, b.v, c.v], ""), ty: vt)
+ // fmuladd: one fused instruction where the processor has one (FMA, NEON), a multiply and an add where
+ // it doesn't (llvm.fma would call a slow library function there, to round only once)
+ return Val(v: vecIntrinsic(g, lt, "fmuladd", vt, [lt, lt, lt], [v.v, b.v, c.v], ""), ty: vt)
}
need(g, m, 0)
return Val(v: vecIntrinsic(g, lt, n, vt, [lt], [v.v], ""), ty: vt)
diff --git a/src/main.fch b/src/main.fch
index 7c59c14..8bf35bd 100644
--- a/src/main.fch
+++ b/src/main.fch
@@ -1,7 +1,4 @@
-// finch-boot: the Finch compiler written in Finch.
-//
-// finch-boot build [-o name] compile a program
-// finch-boot ir print the LLVM IR
+// finch: the Finch compiler, written in Finch (`finch` with no arguments lists the commands).
//
// It reads the program and the modules it imports, checks it, writes LLVM IR as text
// and lets clang turn that into a program, linked with Finch's C runtime.
diff --git a/src/platform.fch b/src/platform.fch
index 44a678f..2cbb0c2 100644
--- a/src/platform.fch
+++ b/src/platform.fch
@@ -1,6 +1,5 @@
// The system a program is built for, and what depends on it: the C compiler that links, the file
// name of the program, how it is run here, and (through the flags) the C calling convention.
-// The same as src/target.cpp.
import host
import "stdlib.h"