Constructors and such should be able to move around seq# sometimes
This code
module SeqCon where
import Control.Exception (evaluate)
blah :: Int -> IO Int
blah x = (+2) <$> evaluate (x + 3)
compiled with -O2 -ddump-prep -dsuppress-coercions produces the following (and -ddump-stg doesn't change much of note):
SeqCon.blah1
:: GHC.Types.Int
-> GHC.Prim.State# GHC.Prim.RealWorld
-> (# GHC.Prim.State# GHC.Prim.RealWorld, GHC.Types.Int #)
[GblId,
Arity=2,
Caf=NoCafRefs,
Str=<L,1*U(U)><S,U>,
Unf=OtherCon []]
SeqCon.blah1
= \ (x_s1cz [Occ=Once!] :: GHC.Types.Int)
(s_s1cA [Occ=Once] :: GHC.Prim.State# GHC.Prim.RealWorld) ->
let {
sat_s1cE [Occ=Once] :: GHC.Types.Int
[LclId]
sat_s1cE
= case x_s1cz of { GHC.Types.I# x1_s1cC [Occ=Once] ->
case GHC.Prim.+# x1_s1cC 3# of sat_s1cD { __DEFAULT ->
GHC.Types.I# sat_s1cD
}
} } in
case GHC.Prim.seq#
@ GHC.Types.Int @ GHC.Prim.RealWorld sat_s1cE s_s1cA
of
{ (# ipv_s1cG [Occ=Once], ipv1_s1cH [Occ=Once!] #) ->
let {
sat_s1cL [Occ=Once] :: GHC.Types.Int
[LclId]
sat_s1cL
= case ipv1_s1cH of { GHC.Types.I# x1_s1cJ [Occ=Once] ->
case GHC.Prim.+# x1_s1cJ 2# of sat_s1cK { __DEFAULT ->
GHC.Types.I# sat_s1cK
}
} } in
(# ipv_s1cG, sat_s1cL #)
}
-- RHS size: {terms: 5, types: 3, coercions: 5, joins: 0/0}
SeqCon.blah :: GHC.Types.Int -> GHC.Types.IO GHC.Types.Int
[GblId,
Arity=2,
Caf=NoCafRefs,
Str=<L,1*U(U)><S,U>,
Unf=OtherCon []]
SeqCon.blah
= (\ (eta_B2 [Occ=Once] :: GHC.Types.Int)
(eta_B1 [Occ=Once] :: GHC.Prim.State# GHC.Prim.RealWorld) ->
SeqCon.blah1 eta_B2 eta_B1)
`cast` <Co:5>
This builds a closure to build an Int and passes it to seq#. That seems a bit wasteful, since we don't actually need the Int box. I think what we'd really like to end up with is something like
blah1 = \ (x :: Int) (s :: State# RealWorld) ->
case seq# x s of { (# s', x' #) ->
case x' of { I# x# -> (# s', I# (x# +# 5#) #) }}
Here's one vague idea: when we analyse x+3 (the argument to seq#) under a strict demand, we see it is strict in x. So we can transform seq# (x + 3) s into
case seq# x s of
(# s', x' #) -> seq# (x' + 3) s'
We know that x' is in WHNF, so we should (I think) be able to see that x' + 3 isn't bottom, so we can use
case seq# x s of {(# s', x' #) ->
case x' + 3 of {!res -> s', res}}
Side note: the redundant eta-expansion in blah is a bit surprising. blah1 already has arity 2, so I'd have expected blah to just coerce it directly.
Trac metadata
| Trac field | Value |
|---|---|
| Version | 8.2.1-rc2 |
| Type | Bug |
| TypeOfFailure | OtherFailure |
| Priority | normal |
| Resolution | Unresolved |
| Component | Compiler |
| Test case | |
| Differential revisions | |
| BlockedBy | |
| Related | |
| Blocking | |
| CC | |
| Operating system | |
| Architecture |