packages feed

primal-0.3.0.0: src/Data/Prim/Atom.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE UndecidableInstances #-}
-- |
-- Module      : Data.Prim.Atom
-- Copyright   : (c) Alexey Kuleshevich 2020
-- License     : BSD3
-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
-- Stability   : experimental
-- Portability : non-portable
--
module Data.Prim.Atom
  ( Atom(..)
  -- * SpinLocks
  , acquireLockByteOffMutableByteArray
  , releaseLockByteOffMutableByteArray
  , acquireLockByteOffAddr
  , releaseLockByteOffAddr
  , withLockMutableByteArray
  , withLockOffAddr
  -- * Helpers and testing
  --
  -- Functions below are used for implementing `Atom` instances and are useful for
  -- testing other types as well as defining potential cusom instances
  -- ** Count
  , atomicAddFetchOldMutableByteArrayNum#
  , atomicAddFetchNewMutableByteArrayNum#
  , atomicSubFetchOldMutableByteArrayNum#
  , atomicSubFetchNewMutableByteArrayNum#
  , atomicAddFetchOldOffAddrNum#
  , atomicAddFetchNewOffAddrNum#
  , atomicSubFetchOldOffAddrNum#
  , atomicSubFetchNewOffAddrNum#
  -- ** Bits
  , atomicAndFetchOldMutableByteArrayBits#
  , atomicAndFetchNewMutableByteArrayBits#
  , atomicNandFetchOldMutableByteArrayBits#
  , atomicNandFetchNewMutableByteArrayBits#
  , atomicOrFetchOldMutableByteArrayBits#
  , atomicOrFetchNewMutableByteArrayBits#
  , atomicXorFetchOldMutableByteArrayBits#
  , atomicXorFetchNewMutableByteArrayBits#
  , atomicAndFetchOldOffAddrBits#
  , atomicAndFetchNewOffAddrBits#
  , atomicNandFetchOldOffAddrBits#
  , atomicNandFetchNewOffAddrBits#
  , atomicOrFetchOldOffAddrBits#
  , atomicOrFetchNewOffAddrBits#
  , atomicXorFetchOldOffAddrBits#
  , atomicXorFetchNewOffAddrBits#
  ) where

import Control.DeepSeq
import Control.Prim.Concurrent
import Control.Prim.Exception
import Control.Prim.Monad.Unsafe
import Data.Bits
import Data.Prim.Atomic
import Data.Prim.Class
import Foreign.Prim hiding (Any)
import GHC.TypeLits

newtype Atom a =
  Atom
    { unAtom :: a
    }
  deriving ( Show
           , Eq
           , Ord
           , Num
           , Enum
           , Integral
           , Real
           , RealFrac
           , Fractional
           , Floating
           , RealFloat
           , Bits
           , NFData
           )


