Draft: Move `CoreM` to GHC.Plugins.Monad

Open Dominik Peteler requested to merge wip/21611-move-corem into master

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

  1. 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 all CoreM uses were removed from GHC.Core.Lint, too. The idea behind this is to make CoreM 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.

  2. In order to reduce coupling CoreToDo is not used by the Core linter and the Core-to-Stg subsystem.

  3. We a new monad SimplCountM to GHC.Core.Opt.Stats. This is essentially a writer monad used to accumulate the SimpleCounts in the CoreToDo interpreter.

  4. 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.

  5. 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 and specConstrProgram are now pure functions. A new module GHC.Core.Opt.CallerCC.Filter got split from GHC.Core.Opt.CallerCC to avoid hs-boot.

  6. In order to reduce partiality in the CoreToDo interpreter we got rid of the CoreDesugar, CoreDesugarOpt, CorePrep and CoreTidy variants. These were not "core -> core" passes anyways, and so never belonged there. They were just added because it was previously necessary to have a CoreToDo to use the "end pass" machinery.

  7. Likewise, we got rid of CoreDoPasses and CoreDoNothing by rewriting getCoreToDo using a Writer monad.

  8. 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.Opt

      runCorePases lives in the former module while the entrypoint in the driver (optimizeCoreIO and optimizeCoreHsc) 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.

  9. 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 .

  1. This is similar in spirit to the "DynFlags problem" laid out in the Modularizing GHC.

Edited by Dominik Peteler

Merge request reports