Skip to content

LLVM 21 → 22: build stack upgrade + codegen/runtime fixes - #23

Open
fxdv wants to merge 2 commits into
murphsicles:bootstrapfrom
fxdv:feat/llvm22
Open

fxdv wants to merge 2 commits into
murphsicles:bootstrapfrom
fxdv:feat/llvm22

Conversation

@fxdv

@fxdv fxdv commented Aug 25, 2026

Copy link
Copy Markdown

What

Upgrades the bootstrap build stack from LLVM 21 → LLVM 22 so the compiler builds with current toolchains (Homebrew now ships llvm@22, not llvm@21), and fixes a set of pre-existing codegen/runtime bugs that the new build surfaces (it runs code the old build rejected at validation).

Commits

  1. LLVM 21 → 22: bump inkwell/llvm-sys, update CI, port runtime

    • inkwell 0.9.0 (llvm22-1) + llvm-sys 221.0.0
    • bootstrap-branch CI (ci/release/benchmarks): apt llvm-22, LLVM_SYS_221_PREFIX
    • wasm-ld-21 → wasm-ld-22; inkwell 0.9 API adaptations
    • JIT function mapping rebuilt as tables + a defensive pass that also maps LLVM's .N-suffixed declaration variants (duplicates were auto-suffixed and missed by by-name mapping → NULL externs)
    • Linux-gated reactor/wakers; new src/runtime/jit_stubs.rs
  2. Fix codegen/runtime bugs surfaced by the LLVM 22 build — all pre-existing on the bootstrap tip:

    • Duplicate std declarations (codegen.rs): the prelude declared 9 runtime symbols twice with conflicting arities (e.g. array_new 2-arg vs the 1-arg real impl). LLVM auto-suffixes duplicates (array_new.10); call sites bound to the numbered copy, which the JIT never maps → NULL → segfault. Now a single canonical declaration set.
    • str_* method resolution (codegen.rs): MIR names method calls with an overload suffix (str_trim_1); the host_ mapping ran on the suffixed name → non-existent host_str_trim_1 → NULL. New host_candidate_for() strips the trailing _<digits> first (also fixes len_str_2 → host_str_len).
    • Neutered array_new (array.rs): returned 0x0BADF00D + a debug print since v0.3.88 (stale autonomous-agent landmine); the real implementation (header + data alloc, canary, 0xCD fill) is restored.
    • Array-like method dispatch (gen.rs): push/append/len/count/get/set only handled DynamicArray receivers; [u8] slices and annotated arrays fell through to an unmapped bare name. Now covers Array | Slice | DynamicArray.
    • use of inline modules (resolver.rs): use math::add; for an inline mod math failed file resolution (W2002), leaving unqualified calls bound to a dead extern while the real body sat registered as math::add. The registered module::item is now aliased under the plain import name (same treatment file imports get). Works when the mod precedes the use (single-pass registration — noted in a comment).

Validation

Full .z suite A/B — this branch vs the shipped May 8 prebuilt binary (bin/zetac-macos-arm64), 477-file bootstrap suite, 30 s per-file timeout:

PASS NOMAIN ERR CRASH HANG
May prebuilt (LLVM 21) 240 101 98 37 1
This PR (LLVM 22) 314 101 23 35 3

Main-branch 785-file suite: PASS 492 → 501, CRASH 94 → 85.

cargo fmt --check ✓ · cargo clippy --workspace --all-targets: 0 warnings ✓ · cargo test: 114/114 ✓
Builds on macOS arm64 with Homebrew llvm@22 (LLVM_SYS_221_PREFIX=/opt/homebrew/opt/llvm@22).

Known pre-existing issues (not caused by, nor fixed in, this PR)

  • [dynamic] non-i64 index-access cluster (~16 sieve/murphy/benchmark files, e.g. tests/primezeta/test_sieve.z): index access on [dynamic]u8-style arrays lowers to raw getelementptr i64 loads/stores (wrong element width, no bounds check), and array_push does not grow a full array. These files previously never ran (validation rejected the array_new call, which is why they were ERR before); now they execute and read/write out of bounds — non-deterministic garbage results, occasional crash/hang depending on heap layout. Suggests a follow-up PR: lower index access through array_get/array_set using the declared element width, and make array_push grow.
  • || parser regression: a function whose body contains || (e.g. a && b || !a) is silently dropped from the file (No main function found. Available: []); the same file works on the May binary. Tip parser issue; follow-up PR.
  • Pre-existing crash set (21 files): crash identically on the May binary (spot-checked — same signal and first diagnostic on both builds).
  • Self-host: zeta_src/main.z hits E4001 on both the May binary and this build (a raw string containing fn main derails parsing) — pre-existing.
  • AOT linking needs zeta_runtime_c.o in the working directory (missing in a fresh checkout) — pre-existing; JIT execution is unaffected.

