[GHC] #15560: Full laziness destroys opportunities for join points

GHC ghc-devs at haskell.org
Tue Aug 28 08:37:22 UTC 2018


#15560: Full laziness destroys opportunities for join points
-------------------------------------+-------------------------------------
        Reporter:  AndreasK          |                Owner:  (none)
            Type:  bug               |               Status:  new
        Priority:  normal            |            Milestone:  8.6.1
       Component:  Compiler          |              Version:  8.4.3
  (CodeGen)                          |
      Resolution:                    |             Keywords:  JoinPoints
Operating System:  Unknown/Multiple  |         Architecture:
                                     |  Unknown/Multiple
 Type of failure:  None/Unknown      |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:  #14287 #13286     |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by simonpj):

 > I assume you are talking about removing the stack check here with the
 optimisation?

 I wasn't very clear. My idea is to ''ignore'' whether a top-level binding
 started life as a join point, and instead optimise ''all'' top-level
 bindings the same way.

 There are three things in play:

 1. '''Eliminating the closure and info-table for some top-level
 functions'''.  Consider a top-level binding
 {{{
 f = \xy. e
 }}}
   When can we do without a closure and info table for `f`?  Answer: if
       * All calls to `f` are known, saturated calls (no partial
 applications).
       * `f` is not exported

     NB 1: it's fine if the call to `f` is in a lazy context, e.g.
 {{{
 g y = let t = f (y+1) in Just t
 }}}

     NB 2: for a ''nested'', let-bound function, we do need a function
 closure, even if all the calls are known, saturated calls.  Why?  Because
 we need a heap-allocated container for its free variables.  So we need the
 info table.  But if all the calls are known, saturated, we do ''not'' need
 any slow-entry code, so the code pointer for the info table could be
 "crash" (will never happen).

 2. '''Eliminating stack checks'''.  Join points already don't have a stack
 check; regular let-bindings do (of course).  Idea: extend to the stack-
 check elimination to more functions; that is, absorb any stack use for
 that function into its call site.  When can we do this?  Answer:
       * All calls to `f` are known, saturated calls (no partial
 applications).
       * `f` is not exported
       * `f` is not recursive; or `f` is top-level and tail-calls itself
 (or is part of a top-level tail-recursive nest).

     NB 1: this works for ''non-top-level'' functions too. Example:
 {{{
 g x = let f y = blah
           t = f 4 + f 5
       in Just t
 }}}
     Currently the thunk for `t` will do a stack check, and `f` will do its
 own stack check too.  We could absorb `f`'s check into `t`.

     NB 2: why not recursive functions?  Consider
 {{{
    let f x = if x==0 then 0 else 1 + f (x-1)
 }}}
     Clearly the stack grows, so we can't eliminate the stack check.  But
 if `f` is a join point there is no problem, and similarly at top level
 (i.e. not a join point) if it tail-calls itself or some other top-level
 function with the same property.... let's call these "top-level join
 points".


 3.  '''Eliminating heap checks'''.   Idea: absorb the heap check for a
 function into its caller.  When can we do this?
     * All calls to `f` are known, saturated calls (no partial
 applications).
     * `f` is not exported
     * `f` is not recursive. Reason: if it's recursive, one of its call
 sites is in its own RHS, so we can't statically bound how much heap it
 uses.

     NB 1: absorbing the heap check is ''not'' currently done even for join
 points. (Reason: it only works for ''non-recursive'' functions.)


 NB: None of these optimisations rely on `f` being a join point.

 All of this is STG-level/code-gen level optimisation, not Core.

 These would be interesting ideas to try out. If you feel motivated, I
 could advise.

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


More information about the ghc-tickets mailing list