GHC Bug report
Simon Peyton-Jones
simonpj at microsoft.com
Fri Oct 2 03:40:22 EDT 2009
Two things to say.
First, you've said INLINE for both functions. GHC understands that as saying "replace a call to this function by the RHS that I'm writing right here". So GHC doesn't optimise them much, if at all. It waits until it sees a call, then inlines, then optimises *that*. So try calling 'firstnonspace' and see what you get.
The only bad thing is that if you write (map firstnonspace xs), then there's no visible call to firstnonspace, so the non-optimised version will get executed. I'm in the middle of fixing that, with an upheaval of the way inlining works.
Simon
From: glasgow-haskell-bugs-bounces at haskell.org [mailto:glasgow-haskell-bugs-bounces at haskell.org] On Behalf Of Jason Dagit
Sent: 02 October 2009 00:01
To: glasgow-haskell-bugs at haskell.org
Cc: Simon Marlow; Ian Lynagh
Subject: Fwd: GHC Bug report
[I just found out that there is a dedicated bugs email address so forwarding the original message there.]
Hello,
I've created a small example of the program I have at this URL with the output of -ddump-simpl:
http://hpaste.org/fastcgi/hpaste.fcgi/view?id=10109#a10109
Notice that on line 139, I would like it if the Word8 could be passed without boxing.
The full program text is here also in case the link above disappears:
\begin{code}
{-# LANGUAGE BangPatterns, MagicHash #-}
module Main where
import GHC.Word ( Word8(W8#) )
import GHC.Exts ( Int#, Int(I#), Ptr(..), Word#, Word(W#) )
import GHC.Prim ( indexWord8OffAddr#, (==#), (>=#), (+#), word2Int#, Addr# )
isSpaceWord8 :: Word8 -> Bool
isSpaceWord8 !w =
w == 0x20 || -- ' '
w == 0x09 || -- '\t'
w == 0x0A || -- '\n'
w == 0x0D -- '\r'
{-# INLINE isSpaceWord8 #-}
firstnonspace :: Ptr Word8 -> Int -> Int -> Int
firstnonspace (Ptr p) (I# n) (I# m) = I# (first p n m)
where
first :: Addr# -> Int# -> Int# -> Int#
first addr n' m'
| n' >=# m' = n'
| otherwise = if (not (isSpaceWord8 ch))
then n'
else first addr (n' +# 1#) m'
where
ch = W8# (indexWord8OffAddr# addr n')
{-# INLINE firstnonspace #-}
main = return ()
\end{code}
The output from ghc -O2 -ddump-simpl is:
\begin{core}
==================== Tidy Core ====================
Main.a :: GHC.Prim.State# GHC.Prim.RealWorld
-> (# GHC.Prim.State# GHC.Prim.RealWorld, () #)
[GlobalId]
[Arity 1
NoCafRefs
Str: DmdType L]
Main.a =
\ (s_aHK :: GHC.Prim.State# GHC.Prim.RealWorld) ->
(# s_aHK, GHC.Unit.() #)
Main.a1 :: GHC.Prim.State# GHC.Prim.RealWorld
-> (# GHC.Prim.State# GHC.Prim.RealWorld, () #)
[GlobalId]
[Arity 1
Str: DmdType L]
Main.a1 =
GHC.TopHandler.a5
@ ()
(Main.a
`cast` (sym ((GHC.IOBase.:CoIO) ())
:: GHC.Prim.State# GHC.Prim.RealWorld
-> (# GHC.Prim.State# GHC.Prim.RealWorld, () #)
~
GHC.IOBase.IO<http://GHC.IOBase.IO> ()))
Main.main :: GHC.IOBase.IO<http://GHC.IOBase.IO> ()
[GlobalId]
[Arity 1
NoCafRefs
Str: DmdType L]
Main.main =
Main.a
`cast` (sym ((GHC.IOBase.:CoIO) ())
:: GHC.Prim.State# GHC.Prim.RealWorld
-> (# GHC.Prim.State# GHC.Prim.RealWorld, () #)
~
GHC.IOBase.IO<http://GHC.IOBase.IO> ())
Main.lit :: GHC.Word.Word8
[GlobalId]
[NoCafRefs
Str: DmdType m]
Main.lit = GHC.Word.W8# __word 13
Main.lit1 :: GHC.Word.Word8
[GlobalId]
[NoCafRefs
Str: DmdType m]
Main.lit1 = GHC.Word.W8# __word 10
Main.lit2 :: GHC.Word.Word8
[GlobalId]
[NoCafRefs
Str: DmdType m]
Main.lit2 = GHC.Word.W8# __word 9
Main.lit3 :: GHC.Word.Word8
[GlobalId]
[NoCafRefs
Str: DmdType m]
Main.lit3 = GHC.Word.W8# __word 32
Main.isSpaceWord8 :: GHC.Word.Word8 -> GHC.Bool.Bool
[GlobalId]
[Arity 1
NoCafRefs
Str: DmdType U(L)]
Main.isSpaceWord8 =
__inline_me (\ (w_ap1 :: GHC.Word.Word8) ->
GHC.Classes.||
(GHC.Word.==2 w_ap1 Main.lit3)
(GHC.Classes.||
(GHC.Word.==2 w_ap1 Main.lit2)
(GHC.Classes.||
(GHC.Word.==2 w_ap1 Main.lit1) (GHC.Word.==2 w_ap1 Main.lit))))
Main.firstnonspace :: GHC.Ptr.Ptr GHC.Word.Word8
-> GHC.Types.Int<http://GHC.Types.Int>
-> GHC.Types.Int<http://GHC.Types.Int>
-> GHC.Types.Int<http://GHC.Types.Int>
[GlobalId]
[Arity 3
NoCafRefs
Str: DmdType U(L)U(L)U(L)m]
Main.firstnonspace =
__inline_me (\ (ds_dGa :: GHC.Ptr.Ptr GHC.Word.Word8)
(ds1_dGb :: GHC.Types.Int<http://GHC.Types.Int>)
(ds2_dGc :: GHC.Types.Int<http://GHC.Types.Int>) ->
case ds_dGa of wild_B1 { GHC.Ptr.Ptr p_ap6 ->
case ds1_dGb of wild1_XB { GHC.Types.I# n_ap8 ->
case ds2_dGc of wild2_XG { GHC.Types.I# m_apa ->
letrec {
first_sH5 :: GHC.Prim.Addr#
-> GHC.Prim.Int#<http://GHC.Prim.Int>
-> GHC.Prim.Int#<http://GHC.Prim.Int>
-> GHC.Prim.Int#<http://GHC.Prim.Int>
[Arity 3
Str: DmdType LLL]
first_sH5 =
\ (addr_ape :: GHC.Prim.Addr#)
(n'_apg :: GHC.Prim.Int#<http://GHC.Prim.Int>)
(m'_api :: GHC.Prim.Int#<http://GHC.Prim.Int>) ->
case GHC.Prim.>=# n'_apg m'_api of wild3_XS {
GHC.Bool.False ->
case GHC.Classes.not
(Main.isSpaceWord8
(GHC.Word.W8# (GHC.Prim.indexWord8OffAddr# addr_ape n'_apg)))
of wild4_XU {
GHC.Bool.False -> first_sH5 addr_ape (GHC.Prim.+# n'_apg 1) m'_api;
GHC.Bool.True -> n'_apg
};
GHC.Bool.True -> n'_apg
}; } in
case first_sH5 p_ap6 n_ap8 m_apa of wild3_XN { __DEFAULT ->
GHC.Types.I# wild3_XN
}
}
}
})
:Main.main :: GHC.IOBase.IO<http://GHC.IOBase.IO> ()
[GlobalId]
[Arity 1
Str: DmdType L]
:Main.main =
Main.a1
`cast` (sym ((GHC.IOBase.:CoIO) ())
:: GHC.Prim.State# GHC.Prim.RealWorld
-> (# GHC.Prim.State# GHC.Prim.RealWorld, () #)
~
GHC.IOBase.IO<http://GHC.IOBase.IO> ())
==================== Tidy Core Rules ====================
\end{core}
Of note is that isSpaceWord8 is not inlined and the Word8 that it takes is strict, but it gets boxed before it is passed there creating an allocation that I would prefer to avoid.
My GHC version is 6.10.4. It may be related to this bug:
http://hackage.haskell.org/trac/ghc/ticket/3181
Thanks,
Jason
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/glasgow-haskell-bugs/attachments/20091002/abfe475d/attachment-0001.html
More information about the Glasgow-haskell-bugs
mailing list