Repository navigation
Releases: brinelang/brine
Release list
brine 0.6.0
Added
- Reading input:
input()/input(prompt)returns the next line of stdin as an
Option[str](Noneat its end) andread_stdin()all of it. Binary files:
os.read_bytes(path)andos.append_bytes, andstr.from_utf8(bytes)checks
and converts.append_file(path, text)appends without rewriting the file. - Parsing that doesn't panic:
s.to_int()ands.to_float()return anOption
(s.to_int[u8]()for other widths).int()andfloat()accept_between
digits, like literals. - Math:
asin,acos,atan,atan2,sinh,cosh,tanh,exp2,log2,
log10,cbrtandhypot, onfloatandf32;powonf32. Float bits:
x.to_bits(),float.from_bits(u),f32.from_bits(u). - Integer methods:
wrapping_add,wrapping_sub,wrapping_mul,wrapping_neg,
rotate_left,rotate_right,count_ones,leading_zerosand
trailing_zeros. Compound assignments&=,|=,^=,<<=and>>=. A
literal takes the type it's converted to (u64(0xcbf29ce484222325)). s.find(sub, start)andxs.index(x, start);xs + ysandxs += ysjoin
arrays;s * nrepeats a string.- Format specs
{x:g}and thousands separators{n:,}(also{x:>12,.2f}). flush(), andos.thread_count()(the threadsparuses).- Ordering:
<,<=,>,>=compare tuples and structs part by part and enums
without data in declaration order, sosort(),min/maxand
min(... for ...)work on them. - Constants: array constants (
const TABLE = [1, 2, 3]),case NAME:matches a
constant's value, and enums without data convert to and fromint
(int(color),Color.from_int(i)returns anOption). - Syntax: multi-line strings (
"""...""", also f-strings), string literals inside
f-string fields (f"{d["k"]}"), names bound in|patterns
(case A(x) | B(x):), tuple assignment (a, b = b, a % b),T(x)in generic
code, andtestandcaseas ordinary names outside their statements. import ..libimports from the parent directory (one.per level), and
from b import Thingtakes a namebimported itself.let t = ref self.fieldnames a field; different fields of one value can be
passed as separaterefarguments, and nested calls liket.f(t.g(x))are
allowed when their order is fixed by the data.mainmay returnResult[int, E]:Ok(n)exits withn.first(...)andpar first(...): the lowest-indexSomeof a generator of
options, the same at every thread count;par firststops the work after a hit.par formay writeout[k * i + c](constantsk >= 1andc, all writes of
outwith the samek), so red-black and strided sweeps run in place.- GPU: 128-bit integer code runs in CUDA kernels.
externfunctions can takestrarguments (C gets a NUL-terminated copy).world:world.any/world.all, arraysum/min/max, edge shifts and
narrow numeric messages.brine teststops a test that runs longer than--timeout(300 s by default);
# fmt: off/# fmt: onkeep lines as written;--help/-hon every command.
Changed
- Breaking:
par for x in xs: out[x] = ...is rejected: the elements ofxs
may repeat, so two iterations could write the same element at the same time.
Loop over a range instead (par for i in 0..len(xs)). - Breaking: a
parbody can't call a function that writes files, runs
processes or reads stdin, however deep the call (these were only caught when
written in the body itself). Do the effect before or after thepar. - Breaking: the
worlddeadlock checker is now sound: it rejects programs it
used to accept that could hang, such as a collective in anassertmessage, an
exit()under a rank-dependent condition, or a builtin result used as if it
were the same on every rank. It also accepts more correct programs: it follows
values through assignments and tracks tuple elements, struct fields and array
lengths separately. - Breaking: the prover no longer accepts several false claims: what a
whilecondition or a mutating array method changes, effects of branches,
comprehension bodies and loop invariants are now modeled. Fix theprove,
requires/ensuresor invariant it reports, or add a runtimeassert. - A rank removes
BRINE_RANK,BRINE_WORLD_SIZEandBRINE_PEERSfrom its
environment after reading them, so programs it starts don't join its world.
Useworld.rank()instead of reading the variable. brine fmtbreaks long lines at operators and inside nested brackets, so
fmt --checkmay ask to reformat files formatted by 0.5.- stdout is written line by line to terminals and pipes (still buffered to
files), so line protocols over pipes work. sin,exp,powand the other math functions give the same bits on every
target (musl's code is built in), and generated C is compiled with
-ffp-contract=off, so float results no longer depend on the C compiler.- The prover knows more: bounds of products, remainders, bit operations, shifts
and bit counts, lengths ofxs + ysands * n, ranges of literal arrays, and
loops and calls forget only the fields they change. It is much faster on
branchy loops (1.45 s to 0.01 s on one test), says when it gave up instead of
"not proven", and its notes show only the parts of a claim it couldn't prove. - Faster code:
- Small enums that can't contain themselves (
Option[int],Result, small
payloads) are stored in place instead of in heap boxes. for x in xs, returning part of a parameter,let/varcopies of fields,
x = f(x),out[i] = f(out[i])in apar for, and the take idiom borrow or
move instead of copying.- Release builds check
a[j + x]once before a loop that calls no
functions instead of every iteration, so C compilers vectorize it (ikj
matmul: 31 to 74 GFLOP/s). - Reference counts use plain instructions while no other thread runs.
- Small local
[x] * narrays live in the stack frame. - x86-64 dev builds share registers, use jump tables for
matchand inline
small functions (a ray tracer: 113 s to 45 s). par sumover a few expensive elements uses all the threads;par anyand
par allstop starting work once the answer is known.- A GPU
par forno longer uploads arrays it only writes; with--ranks, the
k-th rank on a machine uses its k-th GPU. worldcollectives take log2(ranks) rounds (sum at 8 ranks: 133 to 51 us),
and each rank gets its share of the cores instead of all of them. A float
world.sumadds in a tree: still the same on every run, but its last digits
can differ from 0.5's rank-by-rank sum.- WebAssembly builds use SIMD.
- Small enums that can't contain themselves (
Fixed
- Crashes in
brine runandbrine testare reported with the reason instead of
exit code 0; a stack overflow is a panic,mainhas a 64 MB stack, and freeing
a deep structure no longer overflows the stack. worldmessages carry their call, so mismatched collectives panic with both
call sites; a failing rank is named, and only the first panic is shown.- GPU kernels were rejected as "using a global" when they used stack slots; the
GPU log now gives the exact reason a construct stays on the CPU. - A string slice that cuts a character in two panics;
unwrap()on anErr
shows the error;nanandinfprint the same everywhere. - By-value arguments that the same call changes through a
refare copied first. - The smallest
i128literal is accepted. - A call's other arguments can't change what one of its
refarguments refers
to, even inside a comprehension (E0405):f(ref xs[0], sum(g(ref xs) for ...))
passed checks and brokef's precondition at run time. - WebAssembly programs run on a worker thread with a 256 MB stack, so deep
recursion works as natively, and--target webprograms run in a Web Worker. - Many error messages: operators not defined for a type, unclosed strings (one
error instead of a cascade), imports (where they looked), and help that
suggested code which would have changed the program.
Install
Linux and macOS:
curl -fsSL https://raw.githubusercontent.com/brinelang/brine/main/install.sh | shWindows (PowerShell):
irm https://raw.githubusercontent.com/brinelang/brine/main/install.ps1 | iexbrine needs a C compiler (gcc or clang; MinGW on Windows): run brine doctor to check.
To install this version rather than the latest, set BRINE_VERSION=0.6.0 first. The
archives below are checked against SHA256SUMS by the installers, and each has a
build provenance attestation (gh attestation verify <file> -R brinelang/brine).
Full changelog: v0.5.1...v0.6.0
brine 0.5.1
Fixed
- WebAssembly modules no longer carry the debug info of wasi-sdk's C library, which
was most of their size: a release hello world goes from 398 KB to 36 KB, so pages
that load brine programs download about a tenth as much.--debugbuilds keep it.
Install
Linux and macOS:
curl -fsSL https://raw.githubusercontent.com/brinelang/brine/main/install.sh | shWindows (PowerShell):
irm https://raw.githubusercontent.com/brinelang/brine/main/install.ps1 | iexbrine needs a C compiler (gcc or clang; MinGW on Windows): run brine doctor to check.
To install this version rather than the latest, set BRINE_VERSION=0.5.1 first. The
archives below are checked against SHA256SUMS by the installers, and each has a
build provenance attestation (gh attestation verify <file> -R brinelang/brine).
Full changelog: v0.5.0...v0.5.1
brine 0.5.0
Added
- WebAssembly:
brine build --target wasmmakes a WASI module (wasm32-wasip1) and
brine build --target webmakes a folder for the browser (the module, a small
loaderbrine.jsand a starter page that rebuilds keep).brine runand
brine testrun WASI modules with Node.js, or with$BRINE_WASM_RUNNER. It needs
wasi-sdk (WASI_SDK_PATH). On WebAssembly programs run on one thread and one
worldrank (parruns in order with the same results); processes, sockets and
the GPU fail with a clear message, and the browser has no files.
Changed
- Much faster release builds: on the benchmarks,
--releasenow takes 0.28x to
0.67x C's time (gcc -O2) on seven of eight programs, and ties C on wordfreq.
Output and panics are unchanged; every fast path checks its conditions at run
time or falls back to the code as written.- x86-64 release programs carry plain, AVX2 (x86-64-v3) and AVX-512 (x86-64-v4)
copies and pick the newest one the CPU supports, so executables still run on
any x86-64 machine.BRINE_CPU=baseorv3caps the level. - The prover removes more overflow checks: compound assignments (
i += 1) and
loop counters. - Loops whose inputs are small run a copy without overflow checks, so C
compilers vectorize them. - Independent loop iterations run four at a time (mandelbrot: 0.59 s to 0.43 s).
- Local
[bool]arrays are kept as bits and small integer arrays as bytes;
reverse, rotate and copy loops run as one operation (fannkuch: 1.6 s to
0.96 s). - Small fixed-size float array loops run as vector kernels with bit-identical
results (nbody: 0.71 s to 0.49 s). - Faster strings and maps: inlined map lookups, one lookup for
if k in m: m[k] += v, in-place byte appends fors += t[i], and string
buffers reused across loop iterations (wordfreq: 77.6 ms to 17.6 ms).
- x86-64 release programs carry plain, AVX2 (x86-64-v3) and AVX-512 (x86-64-v4)
- Programs start 2 ms faster on Windows (3.0 ms for an empty program, from 5.0 ms).
BRINE_LEAKCHECKis the only thing that counts live objects now, so allocation
no longer pays for a locked counter.
Fixed
brine testreported zero tests and success when listing the tests failed.
Install
Linux and macOS:
curl -fsSL https://raw.githubusercontent.com/brinelang/brine/main/install.sh | shWindows (PowerShell):
irm https://raw.githubusercontent.com/brinelang/brine/main/install.ps1 | iexbrine needs a C compiler (gcc or clang; MinGW on Windows): run brine doctor to check.
To install this version rather than the latest, set BRINE_VERSION=0.5.0 first. The
archives below are checked against SHA256SUMS by the installers, and each has a
build provenance attestation (gh attestation verify <file> -R brinelang/brine).
Full changelog: v0.4.0...v0.5.0
brine 0.4.0
Added
par for,par [...]maps andparreductions run on the GPU when that's
faster: NVIDIA GPUs through CUDA (Windows and Linux) and Apple GPUs (M1 and later)
through Metal. Bodies that only compute qualify (arithmetic, comparisons,
branches, loops, reads of plain data and arrays, calls to such functions), and
nothing changes in the source. Results are bit-identical to the CPU's; a check
that fails on the device reruns the construct on the CPU, which panics as usual.
The GPU driver is loaded when the program runs, so there's nothing to install or
link.BRINE_GPU=off|on|autopicks the policy andBRINE_GPU_LOG=1prints where
each construct ran and why.- A native AArch64 backend for Linux: dev and debug builds on 64-bit ARM Linux go
straight to machine code, as on x86-64. - Native debug builds:
--debugon Windows and Linux carries DWARF line and
variable info, so gdb and lldb break atfile.br:lineor a brine function, step
through brine lines and show locals by their brine names and types. brine debugshows values the way brine prints them ("hello",[1, 2, 3],
Some(5)) when gdb has Python, and steps over the runtime.- Release builds on GitHub for Linux (x64, arm64), macOS (arm64, x64) and Windows
(x64), with checksums and build provenance, and one-line installers:
curl -fsSL https://raw.githubusercontent.com/brinelang/brine/main/install.sh | sh
andirm https://raw.githubusercontent.com/brinelang/brine/main/install.ps1 | iex. examples/find_signal.br: a GPS signal search whose indexing is proved safe and
whose search runs on the GPU.
Changed
- Breaking:
parreductions combine their elements in a fixed order: leaves of
16 consecutive elements, each folded left to right, then a balanced tree. The
result is the same for any thread count and on the GPU.par sumand
par productof floats can differ from 0.3.0 in the last bits (usually closer to
the exact result), and whether an integerpar sumorpar productoverflows is
decided by the new order. Programs that need the old bits must sum sequentially. - Faster native code: local variables and floats live in registers (dev builds of
nbody go from 7.96x C's time to 3.45x, spectral norm from 6.54x to 2.05x). - Loops that index a local array load it once and make it unique before the loop,
so C compilers vectorize them (matrix multiply: 8.7x C's time to 1.0x). - Faster strings:
s += tgrows a string in place ands[i]is inlined. - Faster allocation: small blocks come from brine's own allocator, and a value with
one reference is freed without an atomic instruction (binary-trees on Windows:
1.67x C's time to 0.67x). - Parallel regions start and end without a lock, so short regions no longer slow
down as threads are added. - Division and remainder by a constant power of two compile to a shift and a mask.
matchon aletvariable or a by-value parameter no longer retains and
releases each value it visits.
Fixed
- Programs failed to link on AArch64 Linux when clang was the C compiler (missing
__muloti4). - Float
minandmaxof-0.0and0.0gave different results on different
platforms;minnow treats-0.0as the smaller. - A panic's message could interleave with what other threads printed.
- The build cache could reuse an object built against an older runtime header,
which then failed to link. - A
BRINE_BACKENDbuild could replace a default build's executable while it ran. brine run --ranks Nlistened on every network interface, so Windows asked to
let each new build through the firewall; with every rank on this machine it
listens on loopback.
Install
Linux and macOS:
curl -fsSL https://raw.githubusercontent.com/brinelang/brine/main/install.sh | shWindows (PowerShell):
irm https://raw.githubusercontent.com/brinelang/brine/main/install.ps1 | iexbrine needs a C compiler (gcc or clang; MinGW on Windows): run brine doctor to check.
To install this version rather than the latest, set BRINE_VERSION=0.4.0 first. The
archives below are checked against SHA256SUMS by the installers, and each has a
build provenance attestation (gh attestation verify <file> -R brinelang/brine).
Full changelog: v0.3.0...v0.4.0