Follow-up (separate PR — a PR can only target one branch)

Main-branch workflows (ci, build-macos, build-binaries, release, benchmarks) all check out bootstrap and install LLVM 21; once this merges they need the same 21 → 22 bump. Related: main-branch build-macos.yml has been failing silently since the May 8 reactor merge (stale bin/ artifacts persist, and bin/zetac-macos-x64 is actually a Linux ELF).

fxdv added 2 commits August 25, 2026 16:05
- Cargo: inkwell 0.9.0 (llvm22-1), llvm-sys 221.0.0
- CI (bootstrap branch): apt llvm-21 → llvm-22, LLVM_SYS_221_PREFIX
- main.rs: wasm-ld-21 → wasm-ld-22; adapt to inkwell 0.9 API changes
- jit.rs: replace ~100 individual if-let function mappings with
  tables; add a defensive pass that also maps .N-suffixed
  declaration variants (LLVM auto-suffixed duplicate declarations
  were missed by the by-name JIT mapping → NULL externs)
- runtime: gate reactor/wakers to Linux, move set_nonblocking /
  monotonic_ns into io.rs, add jit_stubs.rs (sieve/avx512/qword/bit/
  operator stubs + real datetime_now/get_time_us)
- misc: cfg all() predicate index fix, module_resolver cleanup

Builds on macOS (Homebrew llvm@22) and Linux (apt llvm-22).
All pre-existing on the bootstrap tip (reproducible without the
LLVM bump); fixed here because the new build runs code the old
build rejected at validation.

- codegen.rs: the std prelude declared the same 9 runtime symbols
  twice with conflicting signatures (array_new 2-arg vs 1-arg,
  array_push i64 vs void, println_i64 void vs i64, ...). LLVM
  auto-suffixes duplicates (array_new.10); call sites bound to the
  numbered copy which the JIT never maps by base name → NULL →
  segfault. Now a single canonical declaration set.
- codegen.rs: MIR names method calls with an overload suffix
  (str_trim_1); the host mapping ran on the suffixed name and
  produced the non-existent host_str_trim_1. New
  host_candidate_for() strips the trailing _<digits> first (also
  fixes the len_str_2 → host_str_len form).
- array.rs: array_new had been neutered since v0.3.88 (returned
  0x0BADF00D plus a debug print); restore the real implementation
  (header + data alloc, canary, 0xCD fill).
- gen.rs: array-like method dispatch (push/append/len/count/get/set)
  only handled DynamicArray receivers; [u8] slices and annotated
  arrays fell through to an unmapped bare name. Now covers
  Array | Slice | DynamicArray.
- resolver.rs: "use math::add;" for an inline "mod math" failed file
  resolution (W2002) and left unqualified calls bound to a dead
  extern while the real body sat registered as "math::add". On
  resolution failure, alias the registered "module::item" under the
  plain import name (same treatment file imports get). Works when
  the mod precedes the use (single-pass registration).

Full suite (bootstrap 477, A/B vs the May prebuilt binary):
PASS 240 → 314, ERR 98 → 23, CRASH 37 → 35, NOMAIN 101 (unchanged).
Remaining non-PASS files are known pre-existing issues: the
[dynamic]u8 index-access OOB cluster (raw GEP-i64 lowering +
non-growing push), the "||" parser regression, and the pre-existing
dual-crash set (crashes identically on the May binary).
@fxdv

fxdv commented Aug 25, 2026

Copy link
Copy Markdown
Author

@murphsicles could you take a look when you have a moment? Two commits: (1) the LLVM 21→22 bump — inkwell llvm22-1 / llvm-sys 221, bootstrap CI, runtime port; (2) five pre-existing codegen/runtime fixes the new build surfaces (details in the description).

Note the bootstrap ci.yml doesn't trigger on PRs, so there are no checks here — the full-suite A/B numbers (240→314 PASS on the 477-file suite) and the known pre-existing issue list are in the description. Happy to split or adjust scope if you'd prefer.

AgenticTimes pushed a commit to AgenticTimes/zeta that referenced this pull request Sep 21, 2026
批次 310 的 dc_audit 只回答"有没有引用"。本批把 src/middle/ 的 5 条命中读实现后分两类:
(a) 被同文件近亲取代/重复挂载 → 删;(b) 已实现但从未接线的能力 → 不删、开任务(它本身是缺陷证据)。

删 (a) 类 48 行:ctfe/evaluator.rs 旧 eval_if_expr(40,活路径是 :1033 的
eval_if_expr_with_else) + resolver.rs 的 identity_inference/capability_inferencer 两字段
及两处初始化(8,真正在用的是 passes/identity_verification.rs:13 那份)。
不删 types/mod.rs:1372 unify_array_size —— 活的 unify:1569 Array 分支把 Literal(0) 当通配
(注释自称 hack),对 ConstParam↔Literal 会误判不可统一,死版反而更正确 ⇒ 登记任务 murphsicles#24。
mir/gen.rs:214 的 async_* 五字段留待批次 312(删字段要连带删写入侧,且 gen.rs 是主线最热文件)。

