integer-gmp-0.5.1.0: GHC/Integer/GMP/Prim.hs
{-# LANGUAGE BangPatterns, CPP, MagicHash, NoImplicitPrelude, UnboxedTuples
, UnliftedFFITypes, GHCForeignImportPrim #-}
{-# OPTIONS_HADDOCK hide #-}
#include "MachDeps.h"
module GHC.Integer.GMP.Prim (
MPZ#,
cmpInteger#,
cmpIntegerInt#,
plusInteger#,
plusIntegerInt#,
minusInteger#,
minusIntegerInt#,
timesInteger#,
timesIntegerInt#,
quotRemInteger#,
quotRemIntegerWord#,
quotInteger#,
quotIntegerWord#,
remInteger#,
remIntegerWord#,
divModInteger#,
divModIntegerWord#,
divInteger#,
divIntegerWord#,
modInteger#,
modIntegerWord#,
divExactInteger#,
divExactIntegerWord#,
gcdInteger#,
gcdExtInteger#,
gcdIntegerInt#,
gcdInt#,
decodeDouble#,
int2Integer#,
integer2Int#,
word2Integer#,
integer2Word#,
andInteger#,
orInteger#,
xorInteger#,
complementInteger#,
testBitInteger#,
mul2ExpInteger#,
fdivQ2ExpInteger#,
powInteger#,
powModInteger#,
powModSecInteger#,
recipModInteger#,
nextPrimeInteger#,
testPrimeInteger#,
sizeInBaseInteger#,
importIntegerFromByteArray#,
importIntegerFromAddr#,
exportIntegerToMutableByteArray#,
exportIntegerToAddr#,
#if WORD_SIZE_IN_BITS < 64
int64ToInteger#, integerToInt64#,
word64ToInteger#, integerToWord64#,
#endif
#ifndef WORD_SIZE_IN_BITS
#error WORD_SIZE_IN_BITS not defined!!!
#endif
) where
import GHC.Prim
import GHC.Types
-- Double isn't available yet, and we shouldn't be using defaults anyway:
default ()
-- | This is represents a @mpz_t@ value in a heap-saving way.
--
-- The first tuple element, @/s/@, encodes the sign of the integer
-- @/i/@ (i.e. @signum /s/ == signum /i/@), and the number of /limbs/
-- used to represent the magnitude. If @abs /s/ > 1@, the 'ByteArray#'
-- contains @abs /s/@ limbs encoding the integer. Otherwise, if @abs
-- /s/ < 2@, the single limb is stored in the 'Word#' element instead
-- (and the 'ByteArray#' element is undefined and MUST NOT be accessed
-- as it doesn't point to a proper 'ByteArray#' but rather to an
-- unsafe-coerced 'Int' in order be polite to the GC -- see
-- @DUMMY_BYTE_ARR@ in gmp-wrappers.cmm)
--
-- 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
--
-- This representation allows to avoid temporary heap allocations
-- (-> Trac #8647) of 1-limb 'ByteArray#'s which fit into the
-- 'S#'-constructor. Moreover, this allows to delays 1-limb
-- 'ByteArray#' heap allocations, as such 1-limb `mpz_t`s can be
-- optimistically allocated on the Cmm stack and returned as a @#word@
-- in case the `mpz_t` wasn't grown beyond 1 limb by the GMP
-- operation.
--
-- See also the 'GHC.Integer.Type.mpzToInteger' function which ought
-- to be used for converting 'MPZ#'s to 'Integer's and the
-- @MP_INT_1LIMB_RETURN()@ macro in @gmp-wrappers.cmm@ which
-- constructs 'MPZ#' values in the first place for implementation
-- details.
type MPZ# = (# Int#, ByteArray#, Word# #)
-- | Returns -1,0,1 according as first argument is less than, equal to, or greater than second argument.
--
foreign import prim "integer_cmm_cmpIntegerzh" cmpInteger#
:: Int# -> ByteArray# -> Int# -> ByteArray# -> Int#
-- | Returns -1,0,1 according as first argument is less than, equal to, or greater than second argument, which
-- is an ordinary Int\#.
foreign import prim "integer_cmm_cmpIntegerIntzh" cmpIntegerInt#
:: Int# -> ByteArray# -> Int# -> Int#
-- |
--
foreign import prim "integer_cmm_plusIntegerzh" plusInteger#
:: Int# -> ByteArray# -> Int# -> ByteArray# -> MPZ#
-- | Optimized version of 'plusInteger#' for summing big-ints with small-ints
--
foreign import prim "integer_cmm_plusIntegerIntzh" plusIntegerInt#
:: Int# -> ByteArray# -> Int# -> MPZ#
-- |
--
foreign import prim "integer_cmm_minusIntegerzh" minusInteger#
:: Int# -> ByteArray# -> Int# -> ByteArray# -> MPZ#
-- | Optimized version of 'minusInteger#' for substracting small-ints from big-ints
--
foreign import prim "integer_cmm_minusIntegerIntzh" minusIntegerInt#
:: Int# -> ByteArray# -> Int# -> MPZ#
-- |
--
foreign import prim "integer_cmm_timesIntegerzh" timesInteger#
:: Int# -> ByteArray# -> Int# -> ByteArray# -> MPZ#
-- | Optimized version of 'timesInteger#' for multiplying big-ints with small-ints
--
foreign import prim "integer_cmm_timesIntegerIntzh" timesIntegerInt#
:: Int# -> ByteArray# -> Int# -> MPZ#
-- | Compute div and mod simultaneously, where div rounds towards negative
-- infinity and\ @(q,r) = divModInteger#(x,y)@ implies
-- @plusInteger# (timesInteger# q y) r = x@.
--
foreign import prim "integer_cmm_quotRemIntegerzh" quotRemInteger#
:: Int# -> ByteArray# -> Int# -> ByteArray# -> (# MPZ#, MPZ# #)
-- | Variant of 'quotRemInteger#'
--
foreign import prim "integer_cmm_quotRemIntegerWordzh" quotRemIntegerWord#
:: Int# -> ByteArray# -> Word# -> (# MPZ#, MPZ# #)
-- | Rounds towards zero.
--
foreign import prim "integer_cmm_quotIntegerzh" quotInteger#
:: Int# -> ByteArray# -> Int# -> ByteArray# -> MPZ#
-- | Rounds towards zero.
foreign import prim "integer_cmm_quotIntegerWordzh" quotIntegerWord#
:: Int# -> ByteArray# -> Word# -> MPZ#
-- | Satisfies \texttt{plusInteger\# (timesInteger\# (quotInteger\# x y) y) (remInteger\# x y) == x}.
--
foreign import prim "integer_cmm_remIntegerzh" remInteger#
:: Int# -> ByteArray# -> Int# -> ByteArray# -> MPZ#
-- | Variant of 'remInteger#'
foreign import prim "integer_cmm_remIntegerWordzh" remIntegerWord#
:: Int# -> ByteArray# -> Word# -> MPZ#
-- | Compute div and mod simultaneously, where div rounds towards negative infinity
-- and\texttt{(q,r) = divModInteger\#(x,y)} implies \texttt{plusInteger\# (timesInteger\# q y) r = x}.
--
foreign import prim "integer_cmm_divModIntegerzh" divModInteger#
:: Int# -> ByteArray# -> Int# -> ByteArray# -> (# MPZ#, MPZ# #)
foreign import prim "integer_cmm_divModIntegerWordzh" divModIntegerWord#
:: Int# -> ByteArray# -> Word# -> (# MPZ#, MPZ# #)
foreign import prim "integer_cmm_divIntegerzh" divInteger#
:: Int# -> ByteArray# -> Int# -> ByteArray# -> MPZ#
foreign import prim "integer_cmm_divIntegerWordzh" divIntegerWord#
:: Int# -> ByteArray# -> Word# -> MPZ#
foreign import prim "integer_cmm_modIntegerzh" modInteger#
:: Int# -> ByteArray# -> Int# -> ByteArray# -> MPZ#
foreign import prim "integer_cmm_modIntegerWordzh" modIntegerWord#
:: Int# -> ByteArray# -> Word# -> MPZ#
-- | Divisor is guaranteed to be a factor of dividend.
--
foreign import prim "integer_cmm_divExactIntegerzh" divExactInteger#
:: Int# -> ByteArray# -> Int# -> ByteArray# -> MPZ#
foreign import prim "integer_cmm_divExactIntegerWordzh" divExactIntegerWord#
:: Int# -> ByteArray# -> Word# -> MPZ#
-- | Greatest common divisor.
--
foreign import prim "integer_cmm_gcdIntegerzh" gcdInteger#
:: Int# -> ByteArray# -> Int# -> ByteArray# -> MPZ#
-- | Extended greatest common divisor.
--
foreign import prim "integer_cmm_gcdExtIntegerzh" gcdExtInteger#
:: Int# -> ByteArray# -> Int# -> ByteArray# -> (# MPZ#, MPZ# #)
-- | Greatest common divisor, where second argument is an ordinary {\tt Int\#}.
--
foreign import prim "integer_cmm_gcdIntegerIntzh" gcdIntegerInt#
:: Int# -> ByteArray# -> Int# -> Int#
-- |
--
foreign import prim "integer_cmm_gcdIntzh" gcdInt#
:: Int# -> Int# -> Int#
-- | Convert to arbitrary-precision integer.
-- First {\tt Int\#} in result is the exponent; second {\tt Int\#} and {\tt ByteArray\#}
-- represent an {\tt Integer\#} holding the mantissa.
--
foreign import prim "integer_cmm_decodeDoublezh" decodeDouble#
:: Double# -> (# Int#, MPZ# #)
-- |
--
-- Note: This primitive doesn't use 'MPZ#' because its purpose is to instantiate a 'J#'-value.
foreign import prim "integer_cmm_int2Integerzh" int2Integer#
:: Int# -> (# Int#, ByteArray# #)
-- |
--
-- Note: This primitive doesn't use 'MPZ#' because its purpose is to instantiate a 'J#'-value.
foreign import prim "integer_cmm_word2Integerzh" word2Integer#
:: Word# -> (# Int#, ByteArray# #)
-- |
--
foreign import prim "integer_cmm_andIntegerzh" andInteger#
:: Int# -> ByteArray# -> Int# -> ByteArray# -> MPZ#
-- |
--
foreign import prim "integer_cmm_orIntegerzh" orInteger#
:: Int# -> ByteArray# -> Int# -> ByteArray# -> MPZ#
-- |
--
foreign import prim "integer_cmm_xorIntegerzh" xorInteger#
:: Int# -> ByteArray# -> Int# -> ByteArray# -> MPZ#
-- |
--
foreign import prim "integer_cmm_testBitIntegerzh" testBitInteger#
:: Int# -> ByteArray# -> Int# -> Int#
-- |
--
foreign import prim "integer_cmm_mul2ExpIntegerzh" mul2ExpInteger#
:: Int# -> ByteArray# -> Int# -> MPZ#
-- |
--
foreign import prim "integer_cmm_fdivQ2ExpIntegerzh" fdivQ2ExpInteger#
:: Int# -> ByteArray# -> Int# -> MPZ#
-- |
--
foreign import prim "integer_cmm_powIntegerzh" powInteger#
:: Int# -> ByteArray# -> Word# -> MPZ#
-- |
--
foreign import prim "integer_cmm_powModIntegerzh" powModInteger#
:: Int# -> ByteArray# -> Int# -> ByteArray# -> Int# -> ByteArray# -> MPZ#
-- |
--
foreign import prim "integer_cmm_powModSecIntegerzh" powModSecInteger#
:: Int# -> ByteArray# -> Int# -> ByteArray# -> Int# -> ByteArray# -> MPZ#
-- |
--
foreign import prim "integer_cmm_recipModIntegerzh" recipModInteger#
:: Int# -> ByteArray# -> Int# -> ByteArray# -> MPZ#
-- |
--
foreign import prim "integer_cmm_nextPrimeIntegerzh" nextPrimeInteger#
:: Int# -> ByteArray# -> MPZ#
-- |
--
foreign import prim "integer_cmm_testPrimeIntegerzh" testPrimeInteger#
:: Int# -> ByteArray# -> Int# -> Int#
-- |
--
foreign import prim "integer_cmm_sizeInBasezh" sizeInBaseInteger#
:: Int# -> ByteArray# -> Int# -> Word#
-- |
--
foreign import prim "integer_cmm_importIntegerFromByteArrayzh" importIntegerFromByteArray#
:: ByteArray# -> Word# -> Word# -> Int# -> MPZ#
-- |
--
foreign import prim "integer_cmm_importIntegerFromAddrzh" importIntegerFromAddr#
:: Addr# -> Word# -> Int# -> State# s -> (# State# s, MPZ# #)
-- |
--
foreign import prim "integer_cmm_exportIntegerToMutableByteArrayzh" exportIntegerToMutableByteArray#
:: Int# -> ByteArray# -> MutableByteArray# s -> Word# -> Int# -> State# s -> (# State# s, Word# #)
-- |
--
foreign import prim "integer_cmm_exportIntegerToAddrzh" exportIntegerToAddr#
:: Int# -> ByteArray# -> Addr# -> Int# -> State# s -> (# State# s, Word# #)
-- |
--
foreign import prim "integer_cmm_complementIntegerzh" complementInteger#
:: Int# -> ByteArray# -> MPZ#
#if WORD_SIZE_IN_BITS < 64
-- Note: This primitive doesn't use 'MPZ#' because its purpose is to instantiate a 'J#'-value.
foreign import prim "integer_cmm_int64ToIntegerzh" int64ToInteger#
:: Int64# -> (# Int#, ByteArray# #)
-- Note: This primitive doesn't use 'MPZ#' because its purpose is to instantiate a 'J#'-value.
foreign import prim "integer_cmm_word64ToIntegerzh" word64ToInteger#
:: Word64# -> (# Int#, ByteArray# #)
foreign import ccall unsafe "hs_integerToInt64"
integerToInt64# :: Int# -> ByteArray# -> Int64#
foreign import ccall unsafe "hs_integerToWord64"
integerToWord64# :: Int# -> ByteArray# -> Word64#
#endif
-- used to be primops:
integer2Int# :: Int# -> ByteArray# -> Int#
integer2Int# s d = if isTrue# (s ==# 0#)
then 0#
else let !v = indexIntArray# d 0# in
if isTrue# (s <# 0#)
then negateInt# v
else v
integer2Word# :: Int# -> ByteArray# -> Word#
integer2Word# s d = int2Word# (integer2Int# s d)