[GHC] #14137: Do more inlining into non-recursive join points

GHC ghc-devs at haskell.org
Fri Aug 18 10:53:45 UTC 2017


#14137: Do more inlining into non-recursive join points
-------------------------------------+-------------------------------------
           Reporter:  simonpj        |             Owner:  (none)
               Type:  bug            |            Status:  new
           Priority:  normal         |         Milestone:
          Component:  Compiler       |           Version:  8.2.1
           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:
-------------------------------------+-------------------------------------
 In pursuing #14068, [https://phabricator.haskell.org/D3811#107745 Joahim
 says] found this code:
 {{{
 let {
   ds5 :: [[Int]]
   ds5 = case ==# x1 ww1 of {
         __DEFAULT -> go1 (+# x1 1#);
         1# -> n
       } } in
 join {
   lvl6 :: [[Int]]
   lvl6 = (ds4 : y) : ds5} in
 joinrec {
   safe :: Int -> Int -> [Int] -> [[Int]]
   safe (x2 :: Int) (d :: Int) (ds6 :: [Int])
     = case ds6 of {
         [] -> jump lvl6;
         : q l ->
           case x2 of wild6 { I# x3 ->
           case q of { I# y1 ->
           case /=# x3 y1 of {
             __DEFAULT -> ds5;
             1# ->
               case d of { I# y2 ->
               case /=# x3 (+# y1 y2) of {
                 __DEFAULT -> ds5;
                 1# ->
                   case /=# x3 (-# y1 y2) of {
                     __DEFAULT -> ds5;
                     1# ->
                       jump safe
                         wild6 (I# (+# y2 1#)) l
                   }}}}}}
       }; } in
 jump safe ds4 lvl y; } in ...
 }}}
 This is terrible!  `lvl6` is a join point, but `ds5` is not.  And it's
 easy to fix: we should simply float `ds5` into `lvl6`'s rhs.

 **Backgound**.  In general, if GHC sees this
 {{{
 -- Version A
 x = f x : g y
 }}}
 it'll float out the `(f x)` and `(g y)` parts thus (B):
 {{{
 -- Version B
 a1 = f x
 a2 = g y
 x = a1 : a2
 }}}
 Reasons:

 1. In the scope of this binding we might have `case x of (a:b) -> rhs`,
 and the new form allows us to eliminate the case.

 2. Version A builds a thunk (which, when eval'd) builds thunks for `(f x)`
 and `(g y)` and returns a cons; whereas Version B builds the two thunks
 ahead of time and allocates a cons directly.  If `x` gets evaluated this
 is a win, by avoiding an extra thunk.  We measured this in our let-
 floating paper, and B is much better on average.

 But if `x` is a join point, all this is wrong wrong wrong:

 1. A join point is never scrutinised by a nested case, so there is no
 benefit in floating.
 2. A join point is not implemented by a thunk, so there is no thunk
 alloc/update to avoid.

 In fact, for join points we want to turn Version B into Version A!

 Specifically:

 * In `Simplify`, do not call `prepareRhs` on join RHSs; nor do floating
 (see `tick LetFloatFromLet`) from the RHS of a join.  In fact this seems
 to be already the case.

 * In `OccurAnal`, do not use `rhsCtxt` for the RHS of a non-recursive join
 point (see `occAnalNonRecRhs`).  Setting this context makes `a1` and `a2`
 get "inside-lam" occurrences (see `occAnalApp`), and that in turn stops
 `a1` and `a2` getting inlined straight back into `x`'s RHS in Version B.
 But for join points we **want** them to be inlined, to get back to Version
 A.

   For a recursive join point we probably do not want to inline `a1` and
 `a2` because then they'd be allocated each time round the loop.  But in
 fact we can't have a recursive join point whose RHS is just a cons, so it
 doesn't really arise.  The point is: we only need to take care with
 `rhsCtxt` for non-recursive join points.

 Bottom line: just that one fix to `OccurAnal` should do the job.

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


More information about the ghc-tickets mailing list