[GHC] #9279: Local wrapper function remains in final program; result = extra closure allocation
GHC
ghc-devs at haskell.org
Tue Sep 11 11:21:38 UTC 2018
#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 at 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
More information about the ghc-tickets
mailing list