integer-gmp: optimise bitBigNat
authorHerbert Valerio Riedel <hvr@gnu.org>
Sat, 29 Aug 2015 10:25:45 +0000 (12:25 +0200)
committerBen Gamari <ben@smart-cactus.org>
Sat, 29 Aug 2015 11:08:18 +0000 (13:08 +0200)
This is a somewhat minor optimisation exploiting the static knowledge
of the operands involved allowing to save a few allocations.

Reviewers: austin, rwbarton, goldfire, bgamari

Reviewed By: bgamari

Subscribers: thomie

Differential Revision: https://phabricator.haskell.org/D1179

libraries/integer-gmp/src/GHC/Integer/Type.hs

index a04d9ad..fd7901a 100644 (file)
@@ -1014,8 +1014,25 @@ timesBigNatWord x@(BN# x#) y#
   where
     nx# = sizeofBigNat# x
 
+-- | Specialised version of
+--
+-- > bitBigNat = shiftLBigNat (wordToBigNat 1##)
+--
+-- avoiding a few redundant allocations
 bitBigNat :: Int# -> BigNat
-bitBigNat i# = shiftLBigNat (wordToBigNat 1##) i# -- FIXME
+bitBigNat i#
+  | isTrue# (i#  <#  0#) = zeroBigNat -- or maybe 'nullBigNat'?
+  | isTrue# (i# ==#  0#) = oneBigNat
+  | True = runS $ do
+      mbn@(MBN# mba#) <- newBigNat# (li# +# 1#)
+      -- FIXME: do we really need to zero-init MBAs returned by 'newByteArray#'?
+      -- clear all limbs (except for the most-significant limb)
+      _ <- svoid (setByteArray# mba# 0# (li# `uncheckedIShiftL#` GMP_LIMB_SHIFT#) 0#)
+      -- set single bit in most-significant limb
+      _ <- svoid (writeBigNat# mbn li# (uncheckedShiftL# 1## bi#))
+      unsafeFreezeBigNat# mbn
+  where
+    (# li#, bi# #) = quotRemInt# i# GMP_LIMB_BITS#
 
 testBitBigNat :: BigNat -> Int# -> Bool
 testBitBigNat bn i#