#include "MachDeps.h"
module Basement.Bits
( BitOps(..)
, FiniteBitsOps(..)
, Bits
, toBits
, allOne
) where
import Basement.Compat.Base
import Basement.Compat.Natural
import Basement.Numerical.Additive
import Basement.Numerical.Subtractive
import Basement.Numerical.Multiplicative
import Basement.Types.OffsetSize
import Basement.Types.Word128 (Word128)
import qualified Basement.Types.Word128 as Word128
import Basement.Types.Word256 (Word256)
import qualified Basement.Types.Word256 as Word256
import Basement.IntegralConv (wordToInt)
import Basement.Nat
import qualified Prelude
import qualified Data.Bits as OldBits
import Data.Maybe (fromMaybe)
import Data.Proxy
import GHC.Base hiding ((.))
import GHC.Prim
import GHC.Types
import GHC.Word
import GHC.Int
#if WORD_SIZE_IN_BITS < 64
import GHC.IntWord64
#endif
class FiniteBitsOps bits where
numberOfBits :: bits -> CountOf Bool
rotateL :: bits -> CountOf Bool -> bits
rotateR :: bits -> CountOf Bool -> bits
popCount :: bits -> CountOf Bool
bitFlip :: bits -> bits
countLeadingZeros :: bits -> CountOf Bool
default countLeadingZeros :: BitOps bits => bits -> CountOf Bool
countLeadingZeros n = loop stop azero
where
stop = numberOfBits n
loop idx count
| idx == azero = count
| isBitSet n (sizeAsOffset idx) = count
| otherwise = loop (fromMaybe azero (idx 1)) (count + 1)
countTrailingZeros :: bits -> CountOf Bool
default countTrailingZeros :: BitOps bits => bits -> CountOf Bool
countTrailingZeros n = loop azero
where
stop = numberOfBits n
loop count
| count == stop = count
| isBitSet n (sizeAsOffset count) = count
| otherwise = loop (count + 1)
class BitOps bits where
(.&.) :: bits -> bits -> bits
(.|.) :: bits -> bits -> bits
(.^.) :: bits -> bits -> bits
(.<<.) :: bits -> CountOf Bool -> bits
(.>>.) :: bits -> CountOf Bool -> bits
bit :: Offset Bool -> bits
default bit :: Integral bits => Offset Bool -> bits
bit n = 1 .<<. (offsetAsSize n)
isBitSet :: bits -> Offset Bool -> Bool
default isBitSet :: (Integral bits, Eq bits) => bits -> Offset Bool -> Bool
isBitSet x n = x .&. (bit n) /= 0
setBit :: bits -> Offset Bool -> bits
default setBit :: Integral bits => bits -> Offset Bool -> bits
setBit x n = x .|. (bit n)
clearBit :: bits -> Offset Bool -> bits
default clearBit :: FiniteBitsOps bits => bits -> Offset Bool -> bits
clearBit x n = x .&. (bitFlip (bit n))
newtype Bits (n :: Nat) = Bits { bitsToNatural :: Natural }
deriving (Show, Eq, Ord, Typeable)
type SizeValid n = (KnownNat n, 1 <= n)
lift :: Int -> Natural
lift = Prelude.fromIntegral
toBits :: SizeValid n => Natural -> Bits n
toBits nat = Bits nat .&. allOne
allOne :: forall n . SizeValid n => Bits n
allOne = Bits (2 Prelude.^ n Prelude.- midentity)
where
n = natVal (Proxy @n)
instance SizeValid n => Enum (Bits n) where
toEnum i | i < 0 && lift i > bitsToNatural maxi = error "Bits n not within bound"
| otherwise = Bits (lift i)
where maxi = allOne :: Bits n
fromEnum (Bits n) = fromEnum n
instance SizeValid n => Bounded (Bits n) where
minBound = azero
maxBound = allOne
instance SizeValid n => Additive (Bits n) where
azero = Bits 0
(+) (Bits a) (Bits b) = toBits (a + b)
instance SizeValid n => Subtractive (Bits n) where
type Difference (Bits n) = Bits n
() (Bits a) (Bits b) = maybe azero toBits (a b)
instance SizeValid n => Multiplicative (Bits n) where
midentity = Bits 1
(*) (Bits a) (Bits b) = Bits (a Prelude.* b)
instance SizeValid n => IDivisible (Bits n) where
div (Bits a) (Bits b) = Bits (a `Prelude.div` b)
mod (Bits a) (Bits b) = Bits (a `Prelude.mod` b)
divMod (Bits a) (Bits b) = let (q, r) = Prelude.divMod a b in (Bits q, Bits r)
instance SizeValid n => BitOps (Bits n) where
(.&.) (Bits a) (Bits b) = Bits (a OldBits..&. b)
(.|.) (Bits a) (Bits b) = Bits (a OldBits..|. b)
(.^.) (Bits a) (Bits b) = Bits (a `OldBits.xor` b)
(.<<.) (Bits a) (CountOf w) = Bits (a `OldBits.shiftL` w)
(.>>.) (Bits a) (CountOf w) = Bits (a `OldBits.shiftR` w)
bit (Offset w) = Bits (OldBits.bit w)
isBitSet (Bits a) (Offset w) = OldBits.testBit a w
setBit (Bits a) (Offset w) = Bits (OldBits.setBit a w)
clearBit (Bits a) (Offset w) = Bits (OldBits.clearBit a w)
instance (SizeValid n, NatWithinBound (CountOf Bool) n) => FiniteBitsOps (Bits n) where
bitFlip (Bits a) = Bits (OldBits.complement a)
numberOfBits _ = natValCountOf (Proxy @n)
rotateL a i = (a .<<. i) .|. (a .>>. d)
where
n = natValCountOf (Proxy :: Proxy n)
d = fromMaybe (fromMaybe (error "impossible") (i n)) (n i)
rotateR a i = (a .>>. i) .|. (a .<<. d)
where
n = natValCountOf (Proxy :: Proxy n)
d = fromMaybe (fromMaybe (error "impossible") (i n)) (n i)
popCount (Bits n) = CountOf (OldBits.popCount n)
instance FiniteBitsOps Bool where
numberOfBits _ = 1
rotateL x _ = x
rotateR x _ = x
popCount True = 1
popCount False = 0
bitFlip = not
countLeadingZeros True = 0
countLeadingZeros False = 1
countTrailingZeros True = 0
countTrailingZeros False = 1
instance BitOps Bool where
(.&.) = (&&)
(.|.) = (||)
(.^.) = (/=)
x .<<. 0 = x
_ .<<. _ = False
x .>>. 0 = x
_ .>>. _ = False
bit 0 = True
bit _ = False
isBitSet x 0 = x
isBitSet _ _ = False
setBit _ 0 = True
setBit _ _ = False
clearBit _ 0 = False
clearBit x _ = x
instance FiniteBitsOps Word8 where
numberOfBits _ = 8
rotateL (W8# x#) (CountOf (I# i#))
| isTrue# (i'# ==# 0#) = W8# x#
| otherwise = W8# (narrow8Word# ((x# `uncheckedShiftL#` i'#) `or#`
(x# `uncheckedShiftRL#` (8# -# i'#))))
where
!i'# = word2Int# (int2Word# i# `and#` 7##)
rotateR (W8# x#) (CountOf (I# i#))
| isTrue# (i'# ==# 0#) = W8# x#
| otherwise = W8# (narrow8Word# ((x# `uncheckedShiftRL#` i'#) `or#`
(x# `uncheckedShiftL#` (8# -# i'#))))
where
!i'# = word2Int# (int2Word# i# `and#` 7##)
bitFlip (W8# x#) = W8# (x# `xor#` mb#)
where !(W8# mb#) = maxBound
popCount (W8# x#) = CountOf $ wordToInt (W# (popCnt8# x#))
countLeadingZeros (W8# w#) = CountOf $ wordToInt (W# (clz8# w#))
countTrailingZeros (W8# w#) = CountOf $ wordToInt (W# (ctz8# w#))
instance BitOps Word8 where
(W8# x#) .&. (W8# y#) = W8# (x# `and#` y#)
(W8# x#) .|. (W8# y#) = W8# (x# `or#` y#)
(W8# x#) .^. (W8# y#) = W8# (x# `xor#` y#)
(W8# x#) .<<. (CountOf (I# i#)) = W8# (narrow8Word# (x# `shiftL#` i#))
(W8# x#) .>>. (CountOf (I# i#)) = W8# (narrow8Word# (x# `shiftRL#` i#))
instance FiniteBitsOps Word16 where
numberOfBits _ = 16
rotateL (W16# x#) (CountOf (I# i#))
| isTrue# (i'# ==# 0#) = W16# x#
| otherwise = W16# (narrow16Word# ((x# `uncheckedShiftL#` i'#) `or#`
(x# `uncheckedShiftRL#` (16# -# i'#))))
where
!i'# = word2Int# (int2Word# i# `and#` 15##)
rotateR (W16# x#) (CountOf (I# i#))
| isTrue# (i'# ==# 0#) = W16# x#
| otherwise = W16# (narrow16Word# ((x# `uncheckedShiftRL#` i'#) `or#`
(x# `uncheckedShiftL#` (16# -# i'#))))
where
!i'# = word2Int# (int2Word# i# `and#` 15##)
bitFlip (W16# x#) = W16# (x# `xor#` mb#)
where !(W16# mb#) = maxBound
popCount (W16# x#) = CountOf $ wordToInt (W# (popCnt16# x#))
countLeadingZeros (W16# w#) = CountOf $ wordToInt (W# (clz16# w#))
countTrailingZeros (W16# w#) = CountOf $ wordToInt (W# (ctz16# w#))
instance BitOps Word16 where
(W16# x#) .&. (W16# y#) = W16# (x# `and#` y#)
(W16# x#) .|. (W16# y#) = W16# (x# `or#` y#)
(W16# x#) .^. (W16# y#) = W16# (x# `xor#` y#)
(W16# x#) .<<. (CountOf (I# i#)) = W16# (narrow16Word# (x# `shiftL#` i#))
(W16# x#) .>>. (CountOf (I# i#)) = W16# (narrow16Word# (x# `shiftRL#` i#))
instance FiniteBitsOps Word32 where
numberOfBits _ = 32
rotateL (W32# x#) (CountOf (I# i#))
| isTrue# (i'# ==# 0#) = W32# x#
| otherwise = W32# (narrow32Word# ((x# `uncheckedShiftL#` i'#) `or#`
(x# `uncheckedShiftRL#` (32# -# i'#))))
where
!i'# = word2Int# (int2Word# i# `and#` 31##)
rotateR (W32# x#) (CountOf (I# i#))
| isTrue# (i'# ==# 0#) = W32# x#
| otherwise = W32# (narrow32Word# ((x# `uncheckedShiftRL#` i'#) `or#`
(x# `uncheckedShiftL#` (32# -# i'#))))
where
!i'# = word2Int# (int2Word# i# `and#` 31##)
bitFlip (W32# x#) = W32# (x# `xor#` mb#)
where !(W32# mb#) = maxBound
popCount (W32# x#) = CountOf $ wordToInt (W# (popCnt32# x#))
countLeadingZeros (W32# w#) = CountOf $ wordToInt (W# (clz32# w#))
countTrailingZeros (W32# w#) = CountOf $ wordToInt (W# (ctz32# w#))
instance BitOps Word32 where
(W32# x#) .&. (W32# y#) = W32# (x# `and#` y#)
(W32# x#) .|. (W32# y#) = W32# (x# `or#` y#)
(W32# x#) .^. (W32# y#) = W32# (x# `xor#` y#)
(W32# x#) .<<. (CountOf (I# i#)) = W32# (narrow32Word# (x# `shiftL#` i#))
(W32# x#) .>>. (CountOf (I# i#)) = W32# (narrow32Word# (x# `shiftRL#` i#))
#if WORD_SIZE_IN_BITS == 64
instance FiniteBitsOps Word64 where
numberOfBits _ = 64
rotateL (W64# x#) (CountOf (I# i#))
| isTrue# (i'# ==# 0#) = W64# x#
| otherwise = W64# ((x# `uncheckedShiftL#` i'#) `or#`
(x# `uncheckedShiftRL#` (64# -# i'#)))
where
!i'# = word2Int# (int2Word# i# `and#` 63##)
rotateR (W64# x#) (CountOf (I# i#))
| isTrue# (i'# ==# 0#) = W64# x#
| otherwise = W64# ((x# `uncheckedShiftRL#` i'#) `or#`
(x# `uncheckedShiftL#` (64# -# i'#)))
where
!i'# = word2Int# (int2Word# i# `and#` 63##)
bitFlip (W64# x#) = W64# (x# `xor#` mb#)
where !(W64# mb#) = maxBound
popCount (W64# x#) = CountOf $ wordToInt (W# (popCnt64# x#))
countLeadingZeros (W64# w#) = CountOf $ wordToInt (W# (clz64# w#))
countTrailingZeros (W64# w#) = CountOf $ wordToInt (W# (ctz64# w#))
instance BitOps Word64 where
(W64# x#) .&. (W64# y#) = W64# (x# `and#` y#)
(W64# x#) .|. (W64# y#) = W64# (x# `or#` y#)
(W64# x#) .^. (W64# y#) = W64# (x# `xor#` y#)
(W64# x#) .<<. (CountOf (I# i#)) = W64# (x# `shiftL#` i#)
(W64# x#) .>>. (CountOf (I# i#)) = W64# (x# `shiftRL#` i#)
#else
instance FiniteBitsOps Word64 where
numberOfBits _ = 64
rotateL (W64# x#) (CountOf (I# i#))
| isTrue# (i'# ==# 0#) = W64# x#
| otherwise = W64# ((x# `uncheckedShiftL64#` i'#) `or64#`
(x# `uncheckedShiftRL64#` (64# -# i'#)))
where
!i'# = word2Int# (int2Word# i# `and#` 63##)
rotateR (W64# x#) (CountOf (I# i#))
| isTrue# (i'# ==# 0#) = W64# x#
| otherwise = W64# ((x# `uncheckedShiftRL64#` i'#) `or64#`
(x# `uncheckedShiftL64#` (64# -# i'#)))
where
!i'# = word2Int# (int2Word# i# `and#` 63##)
bitFlip (W64# x#) = W64# (not64# x#)
popCount (W64# x#) = CountOf $ wordToInt (W# (popCnt64# x#))
countLeadingZeros (W64# w#) = CountOf $ wordToInt (W# (clz64# w#))
countTrailingZeros (W64# w#) = CountOf $ wordToInt (W# (ctz64# w#))
instance BitOps Word64 where
(W64# x#) .&. (W64# y#) = W64# (x# `and64#` y#)
(W64# x#) .|. (W64# y#) = W64# (x# `or64#` y#)
(W64# x#) .^. (W64# y#) = W64# (x# `xor64#` y#)
(W64# x#) .<<. (CountOf (I# i#)) = W64# (x# `shiftL64#` i#)
(W64# x#) .>>. (CountOf (I# i#)) = W64# (x# `shiftRL64#` i#)
shiftL64#, shiftRL64# :: Word64# -> Int# -> Word64#
a `shiftL64#` b | isTrue# (b >=# 64#) = wordToWord64# 0##
| otherwise = a `uncheckedShiftL64#` b
a `shiftRL64#` b | isTrue# (b >=# 64#) = wordToWord64# 0##
| otherwise = a `uncheckedShiftRL64#` b
#endif
instance FiniteBitsOps Word128 where
numberOfBits _ = 128
rotateL w (CountOf n) = Word128.rotateL w n
rotateR w (CountOf n) = Word128.rotateR w n
bitFlip = Word128.complement
popCount = CountOf . Word128.popCount
instance BitOps Word128 where
(.&.) = Word128.bitwiseAnd
(.|.) = Word128.bitwiseOr
(.^.) = Word128.bitwiseXor
(.<<.) w (CountOf n) = Word128.shiftL w n
(.>>.) w (CountOf n) = Word128.shiftR w n
instance FiniteBitsOps Word256 where
numberOfBits _ = 256
rotateL w (CountOf n) = Word256.rotateL w n
rotateR w (CountOf n) = Word256.rotateR w n
bitFlip = Word256.complement
popCount = CountOf . Word256.popCount
instance BitOps Word256 where
(.&.) = Word256.bitwiseAnd
(.|.) = Word256.bitwiseOr
(.^.) = Word256.bitwiseXor
(.<<.) w (CountOf n) = Word256.shiftL w n
(.>>.) w (CountOf n) = Word256.shiftR w n
instance FiniteBitsOps Int8 where
numberOfBits _ = 8
rotateL (I8# x#) (CountOf (I# i#))
| isTrue# (i'# ==# 0#) = I8# x#
| otherwise = I8# (narrow8Int# (word2Int# ((x'# `uncheckedShiftL#` i'#) `or#`
(x'# `uncheckedShiftRL#` (8# -# i'#)))))
where
!x'# = narrow8Word# (int2Word# x#)
!i'# = word2Int# (int2Word# i# `and#` 7##)
rotateR (I8# x#) (CountOf (I# i#))
| isTrue# (i'# ==# 0#) = I8# x#
| otherwise = I8# (narrow8Int# (word2Int# ((x'# `uncheckedShiftRL#` i'#) `or#`
(x'# `uncheckedShiftL#` (8# -# i'#)))))
where
!x'# = narrow8Word# (int2Word# x#)
!i'# = word2Int# (int2Word# i# `and#` 7##)
bitFlip (I8# x#) = I8# (word2Int# (not# (int2Word# x#)))
popCount (I8# x#) = CountOf $ wordToInt (W# (popCnt8# (int2Word# x#)))
countLeadingZeros (I8# w#) = CountOf $ wordToInt (W# (clz8# (int2Word# w#)))
countTrailingZeros (I8# w#) = CountOf $ wordToInt (W# (ctz8# (int2Word# w#)))
instance BitOps Int8 where
(I8# x#) .&. (I8# y#) = I8# (x# `andI#` y#)
(I8# x#) .|. (I8# y#) = I8# (x# `orI#` y#)
(I8# x#) .^. (I8# y#) = I8# (x# `xorI#` y#)
(I8# x#) .<<. (CountOf (I# i#)) = I8# (narrow8Int# (x# `iShiftL#` i#))
(I8# x#) .>>. (CountOf (I# i#)) = I8# (narrow8Int# (x# `iShiftRL#` i#))
instance FiniteBitsOps Int16 where
numberOfBits _ = 16
rotateL (I16# x#) (CountOf (I# i#))
| isTrue# (i'# ==# 0#) = I16# x#
| otherwise = I16# (narrow16Int# (word2Int# ((x'# `uncheckedShiftL#` i'#) `or#`
(x'# `uncheckedShiftRL#` (16# -# i'#)))))
where
!x'# = narrow16Word# (int2Word# x#)
!i'# = word2Int# (int2Word# i# `and#` 15##)
rotateR (I16# x#) (CountOf (I# i#))
| isTrue# (i'# ==# 0#) = I16# x#
| otherwise = I16# (narrow16Int# (word2Int# ((x'# `uncheckedShiftRL#` i'#) `or#`
(x'# `uncheckedShiftL#` (16# -# i'#)))))
where
!x'# = narrow16Word# (int2Word# x#)
!i'# = word2Int# (int2Word# i# `and#` 15##)
bitFlip (I16# x#) = I16# (word2Int# (not# (int2Word# x#)))
popCount (I16# x#) = CountOf $ wordToInt (W# (popCnt16# (int2Word# x#)))
countLeadingZeros (I16# w#) = CountOf $ wordToInt (W# (clz16# (int2Word# w#)))
countTrailingZeros (I16# w#) = CountOf $ wordToInt (W# (ctz16# (int2Word# w#)))
instance BitOps Int16 where
(I16# x#) .&. (I16# y#) = I16# (x# `andI#` y#)
(I16# x#) .|. (I16# y#) = I16# (x# `orI#` y#)
(I16# x#) .^. (I16# y#) = I16# (x# `xorI#` y#)
(I16# x#) .<<. (CountOf (I# i#)) = I16# (narrow16Int# (x# `iShiftL#` i#))
(I16# x#) .>>. (CountOf (I# i#)) = I16# (narrow16Int# (x# `iShiftRL#` i#))
instance FiniteBitsOps Int32 where
numberOfBits _ = 32
rotateL (I32# x#) (CountOf (I# i#))
| isTrue# (i'# ==# 0#) = I32# x#
| otherwise = I32# (narrow32Int# (word2Int# ((x'# `uncheckedShiftL#` i'#) `or#`
(x'# `uncheckedShiftRL#` (32# -# i'#)))))
where
!x'# = narrow32Word# (int2Word# x#)
!i'# = word2Int# (int2Word# i# `and#` 31##)
rotateR (I32# x#) (CountOf (I# i#))
| isTrue# (i'# ==# 0#) = I32# x#
| otherwise = I32# (narrow32Int# (word2Int# ((x'# `uncheckedShiftRL#` i'#) `or#`
(x'# `uncheckedShiftL#` (32# -# i'#)))))
where
!x'# = narrow32Word# (int2Word# x#)
!i'# = word2Int# (int2Word# i# `and#` 31##)
bitFlip (I32# x#) = I32# (word2Int# (not# (int2Word# x#)))
popCount (I32# x#) = CountOf $ wordToInt (W# (popCnt32# (int2Word# x#)))
countLeadingZeros (I32# w#) = CountOf $ wordToInt (W# (clz32# (int2Word# w#)))
countTrailingZeros (I32# w#) = CountOf $ wordToInt (W# (ctz32# (int2Word# w#)))
instance BitOps Int32 where
(I32# x#) .&. (I32# y#) = I32# (x# `andI#` y#)
(I32# x#) .|. (I32# y#) = I32# (x# `orI#` y#)
(I32# x#) .^. (I32# y#) = I32# (x# `xorI#` y#)
(I32# x#) .<<. (CountOf (I# i#)) = I32# (narrow32Int# (x# `iShiftL#` i#))
(I32# x#) .>>. (CountOf (I# i#)) = I32# (narrow32Int# (x# `iShiftRL#` i#))
#if WORD_SIZE_IN_BITS == 64
instance FiniteBitsOps Int64 where
numberOfBits _ = 64
rotateL (I64# x#) (CountOf (I# i#))
| isTrue# (i'# ==# 0#) = I64# x#
| otherwise = I64# (word2Int# ((x'# `uncheckedShiftL#` i'#) `or#`
(x'# `uncheckedShiftRL#` (64# -# i'#))))
where
!x'# = int2Word# x#
!i'# = word2Int# (int2Word# i# `and#` 63##)
rotateR (I64# x#) (CountOf (I# i#))
| isTrue# (i'# ==# 0#) = I64# x#
| otherwise = I64# (word2Int# ((x'# `uncheckedShiftRL#` i'#) `or#`
(x'# `uncheckedShiftL#` (64# -# i'#))))
where
!x'# = int2Word# x#
!i'# = word2Int# (int2Word# i# `and#` 63##)
bitFlip (I64# x#) = I64# (word2Int# (int2Word# x# `xor#` int2Word# (1#)))
popCount (I64# x#) = CountOf $ wordToInt (W# (popCnt64# (int2Word# x#)))
countLeadingZeros (I64# w#) = CountOf $ wordToInt (W# (clz64# (int2Word# w#)))
countTrailingZeros (I64# w#) = CountOf $ wordToInt (W# (ctz64# (int2Word# w#)))
instance BitOps Int64 where
(I64# x#) .&. (I64# y#) = I64# (x# `andI#` y#)
(I64# x#) .|. (I64# y#) = I64# (x# `orI#` y#)
(I64# x#) .^. (I64# y#) = I64# (x# `xorI#` y#)
(I64# x#) .<<. (CountOf (I# w#)) = I64# (x# `iShiftL#` w#)
(I64# x#) .>>. (CountOf (I# w#)) = I64# (x# `iShiftRL#` w#)
#else
instance FiniteBitsOps Int64 where
numberOfBits _ = 64
rotateL (I64# x#) (CountOf (I# i#))
| isTrue# (i'# ==# 0#) = I64# x#
| otherwise = I64# (word64ToInt64# ((x'# `uncheckedShiftL64#` i'#) `or64#`
(x'# `uncheckedShiftRL64#` (64# -# i'#))))
where
!x'# = int64ToWord64# x#
!i'# = word2Int# (int2Word# i# `and#` 63##)
rotateR (I64# x#) (CountOf (I# i#))
| isTrue# (i'# ==# 0#) = I64# x#
| otherwise = I64# (word64ToInt64# ((x'# `uncheckedShiftRL64#` i'#) `or64#`
(x'# `uncheckedShiftL64#` (64# -# i'#))))
where
!x'# = int64ToWord64# x#
!i'# = word2Int# (int2Word# i# `and#` 63##)
bitFlip (I64# x#) = I64# (word64ToInt64# (not64# (int64ToWord64# x#)))
popCount (I64# x#) = CountOf $ wordToInt (W# (popCnt64# (int64ToWord64# x#)))
countLeadingZeros (I64# w#) = CountOf $ wordToInt (W# (clz64# (int64ToWord64# w#)))
countTrailingZeros (I64# w#) = CountOf $ wordToInt (W# (ctz64# (int64ToWord64# w#)))
instance BitOps Int64 where
(I64# x#) .&. (I64# y#) = I64# (word64ToInt64# (int64ToWord64# x# `and64#` int64ToWord64# y#))
(I64# x#) .|. (I64# y#) = I64# (word64ToInt64# (int64ToWord64# x# `or64#` int64ToWord64# y#))
(I64# x#) .^. (I64# y#) = I64# (word64ToInt64# (int64ToWord64# x# `xor64#` int64ToWord64# y#))
(I64# x#) .<<. (CountOf (I# w#)) = I64# (x# `iShiftL64#` w#)
(I64# x#) .>>. (CountOf (I# w#)) = I64# (x# `iShiftRA64#` w#)
iShiftL64#, iShiftRA64# :: Int64# -> Int# -> Int64#
a `iShiftL64#` b | isTrue# (b >=# 64#) = intToInt64# 0#
| otherwise = a `uncheckedIShiftL64#` b
a `iShiftRA64#` b | isTrue# (b >=# 64#) && isTrue# (a `ltInt64#` (intToInt64# 0#))
= intToInt64# (1#)
| isTrue# (b >=# 64#) = intToInt64# 0#
| otherwise = a `uncheckedIShiftRA64#` b
#endif