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 |