[GHC] #8032: Worker-wrapper transform triggers bad reboxing behavior

#8032: Worker-wrapper transform triggers bad reboxing behavior
------------------------------------+---------------------------------------
Reporter: ezyang | Owner:
Type: bug | Status: new
Priority: normal | Component: Compiler
Version: 7.7 | Keywords:
Os: Unknown/Multiple | Architecture: Unknown/Multiple
Failure: Runtime performance bug | Blockedby:
Blocking: | Related:
------------------------------------+---------------------------------------
When we worker-wrapper transform functions, we tend to be to eager to
unbox all of our arguments and pass them to the worker. This backfires
when the boxed version of the argument is needed:
{{{
module Gnam where
data KST = KST {
ke :: {-# UNPACK #-} !Int
, ka :: {-# UNPACK #-} !Int
}
data KStop r = KNeedInput Int !(KC r)
data Result r = Result r
type KC r = KST -> Int -> Result r
newtype K r a = K {
unK :: (KST -> KStop r -> Result r) -> KC r
}
skipWhileK :: K () ()
skipWhileK =
K $ \kf kst@KST{ ke = e } i0 ->
let loop i rw0 -- Note: removing rw0 argument gets rid of re-boxing
behavior
| i < e = loop (i + 1) rw0
| otherwise = unK recurse kf kst i
in loop i0 (0 :: Int)
where -- Note that without NOINLINE, we get an unnecessary eager
-- closure allocation even when closure is never used. This
-- is unfortunate because recurse is the slow path (e.g.,
-- called 1/4000 of the time in the real code).
{-# NOINLINE recurse #-}
recurse = K $ \kf kst i -> kf kst $ KNeedInput i $ unK skipWhileK
kf
}}}
skipWhileK is an important loop which we would like to avoid performing
heap allocation on. However, this code is compiled by HEAD with an
allocation which reboxes KST:
{{{
Gnam.$wa
:: (Gnam.KST -> Gnam.KStop () -> Gnam.Result ())
-> GHC.Prim.Int#
-> GHC.Prim.Int#
-> GHC.Prim.Int#
-> Gnam.Result ()
[GblId,
Arity=4,
Caf=NoCafRefs,
Str=DmdType
participants (1)
-
GHC