Repository navigation
Releases: rynlanguage/Ryn
Release list
Ryn 0.1.13: registers, AArch64, variadic C calls
Native language fixes (2026-10-13): the Windows ZIP and its SHA-256 were rebuilt from commit d7ef69b. Custom-destructor resources can be moved into enum payloads, propagated with ? and extracted with unwrap/expect/unwrap_err without duplicate handles or destruction. Integer as char validates Unicode scalars without truncation. Map() infers key/value types from annotations and structure fields. use module::PublicItem imports public types/functions/aliases. Checking a source file discovers its enclosing manifest and resolves path dependencies relative to it; Windows CLI path separators are normalized. Includes all previous keyboard/thread/mutex and FFI fixes. Verified on Windows: 26 tests, including six existing ownership programs and packaged check/build/run, and byte-identical compiler bootstrap stages. The Linux assets and release tag are unchanged.
Windows threads and mutexes (2026-10-13): the Windows ZIP and its SHA-256 were rebuilt from commit f0bb305. std::thread::Thread now supports spawn/id/join/drop; std::sync::Mutex, MutexGuard and lock_raw use exclusive non-recursive SRW locks. The Windows allocator serializes parallel malloc/free. Includes the keyboard hotfix and all previous FFI fixes. std::sync::JoinHandle, RwLock, Condvar, Barrier, Once and Local remain Linux-only. Verified on Windows: eleven regression tests including packaged check/build/run, and byte-identical compiler bootstrap stages. The Linux assets and release tag are unchanged.
Windows keyboard hotfix (2026-10-13): the Windows ZIP and its SHA-256 were rebuilt from commit c1f72f6. std::keyboard now supports continuous key state, pressed/released edges and read_key through user32.dll, fixing R0905 (opendir). Includes all previous FFI fixes. Verified on Windows: five regression tests including packaged check/build/run, and byte-identical compiler bootstrap stages. The Linux assets and release tag are unchanged.
Updated: this release now also includes pointers to array elements and C strings for FFI: &array[index] of a local integer or bool array passed to an extern "C" function, and std::cstring::CString for str as a NUL-terminated C string. Also includes the earlier fixes (unknown type and enum diagnostics, and passing &local to pointer parameters). The archives were rebuilt from commit e8321af.
Updated: this release now includes the fixes for unknown types and enums (R0230 / R0233 with the name and location) and for passing a local by reference to a pointer parameter of an extern "C" function (for example time(&value), also through a function pointer from load_symbol). The archives were rebuilt from commit de03ba2.
Updated: this release now includes the fix for unknown types and enums (R0230 / R0233 with the name and location instead of the generic unsupported error). The archives were rebuilt from commit cfccd66.
Released together with the work of 0.1.11 and 0.1.12, which had no separate release.
extern "C" fun printf(format: *u8, ...) -> i32;:...after the named parameters of anextern "C"function. Call
it with any number of variable arguments: integers of any width,f64and raw pointers are passed as they are; an
f32(R0270, writeas f64), a string or a structure is rejected. The native backend setsalto the number of
vector registers in use before each C call, as the System V convention requires. Variadic calls on Windows are
rejected....in a non-extern "C"function isR0010. Tests:tests/suite/ffi/variadic_*.- The function-record encoding carries a
variadicflag (parser, AST and generics). - Documentation:
docs/language-0.2.mdreplaces the old "cannot be declared" limitation. - x86-64 encoder (
selfhost/src/back/x64.ryn): EVEX for 512-bitzmm0-zmm31(evex_rr,zmm_move_at, opmask
{%kN}and zeroing{z}), opmask instructions (kmovw/kmovqto and from general registers,kandw,korw,
kxorw,knotw,kortestw,ktestw), MMX onmm0-mm7(mmx_rr,movq,emms), and VEX registers 8 to 15 for
ymm(the VEX prefix now carries R and B).tools/tests/test_encoder_bytes.pychecks 31 instructions against llvm-mc
(19 identical bytes, the rest equivalent forms that decode the same). These encodings are not yet reachable from Ryn
programs; the AVX-512 forms have not been executed, since the development machine has no AVX-512. - Vector types from Ryn programs:
std::simdhas 512-bit typesF32x16,F64x8,I32x16,I64x8(generated by
tools/gen-simd.py). Arithmetic uses EVEX on one zmm register whenstd::cpureports AVX-512F and two 256-bit halves
otherwise. Comparisons return integer lane masks (u16for 16 lanes,u8for 8);blend(other, mask)merges by mask.
The AVX-512 form is verified by its bytes and by llvm-objdump only: this host has no AVX-512. std::mmx(Mmx, a 64-bit value): add, subtract, multiply, compare and bit operations on 8, 16, 32 or 64-bit lanes.
Each operation runs in mm0/mm1 and ends withemms. Tests:tests/suite/mmx/,tests/suite/simd/zmm_*.- AArch64 backend for Linux:
ryn build --target aarch64-linuxandrync --target aarch64-linuxwrite a static ARM64
executable from the same IR. The subset (integer andboolfunctions, loops,echoof integers andbools, self tail
calls, the x86-64 runtime errors and their exit statuses) is compiled; everything else is refused with a named reason.
Verified by encoding checks against llvm-mc and by running the suite's accepted programs under the Unicorn emulator:
70 of 538 run programs are accepted, all match. Seedocs/arm64-backend.md. RYN_DUMP_IR=<path>writes the IR text of a program (a debugging aid for the code generators).
Full changelog: https://github.com/rynlanguage/Ryn/blob/v0.1.13/CHANGELOG.md
Ryn 0.1.10
Code speed: a fourth pass over what rync generates for calls, locals, small functions and frames, with the assembly of
the same programs in Rust and C++ next to it (docs/native-performance.md, benches/versus/). RYN_NO_OPT=1 turns it all off.
- Arguments of a function with at most six one-cell parameters travel in registers (
rdi,rsi,rdx,rcx,r8,r9),
not on the stack; the callee does not copy them.fib(40): 49 instructions and 219 bytes became 25 and 104. - The four most used scalar locals of a function live in
r12tor15(saved in the frame, restored on every return);
x = x + c, comparisons andleause them directly. - A function with no owned value no longer zeroes its frame (14 instructions per call);
leave, no second epilogue, no jump
over an emptyelse; a comparison is one compare and one jump (&&,||,!are jumps);x & mask == 0and
x % 2^k == 0are onetest; loops test at the bottom;when c { x = a } else { x = b }of integers is acmov. - Small functions of
let, assignment,ifandreturn(four parameters, eight locals, 40 nodes) are inlined, with their
locals in the caller's frame. - Signed division and remainder by any constant use the multiply-high form (only unsigned and powers of two had it);
indexing andsetof a vector with a constant or local index push nothing. - Measured against
rustc -Oandg++ -O2on one machine:fib(40)1.07 s to 0.67 s (Rust 0.32, C++ 0.16),collatz
1.05 s to 0.58 s (0.44, 0.32), the sieve 0.45 s to 0.39 s (0.12, 0.10); the hash map is unchanged at 0.76 s (0.25, 0.27).
Ryn starts in 0.19 ms (Rust 0.62, C++ 0.43),hellois 8 KB (4.3 MB, 16 KB), 3000 functions build in 2.5 s (15.2 s, 13.3 s),
std::simd::sum_f32sums in 0.0085 s (0.052 s, 0.014 s) and 5 000 000 list nodes fromstd::alloc::Pooltake 0.15 s
(0.21 s, 0.21 s). Ryn is slower on compute-bound code, as the document says. - Standard output that is not a terminal is buffered on Linux (64 KiB, flushed at exit, after a panic or runtime error, before
an error message, before reading standard input or starting a process, and byio::stdout_flush()); a terminal and a program
with threads write at once. Printing 1 000 000 lines: 1.50 s to 0.037 s (Rust 0.46 s, C++ 0.068 s). The frame cell of a local
that lives in a register is no longer written (checked by running the suite and the bootstrap withRYN_REGPOISON=1). - Seven new tests in
tests/suite/(optimize/andoutput/); suite 695/695,tools/run-tests.py260 tests. A function with only a few
statements is now inlined, sotools/tests/test_perf_019.pygives its functions a loop to keep them out of line.
Ryn 0.1.9
Compiler speed, code speed and systems features. docs/native-performance.md has the state of each item, the
measurements and the limits. Suite 688/688 with the self-built compiler. The committed seed is still the 0.1.8 compiler:
stage2 == stage3 holds when the seed is a compiler built from this source (one stage), and the seed in bootstrap/ has to be
updated to a stage2 of this tree (and its checksum regenerated) before the CI bootstrap, which starts from the seed, passes.
Scalar optimizations (RYN_NO_OPT=1 turns them off): constant propagation of locals defined once, removal of
unreachable statements, constant if conditions and unused scalar lets, strength reduction (division and remainder
by constants without a divide, signed shifts, immediates), self-recursive tail calls in constant stack, and operands
read without push/pop. loop_sum 1.97 s to 0.49 s. Copy propagation, loop invariant code motion, common
subexpression elimination, loop bounds check elimination and escape analysis are not implemented
(docs/native-performance.md says why). Suite 687/687.
Compiling the compiler: 15.5 s to 6.7 s, bootstrap 32 s to 23 s, same peak memory. A field of a vector element
(self.structs[id].field_names) is read where the element lies and cloned alone, or lent to a builtin that only
borrows it, instead of copying the whole element; a few linear scans became hash lookups.
RYN_SYMBOLS=1 writes the function offsets of a build to standard error, for profiling the compiler.
Compiler speed (all measured on one machine, medians of 5 runs; "before" is the shipped 0.1.8 bootstrap/rync-seed):
- Lowering finds types, structures, functions and aliases through hash indexes instead of scanning every declaration
(type_index,struct_index,signature_map,alias_index), and the code generator finds drop and glue routines
the same way. This was the quadratic part: compiling the compiler took 152 s and takes 15 s; the bootstrap
(stage2 + stage3) took 4 min 50 s and takes 32 s. - Functions of the native runtime module (
std::native) are lowered only when something reaches them, so a small
program no longer pays for the whole module:hellocompiles in 0.11 s instead of 0.38 s.RYN_LOWER_ALL=1
lowers all of them (to check the module itself). RYN_TIMINGS=1makesryncwrite the time of each phase to standard error.
Code speed and size:
- Leaf functions whose body is one small expression are inlined; a structure literal that is returned is written
straight into the result cells; expressions made of literals are folded to immediates (and multiplications,
divisions and remainders by a power of two become shifts and masks); a small frame is zeroed by a counted qword loop.
inline_leaf_calls: 1.11 s to 0.15 s;alloc_pool: 0.58 s to 0.22 s. - Only the runtime routines the code names are written, equal string literals share one copy, and large blocks own their
mapping: a hello program is 8.3 KB instead of 16 KB. - Profile-guided code layout:
rync build --profile-generate FILEmakes an executable that writes the entry count of
each function at exit;rync build --profile-use FILEgenerates the functions most entered first. An unreadable
or damaged profile only costs the layout (a warning is printed). std::simd::sum_f32,sum_i32,dot_f32andadd_f32: fused array loops that keep the vector registers across
iterations (AVX2 whenstd::cpureports it, SSE2 otherwise, identical results on both).simd_fused_sum: 0.010 s
against 0.27 s for the scalar loop.
Systems features (see docs/native-performance.md for the exact state and the limits).
std::bits,std::mem,std::overflow: bit and memory intrinsics (compiled tobsr/bsf/bswap/rol/ror/rep movsb), checked, wrapping and saturating arithmetic.std::atomic(Atomic<T>,AtomicCell, orderings;lock xadd,lock cmpxchg,xchg,mfence),std::sync(threads with arguments,Mutex,RwLock,Condvar,Barrier,Once, thread-local storage).std::alloc:StackandPoolallocators next tostd::arena.#[repr(C, packed)],#[repr(C, packed(N))],#[repr(C, align(N))]; compile-timesize_of::<T>(),align_of::<T>(),offset_of::<S>("field").std::cpu(CPUID and XGETBV with OS-state checks) andstd::simd(SSE2/AVX2 vectors with runtime dispatch and scalar fallback).ryn asm(assembly listing,--function,--summary,--compare),ryn update, andbenches/forryn bench.- Fixes: operator methods (
a + b) on structures declared in a module; instances of a public generic structure are public; IR carries function names. - Known: the SIMD vector types are still slower than the scalar loop (only the fused array loops are fast); no ARM64/NEON.
Ryn 0.1.8
Maintenance release. The version strings say 0.1.8; the compiler and the language are unchanged from 0.1.7.
- Issue and pull request templates and
SUPPORT.mdno longer ask for acraneliftbackend orryn bootstrap --native
(both were removed in 0.1.6); they ask for the target and point attools/bootstrap-native.sh. docs/native-ownership-validation.md,docs/native-float-validation.mdanddocs/language-0.2.mdare marked as
historical: they describe the Rust and Cargo era.
Ryn 0.1.7 — Native Power & Benchmarks
"Native Power & Benchmarks". The version strings (VERSION, ryn --version, rync --version, the registry header, the CI
archive names) say 0.1.7.
Nested structures
- A path of fields is stored through a reference:
self.q.p.y = 1andl.a.x += 1in amut selfmethod or through a
&mutparameter (the native backend declined these as "assignment through this reference"). The store goes to the
address of the nested field (PlaceAddressin the IR), so the old value is dropped and the new one moved in once. - A
mut selfmethod is called on a structure nested in another one (self.b.shift(1),l.b.shift(1)), in place, with the
mutability of the root checked (R0204on an immutable local). It wasR0235("method receivers must be a local
variable"). - A field of a structure nested in the result of a call is read (
make().q.p.x), and the rest of the result is dropped. - A method is called on a
Stringfield of a call result (make().label.len(),make().q.p.name.clone()): the string moves
into a hidden local that lives as long as the enclosing block, so nothing leaks or is freed twice (it was R0905). Alet
whose statement needed such a temporary no longer drops the bound name at the end of the statement. - A structure stored through a pointer as a whole (
self.seen = ...of aVec, aStringor a nested structure) works
for the native backend; it was declined as "a structure field of a structure type". This is what stopped programs with
a collection field changed throughselfinside loops from compiling. - C calls with more than six integer arguments pass the rest on the stack, for named functions and for calls through a
function pointer (scalar arguments only; records and the freestanding and Windows targets still decline). - The help of
R0905no longer points at the removed--backend cranelift. - Tests:
tests/suite/structs/nested_struct_*,vec_field_mutated_through_self_in_loops,
raii/nested_destructor_runs_once_per_resource,ffi/foreign_call_with_stack_arguments.
ryn bench
ryn bench <file.ryn|project-dir>compiles the program, times the compiler (--compile-runs N), runs the program
--warmup Ntimes without counting and then--iterations Ntimes with its output captured, and prints the minimum,
median, mean, maximum and standard deviation.--jsonprints the report as JSON,--save-baseline FILEwrites it,
--baseline FILE --threshold PERCENTcompares medians (default 10%) and exits 1 on a regression. A project with a
benches/directory times every.rynfile in it by name. Written in Ryn (selfhost/src/driver/bench.ryn).- The peak resident memory of the compiler and of the program is reported and written to the JSON (
peak_memory_kb), and a
baseline that has it makes memory growth past the threshold a regression too.std::process::ProcessResulthas a new
fieldpeak_memory_kb(the child'sru_maxrssfromwait4; 0 on Windows, where it is not measured). - Tests:
tools/tests/test_bench.py.
Ryn 0.1.6
Ryn 0.1.6 "Native First".
The toolchain is written in Ryn. The ryn command, the native compiler rync (lexer, parser, analysis, code generator, ELF and PE writers) and the runtime are Ryn code; the Rust implementation and the Cranelift backend are removed. The compiler is built from the committed seed (bootstrap/rync-seed) by tools/bootstrap-native.sh, which requires stage 2 and stage 3 to be byte-identical (they also equal the seed).
Archives (each is one directory; ryn finds rync and stdlib next to itself):
ryn-0.1.6-linux-x86_64.tar.gz:ryn,rync, standard library, compiler sources, bootstrap script.ryn-0.1.6-windows-x86_64.zip:ryn.exe,rync.exe, standard library (cross-compiled by the Linux compiler).
What was verified (from a clean clone, PATH=/usr/bin:/bin, no cargo/rustc/cc/ld): bootstrap fixpoint; 639 of 641 suite programs (2 have no test header); 241 Python tests; the archives run.
Limits, stated plainly:
- Windows is experimental and was run under Wine only, never on Windows itself. Threads, sockets,
pipe/fork, keyboard input and records passed to or returned from C by value are not available there (declined when compiling). - The GitHub workflows (CI and release) were rewritten for the Cargo-free build and have not been run before this release.
- Linux x86-64 is the only supported native host; macOS is not supported.
- Exact spans and help texts of the removed Rust analyzer are no longer pinned by tests (codes and messages are).
See CHANGELOG.md for the full list; the Rust implementation remains in the git history before commit 950e152.
Ryn 0.1.5
Ryn 0.1.5 brings deterministic ownership to the native backend and a verified native compiler bootstrap. No garbage collector is introduced.
Native compiler and ownership
- Deterministically release String, Vec, Map, Option, Result and owning enum payloads, including temporaries, replacements, loop exits and early propagation.
- Clone nested enum payloads and unborrowed reference fields independently; invalidate moved owners to prevent repeated frees.
- Verify native seed → stage2 → stage3 bootstrap under a 1 GiB address limit, with byte-identical stage2 and stage3 binaries.
- Add live allocation/byte accounting and regressions for double-free, nested ownership and 30 million short-lived allocations.
Compiler and language improvements
- Shared Ryn frontend and middle end, with Rust analyzer parity checks.
- Updated output functions, compile-time constants/evaluation, metadata and derive support, nested patterns, generic extensions, C ABI handling and std::arena.
- 571-program language regression corpus, plus native ownership and compiler project parity tests.
Freestanding float text and math
- The native backend embeds the typed IR of the Ryn float runtime, so shortest round-tripping formatting and direct-width parsing (binary32 and binary64) need no libc:
f32parsing no longer rounds throughf64. std::mathruns without libm on SSE2 and x87: sqrt, rounding, logarithms, trigonometry withfprem1reduction, andpowwith full special-case classification.- The 17 known freestanding float-text declines of earlier notes are resolved: the native sweep is 424 passing cases, 0 declined.
Downloads
Linux x86_64 and Windows x86_64 archives are accompanied by SHA-256 checksums, plus a Linux rync-0.1.5-linux-x86_64 archive with the self-hosted compiler, its Ryn sources, the standard library and the native bootstrap script. The standard ryn executable uses the Rust/Cranelift backend.
Validation and limits
- Full Linux Cargo validation: 382 passing tests with a 16 MiB test-thread stack.
- Native sweep: 424 passing cases, 0 declined; the 17 former float declines are fixed.
- Native bootstrap peak RSS: 403528 KiB; the native stage2/stage3 fixpoint is byte-identical.
- Native/Rust stress program outputs match. The Rust-built full compiler comparison exceeded the same 1 GiB limit, so no completed Rust/native full-compiler binary comparison is claimed.
rync's own frontend pipeline still passes 303 of 424 corpus programs directly from source; the remaining cases are compile-time evaluation, compile-time function calls, metaprogramming, some pattern forms, module path lookup and C imports.
Exact measurements and reproduction commands: https://github.com/rynlanguage/Ryn/blob/v0.1.5/docs/native-ownership-validation.md and https://github.com/rynlanguage/Ryn/blob/v0.1.5/docs/native-float-validation.md
Ryn 0.1.2
Ryn 0.1.2 adds packages from the pods registry.
- Version dependencies such as
rynix: 0.2.0resolve from https://pods.ryn-lang.xyz with Cargo-style requirements (^,~,=,*). ryn lockpins each package version and the SHA-256 of its archive; the first build withoutryn.lockcreates it. Downloads are verified before they are unpacked.ryn login <token>andryn publish [project-dir]upload packages.ryn.yamlacceptsdescription,license,repository,homepage, andkeywords.
The Windows x86_64 archive is attached; the Linux archive is added by the release workflow.
Ryn 0.1.1
Ryn 0.1.1 is a correctness update.
- Copyable method receivers used in a
when/else whencondition, aforrange bound, or afor ... incollection are evaluated before the condition. Previously the temporary was emitted into the first statement of the branch or loop body, so a condition such aswhen first(V::ZERO.add(V::ONE)) != 1could read an uninitialized value and take the wrong branch. - Raw pointers and function pointers can be compared with
==and!=. - An integer literal range start takes the end bound's type, so
for i in 0..items.count()type-checks whencount()returnsu64.
The Windows x86_64 archive is attached; the Linux archive is added by the release workflow.
Ryn 0.1.0
Ryn 0.1.0 introduces a self-hosted compiler frontend. The Ryn lexer, parser, and generic specialization frontend are used by check/build/run; bootstrap verifies a three-stage fixpoint. Semantic analysis, Ryn Guard, Cranelift code generation, and the CLI remain Rust components.