Skip to content

Releases

v2.2.0

Choose a tag to compare

@kvthweatt kvthweatt released this 11 Nov 04:56

Blazing Bulldog

What's new?

  • Full comptime support including inline ASM now possible with our native SSA-based x86_64 backend.
  • Native REPL written in Ideka
  • 31% compiler binary size reduction

Native x86_64 backend (LLVM replacement)

Ideka's compiler generates its own x86_64 machine code through an SSA pipeline (issa.idk / ix64.idk, plus iasm/ilink for assembling and linking) instead of emitting LLVM IR.

Optimization passes added/tuned on this backend:

  • Rolling copy loops
  • Strength reduction (s_sr)
  • BMI instruction selection (andn, bzhi, rorx, blsr, blsi via flagless VEX forms)
  • Redundant-load removal (DOMLD): implemented, measured a negligible gain at a real compile-time cost, left disabled
  • Loop-invariant code motion (LICM): implemented, measured a regression (+0.27% dynamic instruction count), reverted/left disabled
  • Constant rematerialization / index sign-extension hoisting
  • An inline keyword path: the compiler already honors inline on a function signature; functions needing it were simply marked, no change to force inlining was made

Measured generated-code gains:

  • t4 test program dynamic instruction count (Ir, via valgrind callgrind): EQCHAIN pass, -2.35%; marking hot small functions inline, a further -0.13% (479,879,364 to 479,255,432).
  • Compiler binary size (on my machine): 2.6 MB to 1.8 MB, about 31% smaller, from this optimization work.
  • Block merging (SSA_OPT_MERGE): a block that ends in a jump to a block nothing else reaches absorbs it, removing the jump and letting a compare fuse with the branch/select that uses it (a cmp, setl, movzbl, testb, cmove sequence at function entry collapses to cmp + cmov). Compiler assembly about 1% smaller.
  • Loop test repetition (SSA_OPT_ROTATE): a jump back to a loop test that is only a compare and a conditional jump now repeats the test in place, so a loop needs one jump per iteration instead of two. Self-compile time: 21.5s to 19.7s, about 8% faster (most of that 8% from this pass).
  • Phi cleanup bug fix: a constant-folded branch could leave a stale phi entry for the removed path, causing a miscompile (a dropped switch optimization and double-extended values) in the compiler built by that compiler, undetected by the test suite, only caught by the fixed-point check. Fixed with s_prunephi, run whenever the CFG is rebuilt.
  • Branch-on-negation: if (!f()) now tests the value directly and inverts the jump, removing a movzbl/xor/test per such branch (the compiler's own xorl $1 count dropped from 1,663 to 1,085). A first attempt that swapped branch targets instead of inverting the branch flag made the compiler about 6% slower, by putting the cold path first in block order; switched to an inversion flag that leaves layout alone.
  • Block layout pass: reorders blocks after register allocation so each is followed by its most likely successor (same/deeper-loop successor before a loop exit; ud2-ending blocks last; everything else keeps relative order). Self-compile: 22.7s to about 21.1s, about 6% faster; unconditional jumps dropped 8% (15,116 to 13,908).
  • Byte-switch range-check removal: a switch on a byte already covers all 256 values via its jump table, so the cmpq $255,%r11; ja default guard before the table jump was redundant and is now removed (applies to every jump-table switch in the compiler, including the lexer's per-character switch, the hot one). Self-compile: 21.7s to 20.8s, about 3-4% faster.
  • Indexing (GEP lowering): shift instead of multiply for power-of-two element sizes other than 1/2/4/8 (compiler's own imulq count 417 to 352), and one sign-extend reused per block for repeated same-index accesses (movslq count 7,318 to 6,554). No measurable self-compile or kernel-benchmark change; smaller, cleaner generated code only. Full value-range analysis to drop the sign-extend entirely was identified as a larger, riskier follow-up with a likely small payoff and was not done.
  • Constant stores and nested address calculations: a store of a constant to a folded address now emits a direct immediate store instead of building the constant in a register first (about 4,600 sites in the compiler); table[i].field now folds to a single addressing mode instead of a separate lea plus offset load. Compiling hashmap_test: 1.112 billion to 1.082 billion dynamic instructions, about 2.7% fewer; generated assembly about 3.4% smaller.
  • Fill-loop rewrite: a loop of the shape i=0; while(i<n){p[i]=c; i++;} (0-based, unsigned 64-bit or signed 32/64-bit count, body only the store and increment, index unused after) compiles to a single rep stosb.
  • Neighboring one-byte constant stores merged: adjacent single-byte constant stores to one stack slot now become 4-, 2-, and 1-byte immediate stores (also merges through a pointer register, for runs of at least two bytes); a 43-character string literal went from 43 movb to 11 movl instructions. Compiler's own output: 500k to 487k lines; compiler binary about 4% smaller.
  • Bootstrap pass 3 speedup: pass 3 of the bootstrap (the compiler compiling itself) went from 6-7.5s to about 4s; pass 4 unchanged at roughly 1.5-2.5s. Two fixes:
    • ptr_overload_call was the largest cost: it re-scanned every function in the module and re-parsed each function name for every call site with arguments. Replaced with ov_index_sync, which indexes each function once (by overload key and its __-suffixes), so the candidate list for the second loop comes from a per-key index instead of a rescan; first function in module order still wins, result identical.
    • ptr_ovl_zero did the same kind of linear scan; indexed the same way, same dotted-keys-first priority.
    • table_grow in allocators.idk was zeroing freshly-grown table pages that the OS already hands back zeroed; that redundant zero loop was removed (stays inside the existing O(1) design of the allocator).

Benchmarks?

Allocator (fmalloc/ffree) vs C

The custom allocator (fmalloc/ffree, stdheap: size-class bins, 32-byte block-table entries, bump slabs doubling 4 MB to 64 MB, hash table with backward-shift removal) was benchmarked against glibc malloc/free, using the real tests/heap_stress.idk test compiled and run through the actual bootstrapped Ideka compiler, and a C port of the same allocator design (/tmp/cb/fmalloc.c, /tmp/cb/heap_stress.c) running the identical workload (same PCG32 generator, same alloc/free patterns, same verification sums) compiled with gcc and clang.

Same-machine comparison (this cloud container)

Ideka, gcc, and clang were all built and run in the same container:
CPU reported only as "Intel(R) Xeon(R) Processor" (2 vCPUs, no hyperthreading, ~5400 BogoMIPS), 7.8 GiB RAM; exact CPU model and memory type/speed are not exposed by this VM. Three runs each, after the SSA backend optimization work above.

Test Ideka (fmalloc) gcc -O2 clang -O2 gcc -O3 -march=native clang -O3 -march=native
1M x 64-byte pairs 5.8-5.9 ms / 10.6k-10.7k MB/s 6.4-7.0 ms / 8.7k-9.5k MB/s 6.7-6.8 ms / 9.0k-9.2k MB/s 6.5-6.7 ms / 9.1k-9.4k MB/s 6.5-6.9 ms / 8.8k-9.4k MB/s
1M mixed pairs 6.1-8.1 ms / 248k-330k MB/s 18.5-21.9 ms / 89.3k-105k MB/s 18.4-18.5 ms / 105k-106k MB/s 18.2-18.8 ms / 104k-107k MB/s 18.5-19.3 ms / 101k-105k MB/s
Fast-path reuse 5.8-6.5 ms / 9.5k-10.7k MB/s 6.4-6.6 ms / 9.3k-9.5k MB/s 6.6-6.9 ms / 8.8k-9.5k MB/s 6.4-6.6 ms / 9.2k-9.5k MB/s 6.6-6.7 ms / 9.1k-9.3k MB/s
64-byte write/read-back 19.2k-20.0k MB/s 11.0k-11.3k MB/s 15.3k-15.7k MB/s 15.7k-16.3k MB/s 15.6k-15.9k MB/s
Mixed write/read-back 35.1k-35.6k MB/s 25.2k-27.0k MB/s 30.6k-33.1k MB/s 27.4k-27.5k MB/s 34.0k-34.1k MB/s
Stream write 6.8k-7.6k MB/s 6.7k-6.8k MB/s 6.8k-6.9k MB/s 7.0k-7.7k MB/s 7.3k-7.8k MB/s
Stream read 14.6k-17.1k MB/s 14.4k-15.2k MB/s 14.8k-15.8k MB/s 16.4k-17.1k MB/s 16.3k-18.7k MB/s

On this machine, Ideka leads gcc and clang at every optimization level on the timed alloc/free tests and on 64-byte/mixed read-back bandwidth; it is roughly level with the C builds on stream write/read bandwidth.
-O3 -march=native did not uniformly help gcc/clang over their own -O2 numbers here (mixed-pairs alloc/free got faster; 64-byte writ...

Read more

v2.0.8

Choose a tag to compare

@kvthweatt kvthweatt released this 22 Oct 02:24

Base (pre-bootstrap) Python Compiler

  • Nested template types: Box<BB> now works in nested type parameters, in return types, and in inference from Box<Box>, such as Pair<A, Box>. This is in both the Python compiler and the bootstrapped compiler.
  • Pointer returns from literals: an integer literal returned from a pointer-returning function now takes the signature’s type. foo() -> MyS* -> 0; compiles without a cast. A 0 becomes a null pointer, and other constants are converted with inttoptr.
  • !? in switch statements: a switch on the not-null operator no longer fails in the Python compiler with i8 true. Case constants are rebuilt at the switch’s integer width.
  • Switch codegen: a switch where every case returns, combined with defer, no longer fails with “must end with return”. A merge block that no case reaches is now marked unreachable.

Bootstrapped compiler

  • Self-hosting: the bootstrapped compiler gets all of the above. The compiler sources were also cleaned up with the new syntax (below).
    f-strings: chained put_str/put_int sequences were collapsed into f-strings. Expressions containing .mem are deliberately left alone, because the f-string buffer has no length check and the inline-asm strings overflow it.
  • Empty default {} stubs: these no longer generate a stub default. When every case diverges, the statements after the switch are hoisted into the default.
  • Void calls: call(); ->; became -> call(); where the function returns void.
  • Verification: a corpus check of 270 programs gave 268 identical outputs and 2 that differ. The fixed point held: the compiler built with itself twice produced identical binaries.

Tooling and editors

  • Notepad++: keywords and autocomplete were rebuilt from the Sublime syntax.
  • setup.py (Windows wizard):
    • Window: it resizes to fit, and the Back/Next buttons are no longer pushed off-screen.
    • MSVC detection: it now finds Visual Studio and Build Tools by looking for the toolset on disk.
    • llc and LLVM version: MSYS2 is installed only if llc is missing or older than LLVM 21. Long steps run with no timeout.
    • PATH and launcher: it refreshes PATH after each install and writes scripts\flux_dev_prompt.bat.
    • Python compiler: it asks whether the Python v1.5.4 compiler is installed. If not, it copies it in from src\compiler\v1.5.4.
    • Two-stage bootstrap: stage 1 is python fxc.py fxc.fx. Stage 2 recompiles with build\fxc\fxc.exe into fxc2.exe.
    • Cleanup: after both stages succeed, it removes exactly the files it copied. A file it overwrote is restored.
  • Setup guides: the Linux, macOS and Windows guides now match the real toolchain per OS, including the copy step, the bootstrap, and a note to use the native compiler afterwards for speed.

Known issues

  • On Windows, fc.py passes freetype.lib to lld-link on every build. This file is not part of the Windows SDK. If linking fails on it, that is why.
  • The borrow checker, effects checking, and the FVM and its codegen (needed for comptime self-execution) are still Python-only.

Full Changelog: v2.0.0...v2.0.8

Flux version 2

Choose a tag to compare

@kvthweatt kvthweatt released this 13 Oct 07:49

Dangling Ditto

You can now bootstrap the Flux compiler and have it run natively on your machine. Afterwards you can drop the Python components in src\compiler\ and fxc.py at the compiler root.

Full Changelog: v1.5.1...v2.0.0

v1.5.1

Choose a tag to compare

@kvthweatt kvthweatt released this 09 Oct 05:05

Allowed single-statement if without braces, which lead to having braceless functions that are return-only because they are single-statement. def can now be omitted because it means default not define, and is in the calling convention position. Can now define circumfix operators like |x| using similar syntax to ternary definition but only single parameter operator(int x) [|][|] -> int -> x < 0 ? -x : x;, can also alias functions as operators like foo(int i) -> int as operator[|][|] -> x < 0 ? -x : x;

Full Changelog: v1.5.0...v1.5.1

v1.5.0

Choose a tag to compare

@kvthweatt kvthweatt released this 09 Oct 02:36

What's Changed

Versions now have names, this one is Spicy Sugar.

Fix to DCE which didn't account for Linux _start entrypoint. Also changed how Linux programs are compiled, skipping ASM output and instead outputs the object file.

Changed XOR from ^^ to ^|. The reasoning is phonetic, if ^ is "ex"ponentiation, then borrowing ^ in the start of ^| we get "ex-or".

New syntax for bit indexing values to complement bit slices. The form is:

x[`y]

Bit indexing starts at 0 and is the most significant bit with respect to endianness of the target value's type.

Added a new prototype IDE which includes the REPL at the bottom output panel and integrates the LSP which also received improvements like completion, signature help, and integrates visualizers for both effects and template constraints.

Fix to arithmetic between literals cast to differing endianness

Fix to endianness handling with bit slices and bit indexing, was double inverting LE

Added remaining language features to comptime

Added typed enums, exhaustive switch on tagged unions, fixed bug in fvmcodegen.py: _visit_function_def was accidentally defined inside another method instead of at class level making it uncallable, and added dictionaries with dict type

Added effects.

Upgrade to contracts: added #binding{pre:post} suffix allowing the specification of contract position, exclusion, and other requirements.

Full Changelog: v1.3.0...v1.5.0

Flux version 1.4.0

Choose a tag to compare

@kvthweatt kvthweatt released this 06 Jul 14:41
27b7d48

Flux v1.4.0 Changelog

New Features

C to Flux Translation Utility (cft.py)

A new tool that translates C source files (.c and .h) into Flux (.fx) using libclang. Supports full function body translation, struct/union/enum/typedef declarations, function pointer typedefs, macros, bitfields, _Alignas, and __int128/__uint128_t as paired 64-bit structs mirroring GCC/Clang ABI. Accepts single files or entire directories, pairing .c/.h files by stem into a single .fx output.

comptime Blocks

Compile-time execution is now supported via comptime blocks. The FVM (Flux Virtual Machine) executes code at compile time, enabling metaprogramming, code generation via emitflux/~$, and FFI at compile time. comptime blocks can now be placed inside structs. Inline ASM is executable at comptime via keystone-engine.

Object Inheritance

Objects now support inheritance. Use + on a child def to override a parent method signature. +callconv syntax is valid within objects for member function definitions, and child objects can override parent methods with !+callconv.

Interfaces

New interface keyword for defining object interfaces. Interfaces enforce traits on implementing objects. New syntax forms: A(B) and A->B. Trait reflection supported via the has keyword: if (myObj has SomeTrait).

Template Constraints (constraint)

Named template relational constraint sets via the constraint keyword (renamed from constra). Constraints are required within :{} blocks inside template definitions. Constraint sets can be combined, parameters renamed, and relational checking enforced (A ~ B, A !~ B). Default types for template parameters are now supported.

Type Functions

Functions can now be defined on types and literals of that type, including structs. Type functions support templates, pointer types, and i-strings.

Algebraic Types

Infrastructure for type relation algebra, with new type relation operators.

not in / !in Operator

Inverse of the in operator. x !in y returns true when x is not a member of y.

REPL (frepl.py)

Interactive Flux REPL added. Also added compiler.fvm.dump(path) builtin to dump comptime FVM opcodes up to the call point to a .fvm file for inspection and standalone execution.

Disassembler (disasm.fx, disasm_x86-64.fx)

New standard library modules for executable disassembly. Precursor to an executable editing suite.

New Standard Library Modules

  • sorting.fx - sorting algorithms
  • search.fx - search algorithms
  • rle.fx - run-length encoding
  • shadowstack.fx - opt-in per-function shadow stack with per-call canary randomization
  • encodings.fx - character encoding utilities
  • csv.fx - CSV parsing
  • matrices.fx - matrix math
  • disasm.fx / disasm_x86-64.fx - executable disassembly

Improvements

  • typeof now has proper per-type distinction; struct types no longer collapse to the same value
  • emitflux and ~$ codification: multiple fixes to compile-time code emission
  • Templated struct inheritance (struct A<T> : B<U>) now correctly produces A<T,U>
  • ++ now works on array index elements (e.g. x[2]++)
  • Multidimensional array type inference from literals fixed
  • Forward references for objects fixed
  • private now supports friend syntax: private : FriendObj1, FriendObj2 { ... };
  • Loop variable declarations (e.g. for (int x;)) no longer cause stack overflows
  • Compiler now detects alternate return routes; return no longer required at the end of a function if a return exists on all paths
  • byte and char integer literal support added to the lexer
  • Scientific notation added to the lexer
  • Inline ASM error messages now show the ASM block itself
  • cdecl functions no longer require !! to suppress name mangling; cdecl implies no mangling

Bug Fixes

  • Fixed Linux heap operations causing segfault
  • Fixed datetime.fx for Linux and macOS
  • Fixed cast widening not recognizing unsigned types
  • Fixed incorrect array index sign extension on unsigned types
  • Fixed array element type metadata
  • Fixed xml.fx
  • Fixed f-string function name lookup and runtime f-strings
  • Fixed struct type context detection in codegen
  • Fixed template parsing for pointer-of-templated-type
  • Fixed try/catch/throw
  • Fixed preprocessor NT path to Unix path conversion
  • Fixed parser regression in C-style array declaration detection
  • FVM: fixed i-string codification, added TernaryOp support
  • FVM temp files now written to build directory instead of /src/stdlib for compatibility with the online compiler
  • Architecture config override: flux_config.cfg is now overridden if architecture setting does not match compiler-detected architecture

Platform

  • macOS ARM64 compilation fixes
  • macOS setup guide contributed by community
  • Linux segfault from heap operations resolved

Documentation

  • Language specification updated to include interface, using, constraint, algebraic types, #package importing, and compiler internals
  • Standard library documentation updated for shadowstack.fx, file_object_raw.fx, and others
  • Notepad++ and VSCode syntax highlighting improved; missing keywords added
  • Official website: https://fluxspl.org/ | Online IDE: https://fluxspl.org/ide

Flux version 1.3.0

Choose a tag to compare

@kvthweatt kvthweatt released this 05 May 22:22

Full Changelog: v1.2.0...v1.3.0

LSP v1

Minimal LSP providing error reporting. Autocompletion coming soon.

Flux version 1.2.0

Choose a tag to compare

@kvthweatt kvthweatt released this 27 Apr 22:09

What's Changed

  • LLVM backend compiler flags as well as dotenv test and more. by @reinitd in #32
  • Fixed visit_ternaryOp handling of pointers in fcodegen.py by @kvthweatt in #31
  • Add support to allow {} if (cond); as well as {} if (cond) else {}; by @kvthweatt in #29
  • macro, contract, templated functions+operators added by @kvthweatt
  • in expression support added by @kvthweatt

New Contributors

Full Changelog: v1.1.0...v1.2.0

Flux version 1.1.0

Choose a tag to compare

@kvthweatt kvthweatt released this 08 Apr 15:42

What's new with Flux?

  • Flux Package Manager
  • AST and type system now fully report line/col information in errors
  • Templates
  • Custom operators
  • Many parser, code generation, and type system fixes
  • Added support for comma separated function prototype declarations and using statements
  • Added double, natural 64-bit floating point type
  • Added threading, atomics, and shared memory libraries
  • Added singinit for single initialization
  • Added calling conventions
  • Added label and goto
  • Added #dir to preprocessor directives
  • Added defer to defer execution, performed in LIFO order
  • Added ternary assignment operator ?=
  • Fixed segfault issue for Linux programs on program termination
  • Implemented the recursion arrow <~
  • Added stringification with $
  • Added deprecation with deprecate
  • Added a ton of documentation
  • Added a JSON parsing library
  • Added a standard arena allocator
  • HKDF, SHA384, x25519, and AES-GCM algorithms added to cryptography.fx
  • f-strings and i-strings now working
  • assert() should work properly now
  • Added the jump keyword to jump execution to a target location in memory
  • Added bit slicing with val[x``y] syntax

Flux version 1.0.1

Choose a tag to compare

@kvthweatt kvthweatt released this 05 Mar 22:48

Newly added features:

  • Partial ownership implementation with ~ -> incomplete but will be resolved soon
  • Object traits with trait
  • main() with arguments
  • Locality with local to restrict a unit from leaving scope
  • Templates for functions with <T>
  • Custom infix operators (Allowing things like a === b or a <|> b)
  • Syntactic sugar for single-parameter object __init methods.
  • Standard library expansion, including memory allocators, Windows and OpenGL FFI, 2D+3D graphing library + many 3D examples
  • Comma separated function prototype definitions
  • Only types required in prototype signature parameters
  • Data restructuring with from
  • Array comprehension
  • Improved error output by adding __repr__ functions to AST nodes
  • endianof() and automatic endianness conversion on assignment

Fixes:

  • Nested functions now disallowed according to spec
  • Many regressions, too many to list
  • Multi-variable declaration not zero initializing undefined items
  • Object, struct, and enum forward declaration
  • Total refactor of AST yielding the type system

Hoping everyone enjoys the latest release! Be sure to join the Discord and share your code or compiler bugs to help improve Flux!
Official Discord