[GHC] #8662: GHC does not inline cheap inner loop when used in two places

GHC ghc-devs at haskell.org
Fri Jan 10 14:31:00 UTC 2014


#8662: GHC does not inline cheap inner loop when used in two places
------------------------------+--------------------------------------------
       Reporter:  nh2         |             Owner:
           Type:  bug         |            Status:  new
       Priority:  normal      |         Milestone:
      Component:  Compiler    |           Version:  7.6.3
       Keywords:              |  Operating System:  Unknown/Multiple
   Architecture:              |   Type of failure:  Runtime performance bug
  Unknown/Multiple            |         Test Case:
     Difficulty:  Unknown     |          Blocking:
     Blocked By:              |
Related Tickets:              |
------------------------------+--------------------------------------------
 When I made a Criterion benchmark of Neil Michell's "Tight Inner Loop"
 blog post (http://neilmitchell.blogspot.co.uk/2014/01/optimising-haskell-
 for-tight-inner-loop.html), I noticed that GHC 7.6.3 will not inline the
 performance-critical function when it's called from two different places
 (inside the same module).

 {{{
 break0_2pleaseinline :: (Char -> Bool) -> ByteString0 -> (ByteString,
 ByteString0)
 break0_2pleaseinline f (BS0 bs) = (BS.unsafeTake i bs, BS0 $ BS.unsafeDrop
 i bs)
     where
         i = Internal.inlinePerformIO $ BS.unsafeUseAsCString bs $ \ptr ->
 do
             let start = castPtr ptr :: Ptr Word8
             let end = go start
             return $! Ptr end `minusPtr` start

         go s@(Ptr a) | c == '\0' || f c = a
                      | otherwise = go $ inc s
             where c = chr s

 versionInl1 :: ByteString0 -> (ByteString, ByteString0)
 versionInl1 str = break0_2pleaseinline test str
   where
     test x = x <= '$' && (x == ' ' || x == '\r' || x == '\n' || x == '$')

 versionInl2 :: ByteString0 -> (ByteString, ByteString0)
 versionInl2 str = break0_2pleaseinline test str
   where
     test x = x <= '$' && (x == ' ' || x == '\r' || x == '\n' || x == '$')
 }}}

 Full code here: https://github.com/nh2/inner-loop-
 benchmarks/blob/6715d1e9946d6b5e6d9bb53203982ed3d2ed32ff/Bench.hs#L166.

 {{{break0_2pleaseinline}}} does not get inlined, which makes
 {{{versionInl1}}} and {{{versionInl2}}} over 4 times slower than when
 inlined. The inlining doens't happen, not even with {{{-O2}}} and
 {{{-O3}}}, only an {{{INLINE}}} pragma will move GHC to do it.

 If I was a compiler, I would so inline that function!

 I am surprised that GHC doesn't decide to do so.

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/8662>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list