Skip to content

minimal stage1#118

Open
angerman wants to merge 6 commits intostable-ghc-9.14from
feat/minimal-stage1
Open

minimal stage1#118
angerman wants to merge 6 commits intostable-ghc-9.14from
feat/minimal-stage1

Conversation

@angerman
Copy link
Copy Markdown

This is a continuation of @luite's shrinkstage1 MR.

Comment thread compiler/GHC/CmmToAsm/Dwarf/Constants.hs
Comment on lines +98 to +99
, stage0 `cabalFlag` "minimal"
, stage0 `cabalFlag` "no-uncommon-ncgs"
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we actually should care about hadrian, or not.

@angerman angerman force-pushed the feat/minimal-stage1 branch 2 times, most recently from d627df0 to b5c275f Compare November 27, 2025 01:07
@angerman angerman force-pushed the stable-ghc-9.14.2025.11.12 branch from 257a3dc to e808dde Compare November 28, 2025 05:57
@angerman angerman force-pushed the stable-ghc-9.14.2025.11.12 branch from e808dde to 537b3a7 Compare November 28, 2025 08:40
@angerman angerman deleted the branch stable-ghc-9.14 November 29, 2025 02:16
@angerman angerman closed this Nov 29, 2025
@angerman angerman reopened this Nov 29, 2025
@angerman angerman changed the base branch from stable-ghc-9.14.2025.11.12 to stable-ghc-9.14 November 29, 2025 02:28
@angerman angerman force-pushed the feat/minimal-stage1 branch from 6d59cbf to b3cd485 Compare November 29, 2025 02:43
Copy link
Copy Markdown

@luite luite left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice cleanup of the register code and organizing stubs.

In the current revision, there are some code that checks HAVE_INTERPRETER as a condition to import some GHC.StgToJS modules, even though those are guarded by a different flag in ghc.cabal.in. It's way too easy to make this kind of mistakes and correcting them by hand is tedious.

For maintainability I think it's essential to automatically prevent this.

Some ideas:

  • a flag to have GHC immediately error when an "unlisted" (i.e. not explicitly named on the command line, even if its source is available in the hs-source-dirs) module from the current package is imported
  • move every set of flag-guarded modules to a specific hs-source-dir that's only added when that flag is active

Perhaps we'd also need to have a testsuite test that checks the dependencies between the modules for when all optional components have been turned off (unless any mistake would already guarantee failure of stage1 to build)

Comment thread compiler/GHC.hs Outdated
}
}
#else
-- MINIMAL build: no plugin support, no IC modifications
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a bunch of references to MINIMAL still in the source, in comments and panic messages. Maybe some LLM can sweep them up quickly.

