Decouple dynflags in Cmm
What
Continuing to decouple DynFlags, see #20730 for project plan and status
Adds two modules:
-
Driver.Config.Cmm
: module that definesinitCmmConfig :: DynFlags -> CmmConfig
-
Cmm.Config
: defines the data typeCmmConfig
Refactors instances of DynFlags
in the compiler/GHC/Cmm
to use CmmConfig
instead of DynFlags
.
This MR does not change Cmm/Parser.y
My reasoning is that since parsers are necessarily external facing DynFlags
is an acceptable input, but I do not know how this integrates with the rest of the compiler.
Other things
- You'll notice that
CmmConfig
has a fieldcmmNCGPayload
due tooneSRT
inCmm.Info.Build
:
-- | Build an SRT for a set of blocks
oneSRT
:: CmmConfig
-> LabelMap CLabel -- which blocks are static function entry points
-> [SomeLabel] -- blocks in this set
-> [CAFLabel] -- labels for those blocks
-> Bool -- True <=> this SRT is for a CAF
-> Set CAFLabel -- SRT for this set
-> Set CLabel -- Static data labels in this group
-> StateT ModuleSRTInfo UniqSM
( [CmmDeclSRTs] -- SRT objects we built
, [(Label, CLabel)] -- SRT fields for these blocks' itbls
, [(Label, [SRTEntry])] -- SRTs to attach to static functions
, Bool -- Whether the group has CAF references
)
oneSRT cfg staticFuns lbls caf_lbls isCAF cafs static_data = do
topSRT <- get
let
this_mod = thisModule topSRT
config = cmmNCGPayload cfg this_mod -- <---- used right here
profile = cmmProfile cfg
platform = profilePlatform profile
srtMap = moduleSRTMap topSRT
And in the initCmmConfig
function this field is populated with a PAP:
initCmmConfig :: DynFlags -> CmmConfig
initCmmConfig dflags = CmmConfig
{ cmmPlatform = targetPlatform dflags
, cmmBackend = backend dflags
, cmmProfile = targetProfile dflags
, cmmPositionInd = positionIndependent dflags
, cmmOptControlFlow = gopt Opt_CmmControlFlow dflags
, cmmOptDoLinting = gopt Opt_DoCmmLinting dflags
, cmmOptElimCommonBlks = gopt Opt_CmmElimCommonBlocks dflags
, cmmOptSink = gopt Opt_CmmSink dflags
, cmmDebugLevel = debugLevel dflags
, cmmNCGPayload = initNCGConfig dflags -- <----- partially applied right here
}
This is a design decision and I'm open to suggestions.
What I chose was to allow a pass through field that curries DynFlags
for the native code generator. This design maintains the design goal of only having initPhase
functions input DynFlags
and then passdown information to subsequent phases via handshakes, but also allows CmmConfig
to not know anything about the DynFlags
required by the native code generator. I think these are both advantages of the approach
The disadvantages is that we are smuggling in DynFlags
via a PAP, but only this time we do not have type information that this is occurring. Similarly, if some downstream code needed to change a field in the hidden DynFlags
then it can no longer do that because the partially applied DynFlags
is read only now.
Other approaches might be to hold NCGConfig
itself, however I'm unsure how this would be possible since NCGConfig
is parameterized by Module
, hence the PAP. Or we might mirror all of NCGConfig in a new type, but then this breaks separation of concerns and couples CmmConfig
to NCGConfig
.