[GHC] #3116: missed opportunity for call-pattern specialisation
GHC
trac at galois.com
Wed Mar 25 22:43:11 EDT 2009
#3116: missed opportunity for call-pattern specialisation
-----------------------------------------+----------------------------------
Reporter: duncan | Owner:
Type: run-time performance bug | Status: new
Priority: normal | Milestone:
Component: Compiler | Version: 6.10.1
Severity: normal | Resolution:
Keywords: | Difficulty: Unknown
Testcase: | Os: Unknown/Multiple
Architecture: Unknown/Multiple |
-----------------------------------------+----------------------------------
Comment (by duncan):
Replying to [comment:3 simonpj]:
> Can't do much better than that. Expect a patch shortly.
Woo hoo! That is indeed perfect. Thanks very much! I will update that
example in my thesis accordingly! :-)
> I don't understand your recent comment above, though. The RULES
generated from the specialisations are indeed applied in the original
function!
Yes, of course. Sorry, I was not very clear.
> Can you give a standalone example showing what happens, and what you
want to happen instead?
Ok, so with your fix we're getting essentially:
{{{
go_chunk n p fpc o l bs'
= case l of
1 -> go (n+1) bs'
_ -> go_chunk (n+1) p fpc (o+1) (l-1) bs'
go !n bs
= case bs of
Empty -> n
Chunk p fpc o l bs' ->
case l of
1 -> go (n+1) bs'
_ -> go_chunk (n+1) p fpc (o+1) (l-1) bs'
}}}
The body of `go` contains a full unfolded instance of `go_chunk`
(obviously, because that's the way `go` was defined and `go_chunk` was
derived from a portion of the body of `go`).
But what if it turned out that calling `go_chunk` was better than having
`go_chunk` unfolded into the body of `go`?
That is, it might be that this turns out to be the faster code:
{{{
go_chunk n p fpc o l bs'
= case l of
1 -> go (n+1) bs'
_ -> go_chunk (n+1) p fpc (o+1) (l-1) bs'
go n bs
= case bs of
Empty -> n
Chunk p fpc o l bs' -> go_chunk b p fpc o l bs'
}}}
Currently, when we do the specialisation we leave the original defintion
unmodified. Of course subsequently we apply the rules to it etc, but
initially it's just kept in it's original form.
The suggestion is that perhaps it is profitable to substitute calls to the
specialised versions of the function into the original definition. We can
always recover the original definition if the inliner decides it's the
right thing to do.
So, in this example, we start with the definition:
{{{
go !n bs = case bs of
Empty -> n
Chunk p fpc o l bs' ->
case l of
1 -> go (n+1) bs'
_ -> go (n+1) (Chunk p fpc (o+1) (l-1) bs')
}}}
Then we construct the specialised versions:
{{{
go_empty n = n
go_chunk n p fpc o l bs'
= case l of
1 -> go (n+1) bs'
_ -> go (n+1) (Chunk p fpc (o+1) (l-1) bs')
}}}
Of course we also make the rules. In the current system we then just move
on to applying the specialisation rules in the body of these functions and
the original.
But suppose instead that we first redefine the original `go` in terms of
it's specialisations:
{{{
go !n bs = case bs of
Empty -> go_empty n
Chunk p fpc o l bs' -> go_chunk n p fpc o l bs'
}}}
I do not mean doing this by rewrite rules, I mean just doing it directly
as part of the procedure of generating specialised versions. Pick a
pattern, lift the correspoding portion of the body out to become the
specialised function and replace it with a call to the new specialised
function. (That's an over-simplification of course but hopefully
illustrates the idea).
Then we move on as normal to apply rules and do ordinary simplification.
This now gives the inliner the choice. It can choose to inline `go_chunk`
in the body of `go` or it can choose to keep it as a call. If `go_chunk`
is quite large then it might be better to keep it as a call. In the
existing scheme it has no choice because the original function definition
is never changed, it always contains the full body of each of its
specialisations.
Does that make any sense?
--
Ticket URL: <http://hackage.haskell.org/trac/ghc/ticket/3116#comment:4>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the Glasgow-haskell-bugs
mailing list