[GHC] #8598: IO hack in demand analyzer gets in the way of CPR

GHC ghc-devs at haskell.org
Fri Dec 6 14:40:09 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):

 Mail from SPJ:

 Well spotted.  I'm on a train, hence email response.  Maybe you can paste
 this into the ticket?

 There are two different issues here.

 '''First''', `isDoubleFinite` is declared as non-side-effecting:
 {{{
 foreign import ccall unsafe "isDoubleFinite" isDoubleFinite :: Double ->
 Int
 }}}
 But (as you can see from the code you give) we currently desugar it into
 something that looks (to Core) as though it might have a side effect, or
 raise a (synchronous) exception.  That is stupid.

 How might we fix that?  I can think of two ways.
  * Generate a `FCallId` whose type is `Double -> Int` rather than (as now)
 `Double -> IO Int`.  There would be a few knock-on consequences to make
 sure they were correctly code-generated.  I like this path best, because
 it reflects the truth.

  * Currently
 {{{
 IO a = State# RealWorld# -> (# State# RealWorld#, a #)
 }}}
   For these non-side-effecting things we could instead generate a
 `FCallId` with a type involving `SafeIO` instead of `IO`:
 {{{
 SafeIO a = State# SafeWorld# -> (# State# SafeWorld#, a #)
 }}}
   The different "world token" would express the idea that the function
 can't throw an exception.

   I don't like this as much, but it might in any case be useful for things
 that ''do'' have side effects but ''don't'' throw exceptions.

 My preference is for the first.

 '''Second''', as you point out, consider
 {{{
    f x = do { when (x>3) exit
             ; return (True, False) }
 }}}
 Function `f` might throw an exception or exit rather than returning, but
 ''if it does return'' it will certainly have the CPR property.  So yes,
 CPR-ness is quite safe.

 It's not quite so obvious for divergence:
 {{{
    g x = do { when (x>3) exit
             ; g x }

    h 0 y = y
    h x y = g x
 }}}
 Is `h` strict in `y`?  You might say (reasonably) that we can ignore the
 possible IO exception/exit in `g` when figuring out that `g` is sure to
 diverge. If so, we'd say that `h` is strict in `y`.  But if `(x>3)` then
 really `y` is not evaluated... and spotting that is exactly what the IO
 hack in the demand analyser is spotting.  So I think it is ''not'' safe to
 propagate divergence information.

 In short, CPR info yes, guaranteed-divergence no.

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8598#comment:2>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list