fix(native-backend): decline SEH funclets, refresh stale corpora, drop setjmp-era attrs (#7302) - #7310
Merged
Merged
Conversation
…p setjmp-era attrs (#7302) 1. --target windows + try/catch was a hard compile error: Perry lowers EH to catchswitch/catchpad/catchret there, which the reader cannot build (inkwell 0.9 has no funclet builders — real support needs llvm-sys FFI). Such modules now decline to the textual path. The decline is narrow (windows triple AND personality present), so #7307's macOS EH support is untouched. 2. spike_text.ll and batch_kernel.ll predated #7305 and still contained setjmp + the #0/#1 groups — the backend's primary gate was validating IR Perry no longer emits. Regenerated: the spike corpus now carries 38 invoke edges and zero setjmp. 3. With the corpora refreshed, the reader's #0/#1 handling is dead and is deleted; stale input now fails loudly instead of being quietly accepted. Byte-identical object verdicts on spike (21393 B), 3-unit batch (56296 B) and the try/catch program (46745 B); 569 tests green.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughThe change adds Windows SEH-funclet fallback detection, removes obsolete LLVM attribute handling, and refreshes LLVM spike corpora for personality-based exception handling and updated Fibonacci lowering. ChangesSEH and LLVM exception-handling migration
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
proggeramlug
added a commit
that referenced
this pull request
Aug 12, 2026
…nfreeze the dialect corpora (#7998) * fix(codegen): teach the in-process native backend today's RS4GC IR, refresh the frozen corpora `PERRY_LLVM_INPROCESS=native` could not build any function containing an RS4GC root slot — which is effectively every function. Every `main` execution of `llvm-inprocess`'s native-backend job failed at in line: %r5 = alloca ptr addrspace(1) The issue warned this was not a one-liner, and it was not: fixing each shape only exposed the next. The family, in the order it surfaced: 1. `basic_type` had no `addrspace(N)` arm — the reported failure. 2. `ty_and_val` split `ptr addrspace(1) null` into type `ptr` and value `addrspace(1) null`. The qualifier belongs to the type but sits after a space, so OPERAND position needed the same treatment as type position. 3. `constant` returned an addrspace(0) `null` regardless of the operand type, which the verifier rejects when stored into an `alloca ptr addrspace(1)`. 4. Define lines carry `"frame-pointer"="non-leaf"` (a string attribute) and `gc "statepoint-example"` (which contains a space, so the whitespace-split attribute loop saw two junk tokens). 5. Callsites carry `"gc-leaf-function"`. 6. Landing pads are now `landingpad token cleanup`. `token` is not an inkwell `BasicType`, so that pad is built through llvm-sys. The `{ptr, i32} catch` shape still occurs and keeps its branch. Two further defects were hiding behind the reader failure, both worse than it: **The native path returned assembly and called it an object.** The statepoint backends compact the stack map at assembly time, so the plan carries `-S`. The textual in-process path has always run the rewrite-and-assemble step afterwards; the native and diff paths returned the bytes straight to the object cache, and the link died with `ld: unknown file type`. Factored into `linker::finish_native_emission` and wired into all four native/diff emit sites. **A natively-constructed module had NO GC strategy, so RS4GC never ran on it.** `native_emit::synth_define_header` was a second, independent copy of `LlFunction::to_ir`'s header renderer, written before `"frame-pointer"="non-leaf"` and `gc "statepoint-example"` existed and never updated. The result verifies, links and executes correctly on any program that does not collect, while having no precise roots at all — #7332's shape, and invisible to a behaviour-parity smoke arm by construction. The two callers now share `LlFunction::define_header`, so the next attribute reaches both; `function.rs` (compiled without the `llvm-inprocess` feature, i.e. visible to per-PR CI) pins `to_ir`'s first line against it. **The corpora, which is the half worth more than the fix.** All three tracked `.ll` files froze on 2026-08-03, 151 codegen commits earlier, and contained zero `addrspace(1)`. `corpus_spike ... ok` proved the tests ran, not that they test today's IR — CLAUDE.md's fourth way a gate cannot fail, inside the liveness assert written to prevent it. The same thing had happened nine days earlier (#7310, stale setjmp calls), which is the argument against fixing it by hand again: * `scripts/refresh_llvm_inprocess_corpora.sh` regenerates all three from the built compiler (`--check` diffs instead of writing). * `scripts/check_llvm_corpus_currency.py` (added to `lint`) asserts every IR form the reader carries a dedicated branch for is PRESENT in the corpora, so a form that disappears fails and must be either refreshed or deleted per the kill policy. Sabotage-verified against the corpora this commit replaces: it names all 10 forms they lacked. * `llvm-inprocess.yml`'s existing age diagnostic was itself vacuous — `git log` on a depth-1 checkout printed `0` commits behind however stale the files were. Now `fetch-depth: 0`, and it fails loudly rather than printing a reassuring zero if history is ever missing again. Corpora refreshed: 497 / 1082 / 420 `addrspace(1)` sites, EH corpus keeps 84 invoke edges and its personality clause. `dialect/mod.rs` crossed the 2000-line cap, so type/constant parsing moved to `dialect/types.rs`. Validated locally against LLVM 22.1.4: 934 `perry-codegen` lib tests green (all three corpus round-trips included); `PERRY_LLVM_INPROCESS=native` compiles and runs the spike and the try/catch program with output byte-identical to the textual backend. Known remaining, NOT closed here and separate defects: `=diff` still reports a byte mismatch on the spike (149,105 text vs 163,902 native — it was 50,995 before the GC-strategy fix, i.e. the gap narrowed from "RS4GC never ran" to a real but much smaller divergence), and the unit-split diff arm fails with `call to undeclared @js_shadow_slot_set`. Neither was ever reached in CI, because the native arm failed first. Refs #7982. * docs(changelog): fragment for #7998 (native backend RS4GC IR + corpus currency) * docs(gc-handoff): KNOBS-NOTES for the #7991/#7982/#7737 batch The knob-parse audit inventory (every GC-family env knob, how it parsed before and after), the corpus-currency findings, and the #7737 triage — including two things worth more than either fix: * `llvm-inprocess.yml`'s corpus-age diagnostic was itself vacuous. It asks `git log` how many IR-affecting commits landed since the corpora changed, on a depth-1 checkout — one commit to answer from, so it printed a confident 0 however stale the files were. * #7737 item 4's stated prerequisite has gone stale in the opposite direction: `gc-ratchet` has zero successes in its last 30 `main` runs and `gc-stress` failed the last three, so promoting either to required today would block every open PR. --------- Co-authored-by: Ralph Küpper <ralph@skelpo.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three follow-ups for the in-process LLVM backend, all found by auditing what it actually covers after the EH migration.
1.
--target windows+ try/catch was a hard compile errorPerry lowers exceptions to SEH funclets on windows-msvc (
catchswitch/catchpad/catchret). The reader can buildinvoke/landingpad(added in #7307) but not the funclet forms — and it can't, cheaply: inkwell 0.9 exposes nobuild_catch_switch/build_catch_pad/build_catch_ret, only an opcode enum for reading them. Real support needs rawllvm-sysFFI.Reproduced before the fix:
Those modules now decline to the textual path — costing only the in-process speedup — instead of failing the build. The decline is deliberately narrow (windows triple and a personality present), so #7307's macOS EH support is untouched; this is not the blanket personality bail that #7307 removed.
2. The tracked corpora were stale
spike_text.llandbatch_kernel.llwere captured before #7305 and still containedsetjmpcalls and the#0/#1attribute groups. So the reader's primary gate was validating IR Perry no longer emits, while not covering the forms it does — the corpus tests passed the whole time, because they're fixed files.Regenerated from current codegen. The spike corpus now carries 38
invokeedges and zero setjmp, and both corpora round-trip through native construction and the LLVM verifier.3. The setjmp-era attribute handling is deleted
With the corpora refreshed, nothing emits or contains
#0(returns_twice) or#1(noinline), so the reader's branches for them are gone — the losing mode stops compiling rather than lingering as an untested branch (CLAUDE.md kill policy). A corpus still carrying one now fails loudly as stale input, which is the point.Verification (local, LLVM 22.1.4)
Every assertion the
native-backendjob makes, plus the EH arm:--target windows+ try/catchperry_runtime.liblink error remains)cargo test -p perry-codegen --features llvm-inprocess --lib: 569 passed, 0 failed.Known limitation left open
SEH construction itself. It needs
llvm-sysfunclet FFI and can't be run-tested for Windows from a macOS host, so it stays a documented decline rather than a half-implementation. Worth doing when the backend moves toward becoming the default; today it's opt-in and the fallback is correct.Summary by CodeRabbit
New Features
Bug Fixes
Documentation