Mettle v0.14.0
Mettle stops carrying its own backend. It compiles against libmtlc, and this
release names the exact backend commit it uses.
BREAKING CHANGE
Building from source now needs libmtlc.
Fetch it once, then build as before:
./get-libmtlc.sh # Windows: .\get-libmtlc.ps1
make # Windows: .\build.batInstalling a release needs nothing extra. The backend is already in the binary.
The backend source has left this repository: src/codegen, src/linker,
src/compiler, src/debug, and the IR core with its optimizer. Send patches
for any of those to libmtlc.
Where each half lives
- This repository holds the language. The lexer, the parser, the type checker,
the memory safety analysis, IR lowering, the driver, the runtime, the
standard library. - libmtlc holds the IR, the optimizers, code generation for x86-64, ARM64, PTX
and SPIR-V, and PE and ELF linking. libmtlc.versionnames one commit, so you can rebuild the compiler that
shipped. SetLIBMTLC_DIRto build against a checkout of your own.- docs/mettle-and-libmtlc.md covers the split, the
include paths, and how to work on both halves at once.
Fixed: two silent miscompiles
The differential fuzzer found both. --verify missed both, and called the
affected program clean.
- A shared scaled index addressed the wrong element.
a[i] * b[i]computes
i << 2twice, and once the optimizer folds the two into one value, two
address computations read it. The x86 address fold wanted that value to have
a single reader, so the pair fell through to a fallback that folded the
already-scaled value in as a unit index. Release builds on the register
allocating backend read the wrong element. The fold now handles a shared
index and keeps the shift for whoever else needs it, which is also one
instruction fewer than before. - A spilled base and a spilled index could land in one register. The scaled
load and address encoders staged each spilled operand through a scratch
register, and for one combination of allocations they picked the same one, so
[base + index*4]encoded as[r11 + r11*4]. Each staging register is now
chosen clear of the ones already in use.
Faster compiles
- Profiling on 200k-line inputs found the compiler in linear
strcmpscans, a
getenvper pass event, and heap churn. Hashed lookups, lazy teardown and a
leaner inliner take a 226k-line build from 2244ms to 1082ms, and peak memory
from 892MB to 508MB. --verifycosts 2 to 4 times a plain compile, down from 8.5. The interpreter
no longer zeroes 570KB per machine, and the pass driver reuses its snapshot
when a pass changed nothing.ui_demo.mettledrops from 6.5s to 0.36s.
The ML optimizer now proves its work
--ml-optruns every model decision through the reference interpreter before
it stands. On a divergence it rolls back, then re-applies one decision at a
time, so the bad one is named with a counterexample and dropped while the
rest hold. No--verifyneeded.- That makes
--ml-opt-speculativeusable. The model's dead-code deletions
carry no proof, so they stand on the validator's word alone. - Across the 49 benchmark programs: 1,190 proposals, 348 applied, 537 rejected
with counterexamples. Every binary matched its baseline at run time. - Writing the speculative action found four holes in the validator. This closes
all four. Each had been blinding--verifytoo.
--explain-json: stable ids and four new sections
- Every decision carries a short id beside its prose. Wordings improve;
int32-sum-narrow-accdoes not. Tools should read the ids. - A per-function table of instruction counts before and after.
- A pass ledger that says what each pass did and which lines it touched. The
vectorizer's row reports both the SIMD kernel it added and the scalar work it
retired. - Per-loop cycles per iteration and the port each loop bottlenecks on. The
optimizer knows which loops it refused to vectorize; only code generation
knows what those loops then cost. - A call graph and a hotspot ranking.
- docs/explain-json.md documents the schema.
Mettle for CLion (new)
A JetBrains plugin in tools/clion-plugin. It loads in CLion and across the
IntelliJ family.
- Diagnostics come from the compiler, so the editor shows the same codes and
help lines as the command line. - The debugger drives
--debug-hooks: breakpoints, stepping, the call stack,
and variables you can edit. Windows only for now. - An optimization report window reads
--explain-jsonand applies the fixes the
compiler already checked. - Lexer, parser, completion, navigation and rename cover the language as the
compiler parses it, down to optional end of line semicolons.
Other
- The benchmark harness builds its C baselines with clang under
-Clang. - Every CI job fetches the pinned backend and caches it. The sanitizer job
instruments the backend too, which is most of the compiler.
What's Changed
- Make Mettle a frontend and require libmtlc for the backend by @suidvandiewereld in #46
Full Changelog: v0.13.0...v0.14.0