Skip to content

refactor(comp): shed tokens and compile large programs faster - #1968

Merged
nicolas-abril merged 4 commits into
mainfrom
refactor/comp-simplify
Oct 30, 2026
Merged

nicolas-abril merged 4 commits into
mainfrom
refactor/comp-simplify

Conversation

@nicolas-abril

@nicolas-abril nicolas-abril commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

comp.ts drops 40 ttok (ttok -m gpt-3.5-turbo, as gates/repo.ts pins it), and large programs compile faster. It merges cleanly with main, taking comp.ts from 66,000 to 65,960, which leaves room under the 66,000 cap.

Compile time (C and JS together, median of 7 alternating runs):

Program Before After
demos/app_slash_boss_3d 746 ms 614 ms
demos/pure_hvm5_mini 270 ms 235 ms

What changes

Compile time

  • c_ids scans only the runtime. The emitted C names no ids, and it was most of the text being scanned.
  • JS builds skip ty_srcs. It only adds ADT names to FL.srcs, and JS reads only the defs from that map.
  • term_const is memoized. It re-walked the same constructor trees.
  • js_lib drops FL after building a module, so the loader's host doesn't keep the book alive. After a module build and a GC, the heap goes from 87 MB to 5.4 MB on boss and from 33 MB to 5 MB on hvm5.

Simplification

  • NATIVE is inlined where it is read, and IO_EMIT where it is used.
  • term_aux returns u32, which removes the (u32)term_aux casts. io_hand_v is the one place that needs the width, and it now casts itself.
  • turn_take and tld_of name repeated expressions.
  • ty_holds takes its predicate as data, where its cache was keyed on a closure's source text.
  • lay_arr returns arr as a number, and a few one-use locals and inferred annotations go.

Behavior

  • One partial fix: js_lib(book, true) overflowed the stack in ty_srcs on tests/check/eta_recursive_type, and that module now builds. Only JS is fixed: ty_srcs still overflows on a recursive type in a C build, as it does on main.
  • C: the emitted program code is unchanged across the corpus. Only the runtime text differs, from the term_aux and turn_take edits.
  • JS: output is byte-identical apart from the fix above.

Verification

  • tests/run/array_lent is new. It covers Array parameters that are shared and passed to defs that ignore them, on every lane. It passes on main too, so it guards behaviour and is not a test of this PR's changes.
  • gates/_run.ts on a clean checkout: repo 54/54, test 1786/1786, perf 124/124. Ping was skipped because that checkout has no site repo next to it.
  • I compared C, JS and module output against main for all 1,875 .bend files under tests, demos and bench; 1,378 of them load, and the rest fail before reaching the compiler.
  • Not tested: the CUDA device path was not built, so the term_aux change is untested there. Metal is covered by the test gate.

🤖 Generated with Claude Code

nicolas-abril and others added 4 commits October 30, 2026 16:49
comp.ts goes from 66,010 to 65894 ttok, back under its cap. Emitted programs
are unchanged; the C runtime's text changes without changing what it does.

Compile time: c_ids scans only the runtime, not the emitted C; JS builds
skip ty_srcs, which only ever fed the C lane; term_const is memoized; and
js_lib drops FL after a module. FL.ty_opens goes, as ty_holds caches the
same answer.

Simplification: NATIVE and CLI_HELP are inlined where they are read,
term_aux returns u32, turn_take and tld_of name repeats, and brw_of loses
an Array case the general rule already covers. ty_holds takes its
predicate as data rather than keying its cache on a closure's source.

Skipping ty_srcs also fixes a stack overflow: js_lib on a module with a
recursive type (tests/check/eta_recursive_type) now builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
comp.ts is at 65,906 ttok, still under the cap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dropping FL.ty_opens made pure_hvm5_mini compile about 3% slower, so it
stays. The two locals that were inlined into loops come back, and the
ty_holds comment no longer describes the closure-keyed cache.

tests/run/array_lent pins Array parameters lent under the general borrow
rule. A compiler that keeps every Array parameter borrowed prints a wrong
value for it.

comp.ts is at 65,928 ttok.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without the Array case every Array parameter starts borrowed, so small
Array programs paid about 15% more compile time for a gain only @unsafe
code could see, and a def called through FID(k) could leak an Array. The
array_lent test stays as a plain behaviour test: it passes either way.

val_box's slot goes back to emit_hold, which always makes a fresh local,
and the JS skip of ty_srcs becomes a plain if with its reason.

comp.ts is at 65,970 ttok.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@nicolas-abril
nicolas-abril merged commit f1273d3 into main Oct 30, 2026
1 check passed
@nicolas-abril
nicolas-abril deleted the refactor/comp-simplify branch October 30, 2026 17:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant