Skip to content

GitLab

  • Menu
Projects Groups Snippets
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
  • GHC GHC
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 4,866
    • Issues 4,866
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
  • Merge requests 456
    • Merge requests 456
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
    • Test Cases
  • Deployments
    • Deployments
    • Releases
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Glasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #20313
Closed
Open
Created Aug 31, 2021 by Andreas Klebinger@AndreasKDeveloper

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.

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
Time tracking