instance Prim a => Prim (Atom a) where
  type PrimBase (Atom a) = Atom a
  type SizeOf (Atom a) = 1 + SizeOf a
  type Alignment (Atom a) = 1 + Alignment a
  sizeOf# _ = 1# +# sizeOf# (proxy# :: Proxy# a)
  {-# INLINE sizeOf# #-}
  alignment# _ = 1# +# alignment# (proxy# :: Proxy# a)
  {-# INLINE alignment# #-}
  indexByteOffByteArray# ba# i# = Atom (indexByteOffByteArray# ba# (1# +# i#))
  {-# INLINE indexByteOffByteArray# #-}
  indexByteArray# ba# i# = indexByteOffByteArray# ba# (i# *# sizeOf# (proxy# :: Proxy# (Atom a)))
  {-# INLINE indexByteArray# #-}
  indexOffAddr# addr# i# =
    Atom (indexOffAddr# (addr# `plusAddr#` (1# +# i# *# sizeOf# (proxy# :: Proxy# (Atom a)))) 0#)
  {-# INLINE indexOffAddr# #-}
  readByteOffMutableByteArray# mba# i# s =
    case readByteOffMutableByteArray# mba# (1# +# i#) s of
      (# s', a #) -> (# s', Atom a #)
  {-# INLINE readByteOffMutableByteArray# #-}
  readMutableByteArray# mba# i# =
    readByteOffMutableByteArray# mba# (i# *# sizeOf# (proxy# :: Proxy# (Atom a)))
  {-# INLINE readMutableByteArray# #-}
  readOffAddr# addr# i# s =
    case readOffAddr# (addr# `plusAddr#` (1# +# i# *# sizeOf# (proxy# :: Proxy# (Atom a)))) 0# s of
      (# s', a #) -> (# s', Atom a #)
  {-# INLINE readOffAddr# #-}
  writeByteOffMutableByteArray# mba# i# (Atom a) s =
    writeByteOffMutableByteArray# mba# i# (0 :: Word8)
      (writeByteOffMutableByteArray# mba# (1# +# i#) a s)
  {-# INLINE writeByteOffMutableByteArray# #-}
  writeMutableByteArray# mba# i# (Atom a) s =
    let i0# = i# *# sizeOf# (proxy# :: Proxy# (Atom a))
    in writeByteOffMutableByteArray# mba# i0# (0 :: Word8)
         (writeByteOffMutableByteArray# mba# (1# +# i0#) a s)
  {-# INLINE writeMutableByteArray# #-}
  writeOffAddr# addr# i# (Atom a) s =
    let i0# = i# *# sizeOf# (proxy# :: Proxy# (Atom a))
    in writeOffAddr# addr# i0# (0 :: Word8) (writeOffAddr# (addr# `plusAddr#` (1# +# i0#)) 0# a s)
  {-# INLINE writeOffAddr# #-}
  setMutableByteArray# = setMutableByteArrayLoop#
  {-# INLINE setMutableByteArray# #-}
  setOffAddr# = setOffAddrLoop#
  {-# INLINE setOffAddr# #-}


acquireLockByteOffMutableByteArray :: MonadPrim s m => MutableByteArray# s -> Int# -> m ()
acquireLockByteOffMutableByteArray mba# i# =
  let go = do
        locked <- unsafeIOToPrim $ syncLockTestSetInt8ArrayIO mba# i#
        unless (locked == 0) $ yield >> go
   in go
{-# INLINE acquireLockByteOffMutableByteArray #-}

releaseLockByteOffMutableByteArray :: MonadPrim s m => MutableByteArray# s -> Int# -> m ()
releaseLockByteOffMutableByteArray mba# i# =
  unsafeIOToPrim $ syncLockReleaseInt8ArrayIO mba# i#
{-# INLINE releaseLockByteOffMutableByteArray #-}


acquireLockByteOffAddr :: MonadPrim s m => Addr# -> Int# -> m ()
acquireLockByteOffAddr addr# i# =
  let go = do
        locked <- unsafeIOToPrim $ syncLockTestSetInt8AddrIO addr# i#
        unless (locked == 0) $ yield >> go
   in go
{-# INLINE acquireLockByteOffAddr #-}

releaseLockByteOffAddr :: MonadPrim s m => Addr#-> Int# -> m ()
releaseLockByteOffAddr addr# i# = unsafeIOToPrim $ syncLockReleaseInt8AddrIO addr# i#
{-# INLINE releaseLockByteOffAddr #-}

withLockMutableByteArray ::
     forall e a m. (Prim e, MonadUnliftPrim RW m)
  => MutableByteArray# RealWorld
  -> Int#
  -> (Atom e -> m (Atom e, a))
  -> m a
withLockMutableByteArray mba# i# f =
  let li0# = i# *# sizeOf# (proxy# :: Proxy# (Atom e))
      li# = 1# +# li0#
   in bracket_
        (acquireLockByteOffMutableByteArray mba# li0#)
        (releaseLockByteOffMutableByteArray mba# li0#) $ do
      a <- prim (readByteOffMutableByteArray# mba# li#)
      (Atom a', b) <- f (Atom a)
      b <$ prim_ (writeByteOffMutableByteArray# mba# li# a')
{-# INLINABLE withLockMutableByteArray #-}


-- | Atomic reads on `Atom` require a lock because otherwise any other thread can
-- overwrite the contnts in the midst of reading, resulting in a value with contents
-- from both values part before and part after the write.
atomicReadAtomMutableByteArray ::
     forall e m s. (Prim e, MonadPrim s m)
  => MutableByteArray# s
  -> Int#
  -> m (Atom e)
atomicReadAtomMutableByteArray mba# i# =
  let li# = i# *# sizeOf# (proxy# :: Proxy# (Atom e))
   in uninterruptibleMaskPrimBase_ $ do
        acquireLockByteOffMutableByteArray mba# li#
        r :: e <- ST (readByteOffMutableByteArray# mba# (1# +# li#))
        coerce r <$ releaseLockByteOffMutableByteArray mba# li#
{-# INLINABLE atomicReadAtomMutableByteArray #-}

-- | Values are no longer guaranteed to be one word in size, as such in order for writes
-- to be atomic we require locking.
atomicWriteAtomMutableByteArray ::
     forall e m s. (Prim e, MonadPrim s m)
  => MutableByteArray# s
  -> Int#
  -> Atom e
  -> m ()
atomicWriteAtomMutableByteArray mba# i# (Atom a) =
  let li# = i# *# sizeOf# (proxy# :: Proxy# (Atom e))
   in uninterruptibleMaskPrimBase_ $ do
        acquireLockByteOffMutableByteArray mba# li#
        prim_ (writeByteOffMutableByteArray# mba# (1# +# li#) a)
        releaseLockByteOffMutableByteArray mba# li# :: ST s ()
{-# INLINABLE atomicWriteAtomMutableByteArray #-}



-- | Same as `atomicReadAtomMutableByteArray`, but for `Addr#` with offset
atomicReadAtomOffAddr ::
     forall e m s. (Prim e, MonadPrim s m)
  => Addr#
  -> Int#
  -> m (Atom e)
atomicReadAtomOffAddr mba# i# =
  let li# = i# *# sizeOf# (proxy# :: Proxy# (Atom e))
   in uninterruptibleMaskPrimBase_ $ do
        acquireLockByteOffAddr mba# li#
        r :: e <- ST (readOffAddr# mba# (1# +# li#))
        coerce r <$ releaseLockByteOffAddr mba# li#
{-# INLINABLE atomicReadAtomOffAddr #-}

-- | Same as `atomicWriteAtomMutableByteArray`, but for `Addr#` with offset
atomicWriteAtomOffAddr ::
     forall e m s. (Prim e, MonadPrim s m)
  => Addr#
  -> Int#
  -> Atom e
  -> m ()
atomicWriteAtomOffAddr addr# i# (Atom a) =
  let li# = i# *# sizeOf# (proxy# :: Proxy# (Atom e))
      lockAddr# = addr# `plusAddr#` li#
      valAddr# = lockAddr# `plusAddr#` 1#
   in uninterruptibleMaskPrimBase_ $ do
        acquireLockByteOffAddr lockAddr# 0#
        prim_ (writeOffAddr# valAddr# 0# a)
        releaseLockByteOffAddr lockAddr# 0# :: ST s ()
{-# INLINABLE atomicWriteAtomOffAddr #-}



withLockOffAddr ::
     forall e b. Prim e
  => Addr#
  -> Int#
  -> (Atom e -> IO (Atom e, b))
  -> IO b
withLockOffAddr addr# i# f =
  let li# = i# *# sizeOf# (proxy# :: Proxy# (Atom e))
      offAddr# = addr# `plusAddr#` (1# +# li#)
   in bracket_
        (acquireLockByteOffAddr addr# li#)
        (releaseLockByteOffAddr addr# li#) $ do
      a <- prim (readOffAddr# offAddr# 0#)
      (Atom a', b) <- f (Atom a)
      b <$ prim_ (writeOffAddr# offAddr# 0# a')
{-# INLINABLE withLockOffAddr #-}


atomicModifyAtomMutableByteArray ::
     forall e a m s. (Prim e, MonadPrim s m)
  => MutableByteArray# s
  -> Int#
  -> (Atom e -> (# Atom e, a #))
  -> m a
atomicModifyAtomMutableByteArray mba# i# f =
  let li# = i# *# sizeOf# (proxy# :: Proxy# (Atom e))
   in uninterruptibleMaskPrimBase_ $ do
        acquireLockByteOffMutableByteArray mba# li#
        r <- ST $ \s ->
          case readByteOffMutableByteArray# mba# (1# +# li#) s of
            (# s', a #) ->
              case f (Atom a) of
                (# Atom a', b #) ->
                  (# writeByteOffMutableByteArray# mba# (1# +# li#) a' s', b #)
        r <$ releaseLockByteOffMutableByteArray mba# li#
{-# INLINE atomicModifyAtomMutableByteArray  #-}

atomicModifyAtomOffAddr ::
     forall e a m s. (Prim e, MonadPrim s m)
  => Addr#
  -> Int#
  -> (Atom e -> (# Atom e, a #))
  -> m a
atomicModifyAtomOffAddr addr# i# f =
  let li# = i# *# sizeOf# (proxy# :: Proxy# (Atom e))
      offAddr# = addr# `plusAddr#` (1# +# li#)
   in uninterruptibleMaskPrimBase_ $ do
        acquireLockByteOffAddr addr# li#
        r <- ST $ \s ->
          case readOffAddr# offAddr# 0# s of
            (# s', a #) ->
              case f (Atom a) of
                (# Atom a', b #) ->
                  (# writeOffAddr# offAddr# 0# a' s', b #)
        r <$ releaseLockByteOffAddr addr# li#
{-# INLINE atomicModifyAtomOffAddr #-}


swapIfEqualVal :: Eq e => Atom e -> Atom e -> Atom e -> (# Atom e, Atom e #)
swapIfEqualVal expected new actual
  | expected == actual = (# new, actual #)
  | otherwise = (# actual, actual #)
{-# INLINE swapIfEqualVal #-}

swapIfEqualBool :: Eq e => Atom e -> Atom e -> Atom e -> (# Atom e, Bool #)
swapIfEqualBool expected new actual
  | expected == actual = (# new, True #)
  | otherwise = (# actual, False #)
{-# INLINE swapIfEqualBool #-}

instance (Eq a, Prim a) => Atomic (Atom a) where
  atomicReadMutableByteArray# mba# i# =
    unST (atomicReadAtomMutableByteArray (unsafeCoerce# mba#) i#)
  {-# INLINABLE atomicReadMutableByteArray# #-}
  atomicWriteMutableByteArray# mba# i# a =
    unST_ (atomicWriteAtomMutableByteArray (unsafeCoerce# mba#) i# a)
  {-# INLINABLE atomicWriteMutableByteArray# #-}
  atomicReadOffAddr# addr# i# = unST (atomicReadAtomOffAddr addr# i#)
  {-# INLINABLE atomicReadOffAddr# #-}
  atomicWriteOffAddr# addr# i# a = unST_ (atomicWriteAtomOffAddr addr# i# a)
  {-# INLINABLE atomicWriteOffAddr# #-}
  casMutableByteArray# mba# i# old new =
    unST (atomicModifyAtomMutableByteArray mba# i# (swapIfEqualVal old new))
  {-# INLINE casMutableByteArray# #-}
  casOffAddr# addr# i# old new =
    atomicModifyOffAddr# addr# i# (swapIfEqualVal old new)
  {-# INLINE casOffAddr# #-}
  casBoolMutableByteArray# mba# i# old new =
    unST (atomicModifyAtomMutableByteArray mba# i# (swapIfEqualBool old new))
  {-# INLINE casBoolMutableByteArray# #-}
  casBoolOffAddr# addr# i# old new =
    atomicModifyOffAddr# addr# i# (swapIfEqualBool old new)
  {-# INLINE casBoolOffAddr# #-}
  atomicModifyMutableByteArray# mba# i# f =
    unST (atomicModifyAtomMutableByteArray mba# i# f)
  {-# INLINE atomicModifyMutableByteArray#  #-}
  atomicModifyOffAddr# addr# i# f = unST (atomicModifyAtomOffAddr addr# i# f)
  {-# INLINE atomicModifyOffAddr#  #-}



atomicAddFetchOldMutableByteArrayNum#
  , atomicAddFetchNewMutableByteArrayNum#
  , atomicSubFetchOldMutableByteArrayNum#
  , atomicSubFetchNewMutableByteArrayNum# ::
     (Num a, Atomic a)
  => MutableByteArray# s
  -> Int#
  -> a
  -> State# s
  -> (# State# s, a #)
atomicAddFetchOldMutableByteArrayNum# mba# i# y =
  atomicModifyMutableByteArray# mba# i# (\x -> (# x + y, x #))
{-# INLINE atomicAddFetchOldMutableByteArrayNum# #-}

atomicAddFetchNewMutableByteArrayNum# mba# i# y =
  atomicModifyMutableByteArray# mba# i# (\x -> let x' = x + y in (# x', x' #))
{-# INLINE atomicAddFetchNewMutableByteArrayNum# #-}

atomicSubFetchOldMutableByteArrayNum# mba# i# y =
  atomicModifyMutableByteArray# mba# i# (\x -> (# x - y, x #))
{-# INLINE atomicSubFetchOldMutableByteArrayNum# #-}

atomicSubFetchNewMutableByteArrayNum# mba# i# y =
  atomicModifyMutableByteArray# mba# i# (\x -> let x' = x - y in (# x', x' #))
{-# INLINE atomicSubFetchNewMutableByteArrayNum# #-}

atomicAddFetchOldOffAddrNum#
  , atomicAddFetchNewOffAddrNum#
  , atomicSubFetchOldOffAddrNum#
  , atomicSubFetchNewOffAddrNum# ::
     (Num a, Atomic a)
  => Addr#
  -> Int#
  -> a
  -> State# s
  -> (# State# s, a #)
atomicAddFetchOldOffAddrNum# addr# i# y =
  atomicModifyOffAddr# addr# i# (\x -> (# x + y, x #))
{-# INLINE atomicAddFetchOldOffAddrNum# #-}
atomicAddFetchNewOffAddrNum# addr# i# y =
  atomicModifyOffAddr# addr# i# (\x -> let x' = x + y in (# x', x' #))
{-# INLINE atomicAddFetchNewOffAddrNum# #-}
atomicSubFetchOldOffAddrNum# addr# i# y =
  atomicModifyOffAddr# addr# i# (\x -> (# x - y, x #))
{-# INLINE atomicSubFetchOldOffAddrNum# #-}
atomicSubFetchNewOffAddrNum# addr# i# y =
  atomicModifyOffAddr# addr# i# (\x -> let x' = x - y in (# x', x' #))
{-# INLINE atomicSubFetchNewOffAddrNum# #-}


instance (Num a, Eq a, Prim a) => AtomicCount (Atom a) where
  atomicAddFetchOldMutableByteArray# = atomicAddFetchOldMutableByteArrayNum#
  {-# INLINE atomicAddFetchOldMutableByteArray# #-}
  atomicAddFetchNewMutableByteArray# = atomicAddFetchNewMutableByteArrayNum#
  {-# INLINE atomicAddFetchNewMutableByteArray# #-}
  atomicSubFetchOldMutableByteArray# = atomicSubFetchOldMutableByteArrayNum#
  {-# INLINE atomicSubFetchOldMutableByteArray# #-}
  atomicSubFetchNewMutableByteArray# = atomicSubFetchNewMutableByteArrayNum#
  {-# INLINE atomicSubFetchNewMutableByteArray# #-}
  atomicAddFetchOldOffAddr# = atomicAddFetchOldOffAddrNum#
  {-# INLINE atomicAddFetchOldOffAddr# #-}
  atomicAddFetchNewOffAddr# = atomicAddFetchNewOffAddrNum#
  {-# INLINE atomicAddFetchNewOffAddr# #-}
  atomicSubFetchOldOffAddr# = atomicSubFetchOldOffAddrNum#
  {-# INLINE atomicSubFetchOldOffAddr# #-}
  atomicSubFetchNewOffAddr# = atomicSubFetchNewOffAddrNum#
  {-# INLINE atomicSubFetchNewOffAddr# #-}

atomicAndFetchOldMutableByteArrayBits#
  , atomicAndFetchNewMutableByteArrayBits#
  , atomicNandFetchOldMutableByteArrayBits#
  , atomicNandFetchNewMutableByteArrayBits#
  , atomicOrFetchOldMutableByteArrayBits#
  , atomicOrFetchNewMutableByteArrayBits#
  , atomicXorFetchOldMutableByteArrayBits#
  , atomicXorFetchNewMutableByteArrayBits# ::
     (Bits a, Atomic a)
  => MutableByteArray# s
  -> Int#
  -> a
  -> State# s
  -> (# State# s, a #)
atomicAndFetchOldMutableByteArrayBits# mba# i# y =
  atomicModifyMutableByteArray# mba# i# (\x -> (# x .&. y, x #))
{-# INLINE atomicAndFetchOldMutableByteArrayBits# #-}
atomicAndFetchNewMutableByteArrayBits# mba# i# y =
  atomicModifyMutableByteArray# mba# i# (\x -> let x' = x .&. y in (# x', x' #))
{-# INLINE atomicAndFetchNewMutableByteArrayBits# #-}
atomicNandFetchOldMutableByteArrayBits# mba# i# y =
  atomicModifyMutableByteArray# mba# i# (\x -> (# complement (x .&. y), x #))
{-# INLINE atomicNandFetchOldMutableByteArrayBits# #-}
atomicNandFetchNewMutableByteArrayBits# mba# i# y =
  atomicModifyMutableByteArray# mba# i# (\x -> let x' = complement (x .&. y) in (# x', x' #))
{-# INLINE atomicNandFetchNewMutableByteArrayBits# #-}
atomicOrFetchOldMutableByteArrayBits# mba# i# y =
  atomicModifyMutableByteArray# mba# i# (\x -> (# x .|. y, x #))
{-# INLINE atomicOrFetchOldMutableByteArrayBits# #-}
atomicOrFetchNewMutableByteArrayBits# mba# i# y =
  atomicModifyMutableByteArray# mba# i# (\x -> let x' = x .|. y in (# x', x' #))
{-# INLINE atomicOrFetchNewMutableByteArrayBits# #-}
atomicXorFetchOldMutableByteArrayBits# mba# i# y =
  atomicModifyMutableByteArray# mba# i# (\x -> (# x `xor` y, x #))
{-# INLINE atomicXorFetchOldMutableByteArrayBits# #-}
atomicXorFetchNewMutableByteArrayBits# mba# i# y =
  atomicModifyMutableByteArray# mba# i# (\x -> let x' = x `xor` y in (# x', x' #))
{-# INLINE atomicXorFetchNewMutableByteArrayBits# #-}

atomicAndFetchOldOffAddrBits#
  , atomicAndFetchNewOffAddrBits#
  , atomicNandFetchOldOffAddrBits#
  , atomicNandFetchNewOffAddrBits#
  , atomicOrFetchOldOffAddrBits#
  , atomicOrFetchNewOffAddrBits#
  , atomicXorFetchOldOffAddrBits#
  , atomicXorFetchNewOffAddrBits# ::
     (Bits a, Atomic a)
  => Addr#
  -> Int#
  -> a
  -> State# s
  -> (# State# s, a #)
atomicAndFetchOldOffAddrBits# addr# i# y =
  atomicModifyOffAddr# addr# i# (\x -> (# x .&. y, x #))
{-# INLINE atomicAndFetchOldOffAddrBits# #-}
atomicAndFetchNewOffAddrBits# addr# i# y =
  atomicModifyOffAddr# addr# i# (\x -> let x' = x .&. y in (# x', x' #))
{-# INLINE atomicAndFetchNewOffAddrBits# #-}
atomicNandFetchOldOffAddrBits# addr# i# y =
  atomicModifyOffAddr# addr# i# (\x -> (# complement (x .&. y), x #))
{-# INLINE atomicNandFetchOldOffAddrBits# #-}
atomicNandFetchNewOffAddrBits# addr# i# y =
  atomicModifyOffAddr# addr# i# (\x -> let x' = complement (x .&. y) in (# x', x' #))
{-# INLINE atomicNandFetchNewOffAddrBits# #-}
atomicOrFetchOldOffAddrBits# addr# i# y =
  atomicModifyOffAddr# addr# i# (\x -> (# x .|. y, x #))
{-# INLINE atomicOrFetchOldOffAddrBits# #-}
atomicOrFetchNewOffAddrBits# addr# i# y =
  atomicModifyOffAddr# addr# i# (\x -> let x' = x .|. y in (# x', x' #))
{-# INLINE atomicOrFetchNewOffAddrBits# #-}
atomicXorFetchOldOffAddrBits# addr# i# y =
  atomicModifyOffAddr# addr# i# (\x -> (# x `xor` y, x #))
{-# INLINE atomicXorFetchOldOffAddrBits# #-}
atomicXorFetchNewOffAddrBits# addr# i# y =
  atomicModifyOffAddr# addr# i# (\x -> let x' = x `xor` y in (# x', x' #))
{-# INLINE atomicXorFetchNewOffAddrBits# #-}


instance (Bits a, Eq a, Prim a) => AtomicBits (Atom a) where
  atomicAndFetchOldMutableByteArray# = atomicAndFetchOldMutableByteArrayBits#
  {-# INLINE atomicAndFetchOldMutableByteArray# #-}
  atomicAndFetchNewMutableByteArray# = atomicAndFetchNewMutableByteArrayBits#
  {-# INLINE atomicAndFetchNewMutableByteArray# #-}
  atomicNandFetchOldMutableByteArray# = atomicNandFetchOldMutableByteArrayBits#
  {-# INLINE atomicNandFetchOldMutableByteArray# #-}
  atomicNandFetchNewMutableByteArray# = atomicNandFetchNewMutableByteArrayBits#
  {-# INLINE atomicNandFetchNewMutableByteArray# #-}
  atomicOrFetchOldMutableByteArray# = atomicOrFetchOldMutableByteArrayBits#
  {-# INLINE atomicOrFetchOldMutableByteArray# #-}
  atomicOrFetchNewMutableByteArray# = atomicOrFetchNewMutableByteArrayBits#
  {-# INLINE atomicOrFetchNewMutableByteArray# #-}
  atomicXorFetchOldMutableByteArray# = atomicXorFetchOldMutableByteArrayBits#
  {-# INLINE atomicXorFetchOldMutableByteArray# #-}
  atomicXorFetchNewMutableByteArray# = atomicXorFetchNewMutableByteArrayBits#
  {-# INLINE atomicXorFetchNewMutableByteArray# #-}
  atomicAndFetchOldOffAddr# = atomicAndFetchOldOffAddrBits#
  {-# INLINE atomicAndFetchOldOffAddr# #-}
  atomicAndFetchNewOffAddr# = atomicAndFetchNewOffAddrBits#
  {-# INLINE atomicAndFetchNewOffAddr# #-}
  atomicNandFetchOldOffAddr# = atomicNandFetchOldOffAddrBits#
  {-# INLINE atomicNandFetchOldOffAddr# #-}
  atomicNandFetchNewOffAddr# = atomicNandFetchNewOffAddrBits#
  {-# INLINE atomicNandFetchNewOffAddr# #-}
  atomicOrFetchOldOffAddr# = atomicOrFetchOldOffAddrBits#
  {-# INLINE atomicOrFetchOldOffAddr# #-}
  atomicOrFetchNewOffAddr# = atomicOrFetchNewOffAddrBits#
  {-# INLINE atomicOrFetchNewOffAddr# #-}
  atomicXorFetchOldOffAddr# = atomicXorFetchOldOffAddrBits#
  {-# INLINE atomicXorFetchOldOffAddr# #-}
  atomicXorFetchNewOffAddr# = atomicXorFetchNewOffAddrBits#
  {-# INLINE atomicXorFetchNewOffAddr# #-}