summaryrefslogtreecommitdiff
path: root/libraries/ghc-bignum/src/GHC/Num/Primitives.hs
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/ghc-bignum/src/GHC/Num/Primitives.hs')
-rw-r--r--libraries/ghc-bignum/src/GHC/Num/Primitives.hs623
1 files changed, 623 insertions, 0 deletions
diff --git a/libraries/ghc-bignum/src/GHC/Num/Primitives.hs b/libraries/ghc-bignum/src/GHC/Num/Primitives.hs
new file mode 100644
index 0000000000..2c1a0b6955
--- /dev/null
+++ b/libraries/ghc-bignum/src/GHC/Num/Primitives.hs
@@ -0,0 +1,623 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE UnliftedFFITypes #-}
+{-# LANGUAGE NegativeLiterals #-}
+{-# LANGUAGE ExplicitForAll #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE BlockArguments #-}
+{-# LANGUAGE BinaryLiterals #-}
+{-# OPTIONS_GHC -fexpose-all-unfoldings #-}
+
+module GHC.Num.Primitives
+ (
+ -- * Bool#
+ Bool#
+ , (&&#)
+ , (||#)
+ , notB#
+ -- * Int#
+ , testBitI#
+ , minI#
+ , maxI#
+ , sgnI#
+ , absI#
+ , cmpI#
+ , intEncodeDouble#
+ , popCntI#
+ -- * Word#
+ , andNot#
+ , cmpW#
+ , bitW#
+ , maxW#
+ , minW#
+ , testBitW#
+ , shiftRW#
+ , plusWord3#
+ , plusWord12#
+ , quotRemWord3#
+ , wordFromAbsInt#
+ , wordLog2#
+ , wordLogBase#
+ , wordSizeInBase#
+ , wordIsPowerOf2#
+ , wordEncodeDouble#
+ , wordReverseBits#
+ , wordReverseBits32#
+ , wordReverseBytes#
+ -- ** Addr import/export
+ , wordFromAddr#
+ , wordFromAddrLE#
+ , wordFromAddrBE#
+ , wordToAddr#
+ , wordToAddrLE#
+ , wordToAddrBE#
+ , wordWriteAddrLE#
+ , wordWriteAddrBE#
+ -- ** ByteArray import/export
+ , wordFromByteArray#
+ , wordFromByteArrayLE#
+ , wordFromByteArrayBE#
+ , wordToMutableByteArray#
+ , wordToMutableByteArrayLE#
+ , wordToMutableByteArrayBE#
+ , wordWriteMutableByteArrayLE#
+ , wordWriteMutableByteArrayBE#
+ -- * Exception
+ , underflow
+ , divByZero
+ , unexpectedValue
+ -- * IO
+ , ioWord#
+ , ioInt#
+ , ioVoid
+ , ioBool
+ )
+where
+
+#include "MachDeps.h"
+#include "WordSize.h"
+
+-- Required for WORDS_BIGENDIAN
+#include <ghcautoconf.h>
+
+#if (__GLASGOW_HASKELL__ < 811)
+import GHC.Magic
+#endif
+
+import GHC.Prim
+import GHC.Types
+import GHC.Tuple () -- See Note [Depend on GHC.Tuple] in GHC.Base
+
+default ()
+
+----------------------------------
+-- Bool#
+----------------------------------
+
+type Bool# = Int#
+
+(&&#) :: Bool# -> Bool# -> Bool#
+(&&#) = andI#
+
+(||#) :: Bool# -> Bool# -> Bool#
+(||#) = orI#
+
+notB# :: Bool# -> Bool#
+notB# x = x `xorI#` 1#
+
+infixr 3 &&#
+infixr 2 ||#
+
+
+----------------------------------
+-- Int#
+----------------------------------
+
+-- | Branchless `abs`
+absI# :: Int# -> Int#
+absI# i# = (i# `xorI#` nsign) -# nsign
+ where
+ -- nsign = negateInt# (i# <# 0#)
+ nsign = uncheckedIShiftRA# i# (WORD_SIZE_IN_BITS# -# 1#)
+
+-- | Branchless `signum`
+sgnI# :: Int# -> Int#
+sgnI# x# = (x# ># 0#) -# (x# <# 0#)
+
+-- | Population count
+popCntI# :: Int# -> Word#
+popCntI# i = popCnt# (int2Word# i)
+
+-- | Branchless comparison
+cmpI# :: Int# -> Int# -> Int#
+cmpI# x# y# = (x# ># y#) -# (x# <# y#)
+
+testBitI# :: Int# -> Word# -> Bool#
+testBitI# x i = ((uncheckedIShiftL# 1# (word2Int# i)) `andI#` x) /=# 0#
+
+minI# :: Int# -> Int# -> Int#
+minI# x y | isTrue# (x <=# y) = x
+ | True = y
+
+maxI# :: Int# -> Int# -> Int#
+maxI# x y | isTrue# (x >=# y) = x
+ | True = y
+
+-- | Encode (# Int# mantissa, Int# exponent #) into a Double#.
+--
+-- (provided by GHC's RTS)
+foreign import ccall unsafe "__int_encodeDouble"
+ intEncodeDouble# :: Int# -> Int# -> Double#
+
+----------------------------------
+-- Word#
+----------------------------------
+
+andNot# :: Word# -> Word# -> Word#
+andNot# x y = x `and#` (not# y)
+
+cmpW# :: Word# -> Word# -> Ordering
+{-# INLINE cmpW# #-}
+cmpW# x# y#
+ | isTrue# (x# `ltWord#` y#) = LT
+ | isTrue# (x# `eqWord#` y#) = EQ
+ | True = GT
+
+-- | Return the absolute value of the Int# in a Word#
+wordFromAbsInt# :: Int# -> Word#
+wordFromAbsInt# i
+ | isTrue# (i >=# 0#) = int2Word# i
+ | True = int2Word# (negateInt# i)
+
+minW# :: Word# -> Word# -> Word#
+minW# x# y# | isTrue# (x# `leWord#` y#) = x#
+ | True = y#
+
+maxW# :: Word# -> Word# -> Word#
+maxW# x# y# | isTrue# (x# `gtWord#` y#) = x#
+ | True = y#
+
+bitW# :: Int# -> Word#
+bitW# k = 1## `uncheckedShiftL#` k
+
+testBitW# :: Word# -> Word# -> Bool#
+testBitW# w k = w `and#` (1## `uncheckedShiftL#` word2Int# k) `neWord#` 0##
+
+-- | Safe right shift for Word#
+shiftRW# :: Word# -> Word# -> Word#
+shiftRW# a b
+ | isTrue# (b `geWord#` WORD_SIZE_IN_BITS##) = 0##
+ | True = a `uncheckedShiftRL#` (word2Int# b)
+
+-- | (h,l) <- a + (hb,lb)
+plusWord12# :: Word# -> (# Word#,Word# #) -> (# Word#,Word# #)
+{-# INLINABLE plusWord12# #-}
+plusWord12# a0 (# b1,b0 #) = (# m1, m0 #)
+ where
+ !(# t, m0 #) = plusWord2# a0 b0
+ !m1 = plusWord# t b1
+
+-- | Add 3 values together
+plusWord3# :: Word# -> Word# -> Word# -> (# Word#, Word# #)
+{-# INLINABLE plusWord3# #-}
+plusWord3# a b c = (# r1, r0 #)
+ where
+ !(# t1, t0 #) = plusWord2# a b
+ !(# t2, r0 #) = plusWord2# t0 c
+ !r1 = plusWord# t1 t2
+
+
+-- | 2-by-1 large division
+--
+-- Requires:
+-- b0 /= 0
+-- a1 >= b0 (not required, but if not q1=0)
+quotRemWord3# :: (# Word#,Word# #) -> Word# -> (# (# Word#,Word# #),Word# #)
+quotRemWord3# (# a1,a0 #) b0 = (# (# q1, q0 #), r0 #)
+ where
+ !(# q1, r' #) = quotRemWord# a1 b0
+ !(# q0, r0 #) = quotRemWord2# r' a0 b0
+
+
+
+-- | Encode (# Word# mantissa, Int# exponent #) into a Double#.
+--
+-- (provided by GHC's RTS)
+foreign import ccall unsafe "__word_encodeDouble"
+ wordEncodeDouble# :: Word# -> Int# -> Double#
+
+-- | Compute base-2 log of 'Word#'
+--
+-- This is internally implemented as count-leading-zeros machine instruction.
+wordLog2# :: Word# -> Word#
+wordLog2# w = (WORD_SIZE_IN_BITS## `minusWord#` 1##) `minusWord#` (clz# w)
+
+-- | Logarithm for an arbitrary base
+wordLogBase# :: Word# -> Word# -> Word#
+wordLogBase# base a
+ | isTrue# (base `leWord#` 1##)
+ = case unexpectedValue of _ -> 0##
+
+ | 2## <- base
+ = wordLog2# a
+
+ | True
+ = case go base of (# _, e' #) -> e'
+ where
+ goSqr pw = case timesWord2# pw pw of
+ (# 0##, l #) -> go l
+ (# _ , _ #) -> (# a, 0## #)
+ go pw = if isTrue# (a `ltWord#` pw)
+ then (# a, 0## #)
+ else case goSqr pw of
+ (# q, e #) -> if isTrue# (q `ltWord#` pw)
+ then (# q, 2## `timesWord#` e #)
+ else (# q `quotWord#` pw
+ , 2## `timesWord#` e `plusWord#` 1## #)
+
+wordSizeInBase# :: Word# -> Word# -> Word#
+wordSizeInBase# _ 0## = 0##
+wordSizeInBase# base w = 1## `plusWord#` wordLogBase# base w
+
+-- | Indicate if the value is a power of two and which one
+wordIsPowerOf2# :: Word# -> (# () | Word# #)
+wordIsPowerOf2# w
+ | isTrue# (popCnt# w `neWord#` 1##) = (# () | #)
+ | True = (# | ctz# w #)
+
+-- | Reverse bytes in a Word#
+wordReverseBytes# :: Word# -> Word#
+wordReverseBytes# x0 = r
+ where
+#if WORD_SIZE_IN_BITS == 64
+ x1 = ((x0 `and#` 0x00FF00FF00FF00FF##) `uncheckedShiftL#` 8#) `or#` ((x0 `and#` 0xFF00FF00FF00FF00##) `uncheckedShiftRL#` 8#)
+ x2 = ((x1 `and#` 0x0000FFFF0000FFFF##) `uncheckedShiftL#` 16#) `or#` ((x1 `and#` 0xFFFF0000FFFF0000##) `uncheckedShiftRL#` 16#)
+ r = ((x2 `and#` 0x00000000FFFFFFFF##) `uncheckedShiftL#` 32#) `or#` ((x2 `and#` 0xFFFFFFFF00000000##) `uncheckedShiftRL#` 32#)
+#else
+ x1 = ((x0 `and#` 0x00FF00FF##) `uncheckedShiftL#` 8#) `or#` ((x0 `and#` 0xFF00FF00##) `uncheckedShiftRL#` 8#)
+ r = ((x1 `and#` 0x0000FFFF##) `uncheckedShiftL#` 16#) `or#` ((x1 `and#` 0xFFFF0000##) `uncheckedShiftRL#` 16#)
+#endif
+
+
+-- | Reverse bits in a Word#
+wordReverseBits# :: Word# -> Word#
+wordReverseBits# x0 = r
+ where
+#if WORD_SIZE_IN_BITS == 64
+ x1 = ((x0 `and#` 0x5555555555555555##) `uncheckedShiftL#` 1#) `or#` ((x0 `and#` 0xAAAAAAAAAAAAAAAA##) `uncheckedShiftRL#` 1#)
+ x2 = ((x1 `and#` 0x3333333333333333##) `uncheckedShiftL#` 2#) `or#` ((x1 `and#` 0xCCCCCCCCCCCCCCCC##) `uncheckedShiftRL#` 2#)
+ x3 = ((x2 `and#` 0x0F0F0F0F0F0F0F0F##) `uncheckedShiftL#` 4#) `or#` ((x2 `and#` 0xF0F0F0F0F0F0F0F0##) `uncheckedShiftRL#` 4#)
+ x4 = ((x3 `and#` 0x00FF00FF00FF00FF##) `uncheckedShiftL#` 8#) `or#` ((x3 `and#` 0xFF00FF00FF00FF00##) `uncheckedShiftRL#` 8#)
+ x5 = ((x4 `and#` 0x0000FFFF0000FFFF##) `uncheckedShiftL#` 16#) `or#` ((x4 `and#` 0xFFFF0000FFFF0000##) `uncheckedShiftRL#` 16#)
+ r = ((x5 `and#` 0x00000000FFFFFFFF##) `uncheckedShiftL#` 32#) `or#` ((x5 `and#` 0xFFFFFFFF00000000##) `uncheckedShiftRL#` 32#)
+#else
+ x1 = ((x0 `and#` 0x55555555##) `uncheckedShiftL#` 1#) `or#` ((x0 `and#` 0xAAAAAAAA##) `uncheckedShiftRL#` 1#)
+ x2 = ((x1 `and#` 0x33333333##) `uncheckedShiftL#` 2#) `or#` ((x1 `and#` 0xCCCCCCCC##) `uncheckedShiftRL#` 2#)
+ x3 = ((x2 `and#` 0x0F0F0F0F##) `uncheckedShiftL#` 4#) `or#` ((x2 `and#` 0xF0F0F0F0##) `uncheckedShiftRL#` 4#)
+ x4 = ((x3 `and#` 0x00FF00FF##) `uncheckedShiftL#` 8#) `or#` ((x3 `and#` 0xFF00FF00##) `uncheckedShiftRL#` 8#)
+ r = ((x4 `and#` 0x0000FFFF##) `uncheckedShiftL#` 16#) `or#` ((x4 `and#` 0xFFFF0000##) `uncheckedShiftRL#` 16#)
+#endif
+
+-- | Reverse bits in the Word32 subwords composing a Word#
+wordReverseBits32# :: Word# -> Word#
+#if WORD_SIZE_IN_BITS == 64
+wordReverseBits32# x0 = r
+ where
+ x1 = ((x0 `and#` 0x5555555555555555##) `uncheckedShiftL#` 1#) `or#` ((x0 `and#` 0xAAAAAAAAAAAAAAAA##) `uncheckedShiftRL#` 1#)
+ x2 = ((x1 `and#` 0x3333333333333333##) `uncheckedShiftL#` 2#) `or#` ((x1 `and#` 0xCCCCCCCCCCCCCCCC##) `uncheckedShiftRL#` 2#)
+ x3 = ((x2 `and#` 0x0F0F0F0F0F0F0F0F##) `uncheckedShiftL#` 4#) `or#` ((x2 `and#` 0xF0F0F0F0F0F0F0F0##) `uncheckedShiftRL#` 4#)
+ x4 = ((x3 `and#` 0x00FF00FF00FF00FF##) `uncheckedShiftL#` 8#) `or#` ((x3 `and#` 0xFF00FF00FF00FF00##) `uncheckedShiftRL#` 8#)
+ r = ((x4 `and#` 0x0000FFFF0000FFFF##) `uncheckedShiftL#` 16#) `or#` ((x4 `and#` 0xFFFF0000FFFF0000##) `uncheckedShiftRL#` 16#)
+#else
+wordReverseBits32# x0 = wordReverseBits# x0
+#endif
+
+
+-- | Write a Word to @/addr/@ in base-256 little-endian representation and
+-- return the number of bytes written.
+wordToAddrLE# :: Word# -> Addr# -> State# s -> (# State# s, Word# #)
+wordToAddrLE# x addr = go x 0#
+ where
+ go w c s
+ | 0## <- w
+ = (# s, int2Word# c #)
+
+ | True
+ = case writeWord8OffAddr# addr c (w `and#` 0xFF##) s of
+ s' -> go (w `uncheckedShiftRL#` 8#) (c +# 1#) s'
+
+-- | Write a Word to @/addr/@ in base-256 big-endian representation and
+-- return the number of bytes written.
+wordToAddrBE# :: Word# -> Addr# -> State# s -> (# State# s, Word# #)
+wordToAddrBE# w addr = go 0# (WORD_SIZE_IN_BITS# -# clz)
+ where
+ !clz = word2Int# (clz# w `and#` (not# 0b0111##)) -- keep complete bytes
+
+ go c sh s
+ | 0# <- sh
+ = (# s, int2Word# c #)
+
+ | True
+ , w' <- (w `uncheckedShiftRL#` (sh -# 8#)) `and#` 0xFF##
+ = case writeWord8OffAddr# addr c w' s of
+ s' -> go (c +# 1#) (sh -# 8#) s'
+
+-- | Write a Word to @/addr/@ in base-256 representation and
+-- return the number of bytes written.
+--
+-- The endianness is selected with the Bool# parameter: write most significant
+-- byte first (big-endian) if @1#@ or least significant byte first
+-- (little-endian) if @0#@.
+wordToAddr# :: Word# -> Addr# -> Bool# -> State# s -> (# State# s, Word# #)
+wordToAddr# a addr 0# s = wordToAddrLE# a addr s
+wordToAddr# a addr _ s = wordToAddrBE# a addr s
+
+
+-- | Read a Word from @/addr/@ in base-256 little-endian representation.
+--
+-- @'n' is the number of bytes to read.
+wordFromAddrLE# :: Word# -> Addr# -> State# s -> (# State# s, Word# #)
+wordFromAddrLE# n addr s
+ -- Optimize when we read a full word
+ | WORD_SIZE_IN_BYTES## <- n
+ = case readWordOffAddr# addr 0# s of
+#if defined(WORDS_BIGENDIAN)
+ (# s', w #) -> (# s', wordReverseBytes# w #)
+#else
+ (# s', w #) -> (# s', w #)
+#endif
+
+wordFromAddrLE# n addr s0 = go 0## 0# s0
+ where
+ go w c s
+ | isTrue# (c ==# word2Int# n)
+ = (# s, w #)
+
+ | True
+ = case readWord8OffAddr# addr c s of
+ (# s', b #) -> go (w `or#` (b `uncheckedShiftL#` (c `uncheckedIShiftL#` 3#)))
+ (c +# 1#)
+ s'
+
+-- | Read a Word from @/addr/@ in base-256 big-endian representation.
+--
+-- @'n' is the number of bytes to read.
+wordFromAddrBE# :: Word# -> Addr# -> State# s -> (# State# s, Word# #)
+wordFromAddrBE# n addr s
+ -- Optimize when we read a full word
+ | WORD_SIZE_IN_BYTES## <- n
+ = case readWordOffAddr# addr 0# s of
+#if defined(WORDS_BIGENDIAN)
+ (# s', w #) -> (# s', w #)
+#else
+ (# s', w #) -> (# s', wordReverseBytes# w #)
+#endif
+
+wordFromAddrBE# n addr s0 = go 0## 0# s0
+ where
+ go w c s
+ | isTrue# (c ==# word2Int# n)
+ = (# s, w #)
+
+ | True
+ = case readWord8OffAddr# addr c s of
+ (# s', b #) -> go ((w `uncheckedShiftL#` 8#) `or#` b)
+ (c +# 1#)
+ s'
+
+-- | Read a Word from @/addr/@ in base-256 representation.
+--
+-- @'n' is the number of bytes to read.
+--
+-- The endianness is selected with the Bool# parameter: write most significant
+-- byte first (big-endian) if @1#@ or least significant byte first
+-- (little-endian) if @0#@.
+wordFromAddr# :: Word# -> Addr# -> Bool# -> State# s -> (# State# s, Word# #)
+wordFromAddr# a addr 0# s = wordFromAddrLE# a addr s
+wordFromAddr# a addr _ s = wordFromAddrBE# a addr s
+
+
+
+-- | Write a full word with little-endian encoding
+wordWriteAddrLE# :: Word# -> Addr# -> State# s -> State# s
+wordWriteAddrLE# w addr = writeWordOffAddr# addr 0#
+#if defined(WORDS_BIGENDIAN)
+ (wordReverseBytes# w)
+#else
+ w
+#endif
+
+-- | Write a full word with little-endian encoding
+wordWriteAddrBE# :: Word# -> Addr# -> State# s -> State# s
+wordWriteAddrBE# w addr = writeWordOffAddr# addr 0#
+#if defined(WORDS_BIGENDIAN)
+ w
+#else
+ (wordReverseBytes# w)
+#endif
+
+-- | Write a Word to @/MutableByteArray/@ in base-256 little-endian
+-- representation and return the number of bytes written.
+--
+-- The offset is in bytes.
+wordToMutableByteArrayLE# :: Word# -> MutableByteArray# s -> Word# -> State# s -> (# State# s, Word# #)
+wordToMutableByteArrayLE# x mba off = go x 0#
+ where
+ go w c s
+ | 0## <- w
+ = (# s, int2Word# c #)
+
+ | True
+ = case writeWord8Array# mba (word2Int# off +# c) (w `and#` 0xFF##) s of
+ s' -> go (w `uncheckedShiftRL#` 8#) (c +# 1#) s'
+
+-- | Write a Word to @/MutableByteArray/@ in base-256 big-endian representation and
+-- return the number of bytes written.
+--
+-- The offset is in bytes.
+wordToMutableByteArrayBE# :: Word# -> MutableByteArray# s -> Word# -> State# s -> (# State# s, Word# #)
+wordToMutableByteArrayBE# w mba off = go 0# (WORD_SIZE_IN_BITS# -# clz)
+ where
+ !clz = word2Int# (clz# w `and#` (not# 0b0111##)) -- keep complete bytes
+
+ go c sh s
+ | 0# <- sh
+ = (# s, int2Word# c #)
+
+ | True
+ , w' <- (w `uncheckedShiftRL#` (sh -# 8#)) `and#` 0xFF##
+ = case writeWord8Array# mba (word2Int# off +# c) w' s of
+ s' -> go (c +# 1#) (sh -# 8#) s'
+
+-- | Write a Word to @/MutableByteArray/@ in base-256 representation and
+-- return the number of bytes written.
+--
+-- The endianness is selected with the Bool# parameter: write most significant
+-- byte first (big-endian) if @1#@ or least significant byte first
+-- (little-endian) if @0#@.
+--
+-- The offset is in bytes.
+wordToMutableByteArray# :: Word# -> MutableByteArray# s -> Word# -> Bool# -> State# s -> (# State# s, Word# #)
+wordToMutableByteArray# a mba off 0# s = wordToMutableByteArrayLE# a mba off s
+wordToMutableByteArray# a mba off _ s = wordToMutableByteArrayBE# a mba off s
+
+-- | Write a full word with little-endian encoding
+wordWriteMutableByteArrayLE# :: Word# -> MutableByteArray# s -> Word# -> State# s -> State# s
+wordWriteMutableByteArrayLE# w mba off = writeWord8ArrayAsWord# mba (word2Int# off)
+#if defined(WORDS_BIGENDIAN)
+ (wordReverseBytes# w)
+#else
+ w
+#endif
+
+-- | Write a full word with little-endian encoding
+wordWriteMutableByteArrayBE# :: Word# -> MutableByteArray# s -> Word# -> State# s -> State# s
+wordWriteMutableByteArrayBE# w mba off = writeWord8ArrayAsWord# mba (word2Int# off)
+#if defined(WORDS_BIGENDIAN)
+ w
+#else
+ (wordReverseBytes# w)
+#endif
+
+-- | Read a Word from @/ByteArray/@ in base-256 little-endian representation.
+--
+-- @'n' is the number of bytes to read.
+wordFromByteArrayLE# :: Word# -> ByteArray# -> Word# -> Word#
+wordFromByteArrayLE# n ba off =
+ case n of
+ -- Optimize when we read a full word
+ WORD_SIZE_IN_BYTES## -> case indexWord8ArrayAsWord# ba (word2Int# off) of
+#if defined(WORDS_BIGENDIAN)
+ w -> wordReverseBytes# w
+#else
+ w -> w
+#endif
+
+ _ -> let
+ go w c
+ | isTrue# (c ==# word2Int# n)
+ = w
+
+ | True
+ = case indexWord8Array# ba (word2Int# off +# c) of
+ b -> go (w `or#` (b `uncheckedShiftL#` (c `uncheckedIShiftL#` 3#)))
+ (c +# 1#)
+ in go 0## 0#
+
+-- | Read a Word from @/ByteArray/@ in base-256 big-endian representation.
+--
+-- @'n' is the number of bytes to read.
+wordFromByteArrayBE# :: Word# -> ByteArray# -> Word# -> Word#
+wordFromByteArrayBE# n ba off
+ -- Optimize when we read a full word
+ | WORD_SIZE_IN_BYTES## <- n
+ = case indexWord8ArrayAsWord# ba (word2Int# off) of
+#if defined(WORDS_BIGENDIAN)
+ w -> w
+#else
+ w -> wordReverseBytes# w
+#endif
+
+wordFromByteArrayBE# n ba off = go 0## 0#
+ where
+ go w c
+ | isTrue# (c ==# word2Int# n)
+ = w
+
+ | True
+ = case indexWord8Array# ba (word2Int# off +# c) of
+ b -> go ((w `uncheckedShiftL#` 8#) `or#` b) (c +# 1#)
+
+-- | Read a Word from @/ByteArray/@ in base-256 representation.
+--
+-- @'n' is the number of bytes to read.
+--
+-- The endianness is selected with the Bool# parameter: write most significant
+-- byte first (big-endian) if @1#@ or least significant byte first
+-- (little-endian) if @0#@.
+wordFromByteArray# :: Word# -> ByteArray# -> Word# -> Bool# -> Word#
+wordFromByteArray# a ba off 0# = wordFromByteArrayLE# a ba off
+wordFromByteArray# a ba off _ = wordFromByteArrayBE# a ba off
+
+----------------------------------
+-- IO
+----------------------------------
+
+ioVoid :: IO a -> State# RealWorld -> State# RealWorld
+ioVoid (IO io) s = case io s of
+ (# s', _ #) -> s'
+
+ioWord# :: IO Word -> State# RealWorld -> (# State# RealWorld, Word# #)
+ioWord# (IO io) s = case io s of
+ (# s', W# w #) -> (# s', w #)
+
+ioInt# :: IO Int -> State# RealWorld -> (# State# RealWorld, Int# #)
+ioInt# (IO io) s = case io s of
+ (# s', I# i #) -> (# s', i #)
+
+ioBool :: IO Bool -> State# RealWorld -> (# State# RealWorld, Bool# #)
+ioBool (IO io) s = case io s of
+ (# s', False #) -> (# s', 0# #)
+ (# s', True #) -> (# s', 1# #)
+
+
+----------------------------------
+-- Exception
+----------------------------------
+
+#if (__GLASGOW_HASKELL__ >= 811)
+
+underflow :: a
+underflow = raiseUnderflow# void#
+
+divByZero :: a
+divByZero = raiseDivZero# void#
+
+unexpectedValue :: a
+unexpectedValue = raiseOverflow# void#
+
+#else
+
+-- Before GHC 8.11 we use the exception trick taken from #14664
+exception :: a
+exception = runRW# \s ->
+ case atomicLoop s of
+ (# _, a #) -> a
+ where
+ atomicLoop s = atomically# atomicLoop s
+
+underflow :: a
+underflow = exception
+
+divByZero :: a
+divByZero = exception
+
+unexpectedValue :: a
+unexpectedValue = exception
+
+#endif