Allocate initial 1-limb mpz_t on the Stack and introduce MPZ# type
authorHerbert Valerio Riedel <hvr@gnu.org>
Wed, 8 Jan 2014 23:19:31 +0000 (00:19 +0100)
committerHerbert Valerio Riedel <hvr@gnu.org>
Mon, 13 Jan 2014 11:42:02 +0000 (12:42 +0100)
commit7bdcadda7e884edffb1427f0685493f3a2e5c5fa
tree743544db84757dce96eea783c6e96f0bb9aa54dc
parent13b4d0cdd18471de33ba89bda11a4b238507b7c7
Allocate initial 1-limb mpz_t on the Stack and introduce MPZ# type

We now allocate a 1-limb mpz_t on the stack instead of doing a more
expensive heap-allocation (especially if the heap-allocated copy becomes
garbage right away); this addresses #8647.

In order to delay heap allocations of 1-limb `ByteArray#`s instead of
the previous `(# Int#, ByteArray# #)` pair, a 3-tuple
`(# Int#, ByteArray#, Word# #)` is returned now. This tuple is given the
type-synonym `MPZ#`.

This 3-tuple representation uses either the 1st and the 2nd element, or
the 1st and the 3rd element to represent the limb(s) (NB: undefined
`ByteArray#` elements must not be accessed as they don't point to a
proper `ByteArray#`, see also `DUMMY_BYTE_ARR`); more specifically, the
following encoding is used (where `⊥` means undefined/unused):

 -  (#  0#, ⊥, 0## #) -> value = 0
 -  (#  1#, ⊥, w   #) -> value = w
 -  (# -1#, ⊥, w   #) -> value = -w
 -  (#  s#, d, 0## #) -> value = J# s d

The `mpzToInteger` helper takes care of converting `MPZ#` into an
`Integer`, and allocating a 1-limb `ByteArray#` in case the
value (`w`/`-w`) doesn't fit the `S# Int#` representation).

The following nofib benchmarks benefit from this optimization:

        Program      Size    Allocs   Runtime   Elapsed  TotalMem
 ------------------------------------------------------------------
     bernouilli     +0.2%     -5.2%      0.12      0.12     +0.0%
         gamteb     +0.2%     -1.7%      0.03      0.03     +0.0%
          kahan     +0.3%    -13.2%      0.17      0.17     +0.0%
         mandel     +0.2%    -24.6%      0.04      0.04     +0.0%
          power     +0.2%     -2.6%     -2.0%     -2.0%     -8.3%
      primetest     +0.1%    -17.3%      0.06      0.06     +0.0%
            rsa     +0.2%    -18.5%      0.02      0.02     +0.0%
            scs     +0.1%     -2.9%     -0.1%     -0.1%     +0.0%
         sphere     +0.3%     -0.8%      0.03      0.03     +0.0%
         symalg     +0.2%     -3.1%      0.01      0.01     +0.0%
 ------------------------------------------------------------------
            Min     +0.1%    -24.6%     -4.6%     -4.6%     -8.3%
            Max     +0.3%     +0.0%     +5.9%     +5.9%     +4.5%
 Geometric Mean     +0.2%     -1.0%     +0.2%     +0.2%     -0.0%

Signed-off-by: Herbert Valerio Riedel <hvr@gnu.org>
GHC/Integer/GMP/Prim.hs
GHC/Integer/Type.lhs
cbits/gmp-wrappers.cmm