Repository navigation
Releases
v2.2.0
Blazing Bulldog
What's new?
- Full
comptimesupport 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,blsivia 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
inlinekeyword path: the compiler already honorsinlineon a function signature; functions needing it were simply marked, no change to force inlining was made
Measured generated-code gains:
t4test program dynamic instruction count (Ir, via valgrind callgrind): EQCHAIN pass, -2.35%; marking hot small functionsinline, 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 (acmp, setl, movzbl, testb, cmovesequence at function entry collapses tocmp+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 amovzbl/xor/testper such branch (the compiler's ownxorl $1count 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
switchon a byte already covers all 256 values via its jump table, so thecmpq $255,%r11; ja defaultguard 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
imulqcount 417 to 352), and one sign-extend reused per block for repeated same-index accesses (movslqcount 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].fieldnow folds to a single addressing mode instead of a separateleaplus offset load. Compilinghashmap_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 singlerep 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
movbto 11movlinstructions. 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_callwas the largest cost: it re-scanned every function in the module and re-parsed each function name for every call site with arguments. Replaced withov_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_zerodid the same kind of linear scan; indexed the same way, same dotted-keys-first priority.table_growinallocators.idkwas 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...
v2.0.8
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
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
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
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
Full Changelog: v1.3.0...v1.5.0
Flux version 1.4.0
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 algorithmssearch.fx- search algorithmsrle.fx- run-length encodingshadowstack.fx- opt-in per-function shadow stack with per-call canary randomizationencodings.fx- character encoding utilitiescsv.fx- CSV parsingmatrices.fx- matrix mathdisasm.fx/disasm_x86-64.fx- executable disassembly
Improvements
typeofnow has proper per-type distinction; struct types no longer collapse to the same valueemitfluxand~$codification: multiple fixes to compile-time code emission- Templated struct inheritance (
struct A<T> : B<U>) now correctly producesA<T,U> ++now works on array index elements (e.g.x[2]++)- Multidimensional array type inference from literals fixed
- Forward references for objects fixed
privatenow 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;
returnno longer required at the end of a function if a return exists on all paths byteandcharinteger literal support added to the lexer- Scientific notation added to the lexer
- Inline ASM error messages now show the ASM block itself
cdeclfunctions no longer require!!to suppress name mangling;cdeclimplies no mangling
Bug Fixes
- Fixed Linux heap operations causing segfault
- Fixed
datetime.fxfor 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/stdlibfor compatibility with the online compiler - Architecture config override:
flux_config.cfgis 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,#packageimporting, 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
Full Changelog: v1.2.0...v1.3.0
LSP v1
Minimal LSP providing error reporting. Autocompletion coming soon.
Flux version 1.2.0
What's Changed
- LLVM backend compiler flags as well as dotenv test and more. by @reinitd in #32
- Fixed
visit_ternaryOphandling of pointers infcodegen.pyby @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 @kvthweattinexpression support added by @kvthweatt
New Contributors
Full Changelog: v1.1.0...v1.2.0
Flux version 1.1.0
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
singinitfor single initialization - Added calling conventions
- Added
labelandgoto - Added
#dirto preprocessor directives - Added
deferto 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
jumpkeyword to jump execution to a target location in memory - Added bit slicing with
val[x``y]syntax
Flux version 1.0.1
Newly added features:
- Partial ownership implementation with
~-> incomplete but will be resolved soon - Object traits with
trait main()with arguments- Locality with
localto restrict a unit from leaving scope - Templates for functions with
<T> - Custom infix operators (Allowing things like
a === bora <|> b) - Syntactic sugar for single-parameter object
__initmethods. - 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