From 0e67cd1e3bad393b6cc067852c05d367b82ed44c Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 18 Oct 2026 08:02:34 -0500 Subject: [PATCH] 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. --- .../node-v24-compatibility-meta.json | 2 +- .../src/generated/node-v24-compatibility.json | 10 +++++----- .../generated/node-v24-backlog.json | 19 +++++++++++-------- .../generated/node-v24-internal.json | 12 ++++++++---- native/llvm-codegen/src/partition.cpp | 10 ++++++++-- native/llvm-codegen/src/partition.h | 4 ++-- 6 files changed, 35 insertions(+), 22 deletions(-) diff --git a/docs/src/generated/node-v24-compatibility-meta.json b/docs/src/generated/node-v24-compatibility-meta.json index 500876593d..db36cdb520 100644 --- a/docs/src/generated/node-v24-compatibility-meta.json +++ b/docs/src/generated/node-v24-compatibility-meta.json @@ -2,6 +2,6 @@ "schemaVersion": 3, "nodeVersion": "24.22.0", "nodeCommit": "f14cd3aa7bf9ca8df2cc5b8bb14beb0f335b1d93", - "artifactVersion": "56f660f5e2eb7391a048", + "artifactVersion": "cade1b8e6e0c5c42fcc9", "rowCount": 3880 } diff --git a/docs/src/generated/node-v24-compatibility.json b/docs/src/generated/node-v24-compatibility.json index 568cdb4c9e..dadc9e836d 100644 --- a/docs/src/generated/node-v24-compatibility.json +++ b/docs/src/generated/node-v24-compatibility.json @@ -569,9 +569,9 @@ "apiEntries": 120, "static": { "supported": 0, - "partial": 50, + "partial": 51, "refused": 0, - "not-implemented": 70, + "not-implemented": 69, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -57593,9 +57593,9 @@ "anchor": "", "nodeStability": null, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the call shapes accepted by the compiler lowering.", + "verification": "test-backed" } }, { diff --git a/internal/compatibility/generated/node-v24-backlog.json b/internal/compatibility/generated/node-v24-backlog.json index 683d477a5f..12b12d63b0 100644 --- a/internal/compatibility/generated/node-v24-backlog.json +++ b/internal/compatibility/generated/node-v24-backlog.json @@ -7,8 +7,8 @@ "tierItemCount": 3456, "tiers": { "static": { - "audit-partial": 1142, - "verify-gap": 2187, + "audit-partial": 1143, + "verify-gap": 2186, "replace-refusal": 40, "classify": 2, "implement": 85 @@ -57507,12 +57507,15 @@ "priority": "normal", "tiers": { "static": { - "status": "not-implemented", - "action": "verify-gap", - "verification": "registry-gap", - "confidence": "low", - "source": "compiler-unmatched:process", - "tests": [] + "status": "partial", + "action": "audit-partial", + "verification": "test-backed", + "confidence": "high", + "source": "surface-manifest:node-builtin.process.execArgv", + "tests": [ + "tests/corpus/990-process-basics.ts", + "tests/corpus/2314-process-introspection.ts" + ] } } }, diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index 393955bc01..2b97f675e0 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -596,9 +596,9 @@ "apiEntries": 120, "static": { "supported": 0, - "partial": 50, + "partial": 51, "refused": 0, - "not-implemented": 70, + "not-implemented": 69, "by-design": 0, "unreviewed": 0, "not-applicable": 0 @@ -80949,8 +80949,12 @@ "anchor": "", "nodeStability": null, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:process" + "status": "partial", + "evidence": "surface-manifest:node-builtin.process.execArgv", + "tests": [ + "tests/corpus/990-process-basics.ts", + "tests/corpus/2314-process-introspection.ts" + ] }, "anchorSource": "chapter" }, diff --git a/native/llvm-codegen/src/partition.cpp b/native/llvm-codegen/src/partition.cpp index 066ba614c1..8ad696d33d 100644 --- a/native/llvm-codegen/src/partition.cpp +++ b/native/llvm-codegen/src/partition.cpp @@ -418,7 +418,12 @@ std::optional partitionProgramText(StringRef Text, // An internal function referenced by exactly one other function, and by // no global, is a whole-program inlining candidate; keep it with that - // function so its partition can inline it without importing. + // function so its partition can inline it without importing. A function + // body larger than this is past LLVM's inline cost limit even for the only + // call to a local function, so it is placed by its own name. Otherwise a + // program's module initializers, which only the entry point calls, would + // all share the entry point's partition. + constexpr size_t MaxInlinedBodyBytes = 256 * 1024; constexpr unsigned Shared = ~1u; std::vector Referrer(Symbols.size(), NoPartition); for (unsigned I = 0; I < Symbols.size(); ++I) { @@ -441,7 +446,8 @@ std::optional partitionProgramText(StringRef Text, for (unsigned Steps = 0; Steps < 1024; ++Steps) { const Symbol &S = Symbols[Root]; unsigned Parent = Referrer[Root]; - if (!S.Local || Parent == NoPartition || Parent == Shared || + if (!S.Local || S.Body.size() > MaxInlinedBodyBytes || + Parent == NoPartition || Parent == Shared || Symbols[Parent].Kind != SymbolKind::Function || Parent == I) break; Root = Parent; diff --git a/native/llvm-codegen/src/partition.h b/native/llvm-codegen/src/partition.h index 9d48548fba..8389194439 100644 --- a/native/llvm-codegen/src/partition.h +++ b/native/llvm-codegen/src/partition.h @@ -22,8 +22,8 @@ struct ProgramPartitions { // Divides the LLVM assembly scriptc emits into Count modules without parsing // it, so the partitions can be parsed concurrently. Functions are placed by a // stable hash of their name; an internal function referenced by exactly one -// other function stays with that function, and a global stays with the first -// function that references it. Returns nullopt for any construct outside the +// other function stays with that function unless its body is too large to +// inline, and a global stays with the first function that references it. Returns nullopt for any construct outside the // emitter's narrow top-level grammar; callers then split a parsed module. std::optional partitionProgramText(llvm::StringRef Text, unsigned Count);