Commit Graph
57 Commits
Author SHA1 Message Date
Chris Tate 0933548b8d Simplify optimized partitions at O1 before the thin link
An optimized program divided into partitions was simplified at O2 before
the thin link and optimized again at O2 after importing, so the work on
each partition's largest functions ran twice. The pre-link now runs the
O1 simplification, which still annotates the profile and inlines and
simplifies enough for the summaries the import decisions read; the
backend's O2 optimization is unchanged. A program optimized as one module
is unchanged.

The O1 simplification has no correlated value propagation. Without it,
SimplifyCFG folds a jammed loop's early exit and its trip-count exit into
one branch, the loop's latch no longer exits, and the backend's unroller
keeps a trip-count test in every unrolled iteration. The pre-link runs the
pass once per function after simplifying it.
2026-10-30 00:51:09 -05:00
Chris Tate f30f622a94 Keep x86-64-v3 copies' code in instrumented and colder-profiled builds
- In a module that counts executions for a profile (--profile-generate,
  also the context-sensitive second phase), every x86-64-v3 copy keeps
  its code. A copy that took its baseline copy's body would increment the
  baseline copy's counters, and a --profile-use build would then treat the
  x86-64-v3 copy as never run.
- With a profile, a copy keeps its code when its baseline copy ran fewer
  times. A profile collected on an x86-64-v3 machine gives the baseline
  copies no runs, and their bodies are optimized as cold code.
2026-10-29 20:47:16 -05:00
Chris Tate 82f5aa9608 Keep x86-64-v3 code from running slower than the baseline
- Worker programs run strip-mined typed-array loops in blocks of 128
  iterations when the program's code is compiled for x86-64-v3 or above,
  or with --cpu-dispatch. At that level the vectorized loop over bytes
  takes 128 iterations a step, so in blocks of 64 its vector code never
  ran.
- In --cpu-dispatch builds, the LLVM helper gives an x86-64-v3 copy the
  optimized code of its baseline copy when the v3 code has vectors of at
  most 128 bits, none wider, and no rounding or bit-count intrinsic in a
  loop. Its direct calls go to the callees' x86-64-v3 copies. The text
  partitioner places each x86-64-v3 copy with its baseline copy, so the
  two are optimized in one partition.
