[GHC] #15327: Optimize remainders by powers of two for Integer and Natural

GHC ghc-devs at haskell.org
Sat Jun 30 20:46:23 UTC 2018


#15327: Optimize remainders by powers of two for Integer and Natural
-------------------------------------+-------------------------------------
           Reporter:  Bodigrim       |             Owner:  (none)
               Type:  feature        |            Status:  new
  request                            |
           Priority:  normal         |         Milestone:  8.6.1
          Component:  Core           |           Version:  8.4.3
  Libraries                          |
           Keywords:                 |  Operating System:  Unknown/Multiple
       Architecture:                 |   Type of failure:  None/Unknown
  Unknown/Multiple                   |
          Test Case:                 |        Blocked By:
           Blocking:                 |   Related Tickets:  #14437
Differential Rev(s):                 |         Wiki Page:
-------------------------------------+-------------------------------------
 It appears that GHC does not optimise `even (n :: Integer)` to a bitwise
 check, as it does for `Int` and `Word` (#14437). Here is a benchmark:

 {{{#!hs
 import Data.Time.Clock

 evenRem :: Integer -> Bool
 evenRem n = fromIntegral n `rem` 2 == (0 :: Word)

 lim :: Integer
 lim = 100000000

 main :: IO ()
 main = do
   t0 <- getCurrentTime
   print $ maximum $ filter even [1..lim]
   t1 <- getCurrentTime
   putStrLn "even"
   print $ diffUTCTime t1 t0

   t0 <- getCurrentTime
   print $ maximum $ filter evenRem [1..lim]
   t1 <- getCurrentTime
   putStrLn "evenRem"
   print $ diffUTCTime t1 t0
 }}}

 {{{
 $ ghc -O2 Even.hs
 [1 of 1] Compiling Main             ( Even.hs, Even.o )
 Linking Even ...
 $ ./Even
 100000000
 even
 6.367393s
 100000000
 evenRem
 4.35664s
 }}}

 The reason is that `even (n :: Integer)` results in `remInteger` call in
 CMM, which remains unoptimized.

 One possible solution is to add a special case of divisor 2 to
 `GHC.Integer.Type.remInteger`. Or perhaps even something like

 {{{#!hs
 remInteger n (S# d#)
   | isPowerOfTwo (I# d#) = fromIntegral (fromIntegral n `rem` I# d#)

 isPowerOfTwo :: Int -> Bool
 isPowerOfTwo d = d /= 0 && d .&. (complement d + 1) == d
 }}}

 Since `remInteger` is not inlined during Core pipeline, such
 implementation of `even` will pattern-match in runtime, which is a bit
 suboptimal. On my machine it benchmarks halfway between `even` and
 `evenRem` above.

 Alternative approach is to add new rules to
 `PrelRules.builtinIntegerRules` to avoid any possible runtime slowdown. Is
 is appropriate?

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


More information about the ghc-tickets mailing list