{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE BangPatterns #-} {-# LANGUAGE GHCForeignImportPrim #-} {-# LANGUAGE MagicHash #-} {-# LANGUAGE UnboxedTuples #-} {-# LANGUAGE UnliftedFFITypes #-} {-# LANGUAGE NegativeLiterals #-} {-# LANGUAGE ForeignFunctionInterface #-} -- | External BigNat backend that directly call FFI operations. -- -- This backend can be useful for specific compilers such as GHCJS or Asterius -- that replace bignat foreign calls with calls to the native platform bignat -- library (e.g. JavaScript's BigInt). You can also link an extra object -- providing the implementation. module GHC.Num.Backend.FFI where import GHC.Prim import GHC.Types import GHC.Num.WordArray import GHC.Num.Primitives import qualified GHC.Num.Backend.Native as Native import {-# SOURCE #-} GHC.Num.Natural import {-# SOURCE #-} GHC.Num.Integer default () -- | Compare two non-zero BigNat of the same length -- -- Return: -- < 0 ==> LT -- == 0 ==> EQ -- > 0 ==> GT bignat_compare :: WordArray# -> WordArray# -> Int# bignat_compare = ghc_bignat_compare foreign import ccall unsafe ghc_bignat_compare :: WordArray# -> WordArray# -> Int# -- | Add two non-zero BigNat -- -- Result is to be stored in the MutableWordArray#. -- The latter has size: max (size a, size b) + 1 -- -- The potential 0 most-significant Word (i.e. the potential carry) will be -- removed by the caller if it is not already done by the backend. bignat_add :: MutableWordArray# RealWorld -- ^ Result -> WordArray# -> WordArray# -> State# RealWorld -> State# RealWorld bignat_add mwa wa wb s = ioVoid (ghc_bignat_add mwa wa wb) s foreign import ccall unsafe ghc_bignat_add :: MutableWordArray# RealWorld -- ^ Result -> WordArray# -> WordArray# -> IO () -- | Add a non-zero BigNat and a non-zero Word# -- -- Result is to be stored in the MutableWordArray#. -- The latter has size: size a + 1 -- -- The potential 0 most-significant Word (i.e. the potential carry) will be -- removed by the caller if it is not already done by the backend. bignat_add_word :: MutableWordArray# RealWorld -- ^ Result -> WordArray# -> Word# -> State# RealWorld -> State# RealWorld bignat_add_word mwa wa b s = ioVoid (ghc_bignat_add_word mwa wa b) s foreign import ccall unsafe ghc_bignat_add_word :: MutableWordArray# RealWorld -- ^ Result -> WordArray# -> Word# -> IO () -- | Multiply a non-zero BigNat and a non-zero Word# -- -- Result is to be stored in the MutableWordArray#. -- The latter has size: size a + 1 -- -- The potential 0 most-significant Word (i.e. the potential carry) will be -- removed by the caller if it is not already done by the backend. bignat_mul_word :: MutableWordArray# RealWorld -- ^ Result -> WordArray# -> Word# -> State# RealWorld -> State# RealWorld bignat_mul_word mwa wa b s = ioVoid (ghc_bignat_mul_word mwa wa b) s foreign import ccall unsafe ghc_bignat_mul_word :: MutableWordArray# RealWorld -- ^ Result -> WordArray# -> Word# -> IO () -- | Sub two non-zero BigNat -- -- Result is to be stored in the MutableWordArray#. -- The latter has size: size a -- -- The potential 0 most-significant Words will be removed by the caller if it is -- not already done by the backend. -- -- Return False# to indicate underflow. bignat_sub :: MutableWordArray# RealWorld -> WordArray# -> WordArray# -> State# RealWorld -> (# State# RealWorld, Bool# #) bignat_sub mwa wa wb s = ioBool (ghc_bignat_sub mwa wa wb) s foreign import ccall unsafe ghc_bignat_sub :: MutableWordArray# RealWorld -- ^ Result -> WordArray# -> WordArray# -> IO Bool -- | Sub a non-zero word from a non-zero BigNat -- -- Result is to be stored in the MutableWordArray#. -- The latter has size: size a -- -- The potential 0 most-significant Words will be removed by the caller if it is -- not already done by the backend. -- -- Return False# to indicate underflow. bignat_sub_word :: MutableWordArray# RealWorld -> WordArray# -> Word# -> State# RealWorld -> (# State# RealWorld, Bool# #) bignat_sub_word mwa wa b s = ioBool (ghc_bignat_sub_word mwa wa b) s foreign import ccall unsafe ghc_bignat_sub_word :: MutableWordArray# RealWorld -- ^ Result -> WordArray# -> Word# -> IO Bool -- | Multiply two non-zero BigNat -- -- Result is to be stored in the MutableWordArray#. -- The latter has size: size a+size b -- -- The potential 0 most-significant Word (i.e. the potential carry) will be -- removed by the caller if it is not already done by the backend. bignat_mul :: MutableWordArray# RealWorld -- ^ Result -> WordArray# -> WordArray# -> State# RealWorld -> State# RealWorld bignat_mul mwa wa wb s = ioVoid (ghc_bignat_mul mwa wa wb) s foreign import ccall unsafe ghc_bignat_mul :: MutableWordArray# RealWorld -- ^ Result -> WordArray# -> WordArray# -> IO () -- | PopCount of a non-zero BigNat bignat_popcount :: WordArray# -> Word# bignat_popcount = ghc_bignat_popcount foreign import ccall unsafe ghc_bignat_popcount :: WordArray# -> Word# -- | Left-shift a non-zero BigNat by a non-zero amount of bits -- -- Result is to be stored in the MutableWordArray#. -- The latter has size: size a + required new limbs -- -- The potential 0 most-significant Word (i.e. the potential carry) will be -- removed by the caller if it is not already done by the backend. bignat_shiftl :: MutableWordArray# RealWorld -> WordArray# -> Word# -> State# RealWorld -> State# RealWorld bignat_shiftl mwa wa n s = ioVoid (ghc_bignat_shiftl mwa wa n) s foreign import ccall unsafe ghc_bignat_shiftl :: MutableWordArray# RealWorld -> WordArray# -> Word# -> IO () -- | Right-shift a non-zero BigNat by a non-zero amount of bits -- -- Result is to be stored in the MutableWordArray#. -- The latter has size: required limbs -- -- The potential 0 most-significant Word (i.e. the potential carry) will be -- removed by the caller if it is not already done by the backend. bignat_shiftr :: MutableWordArray# RealWorld -> WordArray# -> Word# -> State# RealWorld -> State# RealWorld bignat_shiftr mwa wa n s = ioVoid (ghc_bignat_shiftr mwa wa n) s foreign import ccall unsafe ghc_bignat_shiftr :: MutableWordArray# RealWorld -> WordArray# -> Word# -> IO () -- | Right-shift a non-zero BigNat by a non-zero amount of bits by first -- converting it into its two's complement representation and then again after -- the arithmetic shift. -- -- Result is to be stored in the MutableWordArray#. -- The latter has size: required limbs -- -- The potential 0 most-significant Words (i.e. the potential carry) will be -- removed by the caller if it is not already done by the backend. bignat_shiftr_neg :: MutableWordArray# RealWorld -> WordArray# -> Word# -> State# RealWorld -> State# RealWorld bignat_shiftr_neg mwa wa n s = ioVoid (ghc_bignat_shiftr_neg mwa wa n) s foreign import ccall unsafe ghc_bignat_shiftr_neg :: MutableWordArray# RealWorld -> WordArray# -> Word# -> IO () -- | OR two non-zero BigNat -- -- Result is to be stored in the MutableWordArray#. -- The latter has size: max (size a, size b) bignat_or :: MutableWordArray# RealWorld -> WordArray# -> WordArray# -> State# RealWorld -> State# RealWorld {-# INLINE bignat_or #-} bignat_or mwa wa wb s = ioVoid (ghc_bignat_or mwa wa wb) s foreign import ccall unsafe ghc_bignat_or :: MutableWordArray# RealWorld -> WordArray# -> WordArray# -> IO () -- | XOR two non-zero BigNat -- -- Result is to be stored in the MutableWordArray#. -- The latter has size: max (size a, size b) -- -- The potential 0 most-significant Words will be removed by the caller if it is -- not already done by the backend. bignat_xor :: MutableWordArray# RealWorld -> WordArray# -> WordArray# -> State# RealWorld -> State# RealWorld {-# INLINE bignat_xor #-} bignat_xor mwa wa wb s = ioVoid (ghc_bignat_xor mwa wa wb) s foreign import ccall unsafe ghc_bignat_xor :: MutableWordArray# RealWorld -> WordArray# -> WordArray# -> IO () -- | AND two non-zero BigNat -- -- Result is to be stored in the MutableWordArray#. -- The latter has size: min (size a, size b) -- -- The potential 0 most-significant Words will be removed by the caller if it is -- not already done by the backend. bignat_and :: MutableWordArray# RealWorld -> WordArray# -> WordArray# -> State# RealWorld -> State# RealWorld {-# INLINE bignat_and #-} bignat_and mwa wa wb s = ioVoid (ghc_bignat_and mwa wa wb) s foreign import ccall unsafe ghc_bignat_and :: MutableWordArray# RealWorld -> WordArray# -> WordArray# -> IO () -- | ANDNOT two non-zero BigNat -- -- Result is to be stored in the MutableWordArray#. -- The latter has size: size a -- -- The potential 0 most-significant Words will be removed by the caller if it is -- not already done by the backend. bignat_and_not :: MutableWordArray# RealWorld -> WordArray# -> WordArray# -> State# RealWorld -> State# RealWorld {-# INLINE bignat_and_not #-} bignat_and_not mwa wa wb s = ioVoid (ghc_bignat_and_not mwa wa wb) s foreign import ccall unsafe ghc_bignat_and_not :: MutableWordArray# RealWorld -> WordArray# -> WordArray# -> IO () -- | QuotRem of two non-zero BigNat -- -- Result quotient and remainder are to be stored in the MutableWordArray#. -- The first one (quotient) has size: size(A)-size(B)+1 -- The second one (remainder) has size: size(b) -- -- The potential 0 most-significant Words will be removed by the caller if it is -- not already done by the backend. bignat_quotrem :: MutableWordArray# RealWorld -- ^ Quotient -> MutableWordArray# RealWorld -- ^ Remainder -> WordArray# -> WordArray# -> State# RealWorld -> State# RealWorld bignat_quotrem mwq mwr wa wb s = ioVoid (ghc_bignat_quotrem mwq mwr wa wb) s foreign import ccall unsafe ghc_bignat_quotrem :: MutableWordArray# RealWorld -> MutableWordArray# RealWorld -> WordArray# -> WordArray# -> IO () -- | Quotient of two non-zero BigNat -- -- Result quotient is to be stored in the MutableWordArray#. -- The latter has size: size(A)-size(B)+1 -- -- The potential 0 most-significant Words will be removed by the caller if it is -- not already done by the backend. bignat_quot :: MutableWordArray# RealWorld -- ^ Quotient -> WordArray# -> WordArray# -> State# RealWorld -> State# RealWorld bignat_quot mwq wa wb s = ioVoid (ghc_bignat_quot mwq wa wb) s foreign import ccall unsafe ghc_bignat_quot :: MutableWordArray# RealWorld -> WordArray# -> WordArray# -> IO () -- | Remainder of two non-zero BigNat -- -- Result remainder is to be stored in the MutableWordArray#. -- The latter has size: size(B) -- -- The potential 0 most-significant Words will be removed by the caller if it is -- not already done by the backend. bignat_rem :: MutableWordArray# RealWorld -- ^ Quotient -> WordArray# -> WordArray# -> State# RealWorld -> State# RealWorld bignat_rem mwr wa wb s = ioVoid (ghc_bignat_rem mwr wa wb) s foreign import ccall unsafe ghc_bignat_rem :: MutableWordArray# RealWorld -> WordArray# -> WordArray# -> IO () -- | QuotRem of a non-zero BigNat and a non-zero Word -- -- Result quotient is to be stored in the MutableWordArray#. -- The latter has size: size(A) -- -- The remainder is returned. -- -- The potential 0 most-significant Words will be removed by the caller if it is -- not already done by the backend. bignat_quotrem_word :: MutableWordArray# RealWorld -- ^ Quotient -> WordArray# -> Word# -> State# RealWorld -> (# State# RealWorld, Word# #) bignat_quotrem_word mwq wa b s = ioWord# (ghc_bignat_quotrem_word mwq wa b) s foreign import ccall unsafe ghc_bignat_quotrem_word :: MutableWordArray# RealWorld -> WordArray# -> Word# -> IO Word -- | Quot of a non-zero BigNat and a non-zero Word -- -- Result quotient is to be stored in the MutableWordArray#. -- The latter has size: size(A) -- -- The potential 0 most-significant Words will be removed by the caller if it is -- not already done by the backend. bignat_quot_word :: MutableWordArray# RealWorld -- ^ Quotient -> WordArray# -> Word# -> State# RealWorld -> State# RealWorld bignat_quot_word mwq wa b s = ioVoid (ghc_bignat_quot_word mwq wa b) s foreign import ccall unsafe ghc_bignat_quot_word :: MutableWordArray# RealWorld -> WordArray# -> Word# -> IO () -- | Remainder of a non-zero BigNat and a non-zero Word -- -- The remainder is returned. bignat_rem_word :: WordArray# -> Word# -> Word# bignat_rem_word = ghc_bignat_rem_word foreign import ccall unsafe ghc_bignat_rem_word :: WordArray# -> Word# -> Word# -- | Greatest common divisor (GCD) of two non-zero and non-one BigNat -- -- Result GCD is to be stored in the MutableWordArray#. -- The latter has size: size(B) -- The first WordArray# is greater than the second WordArray#. -- -- The potential 0 most-significant Words will be removed by the caller if it is -- not already done by the backend. bignat_gcd :: MutableWordArray# RealWorld -> WordArray# -> WordArray# -> State# RealWorld -> State# RealWorld bignat_gcd mwr wa wb s = ioVoid (ghc_bignat_gcd mwr wa wb) s foreign import ccall unsafe ghc_bignat_gcd :: MutableWordArray# RealWorld -> WordArray# -> WordArray# -> IO () -- | Greatest common divisor (GCD) of a non-zero/non-one BigNat and a -- non-zero/non-one Word# -- -- Result GCD is returned bignat_gcd_word :: WordArray# -> Word# -> Word# bignat_gcd_word = ghc_bignat_gcd_word foreign import ccall unsafe ghc_bignat_gcd_word :: WordArray# -> Word# -> Word# -- | Greatest common divisor (GCD) of two Word# -- -- Result GCD is returned bignat_gcd_word_word :: Word# -> Word# -> Word# bignat_gcd_word_word = ghc_bignat_gcd_word_word foreign import ccall unsafe ghc_bignat_gcd_word_word :: Word# -> Word# -> Word# -- | Encode (# BigNat mantissa, Int# exponent #) into a Double# bignat_encode_double :: WordArray# -> Int# -> Double# bignat_encode_double = ghc_bignat_encode_double foreign import ccall unsafe ghc_bignat_encode_double :: WordArray# -> Int# -> Double# -- | \"@'bignat_powmod_word' /b/ /e/ /m/@\" computes base @/b/@ raised to -- exponent @/e/@ modulo @/m/@. -- -- b > 1 -- e > 0 -- m > 1 bignat_powmod_word :: WordArray# -> WordArray# -> Word# -> Word# bignat_powmod_word = ghc_bignat_powmod_word foreign import ccall unsafe ghc_bignat_powmod_word :: WordArray# -> WordArray# -> Word# -> Word# -- | \"@'bignat_powmod' r /b/ /e/ /m/@\" computes base @/b/@ raised to -- exponent @/e/@ modulo @/m/@. -- -- b > 1 -- e > 0 -- m > 1 -- -- Result is to be stored in the MutableWordArray# (which size is equal to the -- one of m). -- -- The potential 0 most-significant Words will be removed by the caller if it is -- not already done by the backend. bignat_powmod :: MutableWordArray# RealWorld -> WordArray# -> WordArray# -> WordArray# -> State# RealWorld -> State# RealWorld bignat_powmod r b e m s = ioVoid (ghc_bignat_powmod r b e m) s foreign import ccall unsafe ghc_bignat_powmod :: MutableWordArray# RealWorld -> WordArray# -> WordArray# -> WordArray# -> IO () -- | \"@'bignat_powmod' /b/ /e/ /m/@\" computes base @/b/@ raised to -- exponent @/e/@ modulo @/m/@. -- -- b > 1 -- e > 0 -- m > 1 bignat_powmod_words :: Word# -> Word# -> Word# -> Word# bignat_powmod_words = ghc_bignat_powmod_words foreign import ccall unsafe ghc_bignat_powmod_words :: Word# -> Word# -> Word# -> Word# -- | Return extended GCD of two non-zero integers. -- -- I.e. integer_gcde a b returns (g,x,y) so that ax + by = g -- -- Input: a and b are non zero. -- Output: g must be > 0 -- integer_gcde :: Integer -> Integer -> (# Integer, Integer, Integer #) integer_gcde = Native.integer_gcde -- for now we use Native's implementation. If some FFI backend user needs a -- specific implementation, we'll need to determine a prototype to pass and -- return BigNat signs and sizes via FFI. -- | Computes the modular inverse of two non-zero integers. -- -- I.e. y = integer_recip_mod x m -- = x^(-1) `mod` m -- -- with 0 < y < abs m integer_recip_mod :: Integer -> Natural -> (# Natural | () #) integer_recip_mod = Native.integer_recip_mod -- for now we use Native's implementation. If some FFI backend user needs a -- specific implementation, we'll need to determine a prototype to pass and -- return BigNat signs and sizes via FFI. -- | Computes the modular exponentiation. -- -- I.e. y = integer_powmod b e m -- = b^e `mod` m -- -- with 0 <= y < abs m integer_powmod :: Integer -> Natural -> Natural -> Natural integer_powmod = Native.integer_powmod -- for now we use Native's implementation. If some FFI backend user needs a -- specific implementation, we'll need to determine a prototype to pass and -- return BigNat signs and sizes via FFI.