[GHC] #855: Improvements to SpecConstr
GHC
ghc-devs at haskell.org
Fri Feb 23 14:09:02 UTC 2018
#855: Improvements to SpecConstr
-------------------------------------+-------------------------------------
Reporter: simonpj | Owner: (none)
Type: task | Status: new
Priority: normal | Milestone: ⊥
Component: Compiler | Version: 6.4.2
Resolution: | Keywords: SpecConstr
Operating System: Unknown/Multiple | Architecture:
Type of failure: Runtime | Unknown/Multiple
performance bug | Test Case: N/A
Blocked By: | Blocking:
Related Tickets: | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Changes (by sgraf):
* blocking: 915 =>
Comment:
Re: Specialising on lambdas.
To have a concrete example to work on, I here is
[https://gist.github.com/sgraf812/7b272f09c7da34073b994efd5425ccc8#file-
stream-fusion-hs stream-fusion.hs], which contains a minimal stream fusion
harness using just `singletonS`, `enumFromToS`, `sumS`, `mapS` and
`concatMapS`. There are three example functions `ex{1,2,3}` with
increasing nesting of `concatMapS` that should all reduce to the same
function `goal`. More examples can follow when we get these running.
Currently, GHC HEAD (8.5, `8529fbba309cd692bbbb0386321515d05a6ed256`)
produces
[https://gist.github.com/sgraf812/7b272f09c7da34073b994efd5425ccc8#file-
stream-fusion-head-simpl-L436 this infamous piece of Core]
([https://gist.github.com/sgraf812/7b272f09c7da34073b994efd5425ccc8#file-
stream-fusion-head-spec-L1387 -ddump-spec]) for `ex1`. The goal is to
specialise `go` for the call-pattern including a lambda
[https://gist.github.com/sgraf812/7b272f09c7da34073b994efd5425ccc8#file-
stream-fusion-head-simpl-L466-L470 here].
Before I found this ticket, I basically re-implemented part of what
simonpj did, results in
[https://github.com/sgraf812/ghc/commit/c6c9fbe1eb5ad117b5bd23e943c82ca7bc2362df
this commit]. I basically tracked `CallOcc`urrences similarly to
`ScrutOcc`s.
With this specialisation for lambdas, things currently look like
[https://gist.github.com/sgraf812/7b272f09c7da34073b994efd5425ccc8#file-
stream-fusion-lam-simpl-L435 this]. The function has been specialised
alright, but the free variables of
[https://gist.github.com/sgraf812/7b272f09c7da34073b994efd5425ccc8#file-
stream-fusion-head-simpl-L466-L470 said lambda], which includes the
constant `Step`, are passed to
[https://gist.github.com/sgraf812/7b272f09c7da34073b994efd5425ccc8#file-
stream-fusion-lam-simpl-L453-L457 the specialisation as arguments].
We want to specialise for this new `Call` pattern! However, without
`-fspec-constr-keen`, !SpecConstr will only fire when it finds a matching
`ScrutOcc`. Looking at the output of
[https://gist.github.com/sgraf812/7b272f09c7da34073b994efd5425ccc8#file-
stream-fusion-lam-spec-L1495-L1499 -ddump-spec] the corresponding
`ScrutOcc` will only become visible in the specialised RHS, but we
currently only specialise the original RHS. Even then, I imagine that in
the general case we need a simplifier run in-between to reliably detect
that we scrutinize the new parameter. But that's not actually a problem,
because we can use `GHC.Types.SPEC` to tell the compiler to specialise
without seeing an `ArgOcc`.
Still, GHC needs to see a `Call` pattern with that constant argument,
which will emerge
[https://gist.github.com/sgraf812/7b272f09c7da34073b994efd5425ccc8#file-
stream-fusion-lam-spec-L1503-L1517 here], but only after the corresponding
RULEs fired.
Here are some ideas:
1. We can query the `exprFreeVarsList`
[https://github.com/sgraf812/ghc/commit/c6c9fbe1eb5ad117b5bd23e943c82ca7bc2362df
#diff-992f9a53caac96c0e6303669d68a20e1R2163 here] and see which free
variables of the lambda have known constant value and include these in the
specialisation. This was somehow fruitless so far for this case, as the
free var for the `Yield ...` wasn't included in the `ValueEnv`. Not sure
if this is even enough to reach the fixed point in all cases.
2. Specialise specialisations (and fix anything non-terminating) (+ mini
simplifier passes) + mini RULE engine. I'm uncomfortable with that much
code duplication.
3. Include call-pattern specialisation in the Simplifier, for a radical
change. On an abstract level, this seems reasonable: Specialisation is a
more modest form of inlining with code size in mind, one that even works
for recursive functions. It could chew on stuff the inliner gave up on
because of code size requirements (even non-recursive functions).
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/855#comment:12>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list