[GHC] #16197: Strictness is not preserved under -O1

GHC ghc-devs at haskell.org
Thu Jan 17 06:36:41 UTC 2019


#16197: Strictness is not preserved under -O1
-------------------------------------+-------------------------------------
        Reporter:  alang9            |                Owner:  (none)
            Type:  bug               |               Status:  new
        Priority:  normal            |            Milestone:
       Component:  Compiler          |              Version:  8.4.1
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
 Type of failure:  Incorrect result  |  Unknown/Multiple
  at runtime                         |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:                    |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------
Changes (by akio):

 * cc: akio (added)


Comment:

 I made a smaller test case that I believe exhibits the same issue:

 {{{#!hs
 data T = T !Bool
 data Box a = Box a

 f :: Int -> T -> Box Bool
 f n t
   | n <= 0 = case t of
       T b -> Box b
   | otherwise = f (n-2) t

 f1 :: Int -> Bool -> Box Bool
 f1 n t
   | n <= 0 = f (-n) $! T t
   | otherwise = f1 (n-2) t

 g :: Int -> Bool
 g k = if k <= 0 then error "crash" else False
 {-# NOINLINE g #-}

 main :: IO ()
 main = case f1 4 (g 0) of
     Box _ -> return ()
 }}}

 With ghc-8.6.2, the above program crashes when compiled with -O0 but not
 when compiled with -O1.

 It looks like the issue has something to do with strictness analysis.
 After the first pass of the demand analyzer, `f` gets the following
 strictness signature:

 {{{
  Str=<S(S),1*U(U)><S(S),1*U(U)>m,
 }}}

 This means `f` is deeply strict in the second argument. This is correct in
 the sense that `f n (T undefined)` is undefined, but it doesn't mean `f`
 is going to deeply evaluate the second argument (it doesn't).

 However, it looks like this strong strictness signature is then used in
 the next simplifier pass to justify dropping the implicit `seq` on `t`
 (arising from the field strictness of `T`) in `f1`. This `seq` is in fact
 the only thing in the program that forces the error thunk, so dropping it
 changes the program behavior.

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


More information about the ghc-tickets mailing list