[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