diff options
author | Simon Peyton Jones <simonpj@microsoft.com> | 2014-01-03 16:13:19 +0000 |
---|---|---|
committer | Simon Peyton Jones <simonpj@microsoft.com> | 2014-01-03 16:13:19 +0000 |
commit | fc8e15b8aca01608c79a42021c7b1efb878e680d (patch) | |
tree | 9eba7714553b8cdd51400fafeef9261f9d05c346 /libraries/integer-gmp/GHC | |
parent | ce3ff03b159c0590d9c6ba7065496e524ae215a5 (diff) | |
download | haskell-fc8e15b8aca01608c79a42021c7b1efb878e680d.tar.gz |
Refactor and comment the smartJ# changes (re Trac #8638)
Diffstat (limited to 'libraries/integer-gmp/GHC')
-rw-r--r-- | libraries/integer-gmp/GHC/Integer/Type.lhs | 50 |
1 files changed, 41 insertions, 9 deletions
diff --git a/libraries/integer-gmp/GHC/Integer/Type.lhs b/libraries/integer-gmp/GHC/Integer/Type.lhs index c206462ead..77d529a572 100644 --- a/libraries/integer-gmp/GHC/Integer/Type.lhs +++ b/libraries/integer-gmp/GHC/Integer/Type.lhs @@ -152,21 +152,52 @@ toBig i@(J# _ _) = i -- | Demote 'J#' to 'S#' if possible. See also 'smartJ#'. toSmall :: Integer -> Integer -toSmall i@(S# _) = i -toSmall (J# 0# _) = S# 0# -toSmall (J# 1# mb#) | isTrue# (v ># 0#) = S# v +toSmall i@(S# _) = i +toSmall (J# s# mb#) = smartJ# s# mb# + + +-- | Smart 'J#' constructor which tries to construct 'S#' if possible +smartJ# :: Int# -> ByteArray# -> Integer +smartJ# 0# _ = S# 0# +smartJ# 1# mb# | isTrue# (v ># 0#) = S# v where v = indexIntArray# mb# 0# -toSmall (J# -1# mb#) | isTrue# (v <# 0#) = S# v +smartJ# (-1#) mb# | isTrue# (v <# 0#) = S# v where v = negateInt# (indexIntArray# mb# 0#) -toSmall i = i - --- | Smart 'J#' constructor which tries to construct 'S#' if possible -smartJ# :: Int# -> ByteArray# -> Integer -smartJ# s# mb# = toSmall (J# s# mb#) +smartJ# s# mb# = J# s# mb# \end{code} +Note [Use S# if possible] +~~~~~~~~~~~~~~~~~~~~~~~~~ +It's a big win to use S#, rather than J#, whenever possible. Not only +does it take less space, but (probably more important) subsequent +operations are more efficient. See Trac #8638. + +'smartJ#' is the smart constructor for J# that performs the necessary +tests. When returning a nested result, we always use smartJ# strictly, +thus + let !r = smartJ# a b in (# r, somthing_else #) +to avoid creating a thunk that is subsequently evaluated to a J#. +smartJ# itself does a pretty small amount of work, so it's not worth +thunking it. + +We call 'smartJ#' in places like quotRemInteger where a big input +might produce a small output. + +Just using smartJ# in this way has good results: + + Program Size Allocs Runtime Elapsed TotalMem +-------------------------------------------------------------------------------- + gamteb +0.1% -19.0% 0.03 0.03 +0.0% + kahan +0.2% -1.2% 0.17 0.17 +0.0% + mandel +0.1% -7.7% 0.05 0.05 +0.0% + power +0.1% -40.8% -32.5% -32.5% +0.0% + symalg +0.2% -0.5% 0.01 0.01 +0.0% +-------------------------------------------------------------------------------- + Min +0.0% -40.8% -32.5% -32.5% -5.1% + Max +0.2% +0.1% +2.0% +2.0% +0.0% + Geometric Mean +0.1% -1.0% -2.5% -2.5% -0.1% %********************************************************* %* * @@ -200,6 +231,7 @@ quotRemInteger (J# s1 d1) (J# s2 d2) (# s3, d3, s4, d4 #) -> let !q = smartJ# s3 d3 !r = smartJ# s4 d4 in (# q, r #) + -- See Note [Use S# if possible] {-# NOINLINE divModInteger #-} divModInteger :: Integer -> Integer -> (# Integer, Integer #) |