From e592c2b96953b3ffd921884e5e7016bb639189c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ralph=20K=C3=BCpper?= Date: Tue, 4 Aug 2026 09:52:46 +0200 Subject: [PATCH] feat(codegen): make the in-process LLVM backend the default, statically linked Perry now links LLVM 22 statically and ships self-contained. We own the assumption rather than pushing it onto the user, and there is no "install a compatible clang" step left to get wrong. It is load-bearing, not a preference. The explicit statepoint bridge is gone (#7348), so RS4GC is the only native-root backend, and RS4GC cannot round-trip its IR through an external `opt` plus a different clang (#7339). Keeping this opt-in meant the only working statepoint path was behind a flag nobody sets. Two defaults flip together, because either alone is half a feature: * `llvm-inprocess` becomes a default cargo feature. * `inprocess_requested()` defaults to ON -- but only iff the backend is actually compiled in. Defaulting to `true` unconditionally would route every compile in a `--no-default-features` build into the not-built-in stub and fail it outright. Verified both ways. `PERRY_LLVM_INPROCESS=0` reverts to the clang subprocess for bisection, and `--no-default-features` still builds the text path. CI: a new `.github/actions/setup-llvm22` composite action, referenced from all 44 toolchain steps across 18 workflows. One definition rather than 44 inline recipes, because the three platforms need three different sources and only one is obvious -- Ubuntu 24.04's own llvm-dev is 18, and chocolatey's `llvm` is the clang toolchain with no llvm-config.exe and none of the static libs. Every arm asserts the major version. Size: 98.9 MB, not the 185.9 MB this would have cost before #7350 -- `initialize_all()` was linking ~18 backends nothing can reach. Also fixed, surfaced by the flip: PERRY_LLVM_KEEP_IR promises the whole scratch dir including the .o. The clang path got that free because the object is a file; in-process returns bytes and silently dropped it, degrading a debugging aid exactly when someone is debugging. Verified on the 81-module zod corpus with no env set: compiles, output byte-identical to the clang path, and PERRY_RS4GC=1 now compiles a try-carrying probe with no further flags. 605 codegen tests pass. --- .github/actions/setup-llvm22/action.yml | 72 +++++++++++++++++++++++ .github/workflows/benchmark.yml | 3 + .github/workflows/cache-warm.yml | 1 + .github/workflows/container-tests.yml | 4 ++ .github/workflows/coverage.yml | 1 + .github/workflows/eh-transport.yml | 1 + .github/workflows/feature-matrix.yml | 1 + .github/workflows/gc-moving-witnesses.yml | 1 + .github/workflows/gc-native-roots.yml | 1 + .github/workflows/gc-ratchet.yml | 1 + .github/workflows/gc-root-dominance.yml | 1 + .github/workflows/node-compat-matrix.yml | 1 + .github/workflows/node-core-subset.yml | 1 + .github/workflows/node-suite-guard.yml | 1 + .github/workflows/npm-package-sweep.yml | 1 + .github/workflows/release-packages.yml | 2 + .github/workflows/security-audit.yml | 2 + .github/workflows/simctl-tests.yml | 1 + .github/workflows/test.yml | 20 +++++++ crates/perry-codegen/Cargo.toml | 23 ++++++-- crates/perry-codegen/src/linker.rs | 53 +++++++++++++++-- crates/perry/Cargo.toml | 8 +-- 22 files changed, 184 insertions(+), 16 deletions(-) create mode 100644 .github/actions/setup-llvm22/action.yml diff --git a/.github/actions/setup-llvm22/action.yml b/.github/actions/setup-llvm22/action.yml new file mode 100644 index 0000000000..75672bcbc3 --- /dev/null +++ b/.github/actions/setup-llvm22/action.yml @@ -0,0 +1,72 @@ +name: Setup LLVM 22 +description: > + Provision the LLVM 22 development libraries that `llvm-inprocess` links + against, and export LLVM_SYS_221_PREFIX. Every job that compiles Rust needs + this now that the feature is on by default. + +# One definition, not 44 inline recipes. The three platforms need three +# different sources and only one of them is obvious: +# +# macOS brew's llvm formula. +# Linux apt.llvm.org. The distro's `llvm-dev` is whatever the release +# froze on (Ubuntu 24.04 ships 18), so the LLVM project's own +# repository is the only way to get a pinned 22. +# Windows the official `clang+llvm-*-pc-windows-msvc` tarball. NOT +# chocolatey: its `llvm` package is the clang *toolchain* — no +# llvm-config.exe and none of the static libraries llvm-sys links +# against — and it has no 22.x pin at all. +# +# Every arm asserts the major version. llvm-sys 221 requires LLVM 22 +# specifically, and a runner image moving its formula on must fail loudly +# here rather than build something subtly different several steps later. +inputs: + version: + description: LLVM major.minor.patch used by the Windows tarball + required: false + default: "22.1.8" + +runs: + using: composite + steps: + - name: LLVM 22 (macOS, brew) + if: runner.os == 'macOS' + shell: bash + run: | + set -euo pipefail + brew install llvm@22 2>/dev/null || brew install llvm + PREFIX="$(brew --prefix llvm@22 2>/dev/null || brew --prefix llvm)" + "$PREFIX/bin/llvm-config" --version | grep -q '^22\.' \ + || { echo "::error::brew LLVM is not 22.x ($("$PREFIX/bin/llvm-config" --version))"; exit 1; } + echo "LLVM_SYS_221_PREFIX=$PREFIX" >> "$GITHUB_ENV" + + - name: LLVM 22 (Linux, apt.llvm.org) + if: runner.os == 'Linux' + shell: bash + run: | + set -euo pipefail + wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key \ + | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc >/dev/null + . /etc/os-release + echo "deb http://apt.llvm.org/${VERSION_CODENAME}/ llvm-toolchain-${VERSION_CODENAME}-22 main" \ + | sudo tee /etc/apt/sources.list.d/llvm22.list >/dev/null + sudo apt-get update -qq + sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \ + llvm-22-dev libpolly-22-dev libzstd-dev + llvm-config-22 --version | grep -q '^22\.' \ + || { echo "::error::apt LLVM is not 22.x"; exit 1; } + echo "LLVM_SYS_221_PREFIX=$(llvm-config-22 --prefix)" >> "$GITHUB_ENV" + + - name: LLVM 22 (Windows, official MSVC tarball) + if: runner.os == 'Windows' + shell: pwsh + run: | + $ErrorActionPreference = "Stop" + $ver = "${{ inputs.version }}" + $url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-$ver/clang+llvm-$ver-x86_64-pc-windows-msvc.tar.xz" + Write-Host "downloading $url" + curl.exe -sSL --retry 3 -o "$env:RUNNER_TEMP\llvm.tar.xz" $url + New-Item -ItemType Directory -Force -Path C:\llvm | Out-Null + tar -xf "$env:RUNNER_TEMP\llvm.tar.xz" -C C:\llvm --strip-components=1 + $v = & "C:\llvm\bin\llvm-config.exe" --version + if (-not $v.StartsWith("22.")) { Write-Error "LLVM is not 22.x ($v)"; exit 1 } + "LLVM_SYS_221_PREFIX=C:\llvm" | Out-File -FilePath $env:GITHUB_ENV -Append diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 7a404a5277..615386c92c 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -43,6 +43,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Cache cargo uses: actions/cache@v6 @@ -264,6 +265,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Cache cargo uses: actions/cache@v6 @@ -361,6 +363,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Measure clean-build time run: | diff --git a/.github/workflows/cache-warm.yml b/.github/workflows/cache-warm.yml index 0328abccec..bbc9000ba3 100644 --- a/.github/workflows/cache-warm.yml +++ b/.github/workflows/cache-warm.yml @@ -64,6 +64,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Install sccache uses: mozilla-actions/sccache-action@v0.0.10 diff --git a/.github/workflows/container-tests.yml b/.github/workflows/container-tests.yml index d4ec4579d5..216562e6b9 100644 --- a/.github/workflows/container-tests.yml +++ b/.github/workflows/container-tests.yml @@ -95,6 +95,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Cache cargo registry uses: actions/cache@v6 @@ -168,6 +169,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Cache cargo registry uses: actions/cache@v6 @@ -209,6 +211,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Cache cargo registry uses: actions/cache@v6 @@ -251,6 +254,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Cache cargo registry uses: actions/cache@v6 diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index c94f801eab..d80962e1ea 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -33,6 +33,7 @@ jobs: uses: dtolnay/rust-toolchain@stable with: components: llvm-tools-preview + - uses: ./.github/actions/setup-llvm22 - uses: Swatinem/rust-cache@v2 with: diff --git a/.github/workflows/eh-transport.yml b/.github/workflows/eh-transport.yml index 4ca6c5bfee..4a33949b48 100644 --- a/.github/workflows/eh-transport.yml +++ b/.github/workflows/eh-transport.yml @@ -76,6 +76,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Setup Node.js uses: actions/setup-node@v7 diff --git a/.github/workflows/feature-matrix.yml b/.github/workflows/feature-matrix.yml index cfb1a5c5db..3c8e4a253e 100644 --- a/.github/workflows/feature-matrix.yml +++ b/.github/workflows/feature-matrix.yml @@ -34,6 +34,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - uses: Swatinem/rust-cache@v2 with: diff --git a/.github/workflows/gc-moving-witnesses.yml b/.github/workflows/gc-moving-witnesses.yml index 81098cf2eb..09ef1d41b1 100644 --- a/.github/workflows/gc-moving-witnesses.yml +++ b/.github/workflows/gc-moving-witnesses.yml @@ -197,6 +197,7 @@ jobs: - name: Install Rust toolchain if: steps.relevance.outputs.run == 'true' uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - uses: Swatinem/rust-cache@v2 if: steps.relevance.outputs.run == 'true' diff --git a/.github/workflows/gc-native-roots.yml b/.github/workflows/gc-native-roots.yml index 7a3c72a2a5..947ce8a193 100644 --- a/.github/workflows/gc-native-roots.yml +++ b/.github/workflows/gc-native-roots.yml @@ -124,6 +124,7 @@ jobs: with: node-version-file: .node-version - uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - uses: Swatinem/rust-cache@v2 with: shared-key: gc-native-roots diff --git a/.github/workflows/gc-ratchet.yml b/.github/workflows/gc-ratchet.yml index 820cd2aa4c..5074f30e48 100644 --- a/.github/workflows/gc-ratchet.yml +++ b/.github/workflows/gc-ratchet.yml @@ -115,6 +115,7 @@ jobs: - name: Install Rust toolchain if: steps.relevance.outputs.run == 'true' uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Cache cargo if: steps.relevance.outputs.run == 'true' diff --git a/.github/workflows/gc-root-dominance.yml b/.github/workflows/gc-root-dominance.yml index ebf89aef1d..e940f820c7 100644 --- a/.github/workflows/gc-root-dominance.yml +++ b/.github/workflows/gc-root-dominance.yml @@ -156,6 +156,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 # ★ The dependency-scale corpus needs the dependency. # diff --git a/.github/workflows/node-compat-matrix.yml b/.github/workflows/node-compat-matrix.yml index de90781364..25d7b4bae8 100644 --- a/.github/workflows/node-compat-matrix.yml +++ b/.github/workflows/node-compat-matrix.yml @@ -57,6 +57,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Start sccache uses: mozilla-actions/sccache-action@v0.0.10 diff --git a/.github/workflows/node-core-subset.yml b/.github/workflows/node-core-subset.yml index 6c254f9928..cb78b0ad93 100644 --- a/.github/workflows/node-core-subset.yml +++ b/.github/workflows/node-core-subset.yml @@ -69,6 +69,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - uses: Swatinem/rust-cache@v2 with: diff --git a/.github/workflows/node-suite-guard.yml b/.github/workflows/node-suite-guard.yml index b883832067..3e10b87526 100644 --- a/.github/workflows/node-suite-guard.yml +++ b/.github/workflows/node-suite-guard.yml @@ -45,6 +45,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Start sccache uses: mozilla-actions/sccache-action@v0.0.10 diff --git a/.github/workflows/npm-package-sweep.yml b/.github/workflows/npm-package-sweep.yml index 22c08a7209..7e291b0954 100644 --- a/.github/workflows/npm-package-sweep.yml +++ b/.github/workflows/npm-package-sweep.yml @@ -40,6 +40,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - uses: Swatinem/rust-cache@v2 with: diff --git a/.github/workflows/release-packages.yml b/.github/workflows/release-packages.yml index e7493d1fe6..3984898992 100644 --- a/.github/workflows/release-packages.yml +++ b/.github/workflows/release-packages.yml @@ -315,6 +315,7 @@ jobs: uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} + - uses: ./.github/actions/setup-llvm22 # Cache cargo registry + target/ per (matrix.target, Cargo.lock). # First run on a target is still a cold build, but every subsequent @@ -1030,6 +1031,7 @@ jobs: uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} + - uses: ./.github/actions/setup-llvm22 - name: Install Rust nightly + rust-src (Tier-3 only) if: matrix.tier3 diff --git a/.github/workflows/security-audit.yml b/.github/workflows/security-audit.yml index 82b77a11c0..ee746829e6 100644 --- a/.github/workflows/security-audit.yml +++ b/.github/workflows/security-audit.yml @@ -23,6 +23,7 @@ jobs: with: persist-credentials: false - uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - uses: Swatinem/rust-cache@v2 with: shared-key: security-audit @@ -155,6 +156,7 @@ jobs: with: persist-credentials: false - uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - uses: Swatinem/rust-cache@v2 with: shared-key: security-audit diff --git a/.github/workflows/simctl-tests.yml b/.github/workflows/simctl-tests.yml index 0986ef3d3a..e4d2510faa 100644 --- a/.github/workflows/simctl-tests.yml +++ b/.github/workflows/simctl-tests.yml @@ -33,6 +33,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Install iOS simulator Rust target run: rustup target add aarch64-apple-ios-sim aarch64-apple-ios diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 52cb6f7ea3..c1a17dced1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -115,6 +115,7 @@ jobs: uses: dtolnay/rust-toolchain@stable with: components: rustfmt, clippy + - uses: ./.github/actions/setup-llvm22 - uses: Swatinem/rust-cache@v2 with: @@ -296,6 +297,7 @@ jobs: uses: dtolnay/rust-toolchain@stable with: components: clippy + - uses: ./.github/actions/setup-llvm22 - name: Install sccache uses: mozilla-actions/sccache-action@v0.0.10 @@ -365,6 +367,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Install sccache uses: mozilla-actions/sccache-action@v0.0.10 @@ -432,6 +435,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Install sccache uses: mozilla-actions/sccache-action@v0.0.10 @@ -542,6 +546,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Install sccache uses: mozilla-actions/sccache-action@v0.0.10 @@ -800,6 +805,7 @@ jobs: - name: Install Rust toolchain if: steps.scope.outputs.suites != '' uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Install sccache if: steps.scope.outputs.suites != '' @@ -894,6 +900,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Setup Node.js uses: actions/setup-node@v7 @@ -1031,6 +1038,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - uses: Swatinem/rust-cache@v2 with: @@ -1137,6 +1145,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Install sccache uses: mozilla-actions/sccache-action@v0.0.10 @@ -1313,6 +1322,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Install sccache uses: mozilla-actions/sccache-action@v0.0.10 @@ -1469,6 +1479,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Install sccache uses: mozilla-actions/sccache-action@v0.0.10 @@ -1560,6 +1571,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - uses: Swatinem/rust-cache@v2 with: @@ -1650,6 +1662,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - uses: Swatinem/rust-cache@v2 with: @@ -1756,6 +1769,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - uses: Swatinem/rust-cache@v2 with: @@ -2133,6 +2147,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - uses: Swatinem/rust-cache@v2 with: @@ -2194,6 +2209,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - uses: Swatinem/rust-cache@v2 with: @@ -2260,6 +2276,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - uses: Swatinem/rust-cache@v2 with: @@ -2313,6 +2330,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - uses: Swatinem/rust-cache@v2 with: @@ -2462,6 +2480,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - name: Set up MSVC environment (Windows) # Populates LIB / INCLUDE / PATH so link.exe can find user32.lib @@ -2612,6 +2631,7 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + - uses: ./.github/actions/setup-llvm22 - uses: Swatinem/rust-cache@v2 with: diff --git a/crates/perry-codegen/Cargo.toml b/crates/perry-codegen/Cargo.toml index 5e3006bf96..e4bf5b4e52 100644 --- a/crates/perry-codegen/Cargo.toml +++ b/crates/perry-codegen/Cargo.toml @@ -9,12 +9,23 @@ description = "LLVM code generation backend for Perry" workspace = true [features] -# exp/llvm-inprocess: compile `.ll -> .o` through the LLVM C API inside this -# process instead of shelling out to a user-supplied `clang -c`. Off by -# default — the default build has no LLVM link dependency and the text path -# is byte-for-byte untouched. Building with this feature requires LLVM 22 -# (`brew install llvm`; set LLVM_SYS_221_PREFIX if llvm-config is not on -# PATH). The backend still only runs when PERRY_LLVM_INPROCESS=1 at runtime. +# Compile `.ll -> .o` through the LLVM C API inside this process instead of +# shelling out to a user-supplied `clang -c`. +# +# ON BY DEFAULT. Perry links LLVM 22 statically and ships self-contained: we +# own the assumption instead of pushing it onto the user, and there is no +# "install a matching clang" step to get wrong. Building Perry therefore needs +# LLVM 22 present (`brew install llvm`, apt.llvm.org, or the official MSVC +# tarball; `LLVM_SYS_221_PREFIX` if llvm-config is not on PATH) — CI provisions +# it via `.github/actions/setup-llvm22`. +# +# It is also load-bearing rather than an optimization: the explicit statepoint +# bridge is gone (#7348), so RS4GC is the only native-root backend, and RS4GC +# needs this pipeline — an external `opt` feeding a different clang cannot +# parse the IR it emits (#7339). +# +# `--no-default-features` still builds the text path for bisection. +default = ["llvm-inprocess"] llvm-inprocess = ["dep:inkwell", "dep:llvm-sys"] [dependencies] diff --git a/crates/perry-codegen/src/linker.rs b/crates/perry-codegen/src/linker.rs index 467deb74a5..33fcd9f833 100644 --- a/crates/perry-codegen/src/linker.rs +++ b/crates/perry-codegen/src/linker.rs @@ -598,14 +598,37 @@ pub(crate) fn native_plan_args( (plan.effective_target, plan.clang_args) } -/// exp/llvm-inprocess: truthy `PERRY_LLVM_INPROCESS` routes `.ll -> .o` -/// through the LLVM C API inside this process (no clang subprocess, no `.ll` -/// on disk). The flag participates in both the build cache and the object -/// cache keys, so the two backends can never share a cached object. +/// Route `.ll -> .o` through the LLVM C API inside this process (no clang +/// subprocess, no `.ll` on disk). +/// +/// **ON BY DEFAULT.** Perry links LLVM 22 statically and ships self-contained, +/// so there is no "find a compatible clang" step to get wrong. It is also +/// load-bearing rather than a preference: the explicit statepoint bridge is +/// gone (#7348), leaving RS4GC as the only native-root backend, and RS4GC +/// cannot round-trip its IR through an external `opt` + a different clang +/// (#7339). +/// +/// `PERRY_LLVM_INPROCESS=0`/`off`/`false` reverts to the clang subprocess for +/// bisection. `=native` additionally builds function bodies through the C API +/// instead of rendering per-function text; that is byte-identical on the +/// 81-module zod corpus but has narrower CI coverage, so it stays opt-in until +/// that widens. +/// +/// The value participates in both the build cache and the object cache keys, +/// so the backends can never share a cached object. fn inprocess_requested() -> bool { match env::var("PERRY_LLVM_INPROCESS").as_deref() { - Ok("") | Ok("0") | Ok("off") | Ok("false") | Err(_) => false, + Ok("0") | Ok("off") | Ok("false") => false, + // Explicitly asked for: honour it even without the feature, so the + // stub below can say "rebuild with the feature" instead of silently + // serving the text path to an A/B arm that asked for this backend. Ok(_) => true, + // Unset means ON *iff* the backend is actually compiled in. It is a + // default feature, so that is the normal case — but a + // `--no-default-features` build must keep working, and defaulting to + // `true` there would route every compile into the not-built-in stub + // and fail the build outright. + Err(_) => cfg!(feature = "llvm-inprocess"), } } @@ -695,7 +718,25 @@ fn compile_ll_inprocess_in( } Ok(obj) } - Ok(bytes) => Ok(bytes), + Ok(bytes) => { + // `PERRY_LLVM_KEEP_IR` promises the whole scratch dir, `.o` + // included. The clang path gets that for free because the object + // IS a file; in-process returns bytes and would silently drop it — + // degrading a debugging aid at exactly the moment someone is + // debugging. Now that this backend is the default, write it. + if policy.keep { + let _ = fs::create_dir_all(&paths.scratch_dir); + if let Err(e) = fs::write(&plan.obj_path, &bytes) { + eprintln!( + "[perry-codegen] could not keep {}: {e}", + plan.obj_path.display() + ); + } else { + eprintln!("[perry-codegen] kept object: {}", plan.obj_path.display()); + } + } + Ok(bytes) + } Err(e) => { // Same contract as a failed clang compile: the IR that produced // the failure is left on disk and named in the error. diff --git a/crates/perry/Cargo.toml b/crates/perry/Cargo.toml index 161f9457d1..c3331a23d9 100644 --- a/crates/perry/Cargo.toml +++ b/crates/perry/Cargo.toml @@ -140,10 +140,10 @@ audit-cli = [] updater-cli = ["dep:ed25519-dalek", "dep:rand"] native-cli = [] -# exp/llvm-inprocess: compile .ll -> .o through the LLVM C API in-process -# instead of a `clang -c` subprocess. Off by default (no LLVM link dependency); -# even when built in, it only runs under PERRY_LLVM_INPROCESS=1. Requires -# LLVM 22 at build time (LLVM_SYS_221_PREFIX or llvm-config on PATH). +# Compile .ll -> .o through the LLVM C API in-process instead of a `clang -c` +# subprocess. ON BY DEFAULT via perry-codegen's own default feature — Perry +# links LLVM 22 statically and ships self-contained. See that crate's manifest +# for why this is load-bearing rather than an optimization. llvm-inprocess = ["perry-codegen/llvm-inprocess"] # Codegen backends for non-native targets. Each enables one backend crate;