
#9279: Local wrapper function remains in final program; result = extra closure allocation -------------------------------------+------------------------------------- Reporter: simonmar | Owner: simonpj Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 7.8.2 Resolution: | Keywords: LateLamLift Operating System: Unknown/Multiple | Architecture: Type of failure: Runtime | Unknown/Multiple performance bug | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by simonpj): Concerning comment@4 I have not looked in detail at the example in the Description, but I'm guessing that we have a situation like this {{{ f x xs = let g :: Int -> Int g y = y+x in map g xs }}} We see that `g` is strict, so we w/w it thus: {{{ f x xs = let $wg :: Int# -> Int# $wg y# = case x of I# x# -> y# + x# g :: Int -> Int {-# Stable unfolding = \y -> <as below> #-} g y = case y of I# y# -> case $wg y# of r# -> I# r# in map g xs }}} But alas, `g` never gets to inline, so it is all in vain. Worse, we have lost out, because `map` calls `g` which calls `$wg` and that's slower than what we started with. What we want is this: * If the only call to `$wg` is from `g`, then inline it back in. Currently there are two calls to `gw`, one in the RHS of `g` and one in the stable unfolding of `g`. If we simply nuked the stable unfolding to `g` (which was added by w/w), then there'd only be one call to `gw` and we'd inine it happily. On the other hand, if the body of f was `(map g xs, g 7)`, then the `g 7` would by now have turned into a call of `$wg`, so whether we inlined `$wg` would depend on how big `$wg` is, which is absolutely fine. Arguably should not do this nuking stuff until after `TidyCore`, which generates bindings to put in the interface file. We want to leave `f`'s RHS undisturbed until then, in case `f` itself is inlined in other modules. (An alternative view: it'd be ok to dump the w/w split in before `TidyCore` because we'll rediscover the strictness (and perhaps better strictness) in any module that inlines `f`.) My conclusion: * for local functions (i.e. bound by a `let`, or at top level but not exported) * that have been w/w'd * at a fairly late stage in the pipeline * kill off the stable-unfolding introduced by w/w * and simplify I think it'd be interesting to try this. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9279#comment:21 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler