[GHC] #13692: Constructors and such should be able to move around seq# sometimes
GHC
ghc-devs at haskell.org
Sat May 13 19:54:52 UTC 2017
#13692: Constructors and such should be able to move around seq# sometimes
-------------------------------------+-------------------------------------
Reporter: dfeuer | Owner: (none)
Type: bug | Status: new
Priority: normal | Milestone: 8.4.1
Component: Compiler | Version: 8.2.1-rc2
Keywords: | Operating System: Unknown/Multiple
Architecture: | Type of failure: Runtime
Unknown/Multiple | performance bug
Test Case: | Blocked By:
Blocking: | Related Tickets:
Differential Rev(s): | Wiki Page:
-------------------------------------+-------------------------------------
This code
{{{#!hs
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
{{{#!hs
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
{{{#!hs
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
{{{#!hs
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.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/13692>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list