Skip to content

Late floating of join points

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.

Trac metadata
Trac field Value
Version 8.0.1
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information