summaryrefslogtreecommitdiff
path: root/libraries/ghc-bignum/src/GHC/Num
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/ghc-bignum/src/GHC/Num')
-rw-r--r--libraries/ghc-bignum/src/GHC/Num/BigNat.hs38
-rw-r--r--libraries/ghc-bignum/src/GHC/Num/BigNat/Check.hs43
-rw-r--r--libraries/ghc-bignum/src/GHC/Num/Integer.hs6
-rw-r--r--libraries/ghc-bignum/src/GHC/Num/Natural.hs14
-rw-r--r--libraries/ghc-bignum/src/GHC/Num/Primitives.hs63
5 files changed, 111 insertions, 53 deletions
diff --git a/libraries/ghc-bignum/src/GHC/Num/BigNat.hs b/libraries/ghc-bignum/src/GHC/Num/BigNat.hs
index 156a76d9ed..cf08320a11 100644
--- a/libraries/ghc-bignum/src/GHC/Num/BigNat.hs
+++ b/libraries/ghc-bignum/src/GHC/Num/BigNat.hs
@@ -101,6 +101,11 @@ bigNatOne :: Void# -> BigNat -- cf Note [Why Void#?]
bigNatOne _ = case bigNatOneW of
BigNatW w -> w
+raiseDivZero_BigNat :: Void# -> BigNat
+raiseDivZero_BigNat _ = case raiseDivZero of
+ !_ -> bigNatZero void#
+ -- see Note [ghc-bignum exceptions] in GHC.Num.Primitives
+
-- | Indicate if a bigNat is zero
bigNatIsZero :: BigNat -> Bool
bigNatIsZero bn = isTrue# (bigNatIsZero# bn)
@@ -486,7 +491,10 @@ bigNatSubUnsafe a b
in withNewWordArrayTrimed# szA \mwa s->
case inline bignat_sub mwa a b s of
(# s', 0# #) -> s'
- (# s', _ #) -> case underflow of _ -> s'
+ (# s', _ #) -> case raiseUnderflow of
+ !_ -> s'
+ -- see Note [ghc-bignum exceptions] in
+ -- GHC.Num.Primitives
-- | Subtract two BigNat
bigNatSub :: BigNat -> BigNat -> (# () | BigNat #)
@@ -511,7 +519,7 @@ bigNatSub a b
bigNatQuotWord# :: BigNat -> Word# -> BigNat
bigNatQuotWord# a b
| 1## <- b = a
- | 0## <- b = case divByZero of _ -> bigNatZero void#
+ | 0## <- b = raiseDivZero_BigNat void#
| True =
let
sz = wordArraySize# a
@@ -531,7 +539,7 @@ bigNatQuotWord a (W# b) = bigNatQuotWord# a b
-- b /= 0
bigNatRemWord# :: BigNat -> Word# -> Word#
bigNatRemWord# a b
- | 0## <- b = case divByZero of _ -> 0##
+ | 0## <- b = raiseDivZero_Word# void#
| 1## <- b = 0##
| bigNatIsZero a = 0##
| True = inline bignat_rem_word a b
@@ -549,7 +557,9 @@ bigNatRemWord a (W# b) = W# (bigNatRemWord# a b)
-- b /= 0
bigNatQuotRemWord# :: BigNat -> Word# -> (# BigNat, Word# #)
bigNatQuotRemWord# a b
- | 0## <- b = case divByZero of _ -> (# bigNatZero void#, 0## #)
+ | 0## <- b = case raiseDivZero of
+ !_ -> (# bigNatZero void#, 0## #)
+ -- see Note [ghc-bignum exceptions] in GHC.Num.Primitives
| 1## <- b = (# a, 0## #)
| isTrue# (bigNatSize# a ==# 1#)
, a0 <- indexWordArray# a 0#
@@ -575,7 +585,9 @@ bigNatQuotRemWord# a b
-- | BigNat division returning (quotient,remainder)
bigNatQuotRem# :: BigNat -> BigNat -> (# BigNat,BigNat #)
bigNatQuotRem# a b
- | bigNatIsZero b = case divByZero of _ -> (# bigNatZero void#, bigNatZero void# #)
+ | bigNatIsZero b = case raiseDivZero of
+ !_ -> (# bigNatZero void#, bigNatZero void# #)
+ -- see Note [ghc-bignum exceptions] in GHC.Num.Primitives
| bigNatIsZero a = (# bigNatZero void#, bigNatZero void# #)
| bigNatIsOne b = (# a , bigNatZero void# #)
| LT <- cmp = (# bigNatZero void#, a #)
@@ -596,7 +608,7 @@ bigNatQuotRem# a b
-- | BigNat division returning quotient
bigNatQuot :: BigNat -> BigNat -> BigNat
bigNatQuot a b
- | bigNatIsZero b = case divByZero of _ -> bigNatZero void#
+ | bigNatIsZero b = raiseDivZero_BigNat void#
| bigNatIsZero a = bigNatZero void#
| bigNatIsOne b = a
| LT <- cmp = bigNatZero void#
@@ -613,7 +625,7 @@ bigNatQuot a b
-- | BigNat division returning remainder
bigNatRem :: BigNat -> BigNat -> BigNat
bigNatRem a b
- | bigNatIsZero b = case divByZero of _ -> bigNatZero void#
+ | bigNatIsZero b = raiseDivZero_BigNat void#
| bigNatIsZero a = bigNatZero void#
| bigNatIsOne b = bigNatZero void#
| LT <- cmp = a
@@ -1036,7 +1048,7 @@ bigNatLog2 a = W# (bigNatLog2# a)
bigNatLogBase# :: BigNat -> BigNat -> Word#
bigNatLogBase# base a
| bigNatIsZero base || bigNatIsOne base
- = case unexpectedValue of _ -> 0##
+ = unexpectedValue_Word# void#
| 1# <- bigNatSize# base
, 2## <- bigNatIndex# base 0#
@@ -1062,8 +1074,8 @@ bigNatLogBase base a = W# (bigNatLogBase# base a)
-- | Logarithm for an arbitrary base
bigNatLogBaseWord# :: Word# -> BigNat -> Word#
bigNatLogBaseWord# base a
- | 0## <- base = case unexpectedValue of _ -> 0##
- | 1## <- base = case unexpectedValue of _ -> 0##
+ | 0## <- base = unexpectedValue_Word# void#
+ | 1## <- base = unexpectedValue_Word# void#
| 2## <- base = bigNatLog2# a
-- TODO: optimize log base power of 2 (256, etc.)
| True = bigNatLogBase# (bigNatFromWord# base) a
@@ -1082,7 +1094,7 @@ bigNatLogBaseWord (W# base) a = W# (bigNatLogBaseWord# base a)
bigNatSizeInBase# :: Word# -> BigNat -> Word#
bigNatSizeInBase# base a
| isTrue# (base `leWord#` 1##)
- = case unexpectedValue of _ -> 0##
+ = unexpectedValue_Word# void#
| bigNatIsZero a
= 0##
@@ -1111,7 +1123,7 @@ powModWord# = bignat_powmod_words
-- | \"@'bigNatPowModWord#' /b/ /e/ /m/@\" computes base @/b/@ raised to
-- exponent @/e/@ modulo @/m/@.
bigNatPowModWord# :: BigNat -> BigNat -> Word# -> Word#
-bigNatPowModWord# !_ !_ 0## = case divByZero of _ -> 0##
+bigNatPowModWord# !_ !_ 0## = raiseDivZero_Word# void#
bigNatPowModWord# _ _ 1## = 0##
bigNatPowModWord# b e m
| bigNatIsZero e = 1##
@@ -1125,7 +1137,7 @@ bigNatPowMod :: BigNat -> BigNat -> BigNat -> BigNat
bigNatPowMod !b !e !m
| (# m' | #) <- bigNatToWordMaybe# m
= bigNatFromWord# (bigNatPowModWord# b e m')
- | bigNatIsZero m = case divByZero of _ -> bigNatZero void#
+ | bigNatIsZero m = raiseDivZero_BigNat void#
| bigNatIsOne m = bigNatFromWord# 0##
| bigNatIsZero e = bigNatFromWord# 1##
| bigNatIsZero b = bigNatFromWord# 0##
diff --git a/libraries/ghc-bignum/src/GHC/Num/BigNat/Check.hs b/libraries/ghc-bignum/src/GHC/Num/BigNat/Check.hs
index aad7d903ff..011330cf5e 100644
--- a/libraries/ghc-bignum/src/GHC/Num/BigNat/Check.hs
+++ b/libraries/ghc-bignum/src/GHC/Num/BigNat/Check.hs
@@ -8,7 +8,6 @@
{-# LANGUAGE NegativeLiterals #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# OPTIONS_GHC -Wno-name-shadowing #-}
-{-# OPTIONS_GHC -ddump-simpl -ddump-to-file #-}
-- | Check Native implementation against another backend
module GHC.Num.BigNat.Check where
@@ -43,7 +42,7 @@ bignat_compare a b =
gr = Other.bignat_compare a b
nr = Native.bignat_compare a b
in case gr ==# nr of
- 0# -> case unexpectedValue of I# x -> x
+ 0# -> unexpectedValue_Int# void#
_ -> gr
mwaCompare
@@ -81,7 +80,10 @@ mwaCompareOp mwa f g s =
case mwaTrimZeroes# mwa s of { s ->
case mwaTrimZeroes# mwb s of { s ->
case mwaCompare mwa mwb s of
- (# s, 0# #) -> case unexpectedValue of _ -> s
+ (# s, 0# #) -> case unexpectedValue of
+ !_ -> s
+ -- see Note [ghc-bignum exceptions] in
+ -- GHC.Num.Primitives
(# s, _ #) -> s
}}}}}}
@@ -106,7 +108,9 @@ mwaCompareOp2 mwa mwb f g s =
case mwaCompare mwa mwa' s of { (# s, ba #) ->
case mwaCompare mwb mwb' s of { (# s, bb #) ->
case ba &&# bb of
- 0# -> case unexpectedValue of _ -> s
+ 0# -> case unexpectedValue of
+ !_ -> s
+ -- see Note [ghc-bignum exceptions] in GHC.Num.Primitives
_ -> s
}}}}}}}}}}}}
@@ -122,13 +126,18 @@ mwaCompareOpBool mwa f g s =
case f mwa s of { (# s, ra #) ->
case g mwb s of { (# s, rb #) ->
case ra ==# rb of
- 0# -> case unexpectedValue of _ -> (# s, ra #)
+ 0# -> case unexpectedValue of
+ !_ -> (# s, ra #)
+ -- see Note [ghc-bignum exceptions] in GHC.Num.Primitives
_ -> case (ra ==# 1#) of -- don't compare MWAs if overflow signaled!
1# -> (# s, ra #)
_ -> case mwaTrimZeroes# mwa s of { s ->
case mwaTrimZeroes# mwb s of { s ->
case mwaCompare mwa mwb s of
- (# s, 0# #) -> case unexpectedValue of _ -> (# s, ra #)
+ (# s, 0# #) -> case unexpectedValue of
+ !_ -> (# s, ra #)
+ -- see Note [ghc-bignum exceptions] in
+ -- GHC.Num.Primitives
_ -> (# s, ra #)
}}}}}}
@@ -147,7 +156,9 @@ mwaCompareOpWord mwa f g s =
case mwaTrimZeroes# mwb s of { s ->
case mwaCompare mwa mwb s of
(# s, b #) -> case b &&# (ra `eqWord#` rb) of
- 0# -> case unexpectedValue of _ -> (# s, ra #)
+ 0# -> case unexpectedValue of
+ !_ -> (# s, ra #)
+ -- see Note [ghc-bignum exceptions] in GHC.Num.Primitives
_ -> (# s, ra #)
}}}}}}
@@ -369,8 +380,7 @@ bignat_rem_word wa b =
nr = Native.bignat_rem_word wa b
in case gr `eqWord#` nr of
1# -> gr
- _ -> case unexpectedValue of
- W# e -> e
+ _ -> unexpectedValue_Word# void#
bignat_gcd
:: MutableWordArray# RealWorld
@@ -393,8 +403,7 @@ bignat_gcd_word wa b =
nr = Native.bignat_gcd_word wa b
in case gr `eqWord#` nr of
1# -> gr
- _ -> case unexpectedValue of
- W# e -> e
+ _ -> unexpectedValue_Word# void#
bignat_gcd_word_word
:: Word#
@@ -406,8 +415,7 @@ bignat_gcd_word_word a b =
nr = Native.bignat_gcd_word_word a b
in case gr `eqWord#` nr of
1# -> gr
- _ -> case unexpectedValue of
- W# e -> e
+ _ -> unexpectedValue_Word# void#
bignat_encode_double :: WordArray# -> Int# -> Double#
bignat_encode_double a e =
@@ -417,7 +425,8 @@ bignat_encode_double a e =
in case gr ==## nr of
1# -> gr
_ -> case unexpectedValue of
- _ -> gr
+ !_ -> 0.0##
+ -- see Note [ghc-bignum exceptions] in GHC.Num.Primitives
bignat_powmod_word :: WordArray# -> WordArray# -> Word# -> Word#
bignat_powmod_word b e m =
@@ -426,8 +435,7 @@ bignat_powmod_word b e m =
nr = Native.bignat_powmod_word b e m
in case gr `eqWord#` nr of
1# -> gr
- _ -> case unexpectedValue of
- W# e -> e
+ _ -> unexpectedValue_Word# void#
bignat_powmod
:: MutableWordArray# RealWorld
@@ -452,5 +460,4 @@ bignat_powmod_words b e m =
nr = Native.bignat_powmod_words b e m
in case gr `eqWord#` nr of
1# -> gr
- _ -> case unexpectedValue of
- W# e -> e
+ _ -> unexpectedValue_Word# void#
diff --git a/libraries/ghc-bignum/src/GHC/Num/Integer.hs b/libraries/ghc-bignum/src/GHC/Num/Integer.hs
index e9e38c9afd..82c109c5f7 100644
--- a/libraries/ghc-bignum/src/GHC/Num/Integer.hs
+++ b/libraries/ghc-bignum/src/GHC/Num/Integer.hs
@@ -767,7 +767,9 @@ integerQuotRem# :: Integer -> Integer -> (# Integer, Integer #)
{-# NOINLINE integerQuotRem# #-}
integerQuotRem# !n (IS 1#) = (# n, IS 0# #)
integerQuotRem# !n (IS -1#) = let !q = integerNegate n in (# q, (IS 0#) #)
-integerQuotRem# !_ (IS 0#) = (# divByZero, divByZero #)
+integerQuotRem# !_ (IS 0#) = case raiseDivZero of
+ !_ -> (# IS 0#, IS 0# #)
+ -- see Note [ghc-bignum exceptions] in GHC.Num.Primitives
integerQuotRem# (IS 0#) _ = (# IS 0#, IS 0# #)
integerQuotRem# (IS n#) (IS d#) = case quotRemInt# n# d# of
(# q#, r# #) -> (# IS q#, IS r# #)
@@ -808,7 +810,7 @@ integerQuot :: Integer -> Integer -> Integer
{-# NOINLINE integerQuot #-}
integerQuot !n (IS 1#) = n
integerQuot !n (IS -1#) = integerNegate n
-integerQuot !_ (IS 0#) = divByZero
+integerQuot !_ (IS 0#) = raiseDivZero
integerQuot (IS 0#) _ = IS 0#
integerQuot (IS n#) (IS d#) = IS (quotInt# n# d#)
integerQuot (IP n) (IS d#)
diff --git a/libraries/ghc-bignum/src/GHC/Num/Natural.hs b/libraries/ghc-bignum/src/GHC/Num/Natural.hs
index 1adb02181d..574f8f04b3 100644
--- a/libraries/ghc-bignum/src/GHC/Num/Natural.hs
+++ b/libraries/ghc-bignum/src/GHC/Num/Natural.hs
@@ -129,7 +129,7 @@ naturalFromIntUnsafe (I# i) = naturalFromIntUnsafe# i
-- Throws 'Control.Exception.Underflow' when passed a negative 'Int'.
naturalFromIntThrow# :: Int# -> Natural
naturalFromIntThrow# i
- | isTrue# (i <# 0#) = case underflow of _ -> NS 0##
+ | isTrue# (i <# 0#) = raiseUnderflow
| True = naturalFromIntUnsafe# i
-- | Create a Natural from an Int
@@ -154,7 +154,7 @@ naturalToInt !n = I# (naturalToInt# n)
naturalFromInt# :: Int# -> Natural
naturalFromInt# !i
| isTrue# (i >=# 0#) = NS (int2Word# i)
- | True = case underflow of _ -> NS 0##
+ | True = raiseUnderflow
-- | Create a Natural from an Int
--
@@ -269,15 +269,15 @@ naturalSub (NB x) (NB y) =
--
-- Throw an Underflow exception if x < y
naturalSubThrow :: Natural -> Natural -> Natural
-naturalSubThrow (NS _) (NB _) = case underflow of _ -> NS 0##
+naturalSubThrow (NS _) (NB _) = raiseUnderflow
naturalSubThrow (NB x) (NS y) = naturalFromBigNat (bigNatSubWordUnsafe# x y)
naturalSubThrow (NS x) (NS y) =
case subWordC# x y of
(# l,0# #) -> NS l
- (# _,_ #) -> case underflow of _ -> NS 0##
+ (# _,_ #) -> raiseUnderflow
naturalSubThrow (NB x) (NB y) =
case bigNatSub x y of
- (# () | #) -> case underflow of _ -> NS 0##
+ (# () | #) -> raiseUnderflow
(# | z #) -> naturalFromBigNat z
-- | Sub two naturals
@@ -325,7 +325,7 @@ naturalSignum _ = NS 1##
naturalNegate :: Natural -> Natural
{-# NOINLINE naturalNegate #-}
naturalNegate (NS 0##) = NS 0##
-naturalNegate _ = case underflow of _ -> NS 0##
+naturalNegate _ = raiseUnderflow
-- | Return division quotient and remainder
--
@@ -463,7 +463,7 @@ naturalLogBase !base !a = W# (naturalLogBase# base a)
-- | \"@'naturalPowMod' /b/ /e/ /m/@\" computes base @/b/@ raised to
-- exponent @/e/@ modulo @/m/@.
naturalPowMod :: Natural -> Natural -> Natural -> Natural
-naturalPowMod !_ !_ (NS 0##) = case divByZero of _ -> naturalZero
+naturalPowMod !_ !_ (NS 0##) = raiseDivZero
naturalPowMod _ _ (NS 1##) = NS 0##
naturalPowMod _ (NS 0##) _ = NS 1##
naturalPowMod (NS 0##) _ _ = NS 0##
diff --git a/libraries/ghc-bignum/src/GHC/Num/Primitives.hs b/libraries/ghc-bignum/src/GHC/Num/Primitives.hs
index 2c1a0b6955..358c83b3be 100644
--- a/libraries/ghc-bignum/src/GHC/Num/Primitives.hs
+++ b/libraries/ghc-bignum/src/GHC/Num/Primitives.hs
@@ -68,9 +68,13 @@ module GHC.Num.Primitives
, wordWriteMutableByteArrayLE#
, wordWriteMutableByteArrayBE#
-- * Exception
- , underflow
- , divByZero
+ , raiseUnderflow
+ , raiseUnderflow_Word#
+ , raiseDivZero
+ , raiseDivZero_Word#
, unexpectedValue
+ , unexpectedValue_Int#
+ , unexpectedValue_Word#
-- * IO
, ioWord#
, ioInt#
@@ -87,6 +91,8 @@ where
#if (__GLASGOW_HASKELL__ < 811)
import GHC.Magic
+#else
+import GHC.Prim.Exception
#endif
import GHC.Prim
@@ -241,7 +247,7 @@ wordLog2# w = (WORD_SIZE_IN_BITS## `minusWord#` 1##) `minusWord#` (clz# w)
wordLogBase# :: Word# -> Word# -> Word#
wordLogBase# base a
| isTrue# (base `leWord#` 1##)
- = case unexpectedValue of _ -> 0##
+ = unexpectedValue_Word# void#
| 2## <- base
= wordLog2# a
@@ -590,32 +596,63 @@ ioBool (IO io) s = case io s of
-- Exception
----------------------------------
-#if (__GLASGOW_HASKELL__ >= 811)
+-- Note [ghc-bignum exceptions]
+-- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+--
+-- `ghc-bignum` package can't depend on `base` package (it would create a cyclic
+-- dependency). Hence it can't import "Control.Exception" and throw exceptions
+-- the usual way. Instead it uses some wired-in functions from `ghc-prim` which
+-- themselves call wired-in functions from the RTS: raiseOverflow,
+-- raiseUnderflow, raiseDivZero.
+--
+-- We have to be careful when we want to throw an exception instead of returning
+-- an unlifted value (e.g. Word#, unboxed tuple, etc.). We have to ensure the
+-- evaluation of the exception throwing function before returning a dummy value,
+-- otherwise it will be removed by the simplifier as dead-code.
+--
+-- foo :: ... -> Word#
+-- foo = ... case raiseDivZero of
+-- !_ -> 0## -- the bang-pattern is necessary!
+-- -- 0## is a dummy value (unreachable code)
+--
+
+unexpectedValue_Int# :: Void# -> Int#
+unexpectedValue_Int# _ = case unexpectedValue of
+ !_ -> 0# -- see Note [ghc-bignum exceptions]
+
+unexpectedValue_Word# :: Void# -> Word#
+unexpectedValue_Word# _ = case unexpectedValue of
+ !_ -> 0## -- see Note [ghc-bignum exceptions]
-underflow :: a
-underflow = raiseUnderflow# void#
+raiseDivZero_Word# :: Void# -> Word#
+raiseDivZero_Word# _ = case raiseDivZero of
+ !_ -> 0## -- see Note [ghc-bignum exceptions]
-divByZero :: a
-divByZero = raiseDivZero# void#
+raiseUnderflow_Word# :: Void# -> Word#
+raiseUnderflow_Word# _ = case raiseUnderflow of
+ !_ -> 0## -- see Note [ghc-bignum exceptions]
+
+#if (__GLASGOW_HASKELL__ >= 811)
unexpectedValue :: a
-unexpectedValue = raiseOverflow# void#
+unexpectedValue = raiseOverflow
#else
-- Before GHC 8.11 we use the exception trick taken from #14664
exception :: a
+{-# NOINLINE exception #-}
exception = runRW# \s ->
case atomicLoop s of
(# _, a #) -> a
where
atomicLoop s = atomically# atomicLoop s
-underflow :: a
-underflow = exception
+raiseUnderflow :: a
+raiseUnderflow = exception
-divByZero :: a
-divByZero = exception
+raiseDivZero :: a
+raiseDivZero = exception
unexpectedValue :: a
unexpectedValue = exception