[GHC] #15770: Missing optimisation opportunity in code gen for always-saturated applications?

GHC ghc-devs at haskell.org
Thu Oct 18 08:24:17 UTC 2018


#15770: Missing optimisation opportunity in code gen for always-saturated
applications?
-------------------------------------+-------------------------------------
           Reporter:  osa1           |             Owner:  (none)
               Type:  bug            |            Status:  new
           Priority:  normal         |         Milestone:
          Component:  Compiler       |           Version:
           Keywords:                 |  Operating System:  Unknown/Multiple
       Architecture:                 |   Type of failure:  None/Unknown
  Unknown/Multiple                   |
          Test Case:                 |        Blocked By:
           Blocking:                 |   Related Tickets:
Differential Rev(s):                 |         Wiki Page:
-------------------------------------+-------------------------------------
 As a part of the work on moving some fragile analyses from Core to final
 phase
 before code gen (#9718) I found an unused analysis in CoreToStg which
 basically
 assigns each binder this:

 {{{
 data StgBinderInfo
   = NoStgBinderInfo
   | SatCallsOnly        -- All occurrences are *saturated* *function*
 calls
                         -- This means we don't need to build an info table
 and
                         -- slow entry code for the thing
                         -- Thunks never get this value
 }}}

 The idea is , as mentioned in the comment, for `SatCallsOnly` binder we
 can
 avoid generating code for slow entry. However this is currently not used
 (see
 Phab:D5232), and this ticket is to decide whether to use or remove this.

 I found these comments in `StgCmmClosure` that explains how this became
 unused
 and how it was used before:

 {{{
 -----------------------------------------------------------------------------
 --                staticClosureRequired
 -----------------------------------------------------------------------------

 {-  staticClosureRequired is never called (hence commented out)

     SimonMar writes (Sept 07) It's an optimisation we used to apply at
     one time, I believe, but it got lost probably in the rewrite of
     the RTS/code generator.  I left that code there to remind me to
     look into whether it was worth doing sometime

 {- Avoiding generating entries and info tables
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 At present, for every function we generate all of the following,
 just in case.  But they aren't always all needed, as noted below:

 [NB1: all of this applies only to *functions*.  Thunks always
 have closure, info table, and entry code.]

 [NB2: All are needed if the function is *exported*, just to play safe.]

 * Fast-entry code  ALWAYS NEEDED

 * Slow-entry code
         Needed iff (a) we have any un-saturated calls to the function
         OR         (b) the function is passed as an arg
         OR         (c) we're in the parallel world and the function has
 free vars
                        [Reason: in parallel world, we always enter
 functions
                        with free vars via the closure.]

 * The function closure
         Needed iff (a) we have any un-saturated calls to the function
         OR         (b) the function is passed as an arg
         OR         (c) if the function has free vars (ie not top level)

   Why case (a) here?  Because if the arg-satis check fails,
   UpdatePAP stuffs a pointer to the function closure in the PAP.
   [Could be changed; UpdatePAP could stuff in a code ptr instead,
    but doesn't seem worth it.]

   [NB: these conditions imply that we might need the closure
   without the slow-entry code.  Here's how.

         f x y = let g w = ...x..y..w...
                 in
                 ...(g t)...

   Here we need a closure for g which contains x and y,
   but since the calls are all saturated we just jump to the
   fast entry point for g, with R1 pointing to the closure for g.]


 * Standard info table
         Needed iff (a) we have any un-saturated calls to the function
         OR         (b) the function is passed as an arg
         OR         (c) the function has free vars (ie not top level)

         NB.  In the sequential world, (c) is only required so that the
 function closure has
         an info table to point to, to keep the storage manager happy.
         If (c) alone is true we could fake up an info table by choosing
         one of a standard family of info tables, whose entry code just
         bombs out.

         [NB In the parallel world (c) is needed regardless because
         we enter functions with free vars via the closure.]

         If (c) is retained, then we'll sometimes generate an info table
         (for storage mgr purposes) without slow-entry code.  Then we need
         to use an error label in the info table to substitute for the
 absent
         slow entry code.
 -}

 staticClosureRequired
         :: Name
         -> StgBinderInfo
         -> LambdaFormInfo
         -> Bool
 staticClosureRequired binder bndr_info
                       (LFReEntrant top_level _ _ _ _)        -- It's a
 function
   = ASSERT( isTopLevel top_level )
         -- Assumption: it's a top-level, no-free-var binding
         not (satCallsOnly bndr_info)

 staticClosureRequired binder other_binder_info other_lf_info = True
 -}
 }}}

-- 
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15770>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list