[GHC] #13286: Late floating of join points

GHC ghc-devs at haskell.org
Thu Feb 16 11:28:25 UTC 2017


#13286: Late floating of join points
-------------------------------------+-------------------------------------
           Reporter:  simonpj        |             Owner:  (none)
               Type:  bug            |            Status:  new
           Priority:  normal         |         Milestone:
          Component:  Compiler       |           Version:  8.0.1
           Keywords:  JoinPoints     |  Operating System:  Unknown/Multiple
       Architecture:                 |   Type of failure:  None/Unknown
  Unknown/Multiple                   |
          Test Case:                 |        Blocked By:
           Blocking:                 |   Related Tickets:
Differential Rev(s):                 |         Wiki Page:
-------------------------------------+-------------------------------------
 Consider this, from `GHC.Real`:
 {{{
 GHC.Real.$w$s^1 [InlPrag=[0]] :: Int -> Int# -> Int#
 GHC.Real.$w$s^1 =
   \ (w_s6xh :: Int) (ww_s6xl :: Int#) ->
     case tagToEnum# @ Bool (<# ww_s6xl 0#) of {
       False ->
         case ww_s6xl of wild1_XdK {
           __DEFAULT ->
             case w_s6xh of { I# ww2_s6xa ->
             joinrec {
               $wf_s6xg [InlPrag=[0], Occ=LoopBreaker] :: Int# -> Int# ->
 Int#
               [LclId[JoinId(2)], Arity=2, Str=<S,U><S,U>, Unf=OtherCon []]
               $wf_s6xg (ww3_X6Hi :: Int#) (ww4_s6xe :: Int#) =
                 case remInt# ww4_s6xe 2# of {
                   __DEFAULT ->
                     case ww4_s6xe of wild3_Xe3 {
                       __DEFAULT ->
                         joinrec {
                           $wg_s6x5 [InlPrag=[0], Occ=LoopBreaker]
                             :: Int# -> Int# -> Int# -> Int#
                           [LclId[JoinId(3)], Arity=3, Str=<S,U><S,U><S,U>,
 Unf=OtherCon []]
                           $wg_s6x5 (ww5_s6wV :: Int#) (ww6_s6wZ :: Int#)
 (ww7_s6x3 :: Int#) =
                             case remInt# ww6_s6wZ 2# of {
                               __DEFAULT ->
                                 case ww6_s6wZ of wild5_Xen {
                                   __DEFAULT ->
                                     jump $wg_s6x5
                                       (*# ww5_s6wV ww5_s6wV)
                                       (quotInt# (-# wild5_Xen 1#) 2#)
                                       (*# ww5_s6wV ww7_s6x3);
                                   1# -> *# ww5_s6wV ww7_s6x3
                                 };
                               0# ->
                                 jump $wg_s6x5
                                   (*# ww5_s6wV ww5_s6wV) (quotInt#
 ww6_s6wZ 2#) ww7_s6x3
                             }; } in
                         jump $wg_s6x5
                           (*# ww3_X6Hi ww3_X6Hi) (quotInt# (-# wild3_Xe3
 1#) 2#) ww3_X6Hi;
                       1# -> ww3_X6Hi
                     };
                   0# -> jump $wf_s6xg (*# ww3_X6Hi ww3_X6Hi) (quotInt#
 ww4_s6xe 2#)
                 }; } in
             jump $wf_s6xg ww2_s6xa wild1_XdK
             };
           0# -> 1#
         };
       True -> case GHC.Real.^2 of wild1_00 { }
     }
 }}}
 Note those two `joinrecs`.  Neither has any free variables.  So we could
 float them to
 top level, as ordinary functions, thus
 {{{
 $wg_s6x5 [InlPrag=[0], Occ=LoopBreaker]
   :: Int# -> Int# -> Int# -> Int#
 $wg_s6x5 (ww5_s6wV :: Int#) (ww6_s6wZ :: Int#) (ww7_s6x3 :: Int#) =
   case remInt# ww6_s6wZ 2# of {
     __DEFAULT ->
       case ww6_s6wZ of wild5_Xen {
         __DEFAULT ->
           jump $wg_s6x5
             (*# ww5_s6wV ww5_s6wV)
             (quotInt# (-# wild5_Xen 1#) 2#)
             (*# ww5_s6wV ww7_s6x3);
         1# -> *# ww5_s6wV ww7_s6x3
       };
     0# ->
       $wg_s6x5 (*# ww5_s6wV ww5_s6wV) (quotInt# ww6_s6wZ 2#) ww7_s6x3

 $wf_s6xg [InlPrag=[0], Occ=LoopBreaker] :: Int# -> Int# -> Int#
 $wf_s6xg (ww3_X6Hi :: Int#) (ww4_s6xe :: Int#) =
   case remInt# ww4_s6xe 2# of {
     __DEFAULT ->
       case ww4_s6xe of wild3_Xe3 {
         __DEFAULT ->
           $wg_s6x5
             (*# ww3_X6Hi ww3_X6Hi) (quotInt# (-# wild3_Xe3 1#) 2#)
 ww3_X6Hi;
         1# -> ww3_X6Hi
       };
     0# -> $wf_s6xg (*# ww3_X6Hi ww3_X6Hi) (quotInt# ww4_s6xe 2#)

 GHC.Real.$w$s^1 [InlPrag=[0]] :: Int -> Int# -> Int#
 GHC.Real.$w$s^1 =
   \ (w_s6xh :: Int) (ww_s6xl :: Int#) ->
     case tagToEnum# @ Bool (<# ww_s6xl 0#) of {
       False ->
         case ww_s6xl of wild1_XdK {
           __DEFAULT ->
             case w_s6xh of { I# ww2_s6xa -> $wf_s6xg ww2_s6xa wild1_XdK
 };
           0# -> 1#
         };
       True -> case GHC.Real.^2 of wild1_00 { }
     }
 }}}
 Is this better?

 * Better before: the nested join points don't allocate a closure; but the
 top-level defns do build a (never used) closure and slow entry point.

 * Better after: the externally-visible function might inline more at call
 sites in other modules.

 So it's a bit moot.  It has something of the flavour of the late lambda-
 lifting pass.

 For now I'm doing nothing; just recording the observation. The simple
 thing is not to float.

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


More information about the ghc-tickets mailing list