判据补特性维度 ZETA_DC_FEATS:默认 114、--all-features 116(多 2 条在 src/integration/,
只有开 integration 特性才进编译图)⇒ 基线要按 cfg 配置分别存。顺带撞出门禁盲区并登记 murphsicles#23:
三套基线从不跑 cargo test,而 cargo test --lib 单线程有 1 个 HEAD 存量失败
(frontend/indent.rs:944,本批未触碰该文件)、并行会 SIGABRT。

验证:cargo check --tests rc=0;dc_audit --diff 无新增、116→114;
三基线 official 194/194 · python_style 285/2/4/0 · corpus 39/39(19:00:29Z,零位移)。
AgenticTimes pushed a commit to AgenticTimes/zeta that referenced this pull request Sep 26, 2026
两处修复:
1. monomorphize.rs 测试初始化器补上批次 437 新增的 Mir 两个字段
(member_bare_calls / plain_call_names)——lib 测试此前根本编译不过,
正是 murphsicles#23'cargo test 从不进基线'的现场证据:坏了两批没人发现。
2. header_colon_stripped_with_trailing_comment 改用 # 写尾注释并改断言:
python 风格方言里代码后的 // 是地板除(t138 三处真用法),行内注释
标记是 #——旧测试用 // 与方言规则相抵,自批次 334 前后红到现在
(refactor.md 批次 311 记的 cargo test 存量 1 failed 即此)。
另加一条方言钉子(缩进证据文件的 //→ floordiv);初版误用平铺输入
(那是批次 334 的深度 0 规则、t406 known-fail 的地盘),已更正。
AgenticTimes pushed a commit to AgenticTimes/zeta that referenced this pull request Sep 26, 2026
并行 cargo test 的 SIGABRT 根因(macOS 崩溃报告实证):
GC_init 懒初始化非线程安全——两个线程同时第一次 std_malloc → 都进
GC_exclude_static_roots → 区间重叠 → libgc abort('Exclusion ranges overlap')。
修:std.rs 用 std::sync::Once 显式 GC_init 一次(libgc 文档允许、完成后幂等),
并发分配从此都是'初始化已完成后的普通分配'。
实测:cargo test --lib 并行 142/0 × 3 连跑(原:并行必 SIGABRT)。
murphsicles#23 前置全清:cargo test 可进门禁(加步骤 = 动 run_all.sh = ABI 锚点搬家,
留给主线按 #52 流程做,见台账)。
AgenticTimes pushed a commit to AgenticTimes/zeta that referenced this pull request Sep 26, 2026
AgenticTimes pushed a commit to AgenticTimes/zeta that referenced this pull request Sep 26, 2026
两处修复:
1. monomorphize.rs 测试初始化器补上批次 437 新增的 Mir 两个字段
(member_bare_calls / plain_call_names)——lib 测试此前根本编译不过,
正是 murphsicles#23'cargo test 从不进基线'的现场证据:坏了两批没人发现。
2. header_colon_stripped_with_trailing_comment 改用 # 写尾注释并改断言:
python 风格方言里代码后的 // 是地板除(t138 三处真用法),行内注释
标记是 #——旧测试用 // 与方言规则相抵,自批次 334 前后红到现在
(refactor.md 批次 311 记的 cargo test 存量 1 failed 即此)。
另加一条方言钉子(缩进证据文件的 //→ floordiv);初版误用平铺输入
(那是批次 334 的深度 0 规则、t406 known-fail 的地盘),已更正。
AgenticTimes pushed a commit to AgenticTimes/zeta that referenced this pull request Sep 26, 2026
并行 cargo test 的 SIGABRT 根因(macOS 崩溃报告实证):
GC_init 懒初始化非线程安全——两个线程同时第一次 std_malloc → 都进
GC_exclude_static_roots → 区间重叠 → libgc abort('Exclusion ranges overlap')。
修:std.rs 用 std::sync::Once 显式 GC_init 一次(libgc 文档允许、完成后幂等),
并发分配从此都是'初始化已完成后的普通分配'。
实测:cargo test --lib 并行 142/0 × 3 连跑(原:并行必 SIGABRT)。
murphsicles#23 前置全清:cargo test 可进门禁(加步骤 = 动 run_all.sh = ABI 锚点搬家,
留给主线按 #52 流程做,见台账)。
AgenticTimes pushed a commit to AgenticTimes/zeta that referenced this pull request Sep 26, 2026
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