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: [email protected] 
[mailto:[email protected]] On Behalf Of Jason Dagit
Sent: 02 October 2009 00:01
To: [email protected]
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
_______________________________________________
Glasgow-haskell-bugs mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs

Reply via email to