Should we inline constructor wrappers into boring contexts?
While working on other things I came across this constructor wrapper:
-- RHS size: {terms: 7, types: 6, coercions: 0, joins: 0/0}
GHC.Unit.Types.$WRealUnit [InlPrag=INLINE[final] CONLIKE]
:: forall uid. Definite uid %1 -> GenUnit uid
[GblId[DataConWrapper],
Arity=1,
Caf=NoCafRefs,
Str=<SL>,
Cpr=1,
Unf=Unf{Src=InlineStable, TopLvl=True, Value=True, ConLike=True,
WorkFree=True, Expandable=True,
Guidance=ALWAYS_IF(arity=1,unsat_ok=True,boring_ok=False)
Tmpl= \ (@uid_a2UY)
(conrep_a3pk [Occ=Once1] :: Definite uid_a2UY) ->
case conrep_a3pk of conrep_X0 [Occ=Once1] { __DEFAULT ->
GHC.Unit.Types.RealUnit @uid_a2UY conrep_X0
}}]
GHC.Unit.Types.$WRealUnit
= \ (@uid_a2UY) (conrep_a3pk [Occ=Once1] :: Definite uid_a2UY) ->
case conrep_a3pk of conrep_X0 [Occ=Once1] { __DEFAULT ->
GHC.Unit.Types.RealUnit @uid_a2UY conrep_X0
}
There are a few cases where this kind of wrapper does not get inlined. For example here:
case ds8_saQo sat_saQs GHC.Prim.void# of {
Solo# ipv12_saQv [Occ=Once1] ->
let {
sat_saQw [Occ=Once1]
:: GHC.Unit.Types.GenUnit GHC.Unit.Types.UnitId
[LclId] =
{ipv12_saQv} \u [] GHC.Unit.Types.$WRealUnit ipv12_saQv;
} in Solo# [sat_saQw];
This is all expected (see the boring_ok=False attribute). I do wonder if it's the right thing to do.
In the example above we will generate a CMM function for the binding sat_saQw
. This means we pay the overhead of two function calls when evaluating sat_saQw
but save a bit in code size/compile time.
Things are different for wrappers which evaluate multiple arguments, these can become non-trivial in code size and probably shouldn't be inlined into boring contexts.
It seems like there are pros and cons for either choice. We could also make it dependent on the number of cases inside the wrapper. But currently there is no reason given in any of the notes for doing it one way or another. So I'm opening this ticket in case anyone wonders about the current choice or wants to evaluate it going forward.