Skip to content

state hack-related regression

Consider the following program exp.hs:

import Control.Monad
import Debug.Trace

expensive :: String -> String
expensive x = trace "$$$" x
{-# NOINLINE expensive #-}

main :: IO ()
main = do
  str <- fmap expensive getLine
  replicateM_ 3 $ print str

When run as echo hi | ./exp, it might print either

$$$
"hi"
"hi"
"hi"

or

$$$
"hi"
$$$
"hi"
$$$
"hi"

depending on the compiler version and optimization settings.

In 7.8.4, building with -O2 produces the second (bad) output, while building with -O2 -fno-state-hack produces the first output, not surprisingly.

However in 7.10.1 and in HEAD both -O2 and -O2 -fno-state-hack produce the second output.

It seems this difference in behavior between 7.8.4 and 7.10.1 may be due to the following difference in the unfolding for IO's fmap. In 7.8.4

ba867929df0910f70431843781ad014d
  $fFunctorIO2 :: (a -> b)
                  -> GHC.Types.IO a
                  -> GHC.Prim.State# GHC.Prim.RealWorld
                  -> (# GHC.Prim.State# GHC.Prim.RealWorld, b #)
    {- Arity: 3, HasNoCafRefs,
       Strictness: <L,1*C1(U)><C(S),1*C1(U(U,U))><L,U>,
       Unfolding: (\ @ a
                     @ b
                     f :: a -> b
                     x :: GHC.Types.IO a
                     s :: GHC.Prim.State# GHC.Prim.RealWorld ->
                   case x `cast` (GHC.Types.NTCo:IO[0] <a>_R)
                          s of ds { (#,#) ipv ipv1 ->
                   (# ipv, f ipv1 #) }) -}

while in 7.10.1

d645bee15151bb50f2bad5912d533b38
  $fFunctorIO2 ::
    (a -> b) -> IO a -> State# RealWorld -> (# State# RealWorld, b #)
  {- Arity: 3, HasNoCafRefs,
     Strictness: <L,1*C1(U)><C(S),1*C1(U(U,U))><L,U>,
     Unfolding: InlineRule (3, True, False)
                (\ @ a @ b f :: a -> b x :: IO a s :: State# RealWorld[OneShot] ->
--                                                                     ^^^^^^^
                 case x `cast` (NTCo:IO[0] <a>_R) s of ds { (#,#) ipv ipv1 ->
                 (# ipv, f ipv1 #) }) -}

I didn't completely confirm this, though, nor determine how that difference arose in the first place (I assume the libraries were built with -O2 for both versions?)

Trac metadata
Trac field Value
Version 7.10.1
Type Bug
TypeOfFailure OtherFailure
Priority normal
Resolution Unresolved
Component Compiler
Test case
Differential revisions
BlockedBy
Related
Blocking
CC
Operating system
Architecture
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information