Blaise v0.14.0 — Changelog
Range: v0.13.0..v0.14.0 (415 commits). Fixpoint verified on 637,968 lines
of QBE IR; all four self-hosting fixpoints green (QBE, native,
internal-assembler, warm-cache). Full test suite: 4,977 tests passing,
2 ignored.
macOS ARM64 backend (new this cycle)
A complete native ARM64/macOS backend was built from scratch this cycle —
still in progress, but already self-hosting a growing slice of the
compiler's own source and running on real Apple Silicon hardware.
- Native AArch64 code generator implementing the AAPCS64 calling convention
for records, classes, interfaces, exceptions, and TLV thread-locals. - Mach-O
MH_OBJECTandMH_EXECUTEwriters behind theIContainerWriter
seam, includingLC_UUID, dyld load commands, and ad-hoc code signing. - A standalone internal AArch64 assembler emitting Mach-O objects directly
— no dependency on Apple'sas/ldtoolchain for object code. macos-arm64registered as a full target in the toolkit registry; a
macOS-built compiler correctly reportsmacos-arm64as its own host.- 40+ "self-cross-compile leg" commits incrementally teaching the arm64
backend enough of the compiler's own feature surface (generics,
interfaces, jumbo sets, closures, unit interfaces embedded in Mach-O
objects) to compile itself. - On-device bring-up: hello-world, class-based programs, and the compiler's
own TestRunner run on Apple Silicon; the majority of the suite reaches a
clean summary with zero crashes. - A dozens-strong cluster of layout-sensitive ARC/width fixes surfaced by
the self-cross-compile push — canonicaladrp+ldrTLV access, descriptor-
driven interface tables (abstract/cross-unit/parent-chain), narrow-int
width handling, and chained field/record access. - Remaining work: OPDF/debugger support on arm64, broader e2e coverage.
Threads are a known pdr gap on this target (PTRACE_O_TRACECLONE).
Tooling: BlaiseGuard (new)
A static analyser purpose-built for the Blaise dialect, reusing the
compiler's own lexer/parser/AST so it always tracks the grammar the
compiler currently accepts.
- Rule families:
BL-1002/BL-1004(unused identifiers),BL-2001–BL-2003
(reference cycles, string indexing),BL-2005,BL-3001/BL-3002
(duplicate detection), plus five rules covering defects the compiler
itself accepts silently. - JSON/XML/HTML report formatters.
- Project-level config discovery and inline suppression comments — cut
BL-2003's false-positive rate by 94% this cycle. - Documented rule-ID scheme (
docs/BlaiseGuard README). - Not bundled in the release tarball — build from source:
pasbuild compile -m blaise-guard --compiler <blaise-binary>.
Language
- Operator overloading (
class operator) — parse, resolve, and lowering
landed end-to-end. - Compile-time file embedding —
{$EMBED 'path'}(byte array) and
{$EMBEDSTR 'path'}(string literal). varargsdirective for binding C-variadicexternalfunctions.- Subranges of enumerated types (
TWeekday = Mon..Fri) — fixes GH #182 and
three follow-ups (array bounds/indexing over an enum subrange). Booleanaccepted as an array index type;array[Boolean]accepted in an
inline typed constant (GH #208).High/Lowof a subrange type return the subrange's own bounds, not the
base enum's (GH #160).- Bit operators allowed in float constant expressions (GH #195).
string/dynamic-array class static variables allowed.- Subscript-terminated record chain accepted as an l-value (GH #187).
- A setter-backed property write is now reachable through a chained base
expression. div/modsignedness now follows the expression's result type rather
than its operands, on both backends (GH #196).
Examples
{ Operator overloading }
type
TVec2 = record
X, Y: Double;
class operator Add(const A, B: TVec2): TVec2;
end;
class operator TVec2.Add(const A, B: TVec2): TVec2;
begin
Result.X := A.X + B.X;
Result.Y := A.Y + B.Y;
end;
{ Compile-time embedding }
const
Greeting: string = {$EMBEDSTR 'greeting.txt'};
{ Enum subranges }
type
TDay = (Mon, Tue, Wed, Thu, Fri, Sat, Sun);
TWeekday = Mon..Fri;
var
D: TWeekday;
begin
for D := Low(TWeekday) to High(TWeekday) do
WriteLn(Ord(D));
end.ARC / runtime
- Static-array-of-managed-field ARC: scope-exit release and record/class
field walks for arrays of managed elements (BUG-017). - Interface pointee reads/writes and sret-
Resultreads through a pointer
fixed across pointer-read, pointer-write, and interface shapes (BUG-012). - An aliased
sretassignment is now staged through a temporary instead of
zeroing a destination that aliases a call argument. - Managed unit globals are released via a per-unit
<Unit>_finiat program
exit; a program-levelreference toglobal's captured environment is
released too. - Two new diagnostic allocator modes:
-dBLAISE_MEMPOISON(poison +
quarantine) and-dBLAISE_MEMDEBUG(double-free detection) in the
small-block allocator. - Every valgrind e2e test now asserts zero ARC leaks under
--debug.
runtime.math — pure-Pascal libm (new this cycle)
Blaise no longer links libm at all. The whole of the transcendental math
Blaise uses is now a from-scratch Pascal port of musl libc's fdlibm-derived
math sources (MIT-licensed), living in runtime.math.pas and lowered to
directly from all three backends:
sin/cos/tanwith full Payne–Hanek argument reduction,asin/acos/
atan/atan2,exp/expm1/ln/log2/log10/pow,sinh/cosh/
tanh, a correctly-rounded bit-by-bitsqrt, andfloor/ceil/round
(half-away-from-zero, matching Blaise's documentedRoundrule).- Double-precision kernels only; each backend widens
Singlearguments and
narrows results at the call site. - Accuracy pinned at ~1 ulp by
runtime/src/test/pascal/test_blaise_math.pas
— roughly 190 glibc reference vectors checked at 2-ulp tolerance, with
exactness classes verified bit-exact. - All three backends (QBE, native x86-64, native arm64) now lower the
float-math builtins to these RTL calls instead of externallibmsymbols;
arm64gains the whole float-builtin family in the same change (previously
unlowered), and afloat-typedAbsarm was added to native x86-64 that
had never existed (Abs(-2.5)previously returned-2.5unchanged there). - Consequence:
--staticfreestanding binaries can now usePowerand
friends — there was no way to static-linklibmbefore — and results are
bit-identical across Linux, FreeBSD and macOS (GH #199,
BUG-20260730-native-libm-not-required).
stdlib
Text.Regex— a new backtracking regular-expression engine..From([...])array-literal constructors forTList<T>, both dictionary
types, andTSet<T>, plus the stdlib's first dedicated Collections test
suite.TUuidvalue type (theGUIDunit was renamed toUUID).AssertRaises/AssertNotRaisesadded toblaise.testing.- Out-of-range list/collection access raises
EListErrorinstead of
crashing. - Collection destructors correctly declared
overrideso vtables resolve
correctly. - Managed elements are released on
TStack/TQueue/TSet/TDictionary
teardown (BUG-012). GCHashOfand read-only container lookups borrow their key instead of
retaining it.
Toolchain / linking
- Auto link mode: a program that binds no C library links freestanding
(no libc, no.dynamic) by default on Linux; bindingexternal '<lib>'
or a bare libc symbol flips the link to dynamic+libc automatically.
--static/--dynamicforce either mode explicitly. - Dynamic linking support for
freebsd-x86_64. - The
blaise_rtl.aarchive and its build/guard machinery were removed —
the compiler source-builds the RTL on demand into a target-keyed object
cache, so there is no archive to install or go stale. - RTL source resolution now searches binary- and CWD-relative ancestor
paths too. - Unit initialisation now runs in dependency order on the incremental
compile path, fixing a class of implementation-only-dependency ordering
bugs. - Demand-driven library linking: the internal linker emits extra
DT_NEEDEDentries only for libraries actually bound;pthreadis now
bound viaexternal 'pthread'rather than always linked. -l<name>resolves via SONAME / linker scripts; new--lib-pathflag
(GH #188).- RTL functions and unit
_finisymbols are weak-bound to prevent
archive/object multiple-definition errors (GH #180 follow-up, GH #191). libmis no longer a link dependency at all — see the dedicated
"runtime.math" section above (GH #199).
Codegen — native x86-64
IContainerWriterseam extracted from the ELF object writer, shared with
the new Mach-O writers.- Inc/Dec on a promoted narrow local, a narrow global, and a field receiver
now route through the correct width / shared l-value slot path. - 2-D field-array element reads return the element address, not a stale
value. - 9th+ float arguments and >6 integer argument slots correctly overflow to
the stack at method and itab call sites. - The stack-machine expression idiom was eliminated from the x86-64 emitter
in favour of direct register allocation. DoubleToStr/SingleToStrcall sites now widen/narrow the float argument
to the correct width (GH #200).
Codegen — interfaces / generics
- itabs are now emitted for generic instances that inherit an interface,
and for interfaces a class inherits, in the unit compilation path (both
backends). - Interface methods inherited across a unit boundary now resolve correctly.
- Interface elements are readable through an indexed property.
- Generic monomorphisation now carries visibility, static, and
parameter-passing-mode facts correctly into instantiated bodies.
Bug-fix clusters
- Jumbo sets (>64-member enum bitmaps): element access fixed across
field, array, and nested-chain shapes on both backends. - Nested-procedure capture: grandparent-scope capture, var/out
double-dereference, sibling capture forwarding, and interface-typed
captures. - Field-array l-values: subscript-on-a-field-array-element used as an
l-value, across Inc/Dec, SetLength, and address-of, on both backends.
Performance
- Stage-1 register promotion — hot scalars kept resident in
%r14/%r15. %r13cross-call pin, for-loop condition push/pop removal, slot-traffic-
based promotion ranking.- Phase-1 inlining — the QBE inliner ported to the native backend.
- Loop rotation and a 4-register promotion pool, extended to inlined bodies.
- Reproducible native-vs-QBE codegen benchmarks added under
tools/performance/.
Tooling / CI
blaise-bindgen(new): generates Blaise bindings from clang AST JSON
— macro constants, function-pointer procedural types, typed C-union
accessors, bitfield packing, and variadic-functionvarargsdirectives.
Shipped with a generatedx11bindings module and a working Xlib GUI
example.flag-coverage(new): a backend annotation-flag drift guard,
sibling tobif-coverage— catches a semantic-pass flag silently going
unread by a backend arm.- A linked-binary self-hosting fixpoint added, covering the
macos-arm64container writer in CI. - CI now runs the full FreeBSD tier (including the stdlib suite) on every
run, with clearer failure diagnostics.
GitHub issues closed this cycle
#160, #180, #182, #187, #188, #189, #191, #195, #196, #208.
Stage-2 QBE IR: 637,968 lines, byte-identical across stage-2/stage-3.
Test suite: 4,977 tests, 2 ignored, all passing.
Built with ❤️ and lots of ☕