Repository navigation
Generate the RTS generic apply code in GHC and link it at link time (9.14 port) - #194
andreabedini wants to merge 10 commits into
Conversation
The RTS's generic application code (rts/AutoApply.cmm and the
AutoApply_V{16,32,64}.cmm vector variants) has so far been produced by the
standalone utils/genapply program, which re-implements things the compiler
already owns: register assignment, argument representations, the pointer-tag
arity check, and eight target constants that it scraped from comment lines
which deriveConstants wrote into DerivedConstants.h for its benefit (#24347).
This adds GHC.StgToCmm.AutoApply, a port of the generator that is driven by
the compiler's Platform: registers come from GHC.Cmm.CallConv.assignArgumentsPos
(the same function used for compiled call sites), the constants from
platformConstants, and the argument tables live in GHC.StgToCmm.ArgRep as
applyTypes and stackApplyTypes, following the structure of GHC.StgToJS.Apply.
It is exposed as a new mode, `ghc --gen-apply[=v16|v32|v64]`, which writes the
Cmm source to the -o file or to stdout. The output is Cmm text, so the RTS's
CPP for PROFILING, REG_YMM1 and friends and the per-file -mavx split are
untouched, and the result is byte-for-byte identical to genapply's output
(checked on x86_64 for all four files; only the header comment differs).
One deliberate special case: an L argument is only ever loaded into a long
register. On 64-bit targets assignArgumentsPos would use a vanilla register,
but toArgRep never produces L there, so the stg_ap_l routines are dead code
and are kept unchanged.
genapply itself is still in place; the build system is switched over in the
next commit.
…napply Replace the stageBoot genapply program with a `GenApply` mode of the Ghc builder. The AutoApply*.cmm files of a stage's RTS are now generated by the same compiler that compiles that RTS, with the RTS's DerivedConstants.h passed via -I so that GHC can read the platform constants while the RTS unit is not yet in a package database. Consequently utils/genapply is deleted, and deriveConstants no longer emits the `// KEY VALUE` comment lines that only genapply consumed. Comments that pointed at genapply now point at GHC.StgToCmm.AutoApply. The generated files are identical to those produced by genapply.
slowCallPattern (which stg_ap_* routine to call for an unknown call) and stdPattern (which ARG_* descriptor a function gets) were hand-written mirrors of the pattern tables that genapply used. Now that those tables live in GHC.StgToCmm.ArgRep as applyTypes and stackApplyTypes, derive both functions from them: slowCallPattern picks the longest table pattern that is a prefix of the argument list, stdPattern looks the pattern up by its index. Behaviour is unchanged. In particular stdPattern still does not return ARG_PPPPPPP or ARG_PPPPPPPP, although the RTS has entries for them; using them would change compiled code and is left for a separate, measured change.
Instead of being compiled into libHSrts, the RTS's generic application code (stg_ap_*_fast, the stg_ap_* return frames, stg_ap_stk_*, stg_stk_save_* and the ARG_*-indexed tables) is generated by GHC.StgToCmm.AutoApply when a program is linked, compiled through the normal Cmm pipeline into temporary objects, and added to the link -- the same way the JS backend emits rts.js at link time. See Note [Linking the generic apply code] in GHC.Driver.Pipeline. The objects go wherever the RTS goes: into every executable (also with -no-hs-main, and the generated iserv), into -shared outputs that contain the RTS (-flink-rts, Windows, wasm; see the new GHC.Linker.Dynamic.dynLibLinksRts) and into -staticlib archives unless -fno-link-rts. Nothing is generated when the RTS is not among the linked units (e.g. GHC linking a plain C program). The generated code follows the RTS way being linked: -DPROFILING arrives via wayOptc; THREADED_RTS, DEBUG and TICKY_TICKY (non-threaded debug only) are added to match the defines Hadrian builds those RTS ways with. The V16/V32/ V64 routines stay separate objects compiled with -mavx2/-mavx512f on x86. Since only installed RTS headers are available at link time, the generator now emits the BUILD_PAP/NEW_PAP/jump_SAVE_CCCS macros itself instead of including rts/AutoApply.h. The new -f[no-]link-autoapply flag (default on) turns this off; `ghc --gen-apply` still prints the Cmm for anyone linking by other means. Measured on x86_64 with a quick-flavour (-O0) compiler: linking a hello-world executable takes ~0.8s instead of ~0.2s, the four Cmm compiles accounting for the difference; the executable size is unchanged. A release-flavour compiler should narrow this, and the objects could be cached per way if needed.
The RTS now only refers to the generic apply symbols; GHC generates and links the code into each program (previous commit). Remove the generated AutoApply*.cmm from rts.cabal, drop the misleading RTS_PRIVATE from the table declarations in rts/Apply.h (the definitions are provided by the program's link and were always exported anyway), and delete rts/AutoApply.h, whose macros are now emitted by the generator. Hadrian loses the AutoApply generation rules, the `GenApply` GhcMode and the per-file -mavx2/-mavx512f flags for AutoApply_V*.cmm (the Jumps_V* ones stay). `ghc --gen-apply` itself is kept.
The previous commits moved the generic apply code out of libHSrts and into
every link that GHC performs. Say so where users will look for it:
* a --gen-apply entry in the modes of operation;
* a new "Linking the runtime's generic apply code" section in the FFI
chapter, covering when GHC adds the code, when it does not (a shared
library built without -flink-rts loaded by a program GHC did not link)
and how to generate, compile and link it by hand, including the way
defines and the -mavx flags for the vector files;
* the shared-libraries chapter no longer says that omitting -flink-rts
and linking the RTS into the final executable always works;
* cross-references from -flink-autoapply and the -no-hs-main note.
Also add a changelog.d entry (MR number to be filled in).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ng from rts.cabal
The previous commits removed utils/genapply and moved the generic apply code
out of libHSrts; this tree builds with the Makefile rather than hadrian, so
take the tool out of that build too:
* Makefile, cabal.project.stage1, cabal.project.stage2.common and the nix
CI workflow no longer build, export or ship genapply;
* rts/configure.ac no longer looks for genapply or generates the
AutoApply*.cmm.h headers;
* rts.cabal drops the generated AutoApply*.cmm.h from autogen-includes and
install-includes together with the "[The AutoApply story]" note. The
per-file -mavx2/-mavx512f options that were only there for the AutoApply
wrappers went with the wrappers in the previous commit; the ones on
Jumps_V32/V64.cmm are still needed and stay.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
V16 generation must clear inherited AVX feature flags before approval.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
Open (1)
What changed in this PR
Moves generic apply-code generation from utils/genapply and libHSrts into GHC, generating and linking it at final link time.
Changes:
- Adds compiler-integrated
--gen-applygeneration and automatic linking. - Removes obsolete RTS, Makefile, and Hadrian generation plumbing.
- Documents automatic and manual generic-apply linking.
| File | Reviewed changes |
|---|---|
utils/genapply/hie.yaml |
Removes obsolete utility configuration. |
utils/genapply/genapply.cabal |
Removes the standalone generator package. |
utils/deriveConstants/Main.hs |
Removes generator-specific metadata. |
rts/rts.cabal |
Removes AutoApply sources and headers from RTS builds. |
rts/include/stg/MiscClosures.h |
Updates generic apply declarations. |
rts/configure.ac |
Removes genapply configuration. |
rts/AutoApply.h |
Removes obsolete helper macros. |
rts/AutoApply.cmm |
Removes the obsolete wrapper. |
rts/AutoApply_V64.cmm |
Removes the obsolete wrapper. |
rts/AutoApply_V32.cmm |
Removes the obsolete wrapper. |
rts/AutoApply_V16.cmm |
Removes the obsolete wrapper. |
rts/Apply.h |
Updates generated symbol declarations. |
rts-headers/include/rts/storage/FunTypes.h |
Documents generic apply table ordering. |
Makefile |
Removes genapply build plumbing. |
hadrian/src/Settings/Packages.hs |
Removes obsolete RTS apply flags. |
hadrian/src/Settings/Default.hs |
Removes the generator package and builder. |
hadrian/src/Settings/Builders/GenApply.hs |
Deletes obsolete builder configuration. |
hadrian/src/Rules/Generate.hs |
Removes AutoApply generation rules. |
hadrian/src/Rules/Compile.hs |
Removes generated-Cmm special handling. |
hadrian/src/Packages.hs |
Removes the genapply package definition. |
hadrian/src/Context.hs |
Updates object-path documentation. |
hadrian/src/Builder.hs |
Removes the GenApply builder. |
hadrian/hadrian.cabal |
Removes the deleted builder module. |
ghc/Main.hs |
Implements --gen-apply. |
ghc/GHC/Driver/Session/Mode.hs |
Adds genapply mode parsing. |
docs/users_guide/using.rst |
Documents --gen-apply. |
docs/users_guide/shared_libs.rst |
Documents shared-library linking requirements. |
docs/users_guide/phases.rst |
Documents -flink-autoapply. |
docs/users_guide/exts/ffi.rst |
Documents manual generic-apply linking. |
docs/stg-spec/stg-spec.mng |
Updates generator references. |
compiler/GHC/StgToCmm/Layout.hs |
Derives standard patterns from shared tables. |
compiler/GHC/StgToCmm/AutoApply.hs |
Adds compiler-side Cmm generation. |
compiler/GHC/StgToCmm/ArgRep.hs |
Adds shared apply tables and naming helpers; stale implementation references should be updated. |
compiler/GHC/Runtime/Interpreter/Init.hs |
Supports extra interpreter link objects. |
compiler/GHC/Runtime/Interpreter/C.hs |
Links extra objects into generated iservs. |
compiler/GHC/Linker/Dynamic.hs |
Centralizes RTS-linking detection. |
compiler/GHC/Driver/Session.hs |
Registers the link-autoapply flag. |
compiler/GHC/Driver/Pipeline.hs |
Generates and links apply objects; V16 must clear AVX flags, with coverage and caching follow-ups noted. |
compiler/GHC/Driver/Make.hs |
Adapts linking to the updated environment API. |
compiler/GHC/Driver/Flags.hs |
Adds the link-autoapply option. |
compiler/GHC/Driver/DynFlags.hs |
Enables auto-apply linking by default. |
compiler/GHC/Driver/Config/Interpreter.hs |
Initializes extra interpreter link objects. |
compiler/GHC/Cmm/CallConv.hs |
Updates AutoApply references. |
compiler/GHC.hs |
Supplies generated objects to GHCi. |
compiler/ghc.cabal.in |
Includes the new compiler module. |
cabal.project.stage2.common |
Removes the deleted utility package. |
cabal.project.stage1 |
Removes the deleted utility package. |
.github/workflows/nix-ci.yml |
Removes obsolete genapply packaging. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| in case mb_vec of | ||
| Just 32 | x86 -> d2 { avx2 = True } | ||
| Just 64 | x86 -> d2 { avx512f = True } | ||
| _ -> d2 |
There was a problem hiding this comment.
Right, and it was slightly wider than the V16 case: every x86 ISA knob (sseVersion, bmiVersion, avx*, fma) was inherited from the link command line by all the baseline objects, including the scalar/V16 Jumps wrappers.
Fixed in c80685e: the ISA level is now pinned per variant (baseline, avx2, avx512f) and no longer follows the link flags; ways, optimisation level and backend still do. Checked with ghc -mavx2 -keep-tmp-files and objdump -D -j .text on the kept objects: before, stg_ap_v16_fast had 7 VEX-encoded instructions and stg_stack_underflow_frame_v16 12; after, both have none, while the V32/V64 objects keep their ymm/zmm code (7 and 12 respectively) and the scalar ones are unchanged.
🤖 Generated with Claude Code
stg_stack_underflow_frame_* and stg_restore_cccs_* (rts/Jumps.h) exist once per argument-register width for the same reason the generic apply code does, need the same per-file -mavx2/-mavx512f flags on the V32/V64 variants, and are referred to by the RTS in the same way. Treat them the same way: GHC now writes the four two-line wrappers around the installed Jumps.h and compiles them along with AutoApply*.cmm when it links the RTS into something (GHC.StgToCmm.AutoApply.genFiles lists all eight files, see the new Note [Link-time RTS Cmm files]), and `ghc --gen-apply` accepts `jumps`, `jumps-v16`, `jumps-v32` and `jumps-v64` so the manual recipe in the users guide still covers everything. rts.cabal loses Jumps_*.cmm and with them the last per-file cmm options; hadrian loses the corresponding -mavx rules. Jumps.h itself stays in the RTS as an installed header. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
GHC.StgToCmm.AutoApply had grown a second job: besides generating the generic apply code it listed every Cmm file GHC compiles when it links the RTS, including the rts/Jumps.h wrappers, which have nothing to do with StgToCmm. Move that catalogue (GenFile, genFiles, genFile, genFileVecWidth, genJumps and Note [Link-time RTS Cmm files]) to a new GHC.Linker.RtsCmm, next to GHC.Linker.Dynamic's dynLibLinksRts, and leave AutoApply.hs with genAutoApply only. The pipeline entry points follow the new name: mkAutoApplyObjs and autoApplyObjsForLink become mkRtsCmmObjs and rtsCmmObjsForLink. The compile step itself stays in GHC.Driver.Pipeline because it runs cmmCppPipeline. No change to the user-facing --gen-apply mode or -flink-autoapply flag. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
mkRtsCmmObjs compiled the generated Cmm with the DynFlags of the link command line and only added -mavx2/-mavx512f for the V32/V64 variants. So `ghc -mavx2 ... -o prog` (or a cabal ghc-options that reaches the link step) compiled AutoApply.cmm, AutoApply_V16.cmm and the scalar/V16 Jumps wrappers with AVX enabled, although those objects go into every program and used to be built at the RTS's baseline. Pin the x86 ISA knobs per variant instead: reset sseVersion, bmiVersion, avx*, fma to the baseline, then enable exactly avx2 for V32 and avx512f for V64. Found by review. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

This is the
genapply-in-compiler+autoapply-linkseries (seewip/andrea/autoapply-link, which is on master) rebased ontostable-ghc-9.14, plus one commit for this tree's Makefile build.What changes
The generic apply code (
stg_ap_*_fast, thestg_ap_*return frames,stg_ap_stk_*,stg_stk_save_*and theARG_*-indexed tables) is no longer produced byutils/genapplyand compiled intolibHSrts. GHC generates it itself from the compiler's own tables (GHC.StgToCmm.AutoApply,ghc --gen-apply), and links it into every program at link time, into-sharedoutputs that contain the RTS (-flink-rts, Windows, wasm) and into-staticlibarchives. The RTS only refers to the symbols.-fno-link-autoapplyturns this off;ghc --gen-apply[=v16|v32|v64]prints the Cmm for anyone linking by other means. See Note [Linking the generic apply code] inGHC.Driver.Pipelineand the new users guide section.Consequence worth knowing: a Haskell shared library built without
-flink-rtsand loaded by a program GHC did not link has no provider forstg_ap_*any more. It must be built with-flink-rts, or the code must be generated and linked by hand; both are documented. Programs and libraries linked by GHC need no changes.Commits:
GHC.StgToCmm.AutoApplyand the--gen-applymodeghc --gen-apply; removeutils/genapplyslowCallPatternandstdPatternfrom the apply tables--gen-applymode-mavx*from the link command line; now pinned per variant)Commits 2–6 leave the Makefile build referring to genapply; 7 fixes that. The
.cmm.hwrapper scheme inrts/configure.acandrts.cabalgoes away with it.Commit 8 came out of a review comment:
stg_stack_underflow_frame_*andstg_restore_cccs_*(rts/Jumps.h) are in the same situation as the apply code. They exist once per argument-register width, the V32/V64 variants need the same per-file-mavxflags, the RTS refers to them the same way, and they encode the argument-register cover that the compiler already has inrealArgRegsCover. So GHC now also writes the four two-line wrappers around the installedJumps.hand compiles them at link time (GHC.StgToCmm.AutoApply.genFileslists all eight files;--gen-applyacceptsjumps,jumps-v16,jumps-v32,jumps-v64).rts.cabalends up with no per-file cmm options at all, and hadrian loses its Jumps-mavxrules.Commit 9 moves the list of link-time files (
GenFile,genFiles, the Jumps wrapper) out ofGHC.StgToCmm.AutoApply, which is left with the apply-code generator only, into a newGHC.Linker.RtsCmm; the pipeline entry points are nowmkRtsCmmObjs/rtsCmmObjsForLink. The compile step stays inGHC.Driver.Pipelinebecause it runscmmCppPipeline. User-facing names (--gen-apply,-flink-autoapply) are unchanged for now; both now also cover the Jumps frames, so renaming them before this merges is worth a thought.Differences from the master version
rts/include/rts/storage/FunTypes.hlives inrts-headers/here.DynFlagshasavx2 :: Boolrather thansseAvxVersion.GHC.Platform.Tag: the generator usesGHC.Cmm.Utils.mAX_PTR_TAGandGHC.StgToCmm.Closure.isSmallFamily.link/link'inGHC.Driver.Pipelinetook the pieces of anHscEnvrather than theHscEnv; the link-time generator needs the real thing, so they now take anHscEnvas on master.GHC.Driver.Makeis the only caller.changelog.d/entry (the directory does not exist on this branch).Verification
make stage2with the Makefile defaults (ghc-9.8.4boot) on x86_64 Linux:_build/dist/binlinks against it.ghc: a test program runs plain and-threaded, with thestg_ap_*symbols and the eight Jumps frames coming from the link-time objects; a Cmainlinked with-no-hs-mainworks;-fno-link-autoapplyfails with undefinedstg_ap_*/stg_arg_bitmaps, as it should; the manual recipe from the users guide (eight--gen-applyfiles,ghc -c, link with-fno-link-autoapply) works. The fourlibHSrts*.aonly reference the Jumps frames now (16–20Uentries each, no definitions).ghc --gen-applyoutput diffed against the old 9.14genapplyon the sameDerivedConstants.h: identical for all four files except the intended preamble, where the 94 lines ofBUILD_PAP/NEW_PAP/jump_SAVE_CCCSmacros replace#include "AutoApply.h".makethen failed in the dist step atpatchelf --set-rpathwith "virtual address space underrun" (patchelf 0.18.0) onghc,ghc-iservandhaddock. The untouched stage1ghcbuilt by 9.8.4 fails the same way, so that looks like a patchelf problem on my machine rather than this branch; the remainingghc-pkg recache/checksteps pass when run by hand.Not done: link-time cost. Four Cmm compiles are added to every link (about 0.2s → 0.8s for hello-world with a quick-flavour master compiler; not measured here). Caching the objects per way is the obvious follow-up.
🤖 Generated with Claude Code