As part of the refactorings tracked in #21872 we plan to decouple the Core optimization pipeline from the driver code. In addition to that we aim to make the various Core passes independently usable, which in turn means that we try to avoid shared environments as those tend to accumulate fields which are not used by all passes1. This means as well that we try to avoid the need to setup a monadic environment for the passes.
Changes in this PR
-
CoreM
got removed from all passes and the CoreToDo interpreter. This leaves Core-to-Core plugins as the sole user of this monad - at least in GHC.Core.Opt - and it was therefore moved to the GHC.Plugins namespace. In order to remove coupling even further allCoreM
uses were removed from GHC.Core.Lint, too. The idea behind this is to makeCoreM
the monad of Core plugins and use more specific monads for other parts of the compiler dealing with Core. The remaining code from GHC.Core.Opt.Monad was moved to GHC.Core.Opt.Utils. -
In order to reduce coupling
CoreToDo
is not used by the Core linter and the Core-to-Stg subsystem. -
We a new monad
SimplCountM
to GHC.Core.Opt.Stats. This is essentially a writer monad used to accumulate theSimpleCount
s in the CoreToDo interpreter. -
A new module GHC.Core.EndPass got split from GHC.Core.Lint. Now, GHC.Core.Lint (still a very large module) is just the domain-layer logic to lint Core, nothing more. Conversely, the endPass logic is application-layer logic using the Core linter, and not actually part of the core linter in any sense. The different endPass and linting functions take configuration record and the respective initialization functions in the driver were added.
-
All references to the driver code where removed from the Specialise pass and it got a config record. The SpecConstr and CallerCC passes got proper configs too and
addCallerCostCentres
andspecConstrProgram
are now pure functions. A new module GHC.Core.Opt.CallerCC.Filter got split from GHC.Core.Opt.CallerCC to avoid hs-boot. -
In order to reduce partiality in the CoreToDo interpreter we got rid of the
CoreDesugar
,CoreDesugarOpt
,CorePrep
andCoreTidy
variants. These were not "core -> core" passes anyways, and so never belonged there. They were just added because it was previously necessary to have aCoreToDo
to use the "end pass" machinery. -
Likewise, we got rid of
CoreDoPasses
andCoreDoNothing
by rewritinggetCoreToDo
using aWriter
monad. -
The Core interpreter got split in several modules:
-
CoreToDo
-> GHC.Core.Opt.Config -
getCoreToDo
-> GHC.Driver.Config.Core.Opt -
runCorePasses
-> GHC.Core.Opt and GHC.Driver.Core.OptrunCorePases
lives in the former module while the entrypoint in the driver (optimizeCoreIO
andoptimizeCoreHsc
) are located in the second one. This way we get a nice separation between code that is responsible for planning (i.e. constructing the Core pipeline along with the configurations of the passes to run) and the one for executing the pipeline.
-
-
A new note "The architecture of the Core optimizer" was added to GHC.Driver.Core.Opt that explains the big picture of the aforementioned changes.
Fixes #21611 .
-
This is similar in spirit to the "DynFlags problem" laid out in the Modularizing GHC.
↩