[GHC] #8598: IO hack in demand analyzer gets in the way of CPR
GHC
ghc-devs at haskell.org
Sat Dec 7 10:15:32 UTC 2013
#8598: IO hack in demand analyzer gets in the way of CPR
-------------------------------------+------------------------------------
Reporter: nomeata | Owner:
Type: task | Status: new
Priority: normal | Milestone:
Component: Compiler | Version: 7.6.3
Resolution: | Keywords:
Operating System: Unknown/Multiple | Architecture: Unknown/Multiple
Type of failure: None/Unknown | Difficulty: Unknown
Test Case: | Blocked By:
Blocking: | Related Tickets:
-------------------------------------+------------------------------------
Comment (by nomeata):
Also note that the current IO hack is very erratic with regard to IO
inside `unsafePerformIO` (including non-IO FFI calls): It only zaps
strictness demands if it actually sees the `IO` type. If, in the example
above, `isDoubleFinite` were not inlined, but a separate function of type
`Double -> IO Bool`, it would behave different. Very unsatisfying.
This proposal should eliminate the need for special-casing in `StrAnal`
completely, and make the analysis more precise.
We could elaborate the `DmdResult` lattice some more (and I include the
`Converges` from the nested-cpr-branch here, to show how that goes
together). Basically we want the `DmdResult` to keep track of:
* whether function may or will diverge.
* whether the function may or will exit cleanly (this is new)
* if it returns, what is the result.
So a first approximation of that would be
{{{
#!haskell
data CPR = NoCRP | RetCon Int [DmdResult]
data TriState = Yes | No | Maybe -- Maybe is top
data DmdResult = DmdResult { diverges :: TriState, exits :: TriState, cpr
:: CPR } -- Product lattice
}}}
which is easy to understand and handle, but it has some invalid states,
i.e. if it definitely exits or diverges, we do not really want a `CPR`
field, and also not both `diverges` and `exists` should be `True` at the
same time.
A format that captures it more precisely would be
{{{
#!haskell
data DmdResult
= Diverges
| Exits
| DmdResult { mayExit :: True, mayDiverge :: True, cpr :: CPR}
}}}
which neatly expresses definite convergence with `DmdResult False False
cpr`. I like that.
So the idea is now that primitive operations have their `DmdResult`
annotation manually (and I guess most of them do not exit). FFI calls
either get a conservative default of `DmdResult True True NoCPR` for
things in the `IO` monad and `DmdResult False True NoCPR` for the others.
Then in the demand analyser no special handling of IO is required any
more. Instead, in `bothDmdType`, one has to handle the `mayExit` flag of
the right argument and possibly zap strictness, just like we do already
for diverging things. And even `IO`-infested code will, as long as it does
not call anything with `mayExit = True` (e.g. numerical calculation,
working with arrays and `IORef`s), will get good strictness demands
inferred.
How does that sound? Or is it overkill adding this to the demand types,
given that (hopefully) almost everything will have `mayExit = False`?
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8598#comment:5>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list