2026-10-29 20:21:41 -05:00
Chris Tate 609d1c5d5b Keep partition placement stable when an edit adds a small helper (#2561) 2026-10-29 15:50:13 -05:00
Chris Tate 6b2af671e5 Weigh program profile matches by the profile's counts (#2528) 2026-10-29 15:10:28 -05:00
Chris Tate f3ed70667e Count the small roots a partition takes toward its cap
A root under one 4 KiB unit went to the first open partition from its
name's whose load from the larger roots was below the cap. When only one
open partition was below the cap, every such root went there, and that
partition could hold most of the module, which then was optimized whole
and lost the per-partition cache. The small roots a partition takes now
count toward its cap for the small roots after them, and a small root
that finds no partition below the cap goes to its name's. The larger
roots' placement still ignores the small roots, so a helper that an edit
adds or removes moves no larger root.
2026-10-29 14:57:26 -05:00
Chris Tate da6665a98a Keep partition placement stable when an edit adds a small helper
Roots under one 4 KiB unit, mostly runtime helpers, no longer count in the
partition loads that balancing compares. They are placed after the larger
roots, each in the first open partition from its name's partition whose
load from the larger roots is within the cap, so where a helper goes
depends only on the larger roots. A helper that an edit adds or removes
used to change the total and the cap and move several other roots, and
every partition they left or joined was compiled again.

A root's size also leaves out the digits of metadata references, which an
edit elsewhere in the module can renumber, so an unchanged function no
longer crosses a unit boundary because its references were renumbered.
2026-10-29 09:20:26 -05:00
Chris Tate 398e2e9e9c Weigh program profile matches by the profile's counts
The LLVM helper's emit reports the sums of the profile's counters on the
functions it annotated and on the functions whose control flow changed since
the profile was collected (annotated_counts and mismatched_counts), and the
partition cache keeps them with each partition's match. The annotated ones
are listed as the profile annotation leaves them, before block counts
recover any. Builds of the native compiler print the share of the profile's
counts that changed functions hold.
2026-10-29 02:42:47 -05:00
Chris Tate ad9fa7f510 Compile the functions a sparse profile never ran as cold code
A profile merged with --sparse has no record of the functions its
training never ran, so a build with it optimized them as without a
profile, and on tsc-ts they are 72% of the program's IR. The block-count
file a recording build writes now also names those functions, with an
entry count of zero and no blocks. A --profile-use build that reads the
file gives such a function an entry count of 0 and the cold attribute,
as it does for a mismatched function the file records as never run, so
LLVM optimizes it for size and places it with the other unlikely code.
A function the file does not name, such as one added since the profile
was collected, keeps no counts.
2026-10-29 02:07:17 -05:00
Chris Tate d10d5578af Put program constructors in .init_array on ELF
The helper's program target options left UseInitArray off, so a program
constructor went to .ctors. The C startup files and lld run only
.init_array entries, so such a constructor never ran. Runtime units
already set the option (runtime-unit.cpp); program code now does too.
No program emits a constructor today, so executables are unchanged.

native-constructors.test.ts emits a constructor through a single object,
split code generation and program partitions, checks that it lands in
.init_array on ELF, and runs it.
2026-10-28 20:37:15 -05:00
Chris Tate 31a9be23a4 Give the entry module's top-level code a partition of its own
The emitter writes "; scriptc-entry" before the entry module's top-level
function (its %init). In modules of fewer than 32 partitions, the helper
places the roots that hold a marked function first, and their partitions
take no other root. A root that finds no partition with room goes to the
first open partition from its own.

An edit of the program's top level then recompiles only the top-level code
and the chain that follows it, not the other roots that balancing placed
beside it.
2026-10-28 13:57:13 -05:00
Chris Tate 8b27e9cd2f Name program modules by the entry's file name so profiles match in every checkout (#2462) 2026-10-28 06:43:48 -05:00
Chris Tate 0bf0f69dc3 Balance program partitions by size (#2461) 2026-10-28 06:10:55 -05:00
Chris Tate 23d95a99fd Name program modules by the entry's file name so profiles match in every checkout
Each partition's source file name was the program entry's absolute path,
and profiles name a module's local functions after it. Since programs keep
partition-local functions internal (#2449), a profile collected in one
directory missed those functions in builds from any other: a native
compiler profile collected on main named 27% of its records, holding 2.2%
of its counts, after the checkout's path. Modules now carry the entry's
file name. The partition cache key still includes the full path.
2026-10-28 05:44:38 -05:00
Chris Tate 007a144cb6 Balance program partitions by size 2026-10-28 05:12:02 -05:00
Chris Tate 3bf316de6b Annotate only mismatched functions from block counts
A block-count file annotated every function the profile left without
counts, including functions the profile has no record of. The recovered
count could then exceed the mismatched functions it annotated and hide the
stale-profile warning for mismatched functions left without counts. Only
functions the profile annotation tagged as mismatched are annotated now, so
the recovered count stays among the mismatched ones.
2026-10-28 05:10:57 -05:00
Chris Tate d9481023c3 Annotate functions a stale profile misses from its block counts
A profile annotates a function only while its control flow hashes as it did
when the profile was collected, so compiler and source changes leave the
changed functions without counts. A --profile-use build now reads a
block-count file beside the profile (app.blocks beside app.profdata). Right
after the annotation before inlining, the helper aligns each uncounted
function's blocks with its recorded blocks by label kind and successor
count. Paired blocks take their recorded counts and their edges the recorded
edge counts, by target or, between targets whose labels changed, by
position. LLVM's flow inference fills in the rest, avoiding the edges the
function's own llvm.expect weights make unlikely. The helper then sets the
entry count, branch weights and hot or cold attribute as the profile
annotation does.

SCRIPTC_RECORD_PROFILE_BLOCKS names the file a --profile-use build writes
for the functions its profile annotates; such a build reuses no cached
artifacts. The block file keys every cache, the build report counts the
functions it annotated, and the staleness warning counts only the functions
left without counts. A single-module build with a context-sensitive profile
no longer counts annotated, mismatched and missing functions a second time
after inlining. scripts/refresh-cli-profile.mjs records the file in the
second phase and build-native-cli.mts reads it beside the profile.
2026-10-28 04:50:01 -05:00
Chris Tate d47df7c9c6 Weigh the runtime profile's staleness by its counts
The runtime-unit helper now lists the functions the profile annotated and
the ones whose control flow changed since it was collected, each with the
sum of its counters in the profile. The Linux x64 pack manifest records the
counts on matched and on changed functions (flavors.speed.runtime_profile
annotated_counts and mismatched_counts) and names the changed functions
with the most counts. A function that one unit variant matches counts as
matched in the other variant too.

The runtime profile test fails when changed functions hold more than 5% of
the counts. RELEASING.md adds refreshing the runtime profile to the release
steps.
2026-10-27 23:20:02 -05:00
Chris Tate ed90c10fce Compile small release and speed programs in partitions (#2449) 2026-10-27 21:35:30 -05:00
Chris Tate 05810305cf Compile small release and speed programs in partitions 2026-10-27 20:49:11 -05:00
Chris Tate 95e715febd Optimize the speed runtime units with a committed runtime profile
The LLVM helper's runtime-unit now optimizes a unit itself (--opt-level),
with IR instrumentation (--profile-generate) or a profile (--profile-use),
through the same pipeline as program code. The Linux x64 pack's speed
units are compiled to unoptimized bitcode and optimized there with
packages/runtime-pack-common/profiles/linux-x64-gnu.profdata.gz, so one
LLVM writes and reads every profile. Release and library flavors are
unchanged. The pack manifest records how the profile matched the units.

Code the runtime profile finds cold is optimized for speed, not size: a
runtime function the training programs rarely call can be hot in another
program. scr_message.c is optimized without the profile.

scripts/refresh-runtime-profile.mjs trains the profile on the runtime
benchmark workloads and, optionally, a tsc-ts checkout, and keeps only the
records of functions the instrumented runtime units define
(merge-profiles --keep-functions). Tests check that the profile still
matches the runtime and names only runtime functions.
2026-10-27 20:11:44 -05:00
Chris Tate 18196d4df0 Lay out code by context-sensitive profiles 2026-10-27 09:36:18 -05:00
Chris Tate 7c770d0887 Name the source file in empty split codegen parts
When --split codegen keeps the module whole, the extra outputs are new
empty modules, and their source file name defaulted to the module
identifier: the path of the private copy of the LLVM input, which has a
random name. That name reached each part's STT_FILE symbol, so two
release builds of one program differed in .strtab. The empty parts now
take the module's source file name, as the first part has it.
2026-10-27 03:30:15 -05:00
Chris Tate 640001b260 Generate code concurrently for optimized executables that stay one partition
Optimized executables with at most 1 MiB of LLVM text were compiled as one
module on one thread. With more than 128 KiB of LLVM text they now pass
several outputs and `--split codegen` to the LLVM helper. The helper
optimizes the module whole, as for a single output, then divides its
functions in module order into runs of about the same instruction count and
generates code for each run on its own thread.

- The output count is 4 or 8 and depends only on the module's size
  (nativeCodegenParts), so artifacts never vary with the host. Node and
  native compiler builds pass the same outputs.
- The helper writes the optimized module to bitcode once with its use-list
  order. Every output after the first parses it and turns the other
  outputs' definitions into declarations; the first output does the same to
  the optimized module in place. Each function's machine code matches a
  single-output build except for jumps to a definition that another output
  also uses.
- Only local definitions that another output uses become hidden. Dead
  constant users are dropped before unused declarations are removed, so no
  output names a thread-local variable it does not use.
- When one run would hold more than three quarters of the instructions, the
  first output is generated from the optimized module as for a single
  output and the others are empty objects.
- Dev builds, partitioned builds and program-object validation are
  unchanged.
2026-10-27 00:22:17 -05:00
Chris Tate 5ab76a4d54 Keep the native compiler's profile matching its functions 2026-10-26 15:31:14 -05:00
Chris Tate 2d2343e36f Keep program partitions local to the code an edit changes 2026-10-26 05:03:24 -05:00
Chris Tate ba2aadcb81 Import callees of up to 40 instructions across program partitions
The thin link imported a callee of up to 100 instructions, LLVM's default,
into every partition that calls it, and each partition then optimized and
compiled its imported copies again. Partitioned programs now import callees
of up to 40 instructions. Programs that compile as one module are
unchanged.
2026-10-26 03:32:39 -05:00
Chris Tate 4c3a1d9c98 Link the Linux release helpers against LLVM built with ThinLTO and a helper profile
The Linux helpers linked LLVM 22.1.8's release archive. The helper's code
generation is LLVM's code, so building that LLVM from its release sources
with ThinLTO and with a profile of the helper's own work makes code
generation 5-9% faster than the helper as released, with identical objects.

- native/llvm-codegen/llvm.profdata.gz is the profile, collected by
  scripts/refresh-llvm-profile.mjs: it builds LLVM with IR instrumentation
  and an instrumented helper, and runs that helper on tsc-ts, five Effect
  fixtures, the runtime benchmark workloads and every 50th corpus program
  (scripts/llvm-helper-inputs.mjs). It follows LLVM's sources, so it needs
  a refresh when LLVM is bumped.
- scripts/build-llvm-dist.mjs builds LLVM with that profile and ThinLTO,
  and packs it with a checksum. The llvm-dist workflow, run by hand, builds
  it for x64 and arm64, requires a helper linked against it to give the
  same objects as one linked against the release archive
  (scripts/check-llvm-dist.mjs), prints both helpers' times and the
  profile's mismatch count, and attaches the archive to the LLVM_DIST_TAG
  release of this repository.
- The release workflow's Linux jobs, and the wasm32-wasi job, which also
  uploads the x64 GNU helper, download that archive and build the helper
  with SCRIPTC_LLVM_THINLTO=1: clang, lld and ThinLTO, and the profile for
  the helper's own sources. Without the archive, or if that build fails,
  the helper links the release archive as before.
- The four Linux helper packages share their build in
  native/llvm-codegen/linux-helper.mjs. Without SCRIPTC_LLVM_THINLTO it
  builds the same executable as before.
2026-10-25 18:53:25 -05:00
Chris Tate d4e8c4f283 Merge main 2026-10-24 21:46:05 -05:00
Chris Tate 65555dace3 Drop struct type names before the thin link instead of renaming promoted locals
The partitions of a program build have no locals for ThinLTO to promote:
symbols that other partitions refer to are already hidden. What changed
the modules after importing, and with them the object cache keys, of
partitions an edit did not touch was the numbering of struct types. Every
partition declares the program's types under the same names, and the thin
link loads the importing partition and the partitions it imports from into
one context, which tells same-named types apart by appending a counter
that runs across the whole link. An edit that adds a type anywhere shifted
the counter.

Partitions now drop the names of their struct types before their summary
is written; importing matches unnamed types by their bodies. The
promoted-locals option, the per-partition source file name and the
partition index in the summary key are removed.
2026-10-24 17:47:58 -05:00
Chris Tate 70f565177e Count profile-annotated functions when the annotation runs
The match report counted the functions with profile counts after the
whole pipeline, so an annotated function that inlining or dead code
elimination later removed was not counted, while the annotation's
mismatch and missing-function warnings were. A pass-instrumentation
callback now counts the annotated functions right after
PGOInstrumentationUse runs, in the one-module and the partitioned
pipelines.

A new test builds helpers that reach the annotation and are then
inlined into main and deleted, and checks that the report counts them.
2026-10-24 16:05:36 -05:00
Chris Tate 396c6944ec Report how well the native compiler's profile matches its functions
The native compiler is built with a committed optimization profile. A
function whose control flow changed since the profile was collected is
optimized as without one, so the profile loses its gain as compiler code
changes, with nothing to show it.

With --profile-use, the helper now counts what the profile annotation
reports while it applies the profile: functions that took the profile's
counts, functions whose control flow no longer matches (hash mismatch),
and functions the profile has no record of. It sums the counts over
partitions, keeps each partition's counts beside its cached summary, and
prints them as one line of JSON after a successful emit. The compiler
reads that line (an older helper prints none) and returns it as the
executable artifact's profileMatch.

build-native-cli prints the share of profiled functions that match, and
warns below 90% that the profile should be refreshed. On main aa1c26845, a
profile refreshed on that commit matches 92.7% of the compiler's profiled
functions, and the one committed about 200 commits earlier 87.2%; that one
kept about half of the fresh profile's gain on a cold tsc-ts build.
2026-10-24 11:20:47 -05:00
Chris Tate 9e4f1253c6 Keep unchanged partitions cached across edits 2026-10-24 10:11:29 -05:00
Chris Tate 6715609695 Place each source file's functions in the same partitions
Partitions were filled by a hash of each function's name, so most calls
crossed partitions and the thin link imported their small callees into
nearly every partition. The emitter now writes a "; scriptc-group" line
before the functions of each source file, and the text partitioner places
a group's functions together: a group larger than the mean partition, or
than 1 MiB, is divided into a power of two of chunks by name, and chunks
go, largest first, to the lighter of two partitions chosen by hash. The
1 MiB bound keeps the code a partition optimizes together, and the
inlining within it, from growing when a program has fewer partitions.
Modules with fewer than 32 partitions, and functions without a group,
keep their name-hash placement: with few partitions per core, the balance
of the largest partitions decides the build time more than the imports.
The placement still depends only on the module text and the partition
count.
2026-10-24 00:34:25 -05:00
Chris Tate fc38e62791 Stop importing runtime bitcode into program builds 2026-10-21 14:10:23 -05:00
Chris Tate 7f9371c4b2 Write merged profiles through a uniquely named temporary file
merge-profiles wrote the merged profile to `<output>.tmp` and renamed it
into place. Opening that fixed path followed an existing link there and
truncated its target. The temporary file is now created exclusively with
createUniqueFile next to the output, as emission does, and is removed when
writing fails or the stream reports an error.
2026-10-21 08:40:46 -05:00
Chris Tate c7569cf502 Limit profile-driven imports between partitions 2026-10-21 04:21:34 -05:00
Chris Tate 8065be3ccd Add profile-guided optimization 2026-10-21 03:13:45 -05:00
Chris Tate 267b77c994 Partition programs with multi-line dispatch tables as text
The emitter writes interface dispatch tables one element per line. The
helper's text partitioner accepted only single-line globals, so any
program with such a table (every partitioned program with class
interfaces) fell back to parsing the whole module before splitting it
with LLVM. The text partitioner now reads a global whose aggregate
initializer opens at the end of its line and closes on a line that holds
only the closing bracket.

Those programs now parse their partitions concurrently and keep the text
partitioner's placement, so an edit to one function changes only that
function's partition again.
2026-10-21 01:08:13 -05:00
Chris Tate 0e67cd1e3b Place functions too large to inline by their own name
The helper keeps an internal function that exactly one other function
references in its referrer's partition, so the partition can inline it.
A program's module initializers are each called only from the entry
point, so all of them, with every single-use helper they call, shared
the entry point's partition. In the three.js nodes fixture that
partition held 1.1 million lines of LLVM IR, almost five times the
average, and set the native build's longest compile.

A function whose body is larger than 256 KiB of LLVM text is past
LLVM's inline cost limit even for the only call to a local function, so
it is now placed by the hash of its own name. Its own single-use
callees still stay with it.
2026-10-18 08:02:34 -05:00
Chris Tate 588e16d8c7 Skip WebAssembly irreducible control flow analysis on reducible functions
LLVM's WebAssembly pass that gives multiple-entry loops a single entry
first records, for every block, every block it can reach. Its time and
memory grow with the square of a function's block count even when the
function has no such loop. In the three.js nodes fixture a module
initializer of 40,000 blocks spent four minutes and 22 GB in it, which
set the helper's peak and most of its wall time.

The helper now runs the pass only on functions whose control flow graph
is irreducible, and WebAssembly object emission leaves out the module
pass that collects external symbols for assembly declarations, so each
function's machine code is freed once it is printed. Optimized
partitions are compiled through the thin backend's pre-codegen hook to
use the same pipeline. Objects are unchanged.
2026-10-18 01:30:29 -05:00
Malte Ubl f4ce6910c7 Inline small runtime functions into release executables
Release executables now import small runtime functions from runtime
bitcode, as speed executables do, so LLVM can inline them into program
code. Release units keep the runtime compiler's own objects, unchanged,
and additionally ship the bitcode of the same compilation reduced by the
helper's prune-import. Their unit-local symbols stay local, so only
bodies that need none of them can be imported, which keeps the import
small: about 1.3 MB per program.

Only unsanitized programs small enough for one codegen partition import.
Every partition reads the bitcode again; on the Effect fixtures (64
partitions) import cost +2..18% compile time and +4.3..4.9% size, so
partitioned release builds stay exactly as before. Speed is unchanged.

Measured against main in Linux Vercel Sandboxes, same-VM interleaved
medians (bench-runtime --layouts=4 --runs=16), on two VMs:

- bench-runtime (31 workloads): -1.3% (8 faster, 0 slower) and -1.0%
  (1 slower, typed-array-scan-workers +3.2%); size +0.0%
- js-compiled suite (22 programs): -2.2% and -1.8%; size -0.1%
- cold builds of all 53 programs, interleaved: +3.1%; helper time per
  build +40..235 ms
- Effect fixtures: byte-identical to main
2026-10-16 14:03:52 -07:00
Malte Ubl 3467efac73 Prune runtime import bitcode to importable bodies
Program builds that import runtime bitcode parsed and merged every unit's
whole module, although the import can only ever take small bodies that
need no second copy of unit-local state. The helper now reduces a unit's
bitcode to exactly that set when the runtime pack is built: the importable
bodies within the size limit at their call distance from any public
function, and the constants they copy. Every other definition becomes a
declaration, as the import would treat it. A program's selection starts
from public functions, so it is always a subset of the pruned set, and
programs import the same bodies as before.

`runtime-unit` writes the pruned bitcode for speed units; the new
`prune-import` command prunes a unit's bitcode as compiled, for units
whose objects the runtime compiler emits itself.

Linux x64 speed bitcode shrinks from 17.0 MB to 8.6 MB. Runtime objects
are byte-identical, and import lists match the unpruned bitcode exactly.
Interleaved cold builds of 53 programs in a Linux Vercel Sandbox: speed
went from +21.4% to +12.1% over release.
2026-10-16 13:12:16 -07:00
Chris Tate 3ea231d70d Optimize and generate native code in parallel partitions
Large executables were simplified and inlined as one module before the
optimizer split them, so most of a release build ran on a single core,
and any edit recompiled the whole program.

The LLVM helper now divides the program before optimization. It splits
the emitter's assembly text directly, so partitions also parse
concurrently, and falls back to LLVM's module splitter for any input
outside the emitter's grammar. Internal functions referenced by a single
function stay with that function, and globals stay with their first user.
Optimized partitions follow the ThinLTO model: each is simplified and
summarized on its own thread, a thin link imports small functions across
partitions for inlining and returns unexported hidden definitions to
internal linkage, then each partition is optimized and compiled on its
own thread. Unoptimized partitions compile independently, so dev builds
of large programs are parallel too.

A private per-helper cache directory stores simplified partitions under
the hash of their source and objects under the hash of the module after
importing, so a rebuild recompiles only the partitions an edit can
affect. To keep unchanged partitions identical across edits, each
partition numbers its metadata in first-use order, lists only the debug
compile units it uses, and orders declarations by name, and interned
string constants are named by their content rather than first-use order.

Partition counts are powers of two that depend only on the module size,
up to 64, so output stays the same on every host and functions keep
their partition across ordinary edits. LLVM text that arrives in parts is
written in large batches and handed to the helper in place instead of
being written a second time.
2026-10-09 19:51:47 -05:00
Malte Ubl 60c30d6ebd Import runtime bitcode into speed programs (H02)
Re-lands perf/h02-runtime-lto (6d373317, b62448f3) behind the speed
posture.

- Runtime packs gain an executable `speed` flavor whenever the host LLVM
  helper can run. Its static units are emitted through the helper's
  `runtime-unit` command (promoted unit-local symbols, object and import
  bitcode from one module); its SCR_DYNAMIC variants reference the release
  objects. Release, dev, and library flavors and the vendor archives are
  built exactly as before (the rebuilt macOS pack's flavors and archives
  are identical to the baseline's).
- Speed program builds load the speed flavor's bitcode and pass it to the
  helper (`--import-bitcode`); release builds never do.
  loadRuntimeBitcode only reads a real speed flavor, never release.
- The helper drops the emitter's inert sanitize_address attributes only
  when it imports, so release modules reach the pipeline unchanged.
- Tests: runtime-pack.test.ts covers speed-variant bitcode selection,
  verification, and that release-flavor bitcode is never imported;
  native-codegen.test.ts covers helper arguments and cache keys.

Release executables stay byte-identical to the stack tip with the rebuilt
helper (14/14 workloads, macOS).
2026-10-08 15:46:34 -05:00
Chris Tate e936346215 Parallelize large native builds and adapt cycle collection (#722) 2026-10-07 10:47:31 -05:00
Chris Tate 668eb78124 Optimize native array loops and preserve live tuple iteration
- Reduce allocation and reference-management overhead in native array loops.
- Enable vectorization while preserving numeric behavior.
- Preserve live tuple iteration and cover reference lifetimes and missing values.
2026-10-04 10:38:10 -05:00
Chris Tate 0845c7ff56 Make native installs portable and smaller (#599)
* Make native installs portable and smaller

- Support glibc 2.34 with portable compiler binaries and static LLVM helpers.
- Bundle the host runtime and discover optional cross-target packs from project dependencies.
- Add application build benchmarks covering latency, executable size, and memory.

* Keep bootstrap tools available in Sandbox validation

- Isolate Zig for native compiler bootstrap and glibc entropy contracts.
- Preserve the existing toolchain scope for cache and corpus tests.

* Fix portable compiler bootstrap linking

- Keep native support objects compatible with the destination host linker.
- Resolve installed targets using the host declared by the toolchain manifest.
2026-10-01 10:46:16 -05:00
Chris Tate 3f66c8e20b Make LLVM the sole production backend
- Remove C emission, debugging options, and automatic backend fallback.
- Complete LLVM lowering and native bootstrap coverage across supported targets.
- Link executables and libraries with precompiled C runtime packs, including iOS and Android.
2026-09-29 20:54:09 -05:00
Chris Tate 6700381ff5 fix(release): build portable musl LLVM helpers (#304)
- Build musl helper packages as static host executables matching LLVM’s glibc and libstdc++ ABI.
- Preserve musl code-generation targets and Zig-built runtime packs.
- Add pre-merge Alpine execution and package verification coverage.
2026-09-13 18:23:41 -05:00