Comment thread compiler/GHC/CmmToAsm/Reg/Target.hs Outdated
-- | Calculate the maximum number of register colors that could be
-- denied to a node of this class due to having this virtual reg as a neighbour.
targetVirtualRegSqueeze :: Platform -> RegClass -> VirtualReg -> Int
targetVirtualRegSqueeze platform = rtVirtualRegSqueeze (selectRegTarget platform)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw some {-# INLINE virtualRegSqueeze #-} in the source that may or may not suggest that this code is performance sensitive. Given the way it's being used I don't expect the pragma to actually be beneficial. Is there any measurable performance difference before and after this change?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good observation. Yes we'll only know once we have good performance testing ... on complex applications :(

Comment thread compiler/GHC/CmmToAsm/Reg/Target.hs Outdated
Comment thread compiler/GHC/Driver/Pipeline.hs Outdated
Comment thread compiler/ghc.cabal.in

-- Code Generation Backends
if flag(js-backend)
cpp-options: -DHAVE_JS_BACKEND
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this flag is never checked, looks like some checks are still on HAVE_INTERPRETER

@angerman angerman force-pushed the feat/minimal-stage1 branch 4 times, most recently from 05a4bf8 to f9d6769 Compare December 2, 2025 03:36
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really, really hat this module. Preferrably we wouldn't need stubs at all.

This to me signals for each of the stubs we have here, we unintentionally use some of this in places we shouldn't even use this to begin with.

Comment thread cabal.project.stage1
Comment on lines +69 to +73
+x86-ncg +aarch64-ncg
-ppc-ncg -riscv64-ncg -loongarch64-ncg
-js-backend -wasm-backend
+llvm-backend
-interpreter -dynamic-linker
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we might want to disable llvm-backend by default. And only enable +x86-ncg with a conditionalif arch(x86), same for aarch64?

@angerman angerman force-pushed the feat/minimal-stage1 branch 2 times, most recently from 9a43f87 to f139792 Compare December 11, 2025 07:27
@angerman angerman force-pushed the feat/minimal-stage1 branch from f139792 to 7e3e08e Compare February 26, 2026 00:41
@angerman angerman requested a review from Copilot February 26, 2026 00:45
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a "minimal stage1" build of GHC by making interpreter support, various native code generators, and other backends optional through Cabal flags. The primary goal is to reduce compilation time and binary size for stage1 builds, which only need to compile the compiler itself, not run Template Haskell or GHCi.

Changes:

  • Added Cabal flags to make NCGs (X86, AArch64, PPC, RISC-V64, LoongArch64), backends (JS, Wasm, LLVM), interpreter, and dynamic linker optional
  • Introduced CPP guards throughout the compiler to conditionally compile code based on these flags
  • Created stub types module for interpreter-less builds
  • Split GHC.Hs.Instances into multiple modules for better parallel compilation
  • Modified stage1 configuration to disable most optional features

Reviewed changes

Copilot reviewed 54 out of 55 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
hadrian/src/Settings/Packages.hs Added "minimal" and "no-uncommon-ncgs" flags for stage0 builds
ghc/ghc-bin.cabal.in Added frontend-plugins flag to control plugin loading support
ghc/Main.hs Added CPP guards for frontend plugin functionality
compiler/ghc.cabal.in Added flags for NCGs, backends, interpreter, and dynamic linker; made module compilation conditional
compiler/GHC/Runtime/Interpreter/Stubs.hs New stub types module for interpreter-less builds
compiler/GHC/Hs/Instances*.hs Split Data instances into separate modules for parallel compilation
compiler/GHC/CmmToAsm/Reg/Target.hs Refactored to use GADT-based dispatch for architecture-specific operations
cabal.project.stage1 Configured stage1 to disable ghci library and optional features

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread compiler/GHC/Hs/Instances/Parsed.hs Outdated
Comment thread compiler/GHC/Hs/Instances/Transitions.hs
Comment thread compiler/GHC/CmmToAsm/Reg/Target.hs
Comment thread compiler/GHC/CmmToAsm/Dwarf/Constants.hs Outdated
Comment thread compiler/GHC/Driver/Main.hs Outdated
Comment thread compiler/GHC/Driver/Pipeline/Execute.hs Outdated
angerman added a commit that referenced this pull request Feb 26, 2026
- Clarify dependency explanation in GHC.Hs.Instances.Parsed comment
- Add DEPRECATED pragma to empty GHC.Hs.Instances.Transitions module
- Clarify toRegNo helper comment in Dwarf/Constants.hs as a fallback
- Log a message when initializePlugins is skipped (no interpreter)
- Fix wrong function name in panic: runHscPhase -> runHscBackendPhase
@angerman angerman force-pushed the feat/minimal-stage1 branch 3 times, most recently from b7fc7be to fd5fec4 Compare March 4, 2026 22:09
angerman and others added 6 commits March 6, 2026 10:10
Add +minimal and +no-uncommon-ncgs flags to compiler/ghc.cabal.in and
cabal.project.stage1, plus -frontend-plugins flag for ghc-bin.

The +minimal flag removes bytecode interpreter, JavaScript backend,
WebAssembly backend, GHCi, and Template Haskell execution from stage1.
The +no-uncommon-ncgs flag removes PPC, RISC-V 64, and LoongArch64
native code generators.

Adds comprehensive CPP guards throughout the compiler to support
minimal builds that can compile code without interpreter/GHCi support.

Co-authored-by: Luite Stegeman <stegeman@gmail.com>
Replace the broad MINIMAL/NO_UNCOMMON_NCGS CPP defines with granular
per-topic flags using positive (opt-in) HAVE_* defines:

- HAVE_X86_NCG, HAVE_AARCH64_NCG, HAVE_PPC_NCG, etc.
- HAVE_JS_BACKEND, HAVE_WASM_BACKEND, HAVE_LLVM_BACKEND
- HAVE_INTERPRETER, HAVE_DYNAMIC_LINKER

Refactor NCG register dispatch from repetitive CPP to a GADT-based
pattern with ArchKind data type, RegOps typeclass, and per-architecture
instances. Reduces CPP blocks from ~25 to ~5 (one per arch).

Update cabal.project.stage1 to use the new granular flags.
Create GHC.Runtime.Interpreter.Stubs module containing all stub type
definitions for builds without interpreter support, eliminating
duplication across 6+ files.

Guard all interpreter-dependent modules (Init.hs, Config/Interpreter.hs,
Eval.hs) with HAVE_INTERPRETER for clean no-interpreter builds.

Fix incorrect CPP guard around hscCheckSafeImports that caused Safe
Haskell metadata inconsistencies in stage1-compiled .hi files. Add
missing ghc-platform to cabal.project.stage1. Fix ghc.cabal.in module
lists for rebase compatibility.

Address PR review comments: split HAVE_INTERPRETER vs HAVE_JS_BACKEND
guards, clean up "MINIMAL build" references, fix PPC/CodeGen.hs import
ambiguity from GADT refactor.
Split the monolithic GHC.Hs.Instances module (344 Data instances, 14MB
object file) into 5 parallel-compilable sub-modules:

  - GHC.Hs.Instances.Common      (phase-independent instances)
  - GHC.Hs.Instances.Transitions (LR types spanning multiple phases)
  - GHC.Hs.Instances.Parsed      (GhcPs instances)
  - GHC.Hs.Instances.Renamed     (GhcRn instances + HsLocalBinds deps)
  - GHC.Hs.Instances.Typechecked (GhcTc instances)

The wrapper module GHC.Hs.Instances re-exports all sub-modules for
backward compatibility.

Add stub object-code linker functions to GHC.Runtime.Interpreter that
panic when called (initObjLinker, lookupSymbol, loadDLL, etc.) for
no-interpreter builds. Guard Interpreter/Init.hs and
Config/Interpreter.hs with HAVE_INTERPRETER.
Add new flags to further reduce stage1 compilation:

- -llvm-backend: Exclude LLVM codegen (~17 modules, ~4200 lines).
  Guard LlvmConfigCache, CodeOutput, Pipeline/Execute LLVM phases.
  Move CmmToLlvm.Version modules to unconditional section (needed by
  GHC.Driver.Errors.Ppr and GHC.SysTools).

- +host-ncg-only: Restrict NCG to host architecture using Cabal's
  arch() condition. Saves 8-10 modules per platform.

- -hpc: Gate GHC.HsToCore.Coverage behind conditional. Stub out
  writeMixEntries and hpcInitCode when disabled (~540 lines).

- Move GHC.Stg.BcPrep behind interpreter flag (~200 lines).

Restore debug RTS default for ghc-bin (accidentally changed when
adding -frontend-plugins flag).
…for stage1

- Guard GHC.HsToCore.Foreign.JavaScript import and ArchJavaScript pattern
  matches in dsFImport/dsFExport behind #if defined(HAVE_JS_BACKEND), matching
  the existing HAVE_INTERPRETER guard pattern for Wasm.

- Move 11 JS-related modules (GHC.HsToCore.Foreign.JavaScript, GHC.JS.*)
  from unconditional Exposed-Modules to the if flag(js-backend) section in
  ghc.cabal.in. These modules are only needed when the JS backend is enabled
  and were being compiled unconditionally in stage1 despite -js-backend.

- Set library-for-ghci: False in cabal.project.stage1. Stage1 never loads
  libraries interactively, so generating GHCi-compatible .o files from every
  .a archive is pure waste. Stage2 retains library-for-ghci: True.

Estimated stage1 build time savings: 3-7% on top of existing minimal-stage1.
@angerman angerman force-pushed the feat/minimal-stage1 branch from fd5fec4 to a55ed28 Compare March 6, 2026 01:10
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.

3 participants