diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,5 @@
+# Changelog for `primal`
+
+## 0.1.0.0
+
+* Initial release
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Alexey Kuleshevich (c) 2020
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Alexey Kuleshevich nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,11 @@
+# primal
+
+**Warning** - it is still in experimental stage.
+
+This package attempts to combine best practices from Haskell eco-system on how to deal
+with `RealWorld`, `IO` and `ST`. It also provides quite a few primitive operations through
+FFI and C that are either not available in older GHC or not available at all.
+
+Unique functionality for unpacking complex types as well as atomic modification of such
+values.
+
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,6 @@
+module Main (main) where
+
+import Distribution.Simple
+
+main :: IO ()
+main = defaultMain
diff --git a/cbits/primal.c b/cbits/primal.c
new file mode 100644
--- /dev/null
+++ b/cbits/primal.c
@@ -0,0 +1,72 @@
+#include <HsFFI.h>
+#include <string.h>
+
+
+HsInt primal_ptreq(HsWord8 *ptr1, HsWord8 *ptr2){
+  return ptr1 == ptr2;
+}
+
+HsInt8 primal_memcmp(HsWord8 *ptr1, HsInt offset1, HsWord8 *ptr2, HsInt offset2, HsInt n){
+  return memcmp(ptr1 + offset1, ptr2 + offset2, n);
+}
+
+void primal_memmove(HsWord8 *src, HsInt src_offset, HsWord8 *dst, HsInt dst_offset, HsInt n){
+  memmove(dst + dst_offset, src + src_offset, n);
+}
+
+
+void primal_memset8(HsWord8 *ptr, HsInt offset, HsInt n, HsWord8 x){
+  memset((void *)(ptr + offset), x, n);
+}
+
+void primal_memset16(HsWord16 *ptr, HsInt offset, HsInt n, HsWord16 x){
+  HsWord8 x8 = (HsWord8) x;
+  ptr+= offset;
+  if((HsWord8) (x >> 8) == x8){
+    memset((void *)ptr, x8, n * 2);
+    return;
+  }
+  while(n > 0){
+    *ptr++ = x;
+    n--;
+  }
+}
+
+void primal_memset32(HsWord32 *ptr, HsInt offset, HsInt n, HsWord32 x){
+  HsWord8 x8 = (HsWord8) x;
+  ptr+= offset;
+  // Use memset if it is a repeating 8bit pattern
+  if((HsWord16) (x >> 16) == (HsWord16) x && (HsWord8) (x >> 24) == x8){
+    memset((void *)ptr, x8, n * 4);
+    return;
+  }
+  while(n > 0){
+    *ptr++ = x;
+    n--;
+  }
+}
+
+void primal_memset64(HsWord64 *ptr, HsInt offset, HsInt n, HsWord64 x){
+  HsWord8 x8 = (HsWord8) x;
+  HsWord32 x32 = (HsWord32) x;
+  ptr+= offset;
+  // Use memset if it is a repeating 8bit pattern
+  if((HsWord32) (x   >> 32) == x32 &&
+     (HsWord16) (x32 >> 16) == (HsWord16) x32 &&
+      (HsWord8) (x32 >> 24) == x8
+     ){
+    memset((void *)ptr, x8, n * 8);
+    return;
+  }
+  // Allow gcc to vectorize with SIMD:
+  HsWord32 *ptr32 = (HsWord32 *)ptr;
+  const HsWord32 *x32p = (const HsWord32 *)(void *)&x;
+  while (n > 0) {
+    ptr32[0] = x32p[0];
+    ptr32[1] = x32p[1];
+    ptr32+= 2;
+    n--;
+  }
+}
+
+
diff --git a/cbits/primal_atomic.c b/cbits/primal_atomic.c
new file mode 100644
--- /dev/null
+++ b/cbits/primal_atomic.c
@@ -0,0 +1,199 @@
+#include <stdbool.h>
+#include <HsFFI.h>
+
+/* See GCC reference for all of the atomic opartions in this file
+ * https://gcc.gnu.org/onlinedocs/gcc-9.3.0/gcc/_005f_005fsync-Builtins.html
+ */
+
+void primal_sync_synchronize (void) {
+  return __sync_synchronize ();
+}
+
+// There are systems that do not support other values except 1 and 0. Moreover, having 1
+// and 0 as only values is sufficient for now.
+HsInt8 primal_sync8_lock_test_set(HsInt8 mba[], HsInt i) {
+  return __sync_lock_test_and_set(&mba[i], 1);
+}
+
+void primal_sync8_lock_release(HsInt8 mba[], HsInt i) {
+  return __sync_lock_release(&mba[i]);
+}
+
+bool primal_sync8_cas_bool(HsWord8 mba[], HsInt i, HsWord8 old, HsWord8 new) {
+	return __sync_bool_compare_and_swap (&mba[i], old, new);
+}
+HsWord8 primal_sync8_cas(HsWord8 mba[], HsInt i, HsWord8 old, HsWord8 new) {
+	return __sync_val_compare_and_swap (&mba[i], old, new);
+}
+HsWord8 primal_sync8_fetch_add(HsWord8 mba[], HsInt i, HsWord8 a){
+	return __sync_fetch_and_add (&mba[i], a);
+}
+HsWord8 primal_sync8_add_fetch(HsWord8 mba[], HsInt i, HsWord8 a){
+	return __sync_add_and_fetch (&mba[i], a);
+}
+HsWord8 primal_sync8_fetch_sub(HsWord8 mba[], HsInt i, HsWord8 a){
+	return __sync_fetch_and_sub (&mba[i], a);
+}
+HsWord8 primal_sync8_sub_fetch(HsWord8 mba[], HsInt i, HsWord8 a){
+	return __sync_sub_and_fetch (&mba[i], a);
+}
+HsWord8 primal_sync8_fetch_and(HsWord8 mba[], HsInt i, HsWord8 a){
+	return __sync_fetch_and_and (&mba[i], a);
+}
+HsWord8 primal_sync8_and_fetch(HsWord8 mba[], HsInt i, HsWord8 a){
+	return __sync_and_and_fetch (&mba[i], a);
+}
+HsWord8 primal_sync8_fetch_nand(HsWord8 mba[], HsInt i, HsWord8 a){
+	return __sync_fetch_and_nand (&mba[i], a);
+}
+HsWord8 primal_sync8_nand_fetch(HsWord8 mba[], HsInt i, HsWord8 a){
+	return __sync_nand_and_fetch (&mba[i], a);
+}
+HsWord8 primal_sync8_fetch_or(HsWord8 mba[], HsInt i, HsWord8 a){
+	return __sync_fetch_and_or (&mba[i], a);
+}
+HsWord8 primal_sync8_or_fetch(HsWord8 mba[], HsInt i, HsWord8 a){
+	return __sync_or_and_fetch (&mba[i], a);
+}
+HsWord8 primal_sync8_fetch_xor(HsWord8 mba[], HsInt i, HsWord8 a){
+	return __sync_fetch_and_xor (&mba[i], a);
+}
+HsWord8 primal_sync8_xor_fetch(HsWord8 mba[], HsInt i, HsWord8 a){
+	return __sync_xor_and_fetch (&mba[i], a);
+}
+
+
+
+bool primal_sync16_cas_bool (HsWord16 mba[], HsInt i, HsWord16 old, HsWord16 new) {
+	return __sync_bool_compare_and_swap (&mba[i], old, new);
+}
+HsWord16 primal_sync16_cas (HsWord16 mba[], HsInt i, HsWord16 old, HsWord16 new) {
+	return __sync_val_compare_and_swap (&mba[i], old, new);
+}
+HsWord16 primal_sync16_fetch_add(HsWord16 mba[], HsInt i, HsWord16 a){
+	return __sync_fetch_and_add (&mba[i], a);
+}
+HsWord16 primal_sync16_add_fetch(HsWord16 mba[], HsInt i, HsWord16 a){
+	return __sync_add_and_fetch (&mba[i], a);
+}
+HsWord16 primal_sync16_fetch_sub(HsWord16 mba[], HsInt i, HsWord16 a){
+	return __sync_fetch_and_sub (&mba[i], a);
+}
+HsWord16 primal_sync16_sub_fetch(HsWord16 mba[], HsInt i, HsWord16 a){
+	return __sync_sub_and_fetch (&mba[i], a);
+}
+HsWord16 primal_sync16_fetch_and(HsWord16 mba[], HsInt i, HsWord16 a){
+	return __sync_fetch_and_and (&mba[i], a);
+}
+HsWord16 primal_sync16_and_fetch(HsWord16 mba[], HsInt i, HsWord16 a){
+	return __sync_and_and_fetch (&mba[i], a);
+}
+HsWord16 primal_sync16_fetch_nand(HsWord16 mba[], HsInt i, HsWord16 a){
+	return __sync_fetch_and_nand (&mba[i], a);
+}
+HsWord16 primal_sync16_nand_fetch(HsWord16 mba[], HsInt i, HsWord16 a){
+	return __sync_nand_and_fetch (&mba[i], a);
+}
+HsWord16 primal_sync16_fetch_or(HsWord16 mba[], HsInt i, HsWord16 a){
+	return __sync_fetch_and_or (&mba[i], a);
+}
+HsWord16 primal_sync16_or_fetch(HsWord16 mba[], HsInt i, HsWord16 a){
+	return __sync_or_and_fetch (&mba[i], a);
+}
+HsWord16 primal_sync16_fetch_xor(HsWord16 mba[], HsInt i, HsWord16 a){
+	return __sync_fetch_and_xor (&mba[i], a);
+}
+HsWord16 primal_sync16_xor_fetch(HsWord16 mba[], HsInt i, HsWord16 a){
+	return __sync_xor_and_fetch (&mba[i], a);
+}
+
+
+
+bool primal_sync32_cas_bool (HsWord32 mba[], HsInt i, HsWord32 old, HsWord32 new) {
+	return __sync_bool_compare_and_swap (&mba[i], old, new);
+}
+HsWord32 primal_sync32_cas (HsWord32 mba[], HsInt i, HsWord32 old, HsWord32 new) {
+	return __sync_val_compare_and_swap (&mba[i], old, new);
+}
+HsWord32 primal_sync32_fetch_add(HsWord32 mba[], HsInt i, HsWord32 a){
+	return __sync_fetch_and_add (&mba[i], a);
+}
+HsWord32 primal_sync32_add_fetch(HsWord32 mba[], HsInt i, HsWord32 a){
+	return __sync_add_and_fetch (&mba[i], a);
+}
+HsWord32 primal_sync32_fetch_sub(HsWord32 mba[], HsInt i, HsWord32 a){
+	return __sync_fetch_and_sub (&mba[i], a);
+}
+HsWord32 primal_sync32_sub_fetch(HsWord32 mba[], HsInt i, HsWord32 a){
+	return __sync_sub_and_fetch (&mba[i], a);
+}
+HsWord32 primal_sync32_fetch_and(HsWord32 mba[], HsInt i, HsWord32 a){
+	return __sync_fetch_and_and (&mba[i], a);
+}
+HsWord32 primal_sync32_and_fetch(HsWord32 mba[], HsInt i, HsWord32 a){
+	return __sync_and_and_fetch (&mba[i], a);
+}
+HsWord32 primal_sync32_fetch_nand(HsWord32 mba[], HsInt i, HsWord32 a){
+	return __sync_fetch_and_nand (&mba[i], a);
+}
+HsWord32 primal_sync32_nand_fetch(HsWord32 mba[], HsInt i, HsWord32 a){
+	return __sync_nand_and_fetch (&mba[i], a);
+}
+HsWord32 primal_sync32_fetch_or(HsWord32 mba[], HsInt i, HsWord32 a){
+	return __sync_fetch_and_or (&mba[i], a);
+}
+HsWord32 primal_sync32_or_fetch(HsWord32 mba[], HsInt i, HsWord32 a){
+	return __sync_or_and_fetch (&mba[i], a);
+}
+HsWord32 primal_sync32_fetch_xor(HsWord32 mba[], HsInt i, HsWord32 a){
+	return __sync_fetch_and_xor (&mba[i], a);
+}
+HsWord32 primal_sync32_xor_fetch(HsWord32 mba[], HsInt i, HsWord32 a){
+	return __sync_xor_and_fetch (&mba[i], a);
+}
+
+
+bool primal_sync_cas_bool (HsWord mba[], HsInt i, HsWord old, HsWord new) {
+	return __sync_bool_compare_and_swap (&mba[i], old, new);
+}
+HsWord primal_sync_cas (HsWord mba[], HsInt i, HsWord old, HsWord new) {
+	return __sync_val_compare_and_swap (&mba[i], old, new);
+}
+HsWord primal_sync_fetch_add(HsWord mba[], HsInt i, HsWord a){
+	return __sync_fetch_and_add (&mba[i], a);
+}
+HsWord primal_sync_add_fetch(HsWord mba[], HsInt i, HsWord a){
+	return __sync_add_and_fetch (&mba[i], a);
+}
+HsWord primal_sync_fetch_sub(HsWord mba[], HsInt i, HsWord a){
+	return __sync_fetch_and_sub (&mba[i], a);
+}
+HsWord primal_sync_sub_fetch(HsWord mba[], HsInt i, HsWord a){
+	return __sync_sub_and_fetch (&mba[i], a);
+}
+HsWord primal_sync_fetch_and(HsWord mba[], HsInt i, HsWord a){
+	return __sync_fetch_and_and (&mba[i], a);
+}
+HsWord primal_sync_and_fetch(HsWord mba[], HsInt i, HsWord a){
+	return __sync_and_and_fetch (&mba[i], a);
+}
+HsWord primal_sync_fetch_nand(HsWord mba[], HsInt i, HsWord a){
+	return __sync_fetch_and_nand (&mba[i], a);
+}
+HsWord primal_sync_nand_fetch(HsWord mba[], HsInt i, HsWord a){
+	return __sync_nand_and_fetch (&mba[i], a);
+}
+HsWord primal_sync_fetch_or(HsWord mba[], HsInt i, HsWord a){
+	return __sync_fetch_and_or (&mba[i], a);
+}
+HsWord primal_sync_or_fetch(HsWord mba[], HsInt i, HsWord a){
+	return __sync_or_and_fetch (&mba[i], a);
+}
+HsWord primal_sync_fetch_xor(HsWord mba[], HsInt i, HsWord a){
+	return __sync_fetch_and_xor (&mba[i], a);
+}
+HsWord primal_sync_xor_fetch(HsWord mba[], HsInt i, HsWord a){
+	return __sync_xor_and_fetch (&mba[i], a);
+}
+
+
diff --git a/cbits/primal_compat.c b/cbits/primal_compat.c
new file mode 100644
--- /dev/null
+++ b/cbits/primal_compat.c
@@ -0,0 +1,51 @@
+#if __GLASGOW_HASKELL__ < 806
+
+#include "Rts.h"
+#include <HsFFI.h>
+#include <string.h>
+
+HsWord16 primal_memread16(const HsWord8 *ptr, HsInt offset){
+  return *((HsWord16 *)(ptr + offset));
+}
+void primal_memwrite16(HsWord8 *ptr, HsInt offset, HsWord16 x){
+  *((HsWord16 *)(ptr + offset)) = x;
+}
+
+HsWord32 primal_memread32(const HsWord8 *ptr, HsInt offset){
+  return *((HsWord32 *)(ptr + offset));
+}
+void primal_memwrite32(HsWord8 *ptr, HsInt offset, HsWord32 x){
+  *((HsWord32 *)(ptr + offset)) = x;
+}
+
+HsWord64 primal_memread64(const HsWord8 *ptr, HsInt offset){
+  return *((HsWord64 *)(ptr + offset));
+}
+void primal_memwrite64(HsWord8 *ptr, HsInt offset, HsWord64 x){
+  *((HsWord64 *)(ptr + offset)) = x;
+}
+
+#if __GLASGOW_HASKELL__ < 802
+/**
+ * Rewrite of some Cmm in C. It is not in Cmm because `bdescr_flags` is not available
+ * until this commit:
+ * https://gitlab.haskell.org/ghc/ghc/commit/310371ff2d5b73cdcb2439b67170ca5e613541c0
+ *
+ * Cmm version can be found here:
+ * https://gitlab.haskell.org/ghc/ghc/blob/4e8a71c1138b587dfbab8a1823b3f7fa6f0166bd/rts/PrimOps.cmm#L157-174
+ *
+ * Its types in Haskell are:
+ * - `ByteArray# -> Int#`
+ * - `MutableByteArray# s -> Int#`
+ *
+ */
+HsInt primal_is_byte_array_pinned(StgPtr ba){
+  bdescr *bd = Bdescr(ba);
+  // All of BF_PINNED, BF_LARGE and BF_COMPACT are considered immovable. Although
+  // BF_COMPACT is only available in ghc-8.2, so we don't care about it.
+  return ((bd->flags & (BF_PINNED | BF_LARGE)) != 0);
+}
+#endif /* __GLASGOW_HASKELL__ < 802 */
+
+
+#endif /* __GLASGOW_HASKELL__ < 806 */
diff --git a/cbits/primal_compat.h b/cbits/primal_compat.h
new file mode 100644
--- /dev/null
+++ b/cbits/primal_compat.h
@@ -0,0 +1,5 @@
+#pragma once
+
+#ifndef HTYPE_BOOL
+#define HTYPE_BOOL Word8
+#endif
diff --git a/cbits/primal_stg.cmm b/cbits/primal_stg.cmm
new file mode 100644
--- /dev/null
+++ b/cbits/primal_stg.cmm
@@ -0,0 +1,78 @@
+/* Copied from ghc for backwards compatibility:
+ * https://gitlab.haskell.org/ghc/ghc/-/blob/6d172e63f3dd3590b0a57371efb8f924f1fcdf05/libraries/base/cbits/CastFloatWord.cmm
+*/
+#include "Cmm.h"
+#include "MachDeps.h"
+
+#if WORD_SIZE_IN_BITS == 64
+#define DOUBLE_SIZE_WDS   1
+#else
+#define DOUBLE_SIZE_WDS   2
+#endif
+
+#if SIZEOF_W == 4
+#define TO_ZXW_(x) %zx32(x)
+#elif SIZEOF_W == 8
+#define TO_ZXW_(x) %zx64(x)
+#endif
+
+primal_stg_word64ToDoublezh(I64 w)
+{
+    D_ d;
+    P_ ptr;
+
+    STK_CHK_GEN_N (DOUBLE_SIZE_WDS);
+
+    reserve DOUBLE_SIZE_WDS = ptr {
+        I64[ptr] = w;
+        d = D_[ptr];
+    }
+
+    return (d);
+}
+
+primal_stg_doubleToWord64zh(D_ d)
+{
+    I64 w;
+    P_ ptr;
+
+    STK_CHK_GEN_N (DOUBLE_SIZE_WDS);
+
+    reserve DOUBLE_SIZE_WDS = ptr {
+        D_[ptr] = d;
+        w = I64[ptr];
+    }
+
+    return (w);
+}
+
+primal_stg_word32ToFloatzh(W_ w)
+{
+    F_ f;
+    P_ ptr;
+
+    STK_CHK_GEN_N (1);
+
+    reserve 1 = ptr {
+        I32[ptr] = %lobits32(w);
+        f = F_[ptr];
+    }
+
+    return (f);
+}
+
+primal_stg_floatToWord32zh(F_ f)
+{
+    W_ w;
+    P_ ptr;
+
+    STK_CHK_GEN_N (1);
+
+    reserve 1 = ptr {
+        F_[ptr] = f;
+        // Fix #16617: use zero-extending (TO_ZXW_) here
+        w = TO_ZXW_(I32[ptr]);
+    }
+
+    return (w);
+}
diff --git a/primal.cabal b/primal.cabal
new file mode 100644
--- /dev/null
+++ b/primal.cabal
@@ -0,0 +1,86 @@
+name:                primal
+version:             0.1.0.0
+synopsis:            Primeval world of Haskell.
+description:         Please see the README on GitHub at <https://github.com/lehins/primal#readme>
+homepage:            https://github.com/lehins/primal
+license:             BSD3
+license-file:        LICENSE
+author:              Alexey Kuleshevich
+maintainer:          alexey@kuleshevi.ch
+copyright:           2020 Alexey Kuleshevich
+category:            Algorithms
+build-type:          Simple
+extra-source-files:  README.md
+                   , CHANGELOG.md
+cabal-version:       1.18
+tested-with:         GHC == 8.4.3
+                   , GHC == 8.4.4
+                   , GHC == 8.6.3
+                   , GHC == 8.6.4
+                   , GHC == 8.6.5
+                   , GHC == 8.8.1
+                   , GHC == 8.8.2
+                   , GHC == 8.10.1
+
+library
+  hs-source-dirs:      src
+  exposed-modules:     Control.Prim.Concurrent
+                     , Control.Prim.Eval
+                     , Control.Prim.Exception
+                     , Control.Prim.Monad
+                     , Control.Prim.Monad.Throw
+                     , Control.Prim.Monad.Unsafe
+                     , Data.Prim
+                     , Data.Prim.Atom
+                     , Data.Prim.Atomic
+                     , Data.Prim.Class
+                     , Data.Prim.StableName
+                     , Foreign.Prim
+                     , Foreign.Prim.Ptr
+                     , Foreign.Prim.StablePtr
+                     , Foreign.Prim.WeakPtr
+
+  other-modules:       Control.Prim.Monad.Internal
+                     , Foreign.Prim.C
+                     , Foreign.Prim.C.Atomic
+                     , Foreign.Prim.C.LtGHC802
+                     , Foreign.Prim.C.LtGHC806
+                     , Foreign.Prim.Cmm
+  build-depends:       base >= 4.8 && < 5
+                     , deepseq
+                     , transformers
+
+  default-language:    Haskell2010
+  ghc-options:         -Wall
+  c-sources: cbits/primal.c
+           , cbits/primal_atomic.c
+           , cbits/primal_stg.cmm
+  cc-options: -Wno-sync-nand
+  if impl(ghc < 8.6)
+     c-sources: cbits/primal_compat.c
+     if impl(ghc < 8.4)
+        build-depends: ghc-prim
+        if impl(ghc < 8.2)
+           include-dirs: cbits
+           install-includes: primal_compat.h
+  if !os(solaris)
+      cc-options: -ftree-vectorize
+  if arch(i386) || arch(x86_64)
+      cc-options: -msse2
+
+test-suite doctests
+  type:             exitcode-stdio-1.0
+  hs-source-dirs:   tests
+  main-is:          doctests.hs
+  build-depends: base
+               , doctest >=0.15
+               , primal
+               , template-haskell
+  default-language:    Haskell2010
+  ghc-options:        -Wall
+                      -threaded
+
+
+source-repository head
+  type:     git
+  location: https://github.com/lehins/primal
diff --git a/src/Control/Prim/Concurrent.hs b/src/Control/Prim/Concurrent.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Prim/Concurrent.hs
@@ -0,0 +1,129 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE UnliftedFFITypes #-}
+-- |
+-- Module      : Control.Prim.Concurrent
+-- Copyright   : (c) Alexey Kuleshevich 2020
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Control.Prim.Concurrent
+  ( module Control.Prim.Concurrent
+  ) where
+
+import qualified Control.Exception as GHC
+import qualified GHC.Conc as GHC
+import Control.Prim.Exception
+import Control.Prim.Monad.Internal
+import GHC.Exts
+import System.Posix.Types
+import Foreign.C.Types
+
+
+spark :: MonadPrim s m => a -> m a
+spark a = prim (spark# a)
+
+numSparks :: MonadPrim s m => m Int
+numSparks =
+  prim $ \s ->
+    case numSparks# s of
+      (# s', n# #) -> (# s', I# n# #)
+
+runSparks :: MonadPrim s m => m ()
+runSparks = prim_ loop
+  where
+    loop s =
+      case getSpark# s of
+        (# s', n#, p #) ->
+          if isTrue# (n# ==# 0#)
+            then s'
+            else p `seq` loop s'
+
+-- | Wrapper for `delay#`. Sleep specified number of microseconds. Not designed for
+-- threaded runtime: __Errors when compiled with @-threaded@__
+delay :: MonadPrim s m => Int -> m ()
+delay (I# i#) = prim_ (delay# i#)
+
+-- | Wrapper for `waitRead#`. Block and wait for input to become available on the
+-- `Fd`. Not designed for threaded runtime: __Errors when compiled with @-threaded@__
+waitRead :: MonadPrim s m => Fd -> m ()
+waitRead fd =
+  case fromIntegral fd of
+    I# i# -> prim_ (waitRead# i#)
+
+
+-- | Wrapper for `waitWrite#`. Block and wait until output is possible on the `Fd`.
+-- Not designed for threaded runtime: __Errors when compiled with @-threaded@__
+waitWrite :: MonadPrim s m => Fd -> m ()
+waitWrite fd =
+  case fromIntegral fd of
+    I# i# -> prim_ (waitWrite# i#)
+
+-- | Wrapper around `fork#`. Unlike `Control.Concurrent.forkIO` it does not install
+-- any exception handlers on the action, so you need make sure to do it yourself.
+fork :: MonadPrim RW m => m () -> m GHC.ThreadId
+fork action =
+  prim $ \s ->
+    case fork# action s of
+      (# s', tid# #) -> (# s', GHC.ThreadId tid# #)
+
+-- | Wrapper around `forkOn#`. Unlike `Control.Concurrent.forkOn` it does not install any
+-- exception handlers on the action, so you need make sure to do it yourself.
+forkOn :: MonadPrim RW m => Int -> m () -> m GHC.ThreadId
+forkOn (I# cap#) action =
+  prim $ \s ->
+    case forkOn# cap# action s of
+      (# s', tid# #) -> (# s', GHC.ThreadId tid# #)
+
+-- | Wrapper around `killThread#`, which throws `GHC.ThreadKilled` exception in the target
+-- thread. Use `throwTo` if you want a different exception to be thrown.
+killThread :: MonadPrim RW m => GHC.ThreadId -> m ()
+killThread tid = throwTo tid GHC.ThreadKilled
+
+
+-- | Wrapper around `yield#`.
+yield :: MonadPrim RW m => m ()
+yield = prim_ yield#
+
+-- | Wrapper around `myThreadId#`.
+myThreadId :: MonadPrim RW m => m GHC.ThreadId
+myThreadId =
+  prim $ \s ->
+    case myThreadId# s of
+      (# s', tid# #) -> (# s', GHC.ThreadId tid# #)
+
+-- | Pointer should refer to UTF8 encoded string of bytes
+labelThread :: MonadPrim RW m => GHC.ThreadId -> Ptr a -> m ()
+labelThread (GHC.ThreadId tid#) (Ptr addr#) = prim_ (labelThread# tid# addr#)
+
+isCurrentThreadBoundPrim :: MonadPrim RW m => m Bool
+isCurrentThreadBoundPrim =
+  prim $ \s ->
+    case isCurrentThreadBound# s of
+      (# s', bool# #) -> (# s', isTrue# bool# #)
+
+threadStatus :: MonadPrim RW m => GHC.ThreadId -> m GHC.ThreadStatus
+threadStatus = liftPrimBase . GHC.threadStatus
+
+threadCapability :: MonadPrim RW m => GHC.ThreadId -> m (Int, Bool)
+threadCapability = liftPrimBase . GHC.threadCapability
+
+-- | Something that is not available in @base@. Convert a `GHC.ThreadId` to a regular
+-- integral type.
+--
+-- @since 0.0.0
+threadIdToCInt :: GHC.ThreadId -> CInt
+threadIdToCInt tid = getThreadId (id2TSO tid)
+
+id2TSO :: GHC.ThreadId -> ThreadId#
+id2TSO (GHC.ThreadId t) = t
+
+-- Relevant ticket: https://gitlab.haskell.org/ghc/ghc/-/issues/8281
+foreign import ccall unsafe "rts_getThreadId" getThreadId :: ThreadId# -> CInt
+
+
diff --git a/src/Control/Prim/Eval.hs b/src/Control/Prim/Eval.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Prim/Eval.hs
@@ -0,0 +1,91 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE UnboxedTuples #-}
+-- |
+-- Module      : Control.Prim.Eval
+-- Copyright   : (c) Alexey Kuleshevich 2020
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Control.Prim.Eval
+  ( module Control.Prim.Eval
+  ) where
+
+import Control.Prim.Monad.Internal
+import Control.Prim.Monad.Unsafe
+import GHC.Exts
+
+
+
+------- Evaluation
+
+
+-- | This is an action that ensures that the value is still available and garbage
+-- collector has not cleaned it up.
+--
+-- Make sure not to use it after some computation that doesn't return, like after
+-- `forever` for example, otherwise touch will simply be removed by ghc and bad things
+-- will happen. If you have a case like that, make sure to use `withAlivePrimBase` or
+-- `withAliveUnliftPrim` instead.
+--
+-- @since 0.1.0
+touch :: MonadPrim s m => a -> m ()
+touch x = unsafeIOToPrim $ prim_ (touch# x)
+{-# INLINE touch #-}
+
+-- | An action that evaluates a value to weak head normal form. Same
+-- as `Control.Exception.evaluate`, except it works in a `MonadPrim`
+--
+-- @since 0.1.0
+seqPrim :: MonadPrim s m => a -> m a
+seqPrim a = prim (seq# a)
+
+
+-- | Forward compatible operator that might be introduced in some future ghc version.
+--
+-- See: [!3131](https://gitlab.haskell.org/ghc/ghc/-/merge_requests/3131)
+--
+-- Current version is not as efficient as the version that will be introduced in the
+-- future, because it works around the ghc bug by simply preventing inlining and relying
+-- on the `touch` function.
+--
+-- @since 0.1.0
+keepAlive# ::
+     a
+  -- ^ The value to preserve
+  -> (State# s -> (# State# s, r #))
+  -- ^ The continuation in which the value will be preserved
+  -> State# s
+  -> (# State# s, r #)
+keepAlive# a m s =
+  case m s of
+    (# s', r #) -> (# unsafeCoerce# (touch# a) s', r #)
+{-# NOINLINE keepAlive# #-}
+
+-- | Similar to `touch`. See `withAlive#` for more info.
+--
+-- @since 0.1.0
+withAlivePrimBase :: (MonadPrimBase s n, MonadPrim s m) => a
+  -- ^ The value to preserve
+  -> n b
+  -- ^ Action to run in which the value will be preserved
+  -> m b
+withAlivePrimBase a m = prim (keepAlive# a (primBase m))
+{-# INLINE withAlivePrimBase #-}
+
+-- | Similar to `touch`. See `withAlive#` for more info.
+--
+-- @since 0.1.0
+withAliveUnliftPrim ::
+     MonadUnliftPrim s m
+  => a
+  -- ^ The value to preserve
+  -> m b
+  -- ^ Action to run in which the value will be preserved
+  -> m b
+withAliveUnliftPrim a m = runInPrimBase m (keepAlive# a)
+{-# INLINE withAliveUnliftPrim #-}
diff --git a/src/Control/Prim/Exception.hs b/src/Control/Prim/Exception.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Prim/Exception.hs
@@ -0,0 +1,132 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE UnboxedTuples #-}
+-- |
+-- Module      : Control.Prim.Exception
+-- Copyright   : (c) Alexey Kuleshevich 2020
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Control.Prim.Exception
+  ( module Control.Prim.Monad.Throw
+  , module Control.Prim.Exception
+  ) where
+
+import Control.Prim.Monad.Throw
+import Control.Exception as GHC
+import qualified GHC.Conc as GHC
+import Control.Prim.Monad.Internal
+import Control.Prim.Monad.Unsafe
+import GHC.Exts
+
+
+
+----- Exceptions
+
+isSyncException :: Exception e => e -> Bool
+isSyncException = not . isAsyncException
+
+isAsyncException :: Exception e => e -> Bool
+isAsyncException exc =
+  case fromException (toException exc) of
+    Just (SomeAsyncException _) -> True
+    Nothing -> False
+
+-- | This is the same as `throwM`, but restricted to `MonadPrim`
+throwPrim :: (Exception e, MonadPrim s m) => e -> m a
+throwPrim e = unsafeIOToPrim $ prim (raiseIO# (toException e))
+
+catch ::
+     forall e a m. (Exception e, MonadUnliftPrim RW m)
+  => m a
+  -> (e -> m a)
+  -> m a
+catch action handler =
+  withRunInPrimBase $ \run ->
+    let handler# :: SomeException -> (State# RW -> (# State# RW, a #))
+        handler# e =
+          case fromException e of
+            Just e' -> primBase (run (handler e') :: IO a)
+            Nothing -> raiseIO# e
+     in prim (catch# (primBase (run action :: IO a)) handler#)
+
+catchAny ::
+     forall a m. MonadUnliftPrim RW m
+  => m a
+  -> (SomeException -> m a)
+  -> m a
+catchAny action handler =
+  withRunInPrimBase $ \run ->
+    let handler# :: SomeException -> (State# RW -> (# State# RW, a #))
+        handler# exc = primBase (run (handler exc) :: IO a)
+     in prim (catch# (primBase (run action :: IO a)) handler#)
+
+catchAnySync ::
+     forall a m. MonadUnliftPrim RW m
+  => m a
+  -> (SomeException -> m a)
+  -> m a
+catchAnySync action handler =
+  withRunInPrimBase $ \run ->
+    let handler# :: SomeException -> (State# RW -> (# State# RW, a #))
+        handler# exc
+          | isAsyncException exc = raiseIO# exc
+          | otherwise = primBase (run (handler exc) :: IO a)
+     in prim (catch# (primBase (run action :: IO a)) handler#)
+
+catchAll ::
+     forall a m. MonadUnliftPrim RW m
+  => m a
+  -> (forall e . Exception e => e -> m a)
+  -> m a
+catchAll action handler =
+  withRunInPrimBase $ \run ->
+    let handler# :: SomeException -> (State# RW -> (# State# RW, a #))
+        handler# (SomeException e) = primBase (run (handler e) :: IO a)
+     in prim (catch# (primBase (run action :: IO a)) handler#)
+
+catchAllSync ::
+     forall a m. MonadUnliftPrim RW m
+  => m a
+  -> (forall e . Exception e => e -> m a)
+  -> m a
+catchAllSync action handler =
+  withRunInPrimBase $ \run ->
+    let handler# :: SomeException -> (State# RW -> (# State# RW, a #))
+        handler# exc@(SomeException e)
+          | isAsyncException exc = raiseIO# exc
+          | otherwise = primBase (run (handler e) :: IO a)
+     in prim (catch# (primBase (run action :: IO a)) handler#)
+
+
+maskAsyncExceptions :: forall a m. MonadUnliftPrim RW m => m a -> m a
+maskAsyncExceptions action =
+  withRunInPrimBase $ \run -> prim (maskAsyncExceptions# (primBase (run action :: IO a)))
+
+unmaskAsyncExceptions :: forall a m. MonadUnliftPrim RW m => m a -> m a
+unmaskAsyncExceptions action =
+  withRunInPrimBase $ \run -> prim (unmaskAsyncExceptions# (primBase (run action :: IO a)))
+
+maskUninterruptible :: forall a m. MonadUnliftPrim RW m => m a -> m a
+maskUninterruptible action =
+  withRunInPrimBase $ \run -> prim (maskUninterruptible# (primBase (run action :: IO a)))
+
+-- | Same as `GHC.getMaskingState`, but generalized to `MonadPrim`
+getMaskingState :: MonadPrim RW m => m MaskingState
+getMaskingState = liftPrimBase GHC.getMaskingState
+
+-- | Similar to @throwTo@ from
+-- [unliftio](https://hackage.haskell.org/package/unliftio/docs/UnliftIO-Exception.html#v:throwTo)
+-- this will wrap any known non-async exception with `SomeAsyncException`, because
+-- otherwise semantics of `throwTo` with respect to asynchronous exceptions are violated.
+throwTo :: (MonadPrim RW m, Exception e) => GHC.ThreadId -> e -> m ()
+throwTo tid e =
+  liftPrimBase $
+  GHC.throwTo tid $
+  if isAsyncException e
+    then toException e
+    else toException $ SomeAsyncException e
diff --git a/src/Control/Prim/Monad.hs b/src/Control/Prim/Monad.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Prim/Monad.hs
@@ -0,0 +1,28 @@
+-- |
+-- Module      : Control.Prim.Monad
+-- Copyright   : (c) Alexey Kuleshevich 2020
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Control.Prim.Monad
+  ( module Control.Prim.Monad.Internal
+  , touch
+  , seqPrim
+  , withAlivePrimBase
+  , withAliveUnliftPrim
+  , showsType
+  -- * Re-export
+  , module Control.Monad
+  ) where
+
+import GHC.Exts
+import Control.Prim.Eval
+import Control.Prim.Monad.Internal
+import Data.Typeable
+import Control.Monad
+
+-- | Helper function that converts a type into a string
+showsType :: Typeable t => proxy t -> ShowS
+showsType = showsTypeRep . typeRep
diff --git a/src/Control/Prim/Monad/Internal.hs b/src/Control/Prim/Monad/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Prim/Monad/Internal.hs
@@ -0,0 +1,223 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE UndecidableInstances #-}
+-- |
+-- Module      : Control.Prim.Monad.Internal
+-- Copyright   : (c) Alexey Kuleshevich 2020
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Control.Prim.Monad.Internal
+  ( RW
+  , RealWorld
+  , MonadPrim(..)
+  , MonadPrimBase(..)
+  , MonadUnliftPrim(..)
+  , prim_
+  , primBase_
+  , runInPrimBase
+  , liftPrimIO
+  , liftPrimST
+  , liftPrimBase
+  , primBaseToIO
+  , primBaseToST
+  ) where
+
+import GHC.Exts
+import GHC.IO
+import GHC.ST
+import Control.Prim.Monad.Throw
+import Control.Monad.Trans.Class (lift)
+import Control.Monad.Trans.Cont (ContT)
+import Control.Monad.Trans.Except (ExceptT)
+import Control.Monad.Trans.Identity (IdentityT(..))
+import Control.Monad.Trans.Maybe (MaybeT)
+import Control.Monad.Trans.Reader (ReaderT(..))
+import Control.Monad.Trans.RWS.Lazy as Lazy (RWST)
+import Control.Monad.Trans.RWS.Strict as Strict (RWST)
+import Control.Monad.Trans.State.Lazy as Lazy (StateT)
+import Control.Monad.Trans.State.Strict as Strict (StateT)
+import Control.Monad.Trans.Writer.Lazy as Lazy (WriterT)
+import Control.Monad.Trans.Writer.Strict as Strict (WriterT)
+
+#if MIN_VERSION_transformers(0, 5, 3)
+import Control.Monad.Trans.Accum (AccumT)
+import Control.Monad.Trans.Select (SelectT)
+#if MIN_VERSION_transformers(0, 5, 6)
+import Control.Monad.Trans.RWS.CPS as CPS (RWST)
+import Control.Monad.Trans.Writer.CPS as CPS (WriterT)
+#endif
+#endif
+
+-- | A shorter synonym for the magical `RealWorld`
+type RW = RealWorld
+
+class MonadUnliftPrim s m => MonadPrimBase s m where
+  -- | Unwrap a primitive action
+  primBase :: m a -> State# s -> (# State# s, a #)
+
+instance MonadPrimBase RealWorld IO where
+  primBase (IO m) = m
+  {-# INLINE primBase #-}
+
+instance MonadPrimBase s (ST s) where
+  primBase (ST m) = m
+  {-# INLINE primBase #-}
+
+instance MonadPrimBase s m => MonadPrimBase s (IdentityT m) where
+  primBase (IdentityT m) = primBase m
+  {-# INLINE primBase #-}
+
+runInPrimBase ::
+     forall s m a b. MonadUnliftPrim s m
+  => m a
+  -> ((State# s -> (# State# s, a #)) -> State# s -> (# State# s, b #))
+  -> m b
+runInPrimBase f g =
+  withRunInPrimBase (\run -> prim (g (primBase (run f :: ST s a))))
+{-# INLINE runInPrimBase #-}
+
+class MonadPrim s m => MonadUnliftPrim s m where
+  withRunInPrimBase :: MonadPrimBase s n => ((forall a. m a -> n a) -> n b) -> m b
+
+instance MonadUnliftPrim RealWorld IO where
+  withRunInPrimBase inner = liftPrimBase (inner liftPrimBase)
+  {-# INLINE withRunInPrimBase #-}
+
+instance MonadUnliftPrim s (ST s) where
+  withRunInPrimBase inner = liftPrimBase (inner liftPrimBase)
+  {-# INLINE withRunInPrimBase #-}
+
+instance MonadUnliftPrim s m => MonadUnliftPrim s (IdentityT m) where
+  withRunInPrimBase inner =
+    IdentityT $ withRunInPrimBase $ \run -> inner (run . runIdentityT)
+  {-# INLINE withRunInPrimBase #-}
+
+instance MonadUnliftPrim s m => MonadUnliftPrim s (ReaderT r m) where
+  withRunInPrimBase inner =
+    ReaderT $ \r -> withRunInPrimBase $ \run -> inner (run . flip runReaderT r)
+  {-# INLINE withRunInPrimBase #-}
+
+
+class MonadThrow m => MonadPrim s m | m -> s where
+  -- | Construct a primitive action
+  prim :: (State# s -> (# State# s, a #)) -> m a
+
+instance MonadPrim RealWorld IO where
+  prim = IO
+  {-# INLINE prim #-}
+
+instance MonadPrim s (ST s) where
+  prim = ST
+  {-# INLINE prim #-}
+
+
+instance MonadPrim s m => MonadPrim s (ContT r m) where
+  prim = lift . prim
+  {-# INLINE prim #-}
+
+instance MonadPrim s m => MonadPrim s (ExceptT e m) where
+  prim = lift . prim
+  {-# INLINE prim #-}
+
+instance MonadPrim s m => MonadPrim s (IdentityT m) where
+  prim = lift . prim
+  {-# INLINE prim #-}
+
+instance MonadPrim s m => MonadPrim s (MaybeT m) where
+  prim = lift . prim
+  {-# INLINE prim #-}
+
+instance MonadPrim s m => MonadPrim s (ReaderT r m) where
+  prim = lift . prim
+  {-# INLINE prim #-}
+
+
+instance (Monoid w, MonadPrim s m) => MonadPrim s (Lazy.RWST r w st m) where
+  prim = lift . prim
+  {-# INLINE prim #-}
+instance (Monoid w, MonadPrim s m) => MonadPrim s (Strict.RWST r w st m) where
+  prim = lift . prim
+  {-# INLINE prim #-}
+
+instance MonadPrim s m => MonadPrim s (Lazy.StateT st m) where
+  prim = lift . prim
+  {-# INLINE prim #-}
+instance MonadPrim s m => MonadPrim s (Strict.StateT st m) where
+  prim = lift . prim
+  {-# INLINE prim #-}
+
+instance (Monoid w, MonadPrim s m) => MonadPrim s (Lazy.WriterT w m) where
+  prim = lift . prim
+  {-# INLINE prim #-}
+instance (Monoid w, MonadPrim s m) => MonadPrim s (Strict.WriterT w m) where
+  prim = lift . prim
+  {-# INLINE prim #-}
+
+
+#if MIN_VERSION_transformers(0, 5, 3)
+
+instance (Monoid w, MonadPrim s m) => MonadPrim s (AccumT w m) where
+  prim = lift . prim
+  {-# INLINE prim #-}
+instance MonadPrim s m => MonadPrim s (SelectT r m) where
+  prim = lift . prim
+  {-# INLINE prim #-}
+
+#if MIN_VERSION_transformers(0, 5, 6)
+
+instance MonadPrim s m => MonadPrim s (CPS.RWST r w st m) where
+  prim = lift . prim
+  {-# INLINE prim #-}
+instance MonadPrim s m => MonadPrim s (CPS.WriterT w m) where
+  prim = lift . prim
+  {-# INLINE prim #-}
+
+#endif
+#endif
+
+primBase_ :: MonadPrimBase s m => m () -> State# s -> State# s
+primBase_ m s = case primBase m s of
+                  (# s', () #) -> s'
+{-# INLINE primBase_ #-}
+
+-- | Construct a primitive action that does not return anything.
+prim_ :: MonadPrim s m => (State# s -> State# s) -> m ()
+prim_ f = prim $ \s -> (# f s, () #)
+{-# INLINE prim_ #-}
+
+-- | Lift an `IO` action to `MonadPrim` with the `RealWorld` state token. Type restricted
+-- synonym for `liftPrimBase`
+liftPrimIO :: MonadPrim RW m => IO a -> m a
+liftPrimIO m = prim (primBase m)
+{-# INLINE liftPrimIO #-}
+
+-- | Lift an `ST` action to `MonadPrim` with the same state token. Type restricted synonym
+-- for `liftPrimBase`
+liftPrimST :: MonadPrim s m => ST s a -> m a
+liftPrimST m = prim (primBase m)
+{-# INLINE liftPrimST #-}
+
+-- | Lift an action from the `MonadPrimBase` to another `MonadPrim` with the same state
+-- token.
+liftPrimBase :: (MonadPrimBase s n, MonadPrim s m) => n a -> m a
+liftPrimBase m = prim (primBase m)
+{-# INLINE liftPrimBase #-}
+
+-- | Restrict a `MonadPrimBase` action that works with `RealWorld` to `IO`.
+primBaseToIO :: MonadPrimBase RealWorld m => m a -> IO a
+primBaseToIO = liftPrimBase
+{-# INLINE primBaseToIO #-}
+
+-- | Restrict a `MonadPrimBase` action that works in `ST`.
+primBaseToST :: MonadPrimBase s m => m a -> ST s a
+primBaseToST = liftPrimBase
+{-# INLINE primBaseToST #-}
diff --git a/src/Control/Prim/Monad/Throw.hs b/src/Control/Prim/Monad/Throw.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Prim/Monad/Throw.hs
@@ -0,0 +1,133 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE TypeFamilies #-}
+-- |
+-- Module      : Control.Prim.Monad.Throw
+-- Copyright   : (c) Alexey Kuleshevich 2020
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Control.Prim.Monad.Throw
+  ( MonadThrow(..)
+  ) where
+
+import Control.Exception
+import Control.Monad.ST
+import Control.Monad.ST.Unsafe
+import GHC.Conc.Sync (STM(..))
+import GHC.Exts
+import Control.Monad.Trans.Class (lift)
+import Control.Monad.Trans.Cont (ContT)
+import Control.Monad.Trans.Except (ExceptT)
+import Control.Monad.Trans.Identity (IdentityT)
+import Control.Monad.Trans.Maybe (MaybeT)
+import Control.Monad.Trans.Reader (ReaderT(..))
+import Control.Monad.Trans.RWS.Lazy as Lazy (RWST)
+import Control.Monad.Trans.RWS.Strict as Strict (RWST)
+import Control.Monad.Trans.State.Lazy as Lazy (StateT)
+import Control.Monad.Trans.State.Strict as Strict (StateT)
+import Control.Monad.Trans.Writer.Lazy as Lazy (WriterT)
+import Control.Monad.Trans.Writer.Strict as Strict (WriterT)
+#if MIN_VERSION_transformers(0, 5, 3)
+import Control.Monad.Trans.Accum (AccumT)
+import Control.Monad.Trans.Select (SelectT)
+#if MIN_VERSION_transformers(0, 5, 6)
+import Control.Monad.Trans.RWS.CPS as CPS (RWST)
+import Control.Monad.Trans.Writer.CPS as CPS (WriterT)
+#endif
+#endif
+
+
+-- | A class for monads in which exceptions may be thrown.
+--
+-- Instances should obey the following law:
+--
+-- > throwM e >> x = throwM e
+--
+-- In other words, throwing an exception short-circuits the rest of the monadic
+-- computation.
+--
+-- === Note
+--
+-- This is an identical class to
+-- [MonadThrow](https://hackage.haskell.org/package/exceptions/docs/Control-Monad-Catch.html#t:MonadThrow)
+-- from @exceptions@ package. The reason why it was copied, instead of a direct depency on
+-- the aforementioned package is because @MonadCatch@ and @MonadMask@ are not right
+-- abstractions for exception handling in presence of concurrency.
+class Monad m => MonadThrow m where
+  -- | Throw an exception. Note that this throws when this action is run in
+  -- the monad @m@, not when it is applied. It is a generalization of
+  -- "Control.Exception"'s 'ControlException.throwIO'.
+  --
+  -- Should satisfy the law:
+  --
+  -- > throwM e >> f = throwM e
+  throwM :: Exception e => e -> m a
+
+instance MonadThrow Maybe where
+  throwM _ = Nothing
+
+instance e ~ SomeException => MonadThrow (Either e) where
+  throwM = Left . toException
+
+instance MonadThrow IO where
+  throwM = throwIO
+
+instance MonadThrow (ST s) where
+  throwM e = unsafeIOToST $ throwIO e
+
+instance MonadThrow STM where
+  throwM e = STM $ raiseIO# (toException e)
+
+
+instance MonadThrow m => MonadThrow (ContT r m) where
+  throwM = lift . throwM
+
+instance MonadThrow m => MonadThrow (ExceptT e m) where
+  throwM = lift . throwM
+
+instance MonadThrow m => MonadThrow (IdentityT m) where
+  throwM = lift . throwM
+
+instance MonadThrow m => MonadThrow (MaybeT m) where
+  throwM = lift . throwM
+
+instance MonadThrow m => MonadThrow (ReaderT r m) where
+  throwM = lift . throwM
+
+instance (Monoid w, MonadThrow m) => MonadThrow (Lazy.RWST r w s m) where
+  throwM = lift . throwM
+
+instance (Monoid w, MonadThrow m) => MonadThrow (Strict.RWST r w s m) where
+  throwM = lift . throwM
+
+instance MonadThrow m => MonadThrow (Lazy.StateT s m) where
+  throwM = lift . throwM
+
+instance MonadThrow m => MonadThrow (Strict.StateT s m) where
+  throwM = lift . throwM
+
+instance (Monoid w, MonadThrow m) => MonadThrow (Lazy.WriterT w m) where
+  throwM = lift . throwM
+
+instance (Monoid w, MonadThrow m) => MonadThrow (Strict.WriterT w m) where
+  throwM = lift . throwM
+
+#if MIN_VERSION_transformers(0, 5, 3)
+
+instance (Monoid w, MonadThrow m) => MonadThrow (AccumT w m) where
+  throwM = lift . throwM
+instance MonadThrow m => MonadThrow (SelectT r m) where
+  throwM = lift . throwM
+
+#if MIN_VERSION_transformers(0, 5, 6)
+
+instance MonadThrow m => MonadThrow (CPS.RWST r w st m) where
+  throwM = lift . throwM
+instance MonadThrow m => MonadThrow (CPS.WriterT w m) where
+  throwM = lift . throwM
+
+#endif
+#endif
diff --git a/src/Control/Prim/Monad/Unsafe.hs b/src/Control/Prim/Monad/Unsafe.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Prim/Monad/Unsafe.hs
@@ -0,0 +1,176 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE UnboxedTuples #-}
+-- |
+-- Module      : Control.Prim.Monad.Unsafe
+-- Copyright   : (c) Alexey Kuleshevich 2020
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Control.Prim.Monad.Unsafe
+  ( unsafePrimBase
+  , unsafePrimBase_
+  , unsafePrimBaseToPrim
+  , unsafePrimBaseToIO
+  , unsafePrimBaseToST
+  , unsafeIOToPrim
+  , unsafeSTToPrim
+  , unsafeLiftPrimBase
+  , noDuplicatePrim
+  , unsafeDupablePerformPrimBase
+  -- * Inline
+  , unsafeInlineIO
+  , unsafeInlineST
+  , unsafeInlinePrimBase
+  -- * Interleave
+  , unsafeInterleavePrimBase
+  , unsafeDupableInterleavePrimBase
+  -- * Re-exports
+  , unsafePerformIO
+  , unsafeDupablePerformIO
+  , unsafeInterleaveIO
+  , unsafeDupableInterleaveIO
+  ) where
+
+import System.IO.Unsafe
+import Control.Prim.Monad.Internal
+import Control.Monad.ST (ST)
+import GHC.IO
+import GHC.Exts
+
+-- | Unwrap any `MonadPrimBase` action while coercing the state token
+--
+-- === Highly unsafe!
+unsafePrimBase :: MonadPrimBase s' m => m a -> State# s -> (# State# s, a #)
+unsafePrimBase m = unsafeCoerce# (primBase m)
+{-# INLINE unsafePrimBase #-}
+
+-- | Unwrap any `MonadPrimBase` action that does not return anything, while coercing the
+-- state token
+--
+-- === Highly unsafe!
+unsafePrimBase_ :: MonadPrimBase s' m => m () -> State# s -> State# s
+unsafePrimBase_ m = unsafeCoerce# (primBase_ m)
+{-# INLINE unsafePrimBase_ #-}
+
+-- | Convert a `MonadPrimBase` action to another `MonadPrim` while coercing the state token.
+--
+-- === Highly unsafe!
+unsafePrimBaseToPrim :: (MonadPrimBase sn n, MonadPrim sm m) => n a -> m a
+unsafePrimBaseToPrim m = prim (unsafeCoerce# (primBase m))
+{-# INLINE unsafePrimBaseToPrim #-}
+
+-- | Convert a `MonadPrimBase` action to `ST` while coercing the state token @s@.
+--
+-- === Highly unsafe!
+unsafePrimBaseToST :: MonadPrimBase sm m => m a -> ST s a
+unsafePrimBaseToST = unsafePrimBaseToPrim
+{-# INLINE unsafePrimBaseToST #-}
+
+-- | Convert a `MonadPrimBase` action to `IO` while coercing the state token to `RealWorld`.
+--
+-- === Highly unsafe!
+unsafePrimBaseToIO :: MonadPrimBase s m => m a -> IO a
+unsafePrimBaseToIO = unsafePrimBaseToPrim
+{-# INLINE unsafePrimBaseToIO #-}
+
+-- | Convert an `IO` action to some `MonadPrim` while coercing the state token.
+--
+-- === Highly unsafe!
+--
+-- It is similar to `Control.Monad.ST.Unsafe.unsafeSTToIO`, except resulting action can be
+-- any other `MonadPrim` action, therefore it is a lot more dangerous.
+unsafeIOToPrim :: MonadPrim s m => IO a -> m a
+unsafeIOToPrim = unsafePrimBaseToPrim
+{-# INLINE unsafeIOToPrim #-}
+
+-- | Convert an `ST` action to some `MonadPrim` while coercing the state token.
+--
+-- === Highly unsafe!
+unsafeSTToPrim :: MonadPrim s' m => ST s a -> m a
+unsafeSTToPrim = unsafePrimBaseToPrim
+{-# INLINE unsafeSTToPrim #-}
+
+-- | Same as `GHC.IO.noDuplicate`, except works in any `MonadPrim`.
+noDuplicatePrim :: MonadPrim s m => m ()
+#if __GLASGOW_HASKELL__ >= 802
+noDuplicatePrim = prim_ noDuplicate#
+#else
+noDuplicatePrim = unsafeIOToPrim $ prim_ noDuplicate#
+#endif
+
+
+-- | Same as `unsafeDupablePerformIO`, except works not only with `IO`, but with other
+-- `MonadPrimBase` actions as well. Reading and writing values into memory is safe, as
+-- long as writing action is idempotent. On the other hand things like memory or resource
+-- allocation, exceptions handling are not safe at all, since supplied action can be run
+-- multiple times and a copy interrupted at will.
+unsafeDupablePerformPrimBase :: MonadPrimBase s m => m a -> a
+unsafeDupablePerformPrimBase m = unsafeDupablePerformIO (unsafePrimBaseToIO m)
+
+-- | Take an `IO` and compute it as a pure value, while inlining the action itself.
+--
+-- === Ridiculously unsafe!
+--
+-- This is even more unsafe then both `unsafePerformIO` and `unsafeDupableInterleaveIO`.
+--
+-- The only time it is really safe to use is on idempotent action that only read values
+-- from memory, but do note do any mutation, allocation and certainly not interaction with
+-- real world.
+--
+-- In
+-- [`bytestring`](https://github.com/haskell/bytestring/blob/95fe6bdf13c9cc86c1c880164f7844d61d989574/Data/ByteString/Internal.hs#L566-L592)
+-- it is known as `accursedUnutterablePerformIO`. Here are some resources that discuss
+-- it's unsafety:
+--
+-- * [Stack overflow question](https://stackoverflow.com/questions/61021205/what-is-the-difference-between-unsafedupableperformio-and-accursedunutterableper)
+-- * [Reddit discussion](https://www.reddit.com/r/haskell/comments/2cbgpz/flee_traveller_flee_or_you_will_be_corrupted_and/)
+--
+unsafeInlineIO :: IO a -> a
+unsafeInlineIO (IO m) = case m realWorld# of (# _, r #) -> r
+{-# INLINE unsafeInlineIO #-}
+
+-- | Take an `ST` and compute it as a pure value, while inlining the action itself. Same
+-- as `unsafeInlineIO`.
+--
+-- === Ridiculously unsafe!
+unsafeInlineST :: ST s a -> a
+unsafeInlineST = unsafeInlinePrimBase
+{-# INLINE unsafeInlineST #-}
+
+
+-- | Take any `MonadPrimBase` action and compute it as a pure value, while inlining the
+-- action. Same as `unsafeInlineIO`, but applied to any `MonadPrimBase` action.
+--
+-- === Ridiculously unsafe!
+unsafeInlinePrimBase :: MonadPrimBase s m => m a -> a
+unsafeInlinePrimBase m = unsafeInlineIO (unsafePrimBaseToIO m)
+{-# INLINE unsafeInlinePrimBase #-}
+
+
+-- | Same as `unsafeInterleaveIO`, except works in any `MonadPrimBase`
+unsafeInterleavePrimBase :: MonadPrimBase s m => m a -> m a
+unsafeInterleavePrimBase x = unsafeDupableInterleavePrimBase (noDuplicatePrim >> x)
+{-# INLINE unsafeInterleavePrimBase #-}
+
+
+-- | Same as `unsafeDupableInterleaveIO`, except works in any `MonadPrimBase`
+unsafeDupableInterleavePrimBase :: MonadPrimBase s m => m a -> m a
+unsafeDupableInterleavePrimBase x =
+  prim $ \s ->
+    let r = case primBase x s of
+              (# _, res #) -> res
+     in (# s, r #)
+{-# NOINLINE unsafeDupableInterleavePrimBase #-}
+
+-- | A version of `liftPrimBase` that coerce the state token.
+--
+-- === Highly unsafe!
+--
+unsafeLiftPrimBase :: forall sn n sm m a. (MonadPrimBase sn n, MonadPrim sm m) => n a -> m a
+unsafeLiftPrimBase m = prim (unsafePrimBase m)
+{-# INLINE unsafeLiftPrimBase #-}
diff --git a/src/Data/Prim.hs b/src/Data/Prim.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Prim.hs
@@ -0,0 +1,310 @@
+{-# LANGUAGE AllowAmbiguousTypes #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeFamilies #-}
+-- |
+-- Module      : Data.Prim
+-- Copyright   : (c) Alexey Kuleshevich 2020
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Data.Prim
+  ( Prim
+  , Atom(..)
+  , Atomic
+  , AtomicCount
+  , AtomicBits
+  , MonadPrim
+  , RW
+  , RealWorld
+  -- * Prim type size
+  , byteCount
+  , byteCountType
+  , byteCountProxy
+  -- * Prim type alignment
+  , alignment
+  , alignmentType
+  , alignmentProxy
+  , Size(..)
+  , Count(..)
+  , fromCount
+  , toByteCount
+  , fromCount#
+  , fromByteCount
+  , fromByteCountRem
+  , countAsProxy
+  , Off(..)
+  , toByteOff
+  , fromOff#
+  , fromByteOff
+  , fromByteOffRem
+  , offAsProxy
+  -- * Prefetch
+  , prefetchValue0
+  , prefetchValue1
+  , prefetchValue2
+  , prefetchValue3
+  -- * Re-export
+  , module Data.Word
+  , module Data.Int
+  , Ptr
+  , ForeignPtr
+  , Typeable
+  , Proxy(..)
+  , module Data.Monoid
+  , module Data.Coerce
+  ) where
+
+import Control.DeepSeq
+import Control.Prim.Monad
+import Data.Prim.Atom
+import Data.Prim.Atomic
+import Data.Prim.Class
+import GHC.Base (quotInt,  quotRemInt)
+import GHC.Exts
+import Data.Word
+import Data.Int
+import Foreign.ForeignPtr (ForeignPtr)
+import Data.Monoid
+import Data.Coerce
+import Data.Typeable
+
+newtype Size = Size { unSize :: Int }
+  deriving (Show, Eq, Ord, Num, Real, Integral, Bounded, Enum)
+
+-- | Get the size of the data type in bytes. Argument is not evaluated.
+byteCount :: forall a . Prim a => a -> Count Word8
+byteCount _ = coerce (I# (sizeOf# (proxy# :: Proxy# a)))
+{-# INLINE byteCount #-}
+
+-- | Same as `sizeOf`, except that the type can be supplied as a type level argument
+--
+-- >>> :set -XTypeApplications
+-- >>> import Data.Prim
+-- >>> byteCountType @Int64
+-- Count {unCount = 8}
+--
+byteCountType :: forall a . Prim a => Count Word8
+byteCountType = coerce (I# (sizeOf# (proxy# :: Proxy# a)))
+{-# INLINE byteCountType #-}
+
+-- | Same as `sizeOf`, but argument is a `Proxy` of @a@, instead of the type itself.
+--
+-- >>> import Data.Prim
+-- >>> import Data.Proxy
+-- >>> byteCountProxy (Proxy :: Proxy Int64)
+-- Count {unCount = 8}
+--
+byteCountProxy :: forall proxy a . Prim a => proxy a -> Count Word8
+byteCountProxy _ = coerce (I# (sizeOf# (proxy# :: Proxy# a)))
+{-# INLINE byteCountProxy #-}
+
+
+
+-- | Get the alignemnt of the type in bytes. Argument is not evaluated.
+alignment :: forall a . Prim a => a -> Int
+alignment _ = I# (alignment# (proxy# :: Proxy# a))
+{-# INLINE alignment #-}
+
+-- | Same as `alignment`, except that the type can be supplied with @TypeApplications@
+--
+-- >>> :set -XTypeApplications
+-- >>> import Data.Prim
+-- >>> alignmentType @Int32
+-- 4
+--
+alignmentType :: forall a . Prim a => Int
+alignmentType = I# (alignment# (proxy# :: Proxy# a))
+{-# INLINE alignmentType #-}
+
+-- | Same as `alignment`, but argument is a `Proxy` of @a@, instead of the type itself.
+--
+-- >>> import Data.Proxy
+-- >>> alignmentProxy (Proxy :: Proxy Int64)
+-- 8
+--
+alignmentProxy :: forall proxy a . Prim a => proxy a -> Int
+alignmentProxy _ = I# (alignment# (proxy# :: Proxy# a))
+{-# INLINE alignmentProxy #-}
+
+
+
+-- | Number of elements
+newtype Count a = Count
+  { unCount :: Int
+  } deriving (Eq, Show, Ord, Enum, Bounded, Num, Integral, Real, NFData)
+
+instance Prim (Count a) where
+  type PrimBase (Count a) = Int
+
+fromCountWord8# :: Count Word8 -> Int#
+fromCountWord8# (Count (I# n#)) = n#
+{-# INLINE fromCountWord8# #-}
+fromCountInt8# :: Count Int8 -> Int#
+fromCountInt8# (Count (I# n#)) = n#
+{-# INLINE fromCountInt8# #-}
+
+fromCount# :: Prim a => Count a -> Int#
+fromCount# c@(Count (I# n#)) =
+  case coerce (byteCountProxy c) of
+    I# sz# -> sz# *# n#
+{-# INLINE[0] fromCount# #-}
+{-# RULES
+"fromCountWord8#" fromCount# = fromCountWord8#
+"fromCountInt8#" fromCount# = fromCountInt8#
+  #-}
+
+-- | Covert to number of bytes as an `Int`
+--
+-- @since 0.1.0
+fromCount :: Prim a => Count a -> Int
+fromCount c = I# (fromCount# c)
+{-# INLINE fromCount #-}
+
+-- | Covert to the `Count` of bytes
+--
+-- @since 0.1.0
+toByteCount :: Prim a => Count a -> Count Word8
+toByteCount = Count . fromCount
+{-# INLINE toByteCount #-}
+
+
+-- | Helper noop function that restricts `Count` to the type of proxy
+--
+-- @since 0.1.0
+countAsProxy :: proxy a -> Count a -> Count a
+countAsProxy _ = id
+
+fromByteCountInt8 :: Count Word8 -> Count Int8
+fromByteCountInt8 = coerce
+{-# INLINE fromByteCountInt8 #-}
+
+fromByteCount :: forall a . Prim a => Count Word8 -> Count a
+fromByteCount sz = coerce (quotSizeOfWith (proxy# :: Proxy# a) (coerce sz) 0 quotInt)
+{-# INLINE[0] fromByteCount #-}
+{-# RULES
+"fromByteCount" fromByteCount = id
+"fromByteCount" fromByteCount = fromByteCountInt8
+  #-}
+
+fromByteCountRemWord8 :: Count Word8 -> (Count Word8, Count Word8)
+fromByteCountRemWord8 i = (coerce i, 0)
+{-# INLINE fromByteCountRemWord8 #-}
+
+fromByteCountRemInt8 :: Count Word8 -> (Count Int8, Count Word8)
+fromByteCountRemInt8 i = (coerce i, 0)
+{-# INLINE fromByteCountRemInt8 #-}
+
+
+fromByteCountRem :: forall a . Prim a => Count Word8 -> (Count a, Count Word8)
+fromByteCountRem sz = coerce (quotSizeOfWith (proxy# :: Proxy# a) (coerce sz) (0, 0) quotRemInt)
+{-# INLINE[0] fromByteCountRem #-}
+{-# RULES
+"fromByteCountRemWord8" fromByteCountRem = fromByteCountRemWord8
+"fromByteCountRemInt8"  fromByteCountRem = fromByteCountRemInt8
+  #-}
+
+quotSizeOfWith :: forall a b. Prim a => Proxy# a -> Int -> b -> (Int -> Int -> b) -> b
+quotSizeOfWith px# sz onZero quotWith
+  | tySize <= 0 = onZero
+  | otherwise = sz `quotWith` tySize
+  where
+    tySize = I# (sizeOf# px#)
+{-# INLINE quotSizeOfWith #-}
+
+
+-- | Offset in number of elements
+newtype Off a = Off
+  { unOff :: Int
+  } deriving (Eq, Show, Ord, Enum, Bounded, Num, Integral, Real, NFData)
+
+instance Prim (Off a) where
+  type PrimBase (Off a) = Int
+
+
+-- | Helper noop function that restricts `Off`set to the type of proxy
+--
+-- @since 0.1.0
+offAsProxy :: proxy a -> Off a -> Off a
+offAsProxy _ = id
+
+
+-- | Compute byte offset from an offset of `Prim` type
+--
+-- >>> toByteOff (10 :: Off Word64)
+-- Off {unOff = 80}
+--
+-- @since 0.1.0
+toByteOff :: Prim e => Off e -> Off Word8
+toByteOff off = Off (I# (fromOff# off))
+{-# INLINE toByteOff #-}
+
+fromOffWord8# :: Off Word8 -> Int#
+fromOffWord8# (Off (I# o#)) = o#
+{-# INLINE fromOffWord8# #-}
+fromOffInt8# :: Off Int8 -> Int#
+fromOffInt8# (Off (I# o#)) = o#
+{-# INLINE fromOffInt8# #-}
+
+-- | Convert offset of some type into number of bytes
+fromOff# :: Prim a => Off a -> Int#
+fromOff# o@(Off (I# o#)) =
+  case coerce (byteCountProxy o) of
+    I# sz# -> sz# *# o#
+{-# INLINE[0] fromOff# #-}
+{-# RULES
+"fromOffWord8#" fromOff# = fromOffWord8#
+"fromOffInt8#" fromOff# = fromOffInt8#
+  #-}
+
+
+
+fromByteOffInt8 :: Off Word8 -> Off Int8
+fromByteOffInt8 = coerce
+{-# INLINE fromByteOffInt8 #-}
+
+fromByteOff :: forall a . Prim a => Off Word8 -> Off a
+fromByteOff sz = coerce (quotSizeOfWith (proxy# :: Proxy# a) (coerce sz) 0 quotInt)
+{-# INLINE[0] fromByteOff #-}
+{-# RULES
+"fromByteOff" fromByteOff = id
+"fromByteOff" fromByteOff = fromByteOffInt8
+  #-}
+
+fromByteOffRemWord8 :: Off Word8 -> (Off Word8, Off Word8)
+fromByteOffRemWord8 i = (coerce i, 0)
+{-# INLINE fromByteOffRemWord8 #-}
+
+fromByteOffRemInt8 :: Off Word8 -> (Off Int8, Off Word8)
+fromByteOffRemInt8 i = (coerce i, 0)
+{-# INLINE fromByteOffRemInt8 #-}
+
+
+fromByteOffRem :: forall a . Prim a => Off Word8 -> (Off a, Off Word8)
+fromByteOffRem sz = coerce (quotSizeOfWith (proxy# :: Proxy# a) (coerce sz) (0, 0) quotRemInt)
+{-# INLINE[0] fromByteOffRem #-}
+{-# RULES
+"fromByteOffRemWord8" fromByteOffRem = fromByteOffRemWord8
+"fromByteOffRemInt8"  fromByteOffRem = fromByteOffRemInt8
+  #-}
+
+
+
+prefetchValue0 :: MonadPrim s m => a -> m ()
+prefetchValue0 a = prim_ (prefetchValue0# a)
+{-# INLINE prefetchValue0 #-}
+
+prefetchValue1 :: MonadPrim s m => a -> m ()
+prefetchValue1 a = prim_ (prefetchValue1# a)
+{-# INLINE prefetchValue1 #-}
+
+prefetchValue2 :: MonadPrim s m => a -> m ()
+prefetchValue2 a = prim_ (prefetchValue2# a)
+{-# INLINE prefetchValue2 #-}
+
+prefetchValue3 :: MonadPrim s m => a -> m ()
+prefetchValue3 a = prim_ (prefetchValue3# a)
+{-# INLINE prefetchValue3 #-}
diff --git a/src/Data/Prim/Atom.hs b/src/Data/Prim/Atom.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Prim/Atom.hs
@@ -0,0 +1,522 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# 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
+  -- ** Expirimental
+  , 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.Exception
+import Control.Monad
+import Control.Prim.Monad
+import Control.Prim.Monad.Unsafe
+import Data.Bits
+import Data.Prim.Atomic
+import Data.Prim.Class
+import Foreign.Prim hiding (Any)
+import GHC.IO
+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 :: MutableByteArray# RealWorld -> Int# -> IO ()
+acquireLockByteOffMutableByteArray mba# i# =
+  let go = do
+        locked <- syncLockTestSetInt8ArrayIO mba# i#
+        when (locked == 0) go
+   in go
+{-# INLINE acquireLockByteOffMutableByteArray #-}
+
+releaseLockByteOffMutableByteArray :: MutableByteArray# RealWorld -> Int# -> IO ()
+releaseLockByteOffMutableByteArray mba# i# = syncLockReleaseInt8ArrayIO mba# i#
+{-# INLINE releaseLockByteOffMutableByteArray #-}
+
+
+acquireLockByteOffAddr :: Addr# -> Int# -> IO ()
+acquireLockByteOffAddr addr# i# =
+  let go = do
+        locked <- syncLockTestSetInt8AddrIO addr# i#
+        when (locked == 0) go
+   in go
+{-# INLINE acquireLockByteOffAddr #-}
+
+releaseLockByteOffAddr :: Addr#-> Int# -> IO ()
+releaseLockByteOffAddr addr# i# = syncLockReleaseInt8AddrIO addr# i#
+{-# INLINE releaseLockByteOffAddr #-}
+
+
+withLockMutableByteArray ::
+     forall e b. Prim e
+  => MutableByteArray# RealWorld
+  -> Int#
+  -> (Atom e -> IO (Atom e, b))
+  -> IO b
+withLockMutableByteArray mba# i# f =
+  let li# = i# *# sizeOf# (proxy# :: Proxy# (Atom e))
+   in bracket_
+        (unsafeUnmask (acquireLockByteOffMutableByteArray mba# li#))
+        (releaseLockByteOffMutableByteArray mba# li#) $
+      IO $ \s ->
+        case readMutableByteArray# mba# i# s of
+          (# s', a #) ->
+            case f a of
+              IO m ->
+                case m s' of
+                  (# s'', (a', b) #) ->
+                    (# writeMutableByteArray# mba# i# a' s'', b #)
+{-# 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. Prim e
+  => MutableByteArray# RealWorld
+  -> Int#
+  -> IO (Atom e)
+atomicReadAtomMutableByteArray mba# i# =
+  let li# = i# *# sizeOf# (proxy# :: Proxy# (Atom e))
+   in bracket_
+        (unsafeUnmask (acquireLockByteOffMutableByteArray mba# li#))
+        (releaseLockByteOffMutableByteArray mba# li#)
+        (coerce (IO (readByteOffMutableByteArray# mba# (1# +# li#)) :: IO e))
+{-# 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. Prim e
+  => MutableByteArray# RealWorld
+  -> Int#
+  -> Atom e
+  -> IO ()
+atomicWriteAtomMutableByteArray mba# i# (Atom a) =
+  let li# = i# *# sizeOf# (proxy# :: Proxy# (Atom e))
+   in bracket_
+        (unsafeUnmask (acquireLockByteOffMutableByteArray mba# li#))
+        (releaseLockByteOffMutableByteArray mba# li#)
+        (prim_ (writeByteOffMutableByteArray# mba# (1# +# li#) a))
+{-# INLINABLE atomicWriteAtomMutableByteArray #-}
+
+
+
+-- | Same as `atomicReadAtomMutableByteArray`, but for `Addr#` with offset
+atomicReadAtomOffAddr ::
+     forall e. Prim e
+  => Addr#
+  -> Int#
+  -> IO (Atom e)
+atomicReadAtomOffAddr mba# i# =
+  let li# = i# *# sizeOf# (proxy# :: Proxy# (Atom e))
+   in bracket_
+        (unsafeUnmask (acquireLockByteOffAddr mba# li#))
+        (releaseLockByteOffAddr mba# li#)
+        (coerce (IO (readOffAddr# mba# (1# +# li#)) :: IO e))
+{-# INLINABLE atomicReadAtomOffAddr #-}
+
+-- | Same as `atomicWriteAtomMutableByteArray`, but for `Addr#` with offset
+atomicWriteAtomOffAddr ::
+     forall e. Prim e
+  => Addr#
+  -> Int#
+  -> Atom e
+  -> IO ()
+atomicWriteAtomOffAddr mba# i# (Atom a) =
+  let li# = i# *# sizeOf# (proxy# :: Proxy# (Atom e))
+   in bracket_
+        (unsafeUnmask (acquireLockByteOffAddr mba# li#))
+        (releaseLockByteOffAddr mba# li#)
+        (prim_ (writeOffAddr# mba# (1# +# li#) a))
+{-# 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))
+   in bracket_
+        (unsafeUnmask (acquireLockByteOffAddr addr# li#))
+        (releaseLockByteOffAddr addr# li#) $
+      IO $ \s ->
+        case readOffAddr# addr# i# s of
+          (# s', a #) ->
+            case f a of
+              IO m ->
+                case m s' of
+                  (# s'', (a', b) #) ->
+                    (# writeOffAddr# addr# i# a' s'', b #)
+{-# INLINABLE withLockOffAddr #-}
+
+atomicModifyAtomMutableByteArray# ::
+     forall e b s. Prim e
+  => MutableByteArray# s
+  -> Int#
+  -> (Atom e -> (# Atom e, b #))
+  -> State# s
+  -> (# State# s, b #)
+atomicModifyAtomMutableByteArray# mba# i# f =
+  let li# = i# *# sizeOf# (proxy# :: Proxy# (Atom e))
+      mba'# = unsafeCoerce# mba# :: MutableByteArray# RealWorld
+   in unsafePrimBase $
+      bracket_
+        (unsafeUnmask (acquireLockByteOffMutableByteArray mba'# li#))
+        (releaseLockByteOffMutableByteArray mba'# li#) $
+      IO $ \s ->
+        case readMutableByteArray# mba'# i# s of
+          (# s', a #) ->
+            case f a of
+              (# a', b #) ->
+                (# writeMutableByteArray# mba'# i# a' s', b #)
+{-# INLINE atomicModifyAtomMutableByteArray#  #-}
+
+atomicModifyAtomOffAddr# ::
+     forall e b s. Prim e
+  => Addr#
+  -> Int#
+  -> (Atom e -> (# Atom e, b #))
+  -> State# s
+  -> (# State# s, b #)
+atomicModifyAtomOffAddr# addr# i# f =
+  let li# = i# *# sizeOf# (proxy# :: Proxy# (Atom e))
+   in unsafePrimBase $
+      bracket_
+        (unsafeUnmask (acquireLockByteOffAddr addr# li#))
+        (releaseLockByteOffAddr addr# li#) $
+      IO $ \s ->
+        case readOffAddr# addr# i# s of
+          (# s', a #) ->
+            case f a of
+              (# a', b #) ->
+                (# writeOffAddr# addr# i# a' s', b #)
+{-# 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# =
+    unsafePrimBase (atomicReadAtomMutableByteArray (unsafeCoerce# mba#) i#)
+  {-# INLINABLE atomicReadMutableByteArray# #-}
+  atomicWriteMutableByteArray# mba# i# a =
+    unsafePrimBase_ (atomicWriteAtomMutableByteArray (unsafeCoerce# mba#) i# a)
+  {-# INLINABLE atomicWriteMutableByteArray# #-}
+  atomicReadOffAddr# addr# i# = unsafePrimBase (atomicReadAtomOffAddr addr# i#)
+  {-# INLINABLE atomicReadOffAddr# #-}
+  atomicWriteOffAddr# addr# i# a = unsafePrimBase_ (atomicWriteAtomOffAddr addr# i# a)
+  {-# INLINABLE atomicWriteOffAddr# #-}
+  casMutableByteArray# mba# i# old new =
+    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 =
+    atomicModifyAtomMutableByteArray# mba# i# (swapIfEqualBool old new)
+  {-# INLINE casBoolMutableByteArray# #-}
+  casBoolOffAddr# addr# i# old new =
+    atomicModifyOffAddr# addr# i# (swapIfEqualBool old new)
+  {-# INLINE casBoolOffAddr# #-}
+  atomicModifyMutableByteArray# = atomicModifyAtomMutableByteArray#
+  {-# INLINE atomicModifyMutableByteArray#  #-}
+  atomicModifyOffAddr# = atomicModifyAtomOffAddr#
+  {-# 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# #-}
diff --git a/src/Data/Prim/Atomic.hs b/src/Data/Prim/Atomic.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Prim/Atomic.hs
@@ -0,0 +1,1579 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DefaultSignatures #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE UnboxedTuples #-}
+#if __GLASGOW_HASKELL__ < 800
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+#endif
+-- |
+-- Module      : Data.Prim.Atomic
+-- Copyright   : (c) Alexey Kuleshevich 2020
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Data.Prim.Atomic
+  ( Atomic(..)
+  , AtomicBits(..)
+  , AtomicCount(..)
+  , atomicBoolModifyMutableByteArray#
+  , atomicBoolModifyFetchOldMutableByteArray#
+  , atomicModifyMutableByteArray_#
+  , atomicModifyFetchOldMutableByteArray#
+  , atomicModifyFetchNewMutableByteArray#
+  , atomicModifyOffAddr_#
+  , atomicBoolModifyOffAddr#
+  , atomicModifyFetchOldOffAddr#
+  , atomicModifyFetchNewOffAddr#
+  , atomicNotFetchOldMutableByteArray#
+  , atomicNotFetchNewMutableByteArray#
+  , atomicNotFetchOldOffAddr#
+  , atomicNotFetchNewOffAddr#
+  ) where
+
+import Control.Prim.Monad.Unsafe
+import Data.Bits
+import Data.Char
+import Data.Functor.Identity
+import Data.Monoid
+import Data.Prim.Class
+import Foreign.C.Error (Errno(..))
+import Foreign.Prim hiding (Any)
+import GHC.Conc
+import GHC.IO.Device
+import System.IO
+#if __GLASGOW_HASKELL__ >= 800
+import Data.Functor.Const
+import Data.Semigroup
+#endif /* __GLASGOW_HASKELL__ >= 800 */
+
+#include "MachDeps.h"
+
+class (Prim a, Eq a) => Atomic a where
+  -- | Read an element from `MutableByteArray#` atomically. Implies full memory barrier.
+  atomicReadMutableByteArray# ::
+       MutableByteArray# s -- ^ Mutable array to read the element from
+    -> Int# -- ^ Offset into the array in number of elements
+    -> State# s
+    -> (# State# s, a #)
+  atomicReadMutableByteArray# mba# i# s = readMutableByteArray# mba# i# (syncSynchronize# s)
+  {-# INLINE atomicReadMutableByteArray# #-}
+
+  -- | Write an element into `MutableByteArray#` atomically. Implies full memory barrier.
+  atomicWriteMutableByteArray# ::
+       MutableByteArray# s -- ^ Mutable array to write the element into
+    -> Int# -- ^ Offset into the array in number of elements
+    -> a -- ^ Element to write
+    -> State# s
+    -> State# s
+  atomicWriteMutableByteArray# mba# i# a = withMemBarrier_# (writeMutableByteArray# mba# i# a)
+  {-# INLINE atomicWriteMutableByteArray# #-}
+
+  -- | Read an element from memory atomically. Implies full memory barrier.
+  atomicReadOffAddr# ::
+       Addr# -- ^ Pointer to the beginning of memory
+    -> Int# -- ^ Offset in number of elements from the supplied pointer
+    -> State# s
+    -> (# State# s, a #)
+  atomicReadOffAddr# addr# i# s = readOffAddr# addr# i# (syncSynchronize# s)
+  {-# INLINE atomicReadOffAddr# #-}
+
+  -- | Write an element directly into memory atomically. Implies full memory barrier.
+  atomicWriteOffAddr# ::
+       Addr# -- ^ Pointer to the beginning of memory
+    -> Int# -- ^ Offset in number of elements from the supplied pointer
+    -> a -- ^ Element to write
+    -> State# s
+    -> State# s
+  atomicWriteOffAddr# addr# i# a = withMemBarrier_# (writeOffAddr# addr# i# a)
+  {-# INLINE atomicWriteOffAddr# #-}
+
+  -- | Compare-and-swap (CAS) operation. Given a mutable array, offset in number of
+  -- elements, an old value and a new value atomically swap the old value for the new one,
+  -- but only if the actual old value was an exact match to the expetced old one that was
+  -- supplied. Returns the actual old value, which if compared to supplied expected one
+  -- will tell us whether atomic swap occured or not.
+  casMutableByteArray# ::
+       MutableByteArray# s -- ^ Array to be mutated
+    -> Int# -- ^ Offset into the array in number of elements
+    -> a -- ^ Expected old value
+    -> a -- ^ New value
+    -> State# s -- ^ Starting state
+    -> (# State# s, a #)
+  default casMutableByteArray#
+    :: Atomic (PrimBase a)
+    => MutableByteArray# s
+    -> Int#
+    -> a
+    -> a
+    -> State# s
+    -> (# State# s, a #)
+  casMutableByteArray# mba# i# old new s =
+    case casMutableByteArray# mba# i# (toPrimBase old) (toPrimBase new) s of
+      (# s', prev #) -> (# s', fromPrimBase prev #)
+  {-# INLINE casMutableByteArray# #-}
+
+  casOffAddr# :: Addr# -> Int# -> a -> a -> State# s -> (# State# s, a #)
+  default casOffAddr# ::
+    Atomic (PrimBase a) => Addr# -> Int# -> a -> a -> State# s -> (# State# s, a #)
+  casOffAddr# addr# i# old new s =
+    case casOffAddr# addr# i# (toPrimBase old) (toPrimBase new) s of
+      (# s', prev #) -> (# s', fromPrimBase prev #)
+  {-# INLINE casOffAddr# #-}
+
+
+  casBoolMutableByteArray# ::
+       MutableByteArray# s -- ^ Array to be mutated
+    -> Int# -- ^ Offset into the array in number of elements
+    -> a -- ^ Expected old value
+    -> a -- ^ New value
+    -> State# s -- ^ Starting state
+    -> (# State# s, Bool #)
+  default casBoolMutableByteArray#
+    :: Atomic (PrimBase a)
+    => MutableByteArray# s
+    -> Int#
+    -> a
+    -> a
+    -> State# s
+    -> (# State# s, Bool #)
+  casBoolMutableByteArray# mba# i# old new s =
+    case casBoolMutableByteArray# mba# i# (toPrimBase old) (toPrimBase new) s of
+      (# s', casSucc #) -> (# s', casSucc #)
+  {-# INLINE casBoolMutableByteArray# #-}
+
+  casBoolOffAddr# :: Addr# -> Int# -> a -> a -> State# s -> (# State# s, Bool #)
+  default casBoolOffAddr# ::
+    Atomic (PrimBase a) => Addr# -> Int# -> a -> a -> State# s -> (# State# s, Bool #)
+  casBoolOffAddr# addr# i# old new s =
+    case casBoolOffAddr# addr# i# (toPrimBase old) (toPrimBase new) s of
+      (# s', casSucc #) -> (# s', casSucc #)
+  {-# INLINE casBoolOffAddr# #-}
+
+
+  -- | Using `casMutableByteArray#` perform atomic modification of an element in a
+  -- `MutableByteArray#`. This is essentially an implementation of a spinlock using CAS.
+  --
+  -- @since 0.1.0
+  atomicModifyMutableByteArray# ::
+       MutableByteArray# s -- ^ Array to be mutated
+    -> Int# -- ^ Index in number of `Int#` elements into the `MutableByteArray#`
+    -> (a -> (# a, b #)) -- ^ Function to be applied atomically to the element
+    -> State# s -- ^ Starting state
+    -> (# State# s, b #)
+  atomicModifyMutableByteArray# mba# i# f s0 =
+    let go s o =
+          case f o of
+            (# n, artifact #) ->
+              case casMutableByteArray# mba# i# o n s of
+                (# s', o' #) ->
+                  if o == o'
+                    then (# s', artifact #)
+                    else go s o'
+     in case readMutableByteArray# mba# i# s0 of
+          (# s', o #) -> go s' o
+  {-# INLINE atomicModifyMutableByteArray# #-}
+
+  -- | Using `casOffAddr#` perform atomic modification of an element in a
+  -- `OffAddr#`. This is essentially an implementation of a spinlock using CAS.
+  --
+  -- @since 0.1.0
+  atomicModifyOffAddr# ::
+       Addr# -- ^ Array to be mutated
+    -> Int# -- ^ Index in number of `Int#` elements into the `OffAddr#`
+    -> (a -> (# a, b #)) -- ^ Function to be applied atomically to the element
+    -> State# s -- ^ Starting state
+    -> (# State# s, b #)
+  atomicModifyOffAddr# addr# i# f s0 =
+    let go s o =
+          case f o of
+            (# n, artifact #) ->
+              case casOffAddr# addr# i# o n s of
+                (# s', o' #) ->
+                  if o == o'
+                    then (# s', artifact #)
+                    else go s o'
+     in case readOffAddr# addr# i# s0 of
+          (# s', o #) -> go s' o
+  {-# INLINE atomicModifyOffAddr# #-}
+
+
+-- | Using `casBoolMutableByteArray#` perform atomic modification of an element in a
+-- `MutableByteArray#`. This is essentially an implementation of a spinlock using CAS.
+--
+-- @since 0.1.0
+atomicBoolModifyMutableByteArray# ::
+     Atomic a =>
+     MutableByteArray# s -- ^ Array to be mutated
+  -> Int# -- ^ Index in number of `Int#` elements into the `MutableByteArray#`
+  -> (a -> (# a, b #)) -- ^ Function to be applied atomically to the element
+  -> State# s -- ^ Starting state
+  -> (# State# s, b #)
+atomicBoolModifyMutableByteArray# mba# i# f s0 =
+  let go s o =
+        case f o of
+          (# n, artifact #) ->
+            case casBoolMutableByteArray# mba# i# o n s of
+              (# s', isCasSucc #) ->
+                if isCasSucc
+                  then (# s', artifact #)
+                  else case readMutableByteArray# mba# i# s' of
+                         (# s'', o' #) -> go s'' o'
+   in case readMutableByteArray# mba# i# s0 of
+        (# s', o #) -> go s' o
+{-# INLINE atomicBoolModifyMutableByteArray# #-}
+
+-- | Using `casBoolMutableByteArray#` perform atomic modification of an element in a
+-- `MutableByteArray#`. Returns the previous value.
+--
+-- @since 0.1.0
+atomicBoolModifyFetchOldMutableByteArray# ::
+     Atomic a =>
+     MutableByteArray# s -- ^ Array to be mutated
+  -> Int# -- ^ Index in number of `Int#` elements into the `MutableByteArray#`
+  -> (a -> a) -- ^ Function to be applied atomically to the element
+  -> State# s -- ^ Starting state
+  -> (# State# s, a #)
+atomicBoolModifyFetchOldMutableByteArray# mba# i# f =
+  atomicBoolModifyMutableByteArray# mba# i# (\a -> let a' = f a in seq a' (# a', a #))
+{-# INLINE atomicBoolModifyFetchOldMutableByteArray# #-}
+
+
+-- | Using `casMutableByteArray#` perform atomic modification of an element in a
+-- `MutableByteArray#`. Returns the previous value.
+--
+-- @since 0.1.0
+atomicModifyFetchOldMutableByteArray# ::
+     Atomic a =>
+     MutableByteArray# s -- ^ Array to be mutated
+  -> Int# -- ^ Index in number of `Int#` elements into the `MutableByteArray#`
+  -> (a -> a) -- ^ Function to be applied atomically to the element
+  -> State# s -- ^ Starting state
+  -> (# State# s, a #)
+atomicModifyFetchOldMutableByteArray# mba# i# f =
+  atomicModifyMutableByteArray# mba# i# (\a -> let a' = f a in seq a' (# a', a #))
+{-# INLINE atomicModifyFetchOldMutableByteArray# #-}
+
+
+-- | Using `casMutableByteArray#` perform atomic modification of an element in a
+-- `MutableByteArray#`. Returns the new value.
+--
+-- @since 0.1.0
+atomicModifyFetchNewMutableByteArray# ::
+     Atomic a =>
+     MutableByteArray# s -- ^ Array to be mutated
+  -> Int# -- ^ Index in number of `Int#` elements into the `MutableByteArray#`
+  -> (a -> a) -- ^ Function to be applied atomically to the element
+  -> State# s -- ^ Starting state
+  -> (# State# s, a #)
+atomicModifyFetchNewMutableByteArray# mba# i# f =
+  atomicModifyMutableByteArray# mba# i# (\a -> let a' = f a in seq a' (# a', a' #))
+{-# INLINE atomicModifyFetchNewMutableByteArray# #-}
+
+-- | Using `casMutableByteArray#` perform atomic modification of an element in a
+-- `MutableByteArray#`.
+--
+-- @since 0.1.0
+atomicModifyMutableByteArray_# ::
+     Atomic a =>
+     MutableByteArray# s -- ^ Array to be mutated
+  -> Int# -- ^ Index in number of `Int#` elements into the `MutableByteArray#`
+  -> (a -> a) -- ^ Function to be applied atomically to the element
+  -> State# s -- ^ Starting state
+  -> State# s
+atomicModifyMutableByteArray_# mba# i# f s =
+  case atomicModifyMutableByteArray# mba# i# (\a -> let a' = f a in seq a' (# a', () #)) s of
+    (# s', () #) -> s'
+{-# INLINE atomicModifyMutableByteArray_# #-}
+
+
+-- | Using `casBoolOffAddr#` perform atomic modification of an element in a
+-- `OffAddr#`. This is essentially an implementation of a spinlock using CAS.
+--
+-- @since 0.1.0
+atomicBoolModifyOffAddr# ::
+     Atomic a =>
+     Addr# -- ^ Array to be mutated
+  -> Int# -- ^ Index in number of `Int#` elements into the `OffAddr#`
+  -> (a -> (# a, b #)) -- ^ Function to be applied atomically to the element
+  -> State# s -- ^ Starting state
+  -> (# State# s, b #)
+atomicBoolModifyOffAddr# addr# i# f s0 =
+  let go s o =
+        case f o of
+          (# n, artifact #) ->
+            case casBoolOffAddr# addr# i# o n s of
+              (# s', isCasSucc #) ->
+                if isCasSucc
+                  then (# s', artifact #)
+                  else case atomicReadOffAddr# addr# i# s' of
+                         (# s'', o' #) -> go s'' o'
+   in case atomicReadOffAddr# addr# i# s0 of
+        (# s', o #) -> go s' o
+{-# INLINE atomicBoolModifyOffAddr# #-}
+
+
+-- | Using `casOffAddr#` perform atomic modification of an element in a
+-- `OffAddr#`. Returns the previous value.
+--
+-- @since 0.1.0
+atomicModifyFetchOldOffAddr# ::
+     Atomic a =>
+     Addr# -- ^ Array to be mutated
+  -> Int# -- ^ Index in number of `Int#` elements into the `OffAddr#`
+  -> (a -> a) -- ^ Function to be applied atomically to the element
+  -> State# s -- ^ Starting state
+  -> (# State# s, a #)
+atomicModifyFetchOldOffAddr# addr# i# f =
+  atomicModifyOffAddr# addr# i# (\a -> let a' = f a in seq a' (# a', a #))
+{-# INLINE atomicModifyFetchOldOffAddr# #-}
+
+
+-- | Using `casOffAddr#` perform atomic modification of an element in a
+-- `OffAddr#`. Returns the new value.
+--
+-- @since 0.1.0
+atomicModifyFetchNewOffAddr# ::
+     Atomic a =>
+     Addr# -- ^ Array to be mutated
+  -> Int# -- ^ Index in number of `Int#` elements into the `OffAddr#`
+  -> (a -> a) -- ^ Function to be applied atomically to the element
+  -> State# s -- ^ Starting state
+  -> (# State# s, a #)
+atomicModifyFetchNewOffAddr# addr# i# f =
+  atomicModifyOffAddr# addr# i# (\a -> let a' = f a in seq a' (# a', a' #))
+{-# INLINE atomicModifyFetchNewOffAddr# #-}
+
+-- | Using `casOffAddr#` perform atomic modification of an element in a
+-- `OffAddr#`.
+--
+-- @since 0.1.0
+atomicModifyOffAddr_# ::
+     Atomic a =>
+     Addr# -- ^ Array to be mutated
+  -> Int# -- ^ Index in number of `Int#` elements into the `OffAddr#`
+  -> (a -> a) -- ^ Function to be applied atomically to the element
+  -> State# s -- ^ Starting state
+  -> State# s
+atomicModifyOffAddr_# addr# i# f s =
+  case atomicModifyOffAddr# addr# i# (\a -> let a' = f a in seq a' (# a', () #)) s of
+    (# s', () #) -> s'
+{-# INLINE atomicModifyOffAddr_# #-}
+
+
+
+class Atomic a => AtomicCount a where
+  atomicAddFetchOldMutableByteArray# :: MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicAddFetchOldMutableByteArray# ::
+    AtomicCount (PrimBase a) => MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicAddFetchOldMutableByteArray# mba# i# x s =
+    case atomicAddFetchOldMutableByteArray# mba# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicAddFetchOldMutableByteArray# #-}
+
+  atomicAddFetchNewMutableByteArray# :: MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicAddFetchNewMutableByteArray# ::
+    AtomicCount (PrimBase a) => MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicAddFetchNewMutableByteArray# mba# i# x s =
+    case atomicAddFetchNewMutableByteArray# mba# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicAddFetchNewMutableByteArray# #-}
+
+  atomicSubFetchOldMutableByteArray# :: MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicSubFetchOldMutableByteArray# ::
+    AtomicCount (PrimBase a) => MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicSubFetchOldMutableByteArray# mba# i# x s =
+    case atomicSubFetchOldMutableByteArray# mba# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicSubFetchOldMutableByteArray# #-}
+
+  atomicSubFetchNewMutableByteArray# :: MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicSubFetchNewMutableByteArray# ::
+    AtomicCount (PrimBase a) => MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicSubFetchNewMutableByteArray# mba# i# x s =
+    case atomicSubFetchNewMutableByteArray# mba# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicSubFetchNewMutableByteArray# #-}
+
+
+  atomicAddFetchOldOffAddr# :: Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicAddFetchOldOffAddr# ::
+    AtomicCount (PrimBase a) => Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicAddFetchOldOffAddr# addr# i# x s =
+    case atomicAddFetchOldOffAddr# addr# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicAddFetchOldOffAddr# #-}
+
+  atomicAddFetchNewOffAddr# :: Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicAddFetchNewOffAddr# ::
+    AtomicCount (PrimBase a) => Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicAddFetchNewOffAddr# addr# i# x s =
+    case atomicAddFetchNewOffAddr# addr# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicAddFetchNewOffAddr# #-}
+
+  atomicSubFetchOldOffAddr# :: Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicSubFetchOldOffAddr# ::
+    AtomicCount (PrimBase a) => Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicSubFetchOldOffAddr# addr# i# x s =
+    case atomicSubFetchOldOffAddr# addr# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicSubFetchOldOffAddr# #-}
+
+  atomicSubFetchNewOffAddr# :: Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicSubFetchNewOffAddr# ::
+    AtomicCount (PrimBase a) => Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicSubFetchNewOffAddr# addr# i# x s =
+    case atomicSubFetchNewOffAddr# addr# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicSubFetchNewOffAddr# #-}
+
+
+
+class (Bits a, Atomic a) => AtomicBits a where
+  atomicAndFetchOldMutableByteArray# :: MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicAndFetchOldMutableByteArray# ::
+    AtomicBits (PrimBase a) => MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicAndFetchOldMutableByteArray# mba# i# x s =
+    case atomicAndFetchOldMutableByteArray# mba# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicAndFetchOldMutableByteArray# #-}
+
+  atomicAndFetchNewMutableByteArray# :: MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicAndFetchNewMutableByteArray# ::
+    AtomicBits (PrimBase a) => MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicAndFetchNewMutableByteArray# mba# i# x s =
+    case atomicAndFetchNewMutableByteArray# mba# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicAndFetchNewMutableByteArray# #-}
+
+  atomicNandFetchOldMutableByteArray# :: MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicNandFetchOldMutableByteArray# ::
+    AtomicBits (PrimBase a) => MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicNandFetchOldMutableByteArray# mba# i# x s =
+    case atomicNandFetchOldMutableByteArray# mba# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicNandFetchOldMutableByteArray# #-}
+
+  atomicNandFetchNewMutableByteArray# :: MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicNandFetchNewMutableByteArray# ::
+    AtomicBits (PrimBase a) => MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicNandFetchNewMutableByteArray# mba# i# x s =
+    case atomicNandFetchNewMutableByteArray# mba# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicNandFetchNewMutableByteArray# #-}
+
+  atomicOrFetchOldMutableByteArray# :: MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicOrFetchOldMutableByteArray# ::
+    AtomicBits (PrimBase a) => MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicOrFetchOldMutableByteArray# mba# i# x s =
+    case atomicOrFetchOldMutableByteArray# mba# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicOrFetchOldMutableByteArray# #-}
+
+  atomicOrFetchNewMutableByteArray# :: MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicOrFetchNewMutableByteArray# ::
+    AtomicBits (PrimBase a) => MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicOrFetchNewMutableByteArray# mba# i# x s =
+    case atomicOrFetchNewMutableByteArray# mba# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicOrFetchNewMutableByteArray# #-}
+
+  atomicXorFetchOldMutableByteArray# :: MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicXorFetchOldMutableByteArray# ::
+    AtomicBits (PrimBase a) => MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicXorFetchOldMutableByteArray# mba# i# x s =
+    case atomicXorFetchOldMutableByteArray# mba# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicXorFetchOldMutableByteArray# #-}
+
+  atomicXorFetchNewMutableByteArray# :: MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicXorFetchNewMutableByteArray# ::
+    AtomicBits (PrimBase a) => MutableByteArray# s -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicXorFetchNewMutableByteArray# mba# i# x s =
+    case atomicXorFetchNewMutableByteArray# mba# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicXorFetchNewMutableByteArray# #-}
+
+
+  atomicAndFetchOldOffAddr# :: Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicAndFetchOldOffAddr# ::
+    AtomicBits (PrimBase a) => Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicAndFetchOldOffAddr# addr# i# x s =
+    case atomicAndFetchOldOffAddr# addr# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicAndFetchOldOffAddr# #-}
+
+  atomicAndFetchNewOffAddr# :: Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicAndFetchNewOffAddr# ::
+    AtomicBits (PrimBase a) => Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicAndFetchNewOffAddr# addr# i# x s =
+    case atomicAndFetchNewOffAddr# addr# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicAndFetchNewOffAddr# #-}
+
+  atomicNandFetchOldOffAddr# :: Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicNandFetchOldOffAddr# ::
+    AtomicBits (PrimBase a) => Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicNandFetchOldOffAddr# addr# i# x s =
+    case atomicNandFetchOldOffAddr# addr# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicNandFetchOldOffAddr# #-}
+
+  atomicNandFetchNewOffAddr# :: Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicNandFetchNewOffAddr# ::
+    AtomicBits (PrimBase a) => Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicNandFetchNewOffAddr# addr# i# x s =
+    case atomicNandFetchNewOffAddr# addr# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicNandFetchNewOffAddr# #-}
+
+  atomicOrFetchOldOffAddr# :: Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicOrFetchOldOffAddr# ::
+    AtomicBits (PrimBase a) => Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicOrFetchOldOffAddr# addr# i# x s =
+    case atomicOrFetchOldOffAddr# addr# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicOrFetchOldOffAddr# #-}
+
+  atomicOrFetchNewOffAddr# :: Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicOrFetchNewOffAddr# ::
+    AtomicBits (PrimBase a) => Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicOrFetchNewOffAddr# addr# i# x s =
+    case atomicOrFetchNewOffAddr# addr# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicOrFetchNewOffAddr# #-}
+
+  atomicXorFetchOldOffAddr# :: Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicXorFetchOldOffAddr# ::
+    AtomicBits (PrimBase a) => Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicXorFetchOldOffAddr# addr# i# x s =
+    case atomicXorFetchOldOffAddr# addr# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicXorFetchOldOffAddr# #-}
+
+  atomicXorFetchNewOffAddr# :: Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  default atomicXorFetchNewOffAddr# ::
+    AtomicBits (PrimBase a) => Addr# -> Int# -> a -> State# s -> (# State# s, a #)
+  atomicXorFetchNewOffAddr# addr# i# x s =
+    case atomicXorFetchNewOffAddr# addr# i# (toPrimBase x) s of
+      (# s', y #) -> (# s', fromPrimBase y #)
+  {-# INLINE atomicXorFetchNewOffAddr# #-}
+
+
+
+-- | Flip all bits atomically in the element of an array at the supplied
+-- offset. Returns the previous value. Implies full memory barrier.
+atomicNotFetchOldMutableByteArray# ::
+  forall a s . AtomicBits a => MutableByteArray# s -> Int# -> State# s -> (# State# s, a #)
+atomicNotFetchOldMutableByteArray# mba# i# =
+  atomicXorFetchOldMutableByteArray# mba# i# (complement (zeroBits :: a))
+{-# INLINE atomicNotFetchOldMutableByteArray# #-}
+
+-- | Flip all bits atomically in the element of an array at the supplied
+-- offset. Returns the new value. Implies full memory barrier.
+atomicNotFetchNewMutableByteArray# ::
+  forall a s . AtomicBits a => MutableByteArray# s -> Int# -> State# s -> (# State# s, a #)
+atomicNotFetchNewMutableByteArray# mba# i# =
+  atomicXorFetchNewMutableByteArray# mba# i# (complement (zeroBits :: a))
+{-# INLINE atomicNotFetchNewMutableByteArray# #-}
+
+
+-- | Flip all bits atomically in the element of an array at the supplied
+-- offset. Returns the previous value. Implies full memory barrier.
+atomicNotFetchOldOffAddr# ::
+  forall a s . AtomicBits a => Addr# -> Int# -> State# s -> (# State# s, a #)
+atomicNotFetchOldOffAddr# addr# i# =
+  atomicXorFetchOldOffAddr# addr# i# (complement (zeroBits :: a))
+{-# INLINE atomicNotFetchOldOffAddr# #-}
+
+-- | Flip all bits atomically in the element of an array at the supplied
+-- offset. Returns the new value. Implies full memory barrier.
+atomicNotFetchNewOffAddr# ::
+  forall a s . AtomicBits a => Addr# -> Int# -> State# s -> (# State# s, a #)
+atomicNotFetchNewOffAddr# addr# i# =
+  atomicXorFetchNewOffAddr# addr# i# (complement (zeroBits :: a))
+{-# INLINE atomicNotFetchNewOffAddr# #-}
+
+
+
+instance Atomic Int8 where
+  casMutableByteArray# mba# i# old new = unsafePrimBase (syncCasInt8ArrayIO mba# i# old new)
+  {-# INLINE casMutableByteArray# #-}
+  casOffAddr# addr# i# old new = unsafePrimBase (syncCasInt8AddrIO addr# i# old new)
+  {-# INLINE casOffAddr# #-}
+  casBoolMutableByteArray# mba# i# old new = ioCBoolToBoolBase (syncCasInt8BoolArrayIO mba# i# old new)
+  {-# INLINE casBoolMutableByteArray# #-}
+  casBoolOffAddr# addr# i# old new = ioCBoolToBoolBase (syncCasInt8BoolAddrIO addr# i# old new)
+  {-# INLINE casBoolOffAddr# #-}
+
+instance AtomicCount Int8 where
+  atomicAddFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncAddFetchOldInt8ArrayIO mba# i# a)
+  {-# INLINE atomicAddFetchOldMutableByteArray# #-}
+  atomicAddFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncAddFetchNewInt8ArrayIO mba# i# a)
+  {-# INLINE atomicAddFetchNewMutableByteArray# #-}
+  atomicSubFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncSubFetchOldInt8ArrayIO mba# i# a)
+  {-# INLINE atomicSubFetchOldMutableByteArray# #-}
+  atomicSubFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncSubFetchNewInt8ArrayIO mba# i# a)
+  {-# INLINE atomicSubFetchNewMutableByteArray# #-}
+  atomicAddFetchOldOffAddr# addr# i# a = unsafePrimBase (syncAddFetchOldInt8AddrIO addr# i# a)
+  {-# INLINE atomicAddFetchOldOffAddr# #-}
+  atomicAddFetchNewOffAddr# addr# i# a = unsafePrimBase (syncAddFetchNewInt8AddrIO addr# i# a)
+  {-# INLINE atomicAddFetchNewOffAddr# #-}
+  atomicSubFetchOldOffAddr# addr# i# a = unsafePrimBase (syncSubFetchOldInt8AddrIO addr# i# a)
+  {-# INLINE atomicSubFetchOldOffAddr# #-}
+  atomicSubFetchNewOffAddr# addr# i# a = unsafePrimBase (syncSubFetchNewInt8AddrIO addr# i# a)
+  {-# INLINE atomicSubFetchNewOffAddr# #-}
+
+instance AtomicBits Int8 where
+  atomicAndFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncAndFetchOldInt8ArrayIO mba# i# a)
+  {-# INLINE atomicAndFetchOldMutableByteArray# #-}
+  atomicAndFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncAndFetchNewInt8ArrayIO mba# i# a)
+  {-# INLINE atomicAndFetchNewMutableByteArray# #-}
+  atomicNandFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncNandFetchOldInt8ArrayIO mba# i# a)
+  {-# INLINE atomicNandFetchOldMutableByteArray# #-}
+  atomicNandFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncNandFetchNewInt8ArrayIO mba# i# a)
+  {-# INLINE atomicNandFetchNewMutableByteArray# #-}
+  atomicOrFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncOrFetchOldInt8ArrayIO mba# i# a)
+  {-# INLINE atomicOrFetchOldMutableByteArray# #-}
+  atomicOrFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncOrFetchNewInt8ArrayIO mba# i# a)
+  {-# INLINE atomicOrFetchNewMutableByteArray# #-}
+  atomicXorFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncXorFetchOldInt8ArrayIO mba# i# a)
+  {-# INLINE atomicXorFetchOldMutableByteArray# #-}
+  atomicXorFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncXorFetchNewInt8ArrayIO mba# i# a)
+  {-# INLINE atomicXorFetchNewMutableByteArray# #-}
+  atomicAndFetchOldOffAddr# addr# i# a = unsafePrimBase (syncAndFetchOldInt8AddrIO addr# i# a)
+  {-# INLINE atomicAndFetchOldOffAddr# #-}
+  atomicAndFetchNewOffAddr# addr# i# a = unsafePrimBase (syncAndFetchNewInt8AddrIO addr# i# a)
+  {-# INLINE atomicAndFetchNewOffAddr# #-}
+  atomicNandFetchOldOffAddr# addr# i# a = unsafePrimBase (syncNandFetchOldInt8AddrIO addr# i# a)
+  {-# INLINE atomicNandFetchOldOffAddr# #-}
+  atomicNandFetchNewOffAddr# addr# i# a = unsafePrimBase (syncNandFetchNewInt8AddrIO addr# i# a)
+  {-# INLINE atomicNandFetchNewOffAddr# #-}
+  atomicOrFetchOldOffAddr# addr# i# a = unsafePrimBase (syncOrFetchOldInt8AddrIO addr# i# a)
+  {-# INLINE atomicOrFetchOldOffAddr# #-}
+  atomicOrFetchNewOffAddr# addr# i# a = unsafePrimBase (syncOrFetchNewInt8AddrIO addr# i# a)
+  {-# INLINE atomicOrFetchNewOffAddr# #-}
+  atomicXorFetchOldOffAddr# addr# i# a = unsafePrimBase (syncXorFetchOldInt8AddrIO addr# i# a)
+  {-# INLINE atomicXorFetchOldOffAddr# #-}
+  atomicXorFetchNewOffAddr# addr# i# a = unsafePrimBase (syncXorFetchNewInt8AddrIO addr# i# a)
+  {-# INLINE atomicXorFetchNewOffAddr# #-}
+
+instance Atomic Int16 where
+  casMutableByteArray# mba# i# old new = unsafePrimBase (syncCasInt16ArrayIO mba# i# old new)
+  {-# INLINE casMutableByteArray# #-}
+  casOffAddr# addr# i# old new = unsafePrimBase (syncCasInt16AddrIO addr# i# old new)
+  {-# INLINE casOffAddr# #-}
+  casBoolMutableByteArray# mba# i# old new =
+    ioCBoolToBoolBase (syncCasInt16BoolArrayIO mba# i# old new)
+  {-# INLINE casBoolMutableByteArray# #-}
+  casBoolOffAddr# addr# i# old new = ioCBoolToBoolBase (syncCasInt16BoolAddrIO addr# i# old new)
+  {-# INLINE casBoolOffAddr# #-}
+
+instance AtomicCount Int16 where
+  atomicAddFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncAddFetchOldInt16ArrayIO mba# i# a)
+  {-# INLINE atomicAddFetchOldMutableByteArray# #-}
+  atomicAddFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncAddFetchNewInt16ArrayIO mba# i# a)
+  {-# INLINE atomicAddFetchNewMutableByteArray# #-}
+  atomicSubFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncSubFetchOldInt16ArrayIO mba# i# a)
+  {-# INLINE atomicSubFetchOldMutableByteArray# #-}
+  atomicSubFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncSubFetchNewInt16ArrayIO mba# i# a)
+  {-# INLINE atomicSubFetchNewMutableByteArray# #-}
+  atomicAddFetchOldOffAddr# addr# i# a = unsafePrimBase (syncAddFetchOldInt16AddrIO addr# i# a)
+  {-# INLINE atomicAddFetchOldOffAddr# #-}
+  atomicAddFetchNewOffAddr# addr# i# a = unsafePrimBase (syncAddFetchNewInt16AddrIO addr# i# a)
+  {-# INLINE atomicAddFetchNewOffAddr# #-}
+  atomicSubFetchOldOffAddr# addr# i# a = unsafePrimBase (syncSubFetchOldInt16AddrIO addr# i# a)
+  {-# INLINE atomicSubFetchOldOffAddr# #-}
+  atomicSubFetchNewOffAddr# addr# i# a = unsafePrimBase (syncSubFetchNewInt16AddrIO addr# i# a)
+  {-# INLINE atomicSubFetchNewOffAddr# #-}
+
+instance AtomicBits Int16 where
+  atomicAndFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncAndFetchOldInt16ArrayIO mba# i# a)
+  {-# INLINE atomicAndFetchOldMutableByteArray# #-}
+  atomicAndFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncAndFetchNewInt16ArrayIO mba# i# a)
+  {-# INLINE atomicAndFetchNewMutableByteArray# #-}
+  atomicNandFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncNandFetchOldInt16ArrayIO mba# i# a)
+  {-# INLINE atomicNandFetchOldMutableByteArray# #-}
+  atomicNandFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncNandFetchNewInt16ArrayIO mba# i# a)
+  {-# INLINE atomicNandFetchNewMutableByteArray# #-}
+  atomicOrFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncOrFetchOldInt16ArrayIO mba# i# a)
+  {-# INLINE atomicOrFetchOldMutableByteArray# #-}
+  atomicOrFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncOrFetchNewInt16ArrayIO mba# i# a)
+  {-# INLINE atomicOrFetchNewMutableByteArray# #-}
+  atomicXorFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncXorFetchOldInt16ArrayIO mba# i# a)
+  {-# INLINE atomicXorFetchOldMutableByteArray# #-}
+  atomicXorFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncXorFetchNewInt16ArrayIO mba# i# a)
+  {-# INLINE atomicXorFetchNewMutableByteArray# #-}
+  atomicAndFetchOldOffAddr# addr# i# a = unsafePrimBase (syncAndFetchOldInt16AddrIO addr# i# a)
+  {-# INLINE atomicAndFetchOldOffAddr# #-}
+  atomicAndFetchNewOffAddr# addr# i# a = unsafePrimBase (syncAndFetchNewInt16AddrIO addr# i# a)
+  {-# INLINE atomicAndFetchNewOffAddr# #-}
+  atomicNandFetchOldOffAddr# addr# i# a = unsafePrimBase (syncNandFetchOldInt16AddrIO addr# i# a)
+  {-# INLINE atomicNandFetchOldOffAddr# #-}
+  atomicNandFetchNewOffAddr# addr# i# a = unsafePrimBase (syncNandFetchNewInt16AddrIO addr# i# a)
+  {-# INLINE atomicNandFetchNewOffAddr# #-}
+  atomicOrFetchOldOffAddr# addr# i# a = unsafePrimBase (syncOrFetchOldInt16AddrIO addr# i# a)
+  {-# INLINE atomicOrFetchOldOffAddr# #-}
+  atomicOrFetchNewOffAddr# addr# i# a = unsafePrimBase (syncOrFetchNewInt16AddrIO addr# i# a)
+  {-# INLINE atomicOrFetchNewOffAddr# #-}
+  atomicXorFetchOldOffAddr# addr# i# a = unsafePrimBase (syncXorFetchOldInt16AddrIO addr# i# a)
+  {-# INLINE atomicXorFetchOldOffAddr# #-}
+  atomicXorFetchNewOffAddr# addr# i# a = unsafePrimBase (syncXorFetchNewInt16AddrIO addr# i# a)
+  {-# INLINE atomicXorFetchNewOffAddr# #-}
+
+instance Atomic Int32 where
+  casMutableByteArray# mba# i# old new = unsafePrimBase (syncCasInt32ArrayIO mba# i# old new)
+  {-# INLINE casMutableByteArray# #-}
+  casOffAddr# addr# i# old new = unsafePrimBase (syncCasInt32AddrIO addr# i# old new)
+  {-# INLINE casOffAddr# #-}
+  casBoolMutableByteArray# mba# i# old new =
+    ioCBoolToBoolBase (syncCasInt32BoolArrayIO mba# i# old new)
+  {-# INLINE casBoolMutableByteArray# #-}
+  casBoolOffAddr# addr# i# old new =
+    ioCBoolToBoolBase (syncCasInt32BoolAddrIO addr# i# old new)
+  {-# INLINE casBoolOffAddr# #-}
+
+instance AtomicCount Int32 where
+  atomicAddFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncAddFetchOldInt32ArrayIO mba# i# a)
+  {-# INLINE atomicAddFetchOldMutableByteArray# #-}
+  atomicAddFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncAddFetchNewInt32ArrayIO mba# i# a)
+  {-# INLINE atomicAddFetchNewMutableByteArray# #-}
+  atomicSubFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncSubFetchOldInt32ArrayIO mba# i# a)
+  {-# INLINE atomicSubFetchOldMutableByteArray# #-}
+  atomicSubFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncSubFetchNewInt32ArrayIO mba# i# a)
+  {-# INLINE atomicSubFetchNewMutableByteArray# #-}
+  atomicAddFetchOldOffAddr# addr# i# a = unsafePrimBase (syncAddFetchOldInt32AddrIO addr# i# a)
+  {-# INLINE atomicAddFetchOldOffAddr# #-}
+  atomicAddFetchNewOffAddr# addr# i# a = unsafePrimBase (syncAddFetchNewInt32AddrIO addr# i# a)
+  {-# INLINE atomicAddFetchNewOffAddr# #-}
+  atomicSubFetchOldOffAddr# addr# i# a = unsafePrimBase (syncSubFetchOldInt32AddrIO addr# i# a)
+  {-# INLINE atomicSubFetchOldOffAddr# #-}
+  atomicSubFetchNewOffAddr# addr# i# a = unsafePrimBase (syncSubFetchNewInt32AddrIO addr# i# a)
+  {-# INLINE atomicSubFetchNewOffAddr# #-}
+
+instance AtomicBits Int32 where
+  atomicAndFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncAndFetchOldInt32ArrayIO mba# i# a)
+  {-# INLINE atomicAndFetchOldMutableByteArray# #-}
+  atomicAndFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncAndFetchNewInt32ArrayIO mba# i# a)
+  {-# INLINE atomicAndFetchNewMutableByteArray# #-}
+  atomicNandFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncNandFetchOldInt32ArrayIO mba# i# a)
+  {-# INLINE atomicNandFetchOldMutableByteArray# #-}
+  atomicNandFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncNandFetchNewInt32ArrayIO mba# i# a)
+  {-# INLINE atomicNandFetchNewMutableByteArray# #-}
+  atomicOrFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncOrFetchOldInt32ArrayIO mba# i# a)
+  {-# INLINE atomicOrFetchOldMutableByteArray# #-}
+  atomicOrFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncOrFetchNewInt32ArrayIO mba# i# a)
+  {-# INLINE atomicOrFetchNewMutableByteArray# #-}
+  atomicXorFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncXorFetchOldInt32ArrayIO mba# i# a)
+  {-# INLINE atomicXorFetchOldMutableByteArray# #-}
+  atomicXorFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncXorFetchNewInt32ArrayIO mba# i# a)
+  {-# INLINE atomicXorFetchNewMutableByteArray# #-}
+  atomicAndFetchOldOffAddr# addr# i# a = unsafePrimBase (syncAndFetchOldInt32AddrIO addr# i# a)
+  {-# INLINE atomicAndFetchOldOffAddr# #-}
+  atomicAndFetchNewOffAddr# addr# i# a = unsafePrimBase (syncAndFetchNewInt32AddrIO addr# i# a)
+  {-# INLINE atomicAndFetchNewOffAddr# #-}
+  atomicNandFetchOldOffAddr# addr# i# a = unsafePrimBase (syncNandFetchOldInt32AddrIO addr# i# a)
+  {-# INLINE atomicNandFetchOldOffAddr# #-}
+  atomicNandFetchNewOffAddr# addr# i# a = unsafePrimBase (syncNandFetchNewInt32AddrIO addr# i# a)
+  {-# INLINE atomicNandFetchNewOffAddr# #-}
+  atomicOrFetchOldOffAddr# addr# i# a = unsafePrimBase (syncOrFetchOldInt32AddrIO addr# i# a)
+  {-# INLINE atomicOrFetchOldOffAddr# #-}
+  atomicOrFetchNewOffAddr# addr# i# a = unsafePrimBase (syncOrFetchNewInt32AddrIO addr# i# a)
+  {-# INLINE atomicOrFetchNewOffAddr# #-}
+  atomicXorFetchOldOffAddr# addr# i# a = unsafePrimBase (syncXorFetchOldInt32AddrIO addr# i# a)
+  {-# INLINE atomicXorFetchOldOffAddr# #-}
+  atomicXorFetchNewOffAddr# addr# i# a = unsafePrimBase (syncXorFetchNewInt32AddrIO addr# i# a)
+  {-# INLINE atomicXorFetchNewOffAddr# #-}
+
+-- TODO: compare with and possibly swap for primops
+instance Atomic Int where
+  casMutableByteArray# mba# i# old new = unsafePrimBase (syncCasIntArrayIO mba# i# old new)
+  {-# INLINE casMutableByteArray# #-}
+  casOffAddr# addr# i# old new = unsafePrimBase (syncCasIntAddrIO addr# i# old new)
+  {-# INLINE casOffAddr# #-}
+  casBoolMutableByteArray# mba# i# old new = ioCBoolToBoolBase (syncCasIntBoolArrayIO mba# i# old new)
+  {-# INLINE casBoolMutableByteArray# #-}
+  casBoolOffAddr# addr# i# old new = ioCBoolToBoolBase (syncCasIntBoolAddrIO addr# i# old new)
+  {-# INLINE casBoolOffAddr# #-}
+
+instance AtomicCount Int where
+  atomicAddFetchOldMutableByteArray# mba# i# a =
+    unsafePrimBase (syncAddFetchOldIntArrayIO mba# i# a)
+    -- case fetchAddIntArray# mba# i# a# s of
+    --   (# s', a'# #) -> (# s', I# a'# #)
+  {-# INLINE atomicAddFetchOldMutableByteArray# #-}
+  atomicAddFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncAddFetchNewIntArrayIO mba# i# a)
+  {-# INLINE atomicAddFetchNewMutableByteArray# #-}
+  atomicSubFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncSubFetchOldIntArrayIO mba# i# a)
+  {-# INLINE atomicSubFetchOldMutableByteArray# #-}
+  atomicSubFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncSubFetchNewIntArrayIO mba# i# a)
+  {-# INLINE atomicSubFetchNewMutableByteArray# #-}
+  atomicAddFetchOldOffAddr# addr# i# a = unsafePrimBase (syncAddFetchOldIntAddrIO addr# i# a)
+  {-# INLINE atomicAddFetchOldOffAddr# #-}
+  atomicAddFetchNewOffAddr# addr# i# a = unsafePrimBase (syncAddFetchNewIntAddrIO addr# i# a)
+  {-# INLINE atomicAddFetchNewOffAddr# #-}
+  atomicSubFetchOldOffAddr# addr# i# a = unsafePrimBase (syncSubFetchOldIntAddrIO addr# i# a)
+  {-# INLINE atomicSubFetchOldOffAddr# #-}
+  atomicSubFetchNewOffAddr# addr# i# a = unsafePrimBase (syncSubFetchNewIntAddrIO addr# i# a)
+  {-# INLINE atomicSubFetchNewOffAddr# #-}
+
+instance AtomicBits Int where
+  atomicAndFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncAndFetchOldIntArrayIO mba# i# a)
+  {-# INLINE atomicAndFetchOldMutableByteArray# #-}
+  atomicAndFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncAndFetchNewIntArrayIO mba# i# a)
+  {-# INLINE atomicAndFetchNewMutableByteArray# #-}
+  atomicNandFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncNandFetchOldIntArrayIO mba# i# a)
+  {-# INLINE atomicNandFetchOldMutableByteArray# #-}
+  atomicNandFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncNandFetchNewIntArrayIO mba# i# a)
+  {-# INLINE atomicNandFetchNewMutableByteArray# #-}
+  atomicOrFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncOrFetchOldIntArrayIO mba# i# a)
+  {-# INLINE atomicOrFetchOldMutableByteArray# #-}
+  atomicOrFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncOrFetchNewIntArrayIO mba# i# a)
+  {-# INLINE atomicOrFetchNewMutableByteArray# #-}
+  atomicXorFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncXorFetchOldIntArrayIO mba# i# a)
+  {-# INLINE atomicXorFetchOldMutableByteArray# #-}
+  atomicXorFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncXorFetchNewIntArrayIO mba# i# a)
+  {-# INLINE atomicXorFetchNewMutableByteArray# #-}
+  atomicAndFetchOldOffAddr# addr# i# a = unsafePrimBase (syncAndFetchOldIntAddrIO addr# i# a)
+  {-# INLINE atomicAndFetchOldOffAddr# #-}
+  atomicAndFetchNewOffAddr# addr# i# a = unsafePrimBase (syncAndFetchNewIntAddrIO addr# i# a)
+  {-# INLINE atomicAndFetchNewOffAddr# #-}
+  atomicNandFetchOldOffAddr# addr# i# a = unsafePrimBase (syncNandFetchOldIntAddrIO addr# i# a)
+  {-# INLINE atomicNandFetchOldOffAddr# #-}
+  atomicNandFetchNewOffAddr# addr# i# a = unsafePrimBase (syncNandFetchNewIntAddrIO addr# i# a)
+  {-# INLINE atomicNandFetchNewOffAddr# #-}
+  atomicOrFetchOldOffAddr# addr# i# a = unsafePrimBase (syncOrFetchOldIntAddrIO addr# i# a)
+  {-# INLINE atomicOrFetchOldOffAddr# #-}
+  atomicOrFetchNewOffAddr# addr# i# a = unsafePrimBase (syncOrFetchNewIntAddrIO addr# i# a)
+  {-# INLINE atomicOrFetchNewOffAddr# #-}
+  atomicXorFetchOldOffAddr# addr# i# a = unsafePrimBase (syncXorFetchOldIntAddrIO addr# i# a)
+  {-# INLINE atomicXorFetchOldOffAddr# #-}
+  atomicXorFetchNewOffAddr# addr# i# a = unsafePrimBase (syncXorFetchNewIntAddrIO addr# i# a)
+  {-# INLINE atomicXorFetchNewOffAddr# #-}
+
+
+
+
+instance Atomic Word8 where
+  casMutableByteArray# mba# i# old new = unsafePrimBase (syncCasWord8ArrayIO mba# i# old new)
+  {-# INLINE casMutableByteArray# #-}
+  casOffAddr# addr# i# old new = unsafePrimBase (syncCasWord8AddrIO addr# i# old new)
+  {-# INLINE casOffAddr# #-}
+  casBoolMutableByteArray# mba# i# old new =
+    ioCBoolToBoolBase (syncCasWord8BoolArrayIO mba# i# old new)
+  {-# INLINE casBoolMutableByteArray# #-}
+  casBoolOffAddr# addr# i# old new = ioCBoolToBoolBase (syncCasWord8BoolAddrIO addr# i# old new)
+  {-# INLINE casBoolOffAddr# #-}
+
+instance AtomicCount Word8 where
+  atomicAddFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncAddFetchOldWord8ArrayIO mba# i# a)
+  {-# INLINE atomicAddFetchOldMutableByteArray# #-}
+  atomicAddFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncAddFetchNewWord8ArrayIO mba# i# a)
+  {-# INLINE atomicAddFetchNewMutableByteArray# #-}
+  atomicSubFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncSubFetchOldWord8ArrayIO mba# i# a)
+  {-# INLINE atomicSubFetchOldMutableByteArray# #-}
+  atomicSubFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncSubFetchNewWord8ArrayIO mba# i# a)
+  {-# INLINE atomicSubFetchNewMutableByteArray# #-}
+  atomicAddFetchOldOffAddr# addr# i# a = unsafePrimBase (syncAddFetchOldWord8AddrIO addr# i# a)
+  {-# INLINE atomicAddFetchOldOffAddr# #-}
+  atomicAddFetchNewOffAddr# addr# i# a = unsafePrimBase (syncAddFetchNewWord8AddrIO addr# i# a)
+  {-# INLINE atomicAddFetchNewOffAddr# #-}
+  atomicSubFetchOldOffAddr# addr# i# a = unsafePrimBase (syncSubFetchOldWord8AddrIO addr# i# a)
+  {-# INLINE atomicSubFetchOldOffAddr# #-}
+  atomicSubFetchNewOffAddr# addr# i# a = unsafePrimBase (syncSubFetchNewWord8AddrIO addr# i# a)
+  {-# INLINE atomicSubFetchNewOffAddr# #-}
+
+instance AtomicBits Word8 where
+  atomicAndFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncAndFetchOldWord8ArrayIO mba# i# a)
+  {-# INLINE atomicAndFetchOldMutableByteArray# #-}
+  atomicAndFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncAndFetchNewWord8ArrayIO mba# i# a)
+  {-# INLINE atomicAndFetchNewMutableByteArray# #-}
+  atomicNandFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncNandFetchOldWord8ArrayIO mba# i# a)
+  {-# INLINE atomicNandFetchOldMutableByteArray# #-}
+  atomicNandFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncNandFetchNewWord8ArrayIO mba# i# a)
+  {-# INLINE atomicNandFetchNewMutableByteArray# #-}
+  atomicOrFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncOrFetchOldWord8ArrayIO mba# i# a)
+  {-# INLINE atomicOrFetchOldMutableByteArray# #-}
+  atomicOrFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncOrFetchNewWord8ArrayIO mba# i# a)
+  {-# INLINE atomicOrFetchNewMutableByteArray# #-}
+  atomicXorFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncXorFetchOldWord8ArrayIO mba# i# a)
+  {-# INLINE atomicXorFetchOldMutableByteArray# #-}
+  atomicXorFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncXorFetchNewWord8ArrayIO mba# i# a)
+  {-# INLINE atomicXorFetchNewMutableByteArray# #-}
+  atomicAndFetchOldOffAddr# addr# i# a = unsafePrimBase (syncAndFetchOldWord8AddrIO addr# i# a)
+  {-# INLINE atomicAndFetchOldOffAddr# #-}
+  atomicAndFetchNewOffAddr# addr# i# a = unsafePrimBase (syncAndFetchNewWord8AddrIO addr# i# a)
+  {-# INLINE atomicAndFetchNewOffAddr# #-}
+  atomicNandFetchOldOffAddr# addr# i# a = unsafePrimBase (syncNandFetchOldWord8AddrIO addr# i# a)
+  {-# INLINE atomicNandFetchOldOffAddr# #-}
+  atomicNandFetchNewOffAddr# addr# i# a = unsafePrimBase (syncNandFetchNewWord8AddrIO addr# i# a)
+  {-# INLINE atomicNandFetchNewOffAddr# #-}
+  atomicOrFetchOldOffAddr# addr# i# a = unsafePrimBase (syncOrFetchOldWord8AddrIO addr# i# a)
+  {-# INLINE atomicOrFetchOldOffAddr# #-}
+  atomicOrFetchNewOffAddr# addr# i# a = unsafePrimBase (syncOrFetchNewWord8AddrIO addr# i# a)
+  {-# INLINE atomicOrFetchNewOffAddr# #-}
+  atomicXorFetchOldOffAddr# addr# i# a = unsafePrimBase (syncXorFetchOldWord8AddrIO addr# i# a)
+  {-# INLINE atomicXorFetchOldOffAddr# #-}
+  atomicXorFetchNewOffAddr# addr# i# a = unsafePrimBase (syncXorFetchNewWord8AddrIO addr# i# a)
+  {-# INLINE atomicXorFetchNewOffAddr# #-}
+
+instance Atomic Word16 where
+  casMutableByteArray# mba# i# old new = unsafePrimBase (syncCasWord16ArrayIO mba# i# old new)
+  {-# INLINE casMutableByteArray# #-}
+  casOffAddr# addr# i# old new = unsafePrimBase (syncCasWord16AddrIO addr# i# old new)
+  {-# INLINE casOffAddr# #-}
+  casBoolMutableByteArray# mba# i# old new =
+    ioCBoolToBoolBase (syncCasWord16BoolArrayIO mba# i# old new)
+  {-# INLINE casBoolMutableByteArray# #-}
+  casBoolOffAddr# addr# i# old new = ioCBoolToBoolBase (syncCasWord16BoolAddrIO addr# i# old new)
+  {-# INLINE casBoolOffAddr# #-}
+
+instance AtomicCount Word16 where
+  atomicAddFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncAddFetchOldWord16ArrayIO mba# i# a)
+  {-# INLINE atomicAddFetchOldMutableByteArray# #-}
+  atomicAddFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncAddFetchNewWord16ArrayIO mba# i# a)
+  {-# INLINE atomicAddFetchNewMutableByteArray# #-}
+  atomicSubFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncSubFetchOldWord16ArrayIO mba# i# a)
+  {-# INLINE atomicSubFetchOldMutableByteArray# #-}
+  atomicSubFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncSubFetchNewWord16ArrayIO mba# i# a)
+  {-# INLINE atomicSubFetchNewMutableByteArray# #-}
+  atomicAddFetchOldOffAddr# addr# i# a = unsafePrimBase (syncAddFetchOldWord16AddrIO addr# i# a)
+  {-# INLINE atomicAddFetchOldOffAddr# #-}
+  atomicAddFetchNewOffAddr# addr# i# a = unsafePrimBase (syncAddFetchNewWord16AddrIO addr# i# a)
+  {-# INLINE atomicAddFetchNewOffAddr# #-}
+  atomicSubFetchOldOffAddr# addr# i# a = unsafePrimBase (syncSubFetchOldWord16AddrIO addr# i# a)
+  {-# INLINE atomicSubFetchOldOffAddr# #-}
+  atomicSubFetchNewOffAddr# addr# i# a = unsafePrimBase (syncSubFetchNewWord16AddrIO addr# i# a)
+  {-# INLINE atomicSubFetchNewOffAddr# #-}
+
+instance AtomicBits Word16 where
+  atomicAndFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncAndFetchOldWord16ArrayIO mba# i# a)
+  {-# INLINE atomicAndFetchOldMutableByteArray# #-}
+  atomicAndFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncAndFetchNewWord16ArrayIO mba# i# a)
+  {-# INLINE atomicAndFetchNewMutableByteArray# #-}
+  atomicNandFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncNandFetchOldWord16ArrayIO mba# i# a)
+  {-# INLINE atomicNandFetchOldMutableByteArray# #-}
+  atomicNandFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncNandFetchNewWord16ArrayIO mba# i# a)
+  {-# INLINE atomicNandFetchNewMutableByteArray# #-}
+  atomicOrFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncOrFetchOldWord16ArrayIO mba# i# a)
+  {-# INLINE atomicOrFetchOldMutableByteArray# #-}
+  atomicOrFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncOrFetchNewWord16ArrayIO mba# i# a)
+  {-# INLINE atomicOrFetchNewMutableByteArray# #-}
+  atomicXorFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncXorFetchOldWord16ArrayIO mba# i# a)
+  {-# INLINE atomicXorFetchOldMutableByteArray# #-}
+  atomicXorFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncXorFetchNewWord16ArrayIO mba# i# a)
+  {-# INLINE atomicXorFetchNewMutableByteArray# #-}
+  atomicAndFetchOldOffAddr# addr# i# a = unsafePrimBase (syncAndFetchOldWord16AddrIO addr# i# a)
+  {-# INLINE atomicAndFetchOldOffAddr# #-}
+  atomicAndFetchNewOffAddr# addr# i# a = unsafePrimBase (syncAndFetchNewWord16AddrIO addr# i# a)
+  {-# INLINE atomicAndFetchNewOffAddr# #-}
+  atomicNandFetchOldOffAddr# addr# i# a = unsafePrimBase (syncNandFetchOldWord16AddrIO addr# i# a)
+  {-# INLINE atomicNandFetchOldOffAddr# #-}
+  atomicNandFetchNewOffAddr# addr# i# a = unsafePrimBase (syncNandFetchNewWord16AddrIO addr# i# a)
+  {-# INLINE atomicNandFetchNewOffAddr# #-}
+  atomicOrFetchOldOffAddr# addr# i# a = unsafePrimBase (syncOrFetchOldWord16AddrIO addr# i# a)
+  {-# INLINE atomicOrFetchOldOffAddr# #-}
+  atomicOrFetchNewOffAddr# addr# i# a = unsafePrimBase (syncOrFetchNewWord16AddrIO addr# i# a)
+  {-# INLINE atomicOrFetchNewOffAddr# #-}
+  atomicXorFetchOldOffAddr# addr# i# a = unsafePrimBase (syncXorFetchOldWord16AddrIO addr# i# a)
+  {-# INLINE atomicXorFetchOldOffAddr# #-}
+  atomicXorFetchNewOffAddr# addr# i# a = unsafePrimBase (syncXorFetchNewWord16AddrIO addr# i# a)
+  {-# INLINE atomicXorFetchNewOffAddr# #-}
+
+
+instance Atomic Word32 where
+  casMutableByteArray# mba# i# old new = unsafePrimBase (syncCasWord32ArrayIO mba# i# old new)
+  {-# INLINE casMutableByteArray# #-}
+  casOffAddr# addr# i# old new = unsafePrimBase (syncCasWord32AddrIO addr# i# old new)
+  {-# INLINE casOffAddr# #-}
+  casBoolMutableByteArray# mba# i# old new =
+    ioCBoolToBoolBase (syncCasWord32BoolArrayIO mba# i# old new)
+  {-# INLINE casBoolMutableByteArray# #-}
+  casBoolOffAddr# addr# i# old new = ioCBoolToBoolBase (syncCasWord32BoolAddrIO addr# i# old new)
+  {-# INLINE casBoolOffAddr# #-}
+
+instance AtomicCount Word32 where
+  atomicAddFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncAddFetchOldWord32ArrayIO mba# i# a)
+  {-# INLINE atomicAddFetchOldMutableByteArray# #-}
+  atomicAddFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncAddFetchNewWord32ArrayIO mba# i# a)
+  {-# INLINE atomicAddFetchNewMutableByteArray# #-}
+  atomicSubFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncSubFetchOldWord32ArrayIO mba# i# a)
+  {-# INLINE atomicSubFetchOldMutableByteArray# #-}
+  atomicSubFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncSubFetchNewWord32ArrayIO mba# i# a)
+  {-# INLINE atomicSubFetchNewMutableByteArray# #-}
+  atomicAddFetchOldOffAddr# addr# i# a = unsafePrimBase (syncAddFetchOldWord32AddrIO addr# i# a)
+  {-# INLINE atomicAddFetchOldOffAddr# #-}
+  atomicAddFetchNewOffAddr# addr# i# a = unsafePrimBase (syncAddFetchNewWord32AddrIO addr# i# a)
+  {-# INLINE atomicAddFetchNewOffAddr# #-}
+  atomicSubFetchOldOffAddr# addr# i# a = unsafePrimBase (syncSubFetchOldWord32AddrIO addr# i# a)
+  {-# INLINE atomicSubFetchOldOffAddr# #-}
+  atomicSubFetchNewOffAddr# addr# i# a = unsafePrimBase (syncSubFetchNewWord32AddrIO addr# i# a)
+  {-# INLINE atomicSubFetchNewOffAddr# #-}
+
+instance AtomicBits Word32 where
+  atomicAndFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncAndFetchOldWord32ArrayIO mba# i# a)
+  {-# INLINE atomicAndFetchOldMutableByteArray# #-}
+  atomicAndFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncAndFetchNewWord32ArrayIO mba# i# a)
+  {-# INLINE atomicAndFetchNewMutableByteArray# #-}
+  atomicNandFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncNandFetchOldWord32ArrayIO mba# i# a)
+  {-# INLINE atomicNandFetchOldMutableByteArray# #-}
+  atomicNandFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncNandFetchNewWord32ArrayIO mba# i# a)
+  {-# INLINE atomicNandFetchNewMutableByteArray# #-}
+  atomicOrFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncOrFetchOldWord32ArrayIO mba# i# a)
+  {-# INLINE atomicOrFetchOldMutableByteArray# #-}
+  atomicOrFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncOrFetchNewWord32ArrayIO mba# i# a)
+  {-# INLINE atomicOrFetchNewMutableByteArray# #-}
+  atomicXorFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncXorFetchOldWord32ArrayIO mba# i# a)
+  {-# INLINE atomicXorFetchOldMutableByteArray# #-}
+  atomicXorFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncXorFetchNewWord32ArrayIO mba# i# a)
+  {-# INLINE atomicXorFetchNewMutableByteArray# #-}
+  atomicAndFetchOldOffAddr# addr# i# a = unsafePrimBase (syncAndFetchOldWord32AddrIO addr# i# a)
+  {-# INLINE atomicAndFetchOldOffAddr# #-}
+  atomicAndFetchNewOffAddr# addr# i# a = unsafePrimBase (syncAndFetchNewWord32AddrIO addr# i# a)
+  {-# INLINE atomicAndFetchNewOffAddr# #-}
+  atomicNandFetchOldOffAddr# addr# i# a = unsafePrimBase (syncNandFetchOldWord32AddrIO addr# i# a)
+  {-# INLINE atomicNandFetchOldOffAddr# #-}
+  atomicNandFetchNewOffAddr# addr# i# a = unsafePrimBase (syncNandFetchNewWord32AddrIO addr# i# a)
+  {-# INLINE atomicNandFetchNewOffAddr# #-}
+  atomicOrFetchOldOffAddr# addr# i# a = unsafePrimBase (syncOrFetchOldWord32AddrIO addr# i# a)
+  {-# INLINE atomicOrFetchOldOffAddr# #-}
+  atomicOrFetchNewOffAddr# addr# i# a = unsafePrimBase (syncOrFetchNewWord32AddrIO addr# i# a)
+  {-# INLINE atomicOrFetchNewOffAddr# #-}
+  atomicXorFetchOldOffAddr# addr# i# a = unsafePrimBase (syncXorFetchOldWord32AddrIO addr# i# a)
+  {-# INLINE atomicXorFetchOldOffAddr# #-}
+  atomicXorFetchNewOffAddr# addr# i# a = unsafePrimBase (syncXorFetchNewWord32AddrIO addr# i# a)
+  {-# INLINE atomicXorFetchNewOffAddr# #-}
+
+
+instance Atomic Word where
+  casMutableByteArray# mba# i# old new = unsafePrimBase (syncCasWordArrayIO mba# i# old new)
+  {-# INLINE casMutableByteArray# #-}
+  casOffAddr# addr# i# old new = unsafePrimBase (syncCasWordAddrIO addr# i# old new)
+  {-# INLINE casOffAddr# #-}
+  casBoolMutableByteArray# mba# i# old new =
+    ioCBoolToBoolBase (syncCasWordBoolArrayIO mba# i# old new)
+  {-# INLINE casBoolMutableByteArray# #-}
+  casBoolOffAddr# addr# i# old new = ioCBoolToBoolBase (syncCasWordBoolAddrIO addr# i# old new)
+  {-# INLINE casBoolOffAddr# #-}
+
+instance AtomicCount Word where
+  atomicAddFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncAddFetchOldWordArrayIO mba# i# a)
+  {-# INLINE atomicAddFetchOldMutableByteArray# #-}
+  atomicAddFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncAddFetchNewWordArrayIO mba# i# a)
+  {-# INLINE atomicAddFetchNewMutableByteArray# #-}
+  atomicSubFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncSubFetchOldWordArrayIO mba# i# a)
+  {-# INLINE atomicSubFetchOldMutableByteArray# #-}
+  atomicSubFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncSubFetchNewWordArrayIO mba# i# a)
+  {-# INLINE atomicSubFetchNewMutableByteArray# #-}
+  atomicAddFetchOldOffAddr# addr# i# a = unsafePrimBase (syncAddFetchOldWordAddrIO addr# i# a)
+  {-# INLINE atomicAddFetchOldOffAddr# #-}
+  atomicAddFetchNewOffAddr# addr# i# a = unsafePrimBase (syncAddFetchNewWordAddrIO addr# i# a)
+  {-# INLINE atomicAddFetchNewOffAddr# #-}
+  atomicSubFetchOldOffAddr# addr# i# a = unsafePrimBase (syncSubFetchOldWordAddrIO addr# i# a)
+  {-# INLINE atomicSubFetchOldOffAddr# #-}
+  atomicSubFetchNewOffAddr# addr# i# a = unsafePrimBase (syncSubFetchNewWordAddrIO addr# i# a)
+  {-# INLINE atomicSubFetchNewOffAddr# #-}
+
+instance AtomicBits Word where
+  atomicAndFetchOldMutableByteArray# mba# i# a =
+    unsafePrimBase (syncAndFetchOldWordArrayIO mba# i# a)
+  {-# INLINE atomicAndFetchOldMutableByteArray# #-}
+  atomicAndFetchNewMutableByteArray# mba# i# a =
+    unsafePrimBase (syncAndFetchNewWordArrayIO mba# i# a)
+  {-# INLINE atomicAndFetchNewMutableByteArray# #-}
+  atomicNandFetchOldMutableByteArray# mba# i# a =
+    unsafePrimBase (syncNandFetchOldWordArrayIO mba# i# a)
+  {-# INLINE atomicNandFetchOldMutableByteArray# #-}
+  atomicNandFetchNewMutableByteArray# mba# i# a =
+    unsafePrimBase (syncNandFetchNewWordArrayIO mba# i# a)
+  {-# INLINE atomicNandFetchNewMutableByteArray# #-}
+  atomicOrFetchOldMutableByteArray# mba# i# a =
+    unsafePrimBase (syncOrFetchOldWordArrayIO mba# i# a)
+  {-# INLINE atomicOrFetchOldMutableByteArray# #-}
+  atomicOrFetchNewMutableByteArray# mba# i# a =
+    unsafePrimBase (syncOrFetchNewWordArrayIO mba# i# a)
+  {-# INLINE atomicOrFetchNewMutableByteArray# #-}
+  atomicXorFetchOldMutableByteArray# mba# i# a =
+    unsafePrimBase (syncXorFetchOldWordArrayIO mba# i# a)
+  {-# INLINE atomicXorFetchOldMutableByteArray# #-}
+  atomicXorFetchNewMutableByteArray# mba# i# a =
+    unsafePrimBase (syncXorFetchNewWordArrayIO mba# i# a)
+  {-# INLINE atomicXorFetchNewMutableByteArray# #-}
+  atomicAndFetchOldOffAddr# addr# i# a = unsafePrimBase (syncAndFetchOldWordAddrIO addr# i# a)
+  {-# INLINE atomicAndFetchOldOffAddr# #-}
+  atomicAndFetchNewOffAddr# addr# i# a = unsafePrimBase (syncAndFetchNewWordAddrIO addr# i# a)
+  {-# INLINE atomicAndFetchNewOffAddr# #-}
+  atomicNandFetchOldOffAddr# addr# i# a = unsafePrimBase (syncNandFetchOldWordAddrIO addr# i# a)
+  {-# INLINE atomicNandFetchOldOffAddr# #-}
+  atomicNandFetchNewOffAddr# addr# i# a = unsafePrimBase (syncNandFetchNewWordAddrIO addr# i# a)
+  {-# INLINE atomicNandFetchNewOffAddr# #-}
+  atomicOrFetchOldOffAddr# addr# i# a = unsafePrimBase (syncOrFetchOldWordAddrIO addr# i# a)
+  {-# INLINE atomicOrFetchOldOffAddr# #-}
+  atomicOrFetchNewOffAddr# addr# i# a = unsafePrimBase (syncOrFetchNewWordAddrIO addr# i# a)
+  {-# INLINE atomicOrFetchNewOffAddr# #-}
+  atomicXorFetchOldOffAddr# addr# i# a = unsafePrimBase (syncXorFetchOldWordAddrIO addr# i# a)
+  {-# INLINE atomicXorFetchOldOffAddr# #-}
+  atomicXorFetchNewOffAddr# addr# i# a = unsafePrimBase (syncXorFetchNewWordAddrIO addr# i# a)
+  {-# INLINE atomicXorFetchNewOffAddr# #-}
+
+#if WORD_SIZE_IN_BITS == 64
+
+-- | Available only on 64bit architectures
+instance Atomic Int64 where
+  casMutableByteArray# mba# i# old new = unsafePrimBase (syncCasInt64ArrayIO mba# i# old new)
+  {-# INLINE casMutableByteArray# #-}
+  casOffAddr# addr# i# old new = unsafePrimBase (syncCasInt64AddrIO addr# i# old new)
+  {-# INLINE casOffAddr# #-}
+  casBoolMutableByteArray# mba# i# old new =
+    ioCBoolToBoolBase (syncCasInt64BoolArrayIO mba# i# old new)
+  {-# INLINE casBoolMutableByteArray# #-}
+  casBoolOffAddr# addr# i# old new = ioCBoolToBoolBase (syncCasInt64BoolAddrIO addr# i# old new)
+  {-# INLINE casBoolOffAddr# #-}
+
+-- | Available only on 64bit architectures
+instance AtomicCount Int64 where
+  atomicAddFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncAddFetchOldInt64ArrayIO mba# i# a)
+  {-# INLINE atomicAddFetchOldMutableByteArray# #-}
+  atomicAddFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncAddFetchNewInt64ArrayIO mba# i# a)
+  {-# INLINE atomicAddFetchNewMutableByteArray# #-}
+  atomicSubFetchOldMutableByteArray# mba# i# a = unsafePrimBase (syncSubFetchOldInt64ArrayIO mba# i# a)
+  {-# INLINE atomicSubFetchOldMutableByteArray# #-}
+  atomicSubFetchNewMutableByteArray# mba# i# a = unsafePrimBase (syncSubFetchNewInt64ArrayIO mba# i# a)
+  {-# INLINE atomicSubFetchNewMutableByteArray# #-}
+  atomicAddFetchOldOffAddr# addr# i# a = unsafePrimBase (syncAddFetchOldInt64AddrIO addr# i# a)
+  {-# INLINE atomicAddFetchOldOffAddr# #-}
+  atomicAddFetchNewOffAddr# addr# i# a = unsafePrimBase (syncAddFetchNewInt64AddrIO addr# i# a)
+  {-# INLINE atomicAddFetchNewOffAddr# #-}
+  atomicSubFetchOldOffAddr# addr# i# a = unsafePrimBase (syncSubFetchOldInt64AddrIO addr# i# a)
+  {-# INLINE atomicSubFetchOldOffAddr# #-}
+  atomicSubFetchNewOffAddr# addr# i# a = unsafePrimBase (syncSubFetchNewInt64AddrIO addr# i# a)
+  {-# INLINE atomicSubFetchNewOffAddr# #-}
+
+-- | Available only on 64bit architectures
+instance AtomicBits Int64 where
+  atomicAndFetchOldMutableByteArray# mba# i# a =
+    unsafePrimBase (syncAndFetchOldInt64ArrayIO mba# i# a)
+  {-# INLINE atomicAndFetchOldMutableByteArray# #-}
+  atomicAndFetchNewMutableByteArray# mba# i# a =
+    unsafePrimBase (syncAndFetchNewInt64ArrayIO mba# i# a)
+  {-# INLINE atomicAndFetchNewMutableByteArray# #-}
+  atomicNandFetchOldMutableByteArray# mba# i# a =
+    unsafePrimBase (syncNandFetchOldInt64ArrayIO mba# i# a)
+  {-# INLINE atomicNandFetchOldMutableByteArray# #-}
+  atomicNandFetchNewMutableByteArray# mba# i# a =
+    unsafePrimBase (syncNandFetchNewInt64ArrayIO mba# i# a)
+  {-# INLINE atomicNandFetchNewMutableByteArray# #-}
+  atomicOrFetchOldMutableByteArray# mba# i# a =
+    unsafePrimBase (syncOrFetchOldInt64ArrayIO mba# i# a)
+  {-# INLINE atomicOrFetchOldMutableByteArray# #-}
+  atomicOrFetchNewMutableByteArray# mba# i# a =
+    unsafePrimBase (syncOrFetchNewInt64ArrayIO mba# i# a)
+  {-# INLINE atomicOrFetchNewMutableByteArray# #-}
+  atomicXorFetchOldMutableByteArray# mba# i# a =
+    unsafePrimBase (syncXorFetchOldInt64ArrayIO mba# i# a)
+  {-# INLINE atomicXorFetchOldMutableByteArray# #-}
+  atomicXorFetchNewMutableByteArray# mba# i# a =
+    unsafePrimBase (syncXorFetchNewInt64ArrayIO mba# i# a)
+  {-# INLINE atomicXorFetchNewMutableByteArray# #-}
+  atomicAndFetchOldOffAddr# addr# i# a = unsafePrimBase (syncAndFetchOldInt64AddrIO addr# i# a)
+  {-# INLINE atomicAndFetchOldOffAddr# #-}
+  atomicAndFetchNewOffAddr# addr# i# a = unsafePrimBase (syncAndFetchNewInt64AddrIO addr# i# a)
+  {-# INLINE atomicAndFetchNewOffAddr# #-}
+  atomicNandFetchOldOffAddr# addr# i# a = unsafePrimBase (syncNandFetchOldInt64AddrIO addr# i# a)
+  {-# INLINE atomicNandFetchOldOffAddr# #-}
+  atomicNandFetchNewOffAddr# addr# i# a = unsafePrimBase (syncNandFetchNewInt64AddrIO addr# i# a)
+  {-# INLINE atomicNandFetchNewOffAddr# #-}
+  atomicOrFetchOldOffAddr# addr# i# a = unsafePrimBase (syncOrFetchOldInt64AddrIO addr# i# a)
+  {-# INLINE atomicOrFetchOldOffAddr# #-}
+  atomicOrFetchNewOffAddr# addr# i# a = unsafePrimBase (syncOrFetchNewInt64AddrIO addr# i# a)
+  {-# INLINE atomicOrFetchNewOffAddr# #-}
+  atomicXorFetchOldOffAddr# addr# i# a = unsafePrimBase (syncXorFetchOldInt64AddrIO addr# i# a)
+  {-# INLINE atomicXorFetchOldOffAddr# #-}
+  atomicXorFetchNewOffAddr# addr# i# a = unsafePrimBase (syncXorFetchNewInt64AddrIO addr# i# a)
+  {-# INLINE atomicXorFetchNewOffAddr# #-}
+
+-- | Available only on 64bit architectures
+instance Atomic Word64 where
+  casMutableByteArray# mba# i# old new = unsafePrimBase (syncCasWord64ArrayIO mba# i# old new)
+  {-# INLINE casMutableByteArray# #-}
+  casOffAddr# addr# i# old new = unsafePrimBase (syncCasWord64AddrIO addr# i# old new)
+  {-# INLINE casOffAddr# #-}
+  casBoolMutableByteArray# mba# i# old new =
+    ioCBoolToBoolBase (syncCasWord64BoolArrayIO mba# i# old new)
+  {-# INLINE casBoolMutableByteArray# #-}
+  casBoolOffAddr# addr# i# old new = ioCBoolToBoolBase (syncCasWord64BoolAddrIO addr# i# old new)
+  {-# INLINE casBoolOffAddr# #-}
+
+-- | Available only on 64bit architectures
+instance AtomicCount Word64 where
+  atomicAddFetchOldMutableByteArray# mba# i# a =
+    unsafePrimBase (syncAddFetchOldWord64ArrayIO mba# i# a)
+  {-# INLINE atomicAddFetchOldMutableByteArray# #-}
+  atomicAddFetchNewMutableByteArray# mba# i# a =
+    unsafePrimBase (syncAddFetchNewWord64ArrayIO mba# i# a)
+  {-# INLINE atomicAddFetchNewMutableByteArray# #-}
+  atomicSubFetchOldMutableByteArray# mba# i# a =
+    unsafePrimBase (syncSubFetchOldWord64ArrayIO mba# i# a)
+  {-# INLINE atomicSubFetchOldMutableByteArray# #-}
+  atomicSubFetchNewMutableByteArray# mba# i# a =
+    unsafePrimBase (syncSubFetchNewWord64ArrayIO mba# i# a)
+  {-# INLINE atomicSubFetchNewMutableByteArray# #-}
+  atomicAddFetchOldOffAddr# addr# i# a = unsafePrimBase (syncAddFetchOldWord64AddrIO addr# i# a)
+  {-# INLINE atomicAddFetchOldOffAddr# #-}
+  atomicAddFetchNewOffAddr# addr# i# a = unsafePrimBase (syncAddFetchNewWord64AddrIO addr# i# a)
+  {-# INLINE atomicAddFetchNewOffAddr# #-}
+  atomicSubFetchOldOffAddr# addr# i# a = unsafePrimBase (syncSubFetchOldWord64AddrIO addr# i# a)
+  {-# INLINE atomicSubFetchOldOffAddr# #-}
+  atomicSubFetchNewOffAddr# addr# i# a = unsafePrimBase (syncSubFetchNewWord64AddrIO addr# i# a)
+  {-# INLINE atomicSubFetchNewOffAddr# #-}
+
+-- | Available only on 64bit architectures
+instance AtomicBits Word64 where
+  atomicAndFetchOldMutableByteArray# mba# i# a =
+    unsafePrimBase (syncAndFetchOldWord64ArrayIO mba# i# a)
+  {-# INLINE atomicAndFetchOldMutableByteArray# #-}
+  atomicAndFetchNewMutableByteArray# mba# i# a =
+    unsafePrimBase (syncAndFetchNewWord64ArrayIO mba# i# a)
+  {-# INLINE atomicAndFetchNewMutableByteArray# #-}
+  atomicNandFetchOldMutableByteArray# mba# i# a =
+    unsafePrimBase (syncNandFetchOldWord64ArrayIO mba# i# a)
+  {-# INLINE atomicNandFetchOldMutableByteArray# #-}
+  atomicNandFetchNewMutableByteArray# mba# i# a =
+    unsafePrimBase (syncNandFetchNewWord64ArrayIO mba# i# a)
+  {-# INLINE atomicNandFetchNewMutableByteArray# #-}
+  atomicOrFetchOldMutableByteArray# mba# i# a =
+    unsafePrimBase (syncOrFetchOldWord64ArrayIO mba# i# a)
+  {-# INLINE atomicOrFetchOldMutableByteArray# #-}
+  atomicOrFetchNewMutableByteArray# mba# i# a =
+    unsafePrimBase (syncOrFetchNewWord64ArrayIO mba# i# a)
+  {-# INLINE atomicOrFetchNewMutableByteArray# #-}
+  atomicXorFetchOldMutableByteArray# mba# i# a =
+    unsafePrimBase (syncXorFetchOldWord64ArrayIO mba# i# a)
+  {-# INLINE atomicXorFetchOldMutableByteArray# #-}
+  atomicXorFetchNewMutableByteArray# mba# i# a =
+    unsafePrimBase (syncXorFetchNewWord64ArrayIO mba# i# a)
+  {-# INLINE atomicXorFetchNewMutableByteArray# #-}
+  atomicAndFetchOldOffAddr# addr# i# a = unsafePrimBase (syncAndFetchOldWord64AddrIO addr# i# a)
+  {-# INLINE atomicAndFetchOldOffAddr# #-}
+  atomicAndFetchNewOffAddr# addr# i# a = unsafePrimBase (syncAndFetchNewWord64AddrIO addr# i# a)
+  {-# INLINE atomicAndFetchNewOffAddr# #-}
+  atomicNandFetchOldOffAddr# addr# i# a = unsafePrimBase (syncNandFetchOldWord64AddrIO addr# i# a)
+  {-# INLINE atomicNandFetchOldOffAddr# #-}
+  atomicNandFetchNewOffAddr# addr# i# a = unsafePrimBase (syncNandFetchNewWord64AddrIO addr# i# a)
+  {-# INLINE atomicNandFetchNewOffAddr# #-}
+  atomicOrFetchOldOffAddr# addr# i# a = unsafePrimBase (syncOrFetchOldWord64AddrIO addr# i# a)
+  {-# INLINE atomicOrFetchOldOffAddr# #-}
+  atomicOrFetchNewOffAddr# addr# i# a = unsafePrimBase (syncOrFetchNewWord64AddrIO addr# i# a)
+  {-# INLINE atomicOrFetchNewOffAddr# #-}
+  atomicXorFetchOldOffAddr# addr# i# a = unsafePrimBase (syncXorFetchOldWord64AddrIO addr# i# a)
+  {-# INLINE atomicXorFetchOldOffAddr# #-}
+  atomicXorFetchNewOffAddr# addr# i# a = unsafePrimBase (syncXorFetchNewWord64AddrIO addr# i# a)
+  {-# INLINE atomicXorFetchNewOffAddr# #-}
+
+-- | Available only on 64bit architectures
+instance Atomic CLLong
+-- | Available only on 64bit architectures
+instance AtomicCount CLLong
+-- | Available only on 64bit architectures
+instance AtomicBits CLLong
+
+-- | Available only on 64bit architectures
+instance Atomic CULLong
+-- | Available only on 64bit architectures
+instance AtomicCount CULLong
+-- | Available only on 64bit architectures
+instance AtomicBits CULLong
+
+#endif
+
+instance Atomic Bool
+instance AtomicBits Bool
+
+instance Atomic Char
+
+instance Atomic (Ptr a)
+
+instance Atomic (FunPtr a)
+
+instance Atomic IntPtr
+instance AtomicCount IntPtr
+instance AtomicBits IntPtr
+
+instance Atomic WordPtr
+instance AtomicCount WordPtr
+instance AtomicBits WordPtr
+
+
+instance Atomic CBool
+instance AtomicCount CBool
+instance AtomicBits CBool
+
+instance Atomic CChar
+instance AtomicCount CChar
+instance AtomicBits CChar
+
+instance Atomic CSChar
+instance AtomicCount CSChar
+instance AtomicBits CSChar
+
+instance Atomic CUChar
+instance AtomicCount CUChar
+instance AtomicBits CUChar
+
+instance Atomic CShort
+instance AtomicCount CShort
+instance AtomicBits CShort
+
+instance Atomic CUShort
+instance AtomicCount CUShort
+instance AtomicBits CUShort
+
+instance Atomic CInt
+instance AtomicCount CInt
+instance AtomicBits CInt
+
+instance Atomic CUInt
+instance AtomicCount CUInt
+instance AtomicBits CUInt
+
+instance Atomic CLong
+instance AtomicCount CLong
+instance AtomicBits CLong
+
+instance Atomic CULong
+instance AtomicCount CULong
+instance AtomicBits CULong
+
+instance Atomic CPtrdiff
+instance AtomicCount CPtrdiff
+instance AtomicBits CPtrdiff
+
+instance Atomic CSize
+instance AtomicCount CSize
+instance AtomicBits CSize
+
+instance Atomic CWchar
+instance AtomicCount CWchar
+instance AtomicBits CWchar
+
+instance Atomic CSigAtomic
+instance AtomicCount CSigAtomic
+instance AtomicBits CSigAtomic
+
+instance Atomic CIntPtr
+instance AtomicCount CIntPtr
+instance AtomicBits CIntPtr
+
+instance Atomic CUIntPtr
+instance AtomicCount CUIntPtr
+instance AtomicBits CUIntPtr
+
+instance Atomic CIntMax
+instance AtomicCount CIntMax
+instance AtomicBits CIntMax
+
+instance Atomic CUIntMax
+instance AtomicCount CUIntMax
+instance AtomicBits CUIntMax
+
+instance Atomic Fd
+instance AtomicCount Fd
+instance AtomicBits Fd
+
+instance Atomic Errno
+instance AtomicCount Errno
+
+
+
+#if defined(HTYPE_DEV_T)
+instance Atomic CDev
+instance AtomicCount CDev
+instance AtomicBits CDev
+#endif
+#if defined(HTYPE_INO_T)
+instance Atomic CIno
+instance AtomicCount CIno
+instance AtomicBits CIno
+#endif
+#if defined(HTYPE_MODE_T)
+instance Atomic CMode
+instance AtomicCount CMode
+instance AtomicBits CMode
+#endif
+#if defined(HTYPE_OFF_T)
+instance Atomic COff
+instance AtomicCount COff
+instance AtomicBits COff
+#endif
+#if defined(HTYPE_PID_T)
+instance Atomic CPid
+instance AtomicCount CPid
+instance AtomicBits CPid
+#endif
+#if defined(HTYPE_SSIZE_T)
+instance Atomic CSsize
+instance AtomicCount CSsize
+instance AtomicBits CSsize
+#endif
+#if defined(HTYPE_GID_T)
+instance Atomic CGid
+instance AtomicCount CGid
+instance AtomicBits CGid
+#endif
+#if defined(HTYPE_NLINK_T)
+instance Atomic CNlink
+instance AtomicCount CNlink
+instance AtomicBits CNlink
+#endif
+#if defined(HTYPE_UID_T)
+instance Atomic CUid
+instance AtomicCount CUid
+instance AtomicBits CUid
+#endif
+#if defined(HTYPE_CC_T)
+instance Atomic CCc
+instance AtomicCount CCc
+instance AtomicBits CCc
+#endif
+#if defined(HTYPE_SPEED_T)
+instance Atomic CSpeed
+instance AtomicCount CSpeed
+instance AtomicBits CSpeed
+#endif
+#if defined(HTYPE_TCFLAG_T)
+instance Atomic CTcflag
+instance AtomicCount CTcflag
+instance AtomicBits CTcflag
+#endif
+#if defined(HTYPE_RLIM_T)
+instance Atomic CRLim
+instance AtomicCount CRLim
+instance AtomicBits CRLim
+#endif
+
+#if __GLASGOW_HASKELL__ >= 802
+
+#if defined(HTYPE_BLKSIZE_T)
+instance Atomic CBlkSize
+instance AtomicCount CBlkSize
+instance AtomicBits CBlkSize
+#endif
+#if defined(HTYPE_BLKCNT_T)
+instance Atomic CBlkCnt
+instance AtomicCount CBlkCnt
+instance AtomicBits CBlkCnt
+#endif
+#if defined(HTYPE_CLOCKID_T)
+instance Atomic CClockId
+instance AtomicCount CClockId
+instance AtomicBits CClockId
+#endif
+#if defined(HTYPE_FSBLKCNT_T)
+instance Atomic CFsBlkCnt
+instance AtomicCount CFsBlkCnt
+instance AtomicBits CFsBlkCnt
+#endif
+#if defined(HTYPE_FSFILCNT_T)
+instance Atomic CFsFilCnt
+instance AtomicCount CFsFilCnt
+instance AtomicBits CFsFilCnt
+#endif
+#if defined(HTYPE_ID_T)
+instance Atomic CId
+instance AtomicCount CId
+instance AtomicBits CId
+#endif
+#if defined(HTYPE_KEY_T)
+instance Atomic CKey
+instance AtomicCount CKey
+instance AtomicBits CKey
+#endif
+#if defined(HTYPE_TIMER_T)
+instance Atomic CTimer
+instance AtomicCount CTimer
+instance AtomicBits CTimer
+#endif
+
+#if __GLASGOW_HASKELL__ >= 810
+
+#if defined(HTYPE_SOCKLEN_T)
+instance Atomic CSocklen
+instance AtomicCount CSocklen
+instance AtomicBits CSocklen
+#endif
+#if defined(HTYPE_NFDS_T)
+instance Atomic CNfds
+instance AtomicCount CNfds
+instance AtomicBIts CNfds
+#endif
+
+#endif /* __GLASGOW_HASKELL__ >= 810 */
+
+#endif /* __GLASGOW_HASKELL__ >= 802 */
+
+#if __GLASGOW_HASKELL__ >= 800
+instance Atomic a => Atomic (Max a)
+instance Atomic a => Atomic (Min a)
+instance Atomic a => Atomic (Data.Semigroup.First a)
+instance Atomic a => Atomic (Data.Semigroup.Last a)
+
+instance Atomic a => Atomic (Const a b)
+instance AtomicCount a => AtomicCount (Const a b)
+instance AtomicBits a => AtomicBits (Const a b)
+
+#else
+
+deriving instance Bits a => Bits (Identity a)
+#endif /* __GLASGOW_HASKELL__ >= 800 */
+
+instance Atomic a => Atomic (Identity a)
+instance AtomicCount a => AtomicCount (Identity a)
+instance AtomicBits a => AtomicBits (Identity a)
+
+instance Atomic Ordering
+
+instance Atomic IODeviceType
+
+instance Atomic SeekMode
+
+instance Atomic BlockReason
+
+instance Atomic ThreadStatus
+
+instance Atomic IOMode
+
+instance Atomic Newline
+
+instance Atomic NewlineMode
+
+instance Atomic GeneralCategory
+
+instance Atomic a => Atomic (Down a)
+instance AtomicCount a => AtomicCount (Down a)
+--instance AtomicBits a => AtomicBits (Down a)
+
+instance Atomic a => Atomic (Dual a)
+instance AtomicCount a => AtomicCount (Dual a)
+--instance AtomicBits a => AtomicBits (Dual a)
+
+instance Atomic a => Atomic (Sum a)
+instance AtomicCount a => AtomicCount (Sum a)
+--instance AtomicBits a => AtomicBits (Sum a)
+
+instance Atomic a => Atomic (Product a)
+instance AtomicCount a => AtomicCount (Product a)
+--instance AtomicBits a => AtomicBits (Product a)
+
+instance Atomic All
+--instance AtomicBits All
+
+instance Atomic Any
+--instance AtomicBits Any
diff --git a/src/Data/Prim/Class.hs b/src/Data/Prim/Class.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Prim/Class.hs
@@ -0,0 +1,1637 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DefaultSignatures #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE UndecidableInstances #-}
+-- |
+-- Module      : Data.Prim.Class
+-- Copyright   : (c) Alexey Kuleshevich 2020
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Data.Prim.Class
+  ( Prim(..)
+  , setMutableByteArrayLoop#
+  , setOffAddrLoop#
+  , errorImpossible
+  , bool2Int#
+  , int2Bool#
+  -- * Backwards compatibility
+  , WordPtr(..)
+  , ptrToWordPtr
+  , wordPtrToPtr
+  , IntPtr(..)
+  , ptrToIntPtr
+  , intPtrToPtr
+  ) where
+
+
+#include "MachDeps.h"
+#include "HsBaseConfig.h"
+
+import Control.Prim.Monad.Unsafe
+import Data.Bits
+import Data.Complex
+import Data.Char
+import Data.Type.Equality
+import Foreign.C.Error (Errno(..))
+import Foreign.Prim hiding (Any)
+import GHC.Conc
+import GHC.Stable
+import GHC.Real
+import GHC.IO.Device
+import GHC.Fingerprint.Type
+import GHC.TypeLits as Nats
+import Data.Functor.Compose
+import Data.Functor.Identity
+import qualified Data.Functor.Product as Functor
+import Data.Monoid
+import System.IO
+#if __GLASGOW_HASKELL__ >= 800
+import Data.Functor.Const
+import Data.Semigroup
+#endif /* __GLASGOW_HASKELL__ >= 800 */
+
+#if __GLASGOW_HASKELL__ < 802
+import qualified Foreign.Ptr as P
+import Unsafe.Coerce
+#include "primal_compat.h"
+
+import Data.Bits (Bits, FiniteBits)
+import Foreign.Storable (Storable)
+
+-- | Replacement for `Foreign.Ptr.IntPtr` with exported constructor.
+newtype IntPtr = IntPtr Int
+  deriving (Eq, Ord, Num, Enum, Storable, Real, Bounded, Integral, Bits, FiniteBits, Read, Show)
+
+-- | Replacement for `Foreign.Ptr.WordPtr` with exported constructor.
+newtype WordPtr = WordPtr Word
+  deriving (Eq, Ord, Num, Enum, Storable, Real, Bounded, Integral, Bits, FiniteBits, Read, Show)
+
+-- | casts a @Ptr@ to a @WordPtr@
+ptrToWordPtr :: Ptr a -> WordPtr
+ptrToWordPtr (Ptr a#) = WordPtr (W# (int2Word# (addr2Int# a#)))
+
+-- | casts a @WordPtr@ to a @Ptr@
+wordPtrToPtr :: WordPtr -> Ptr a
+wordPtrToPtr (WordPtr (W# w#)) = Ptr (int2Addr# (word2Int# w#))
+
+-- | casts a @Ptr@ to an @IntPtr@
+ptrToIntPtr :: Ptr a -> IntPtr
+ptrToIntPtr (Ptr a#) = IntPtr (I# (addr2Int# a#))
+
+-- | casts an @IntPtr@ to a @Ptr@
+intPtrToPtr :: IntPtr -> Ptr a
+intPtrToPtr (IntPtr (I# i#)) = Ptr (int2Addr# i#)
+
+instance Prim P.IntPtr where
+  type PrimBase P.IntPtr = IntPtr
+  -- Constructor for newtype was not exported
+  toPrimBase = unsafeCoerce
+  fromPrimBase = unsafeCoerce
+
+instance Prim P.WordPtr where
+  type PrimBase P.WordPtr = WordPtr
+  -- Constructor for newtype was not exported
+  toPrimBase = unsafeCoerce
+  fromPrimBase = unsafeCoerce
+#else
+import Foreign.Ptr
+#endif
+
+-- | Invariants:
+--
+-- * Reading should never fail on memory that contains only zeros
+--
+-- * Writing should always overwrite all of the bytes allocated for the element. In other
+--   words, writing to a dirty (uninitilized) region of memory should never leave any
+--   garbage around. For example, if a type requires 31 bytes of memory then on any write
+--   all 31 bytes must be overwritten.
+--
+-- * A single thread write/read sequence must always roundtrip
+--
+-- * This is not a class for serialization, therefore memory layout of unpacked datatype
+--   is selfcontained in `Prim` class and representation is not expected to stay the same
+--   between different versions of software. Primitive types like `Int`, `Word`, `Char`
+--   are an exception to this rule for obvious reasons.
+--
+class Prim a where
+  type PrimBase a :: *
+
+  type SizeOf a :: Nat
+  type SizeOf a = SizeOf (PrimBase a)
+  type Alignment a :: Nat
+  type Alignment a = Alignment (PrimBase a)
+
+  toPrimBase :: a -> PrimBase a
+  default toPrimBase :: Coercible a (PrimBase a) => a -> PrimBase a
+  toPrimBase = coerce
+
+  fromPrimBase :: PrimBase a -> a
+  default fromPrimBase :: Coercible a (PrimBase a) => PrimBase a -> a
+  fromPrimBase = coerce
+
+  -- | Returned value must match the `SizeOf` type level Nat
+  sizeOf# :: Proxy# a -> Int#
+  default sizeOf# :: Prim (PrimBase a) => Proxy# a -> Int#
+  sizeOf# _ = sizeOf# (proxy# :: Proxy# (PrimBase a))
+  {-# INLINE sizeOf# #-}
+
+  -- | Returned value must match the `Alignment` type level Nat
+  alignment# :: Proxy# a -> Int#
+  default alignment# :: Prim (PrimBase a) => Proxy# a -> Int#
+  alignment# _ = alignment# (proxy# :: Proxy# (PrimBase a))
+  {-# INLINE alignment# #-}
+
+
+  indexByteOffByteArray# :: ByteArray# -> Int# -> a
+  default indexByteOffByteArray# :: Prim (PrimBase a) => ByteArray# -> Int# -> a
+  indexByteOffByteArray# ba# i# = fromPrimBase (indexByteOffByteArray# ba# i# :: PrimBase a)
+  {-# INLINE indexByteOffByteArray# #-}
+
+  --
+  -- These equalities hold:
+  --
+  -- > indexByteArray# ba# i# == indexOffAddr# (byteArrayContents# ba#) i#
+  --
+  -- > indexByteArray# ba# i# == indexByteOffByteArray# ba# (i# *# sizeOf (proxy# :: Proxy# a))
+  --
+  indexByteArray# :: ByteArray# -> Int# -> a
+  default indexByteArray# :: Prim (PrimBase a) => ByteArray# -> Int# -> a
+  indexByteArray# ba# i# = fromPrimBase (indexByteArray# ba# i# :: PrimBase a)
+  {-# INLINE indexByteArray# #-}
+
+  indexOffAddr# :: Addr# -> Int# -> a
+  default indexOffAddr# :: Prim (PrimBase a) => Addr# -> Int# -> a
+  indexOffAddr# addr# i# = fromPrimBase (indexOffAddr# addr# i# :: PrimBase a)
+  {-# INLINE indexOffAddr# #-}
+
+
+  readByteOffMutableByteArray# :: MutableByteArray# s -> Int# -> State# s -> (# State# s, a #)
+  default readByteOffMutableByteArray# ::
+    Prim (PrimBase a) => MutableByteArray# s -> Int# -> State# s -> (# State# s, a #)
+  readByteOffMutableByteArray# mba# i# s = case readByteOffMutableByteArray# mba# i# s of
+                                             (# s', pa :: PrimBase a #) -> (# s', fromPrimBase pa #)
+  {-# INLINE readByteOffMutableByteArray# #-}
+
+  readMutableByteArray# :: MutableByteArray# s -> Int# -> State# s -> (# State# s, a #)
+  default readMutableByteArray# ::
+    Prim (PrimBase a) => MutableByteArray# s -> Int# -> State# s -> (# State# s, a #)
+  readMutableByteArray# mba# i# s = case readMutableByteArray# mba# i# s of
+                                      (# s', pa :: PrimBase a #) -> (# s', fromPrimBase pa #)
+  {-# INLINE readMutableByteArray# #-}
+
+  readOffAddr# :: Addr# -> Int# -> State# s -> (# State# s, a #)
+  default readOffAddr# ::
+    Prim (PrimBase a) => Addr# -> Int# -> State# s -> (# State# s, a #)
+  readOffAddr# addr# i# s = case readOffAddr# addr# i# s of
+                              (# s', pa :: PrimBase a #) -> (# s', fromPrimBase pa #)
+  {-# INLINE readOffAddr# #-}
+
+
+  writeByteOffMutableByteArray# :: MutableByteArray# s -> Int# -> a -> State# s -> State# s
+  default writeByteOffMutableByteArray# ::
+    Prim (PrimBase a) => MutableByteArray# s -> Int# -> a -> State# s -> State# s
+  writeByteOffMutableByteArray# mba# i# a =
+    writeByteOffMutableByteArray# mba# i# (toPrimBase a :: PrimBase a)
+  {-# INLINE writeByteOffMutableByteArray# #-}
+
+  writeMutableByteArray# :: MutableByteArray# s -> Int# -> a -> State# s -> State# s
+  default writeMutableByteArray# ::
+    Prim (PrimBase a) => MutableByteArray# s -> Int# -> a -> State# s -> State# s
+  writeMutableByteArray# mba# i# a = writeMutableByteArray# mba# i# (toPrimBase a :: PrimBase a)
+  {-# INLINE writeMutableByteArray# #-}
+
+  writeOffAddr# :: Addr# -> Int# -> a -> State# s -> State# s
+  default writeOffAddr# :: Prim (PrimBase a) => Addr# -> Int# -> a -> State# s -> State# s
+  writeOffAddr# addr# i# a = writeOffAddr# addr# i# (toPrimBase a)
+  {-# INLINE writeOffAddr# #-}
+
+  -- TODO: implement
+  -- setByteOffMutableByteArray# :: MutableByteArray# s -> Int# -> Int# -> a -> State# s -> State# s
+  -- default setMutableByteArray# ::
+  --   Prim (PrimBase a) => MutableByteArray# s -> Int# -> Int# -> a -> State# s -> State# s
+  -- setByteOffMutableByteArray# mba# i# n# a = setByteOffMutableByteArray# mba# i# n# (toPrimBase a)
+  -- {-# INLINE setByteOffMutableByteArray# #-}
+
+  -- | Set the region of MutableByteArray to the same value. Offset is in number of elements
+  setMutableByteArray# :: MutableByteArray# s -> Int# -> Int# -> a -> State# s -> State# s
+  default setMutableByteArray# ::
+    Prim (PrimBase a) => MutableByteArray# s -> Int# -> Int# -> a -> State# s -> State# s
+  setMutableByteArray# mba# i# n# a = setMutableByteArray# mba# i# n# (toPrimBase a)
+  {-# INLINE setMutableByteArray# #-}
+
+  -- | Set the region of memory to the same value. Offset is in number of elements
+  setOffAddr# :: Addr# -> Int# -> Int# -> a -> State# s -> State# s
+  default setOffAddr# ::
+    Prim (PrimBase a) => Addr# -> Int# -> Int# -> a -> State# s -> State# s
+  setOffAddr# addr# i# n# a = setOffAddr# addr# i# n# (toPrimBase a)
+  {-# INLINE setOffAddr# #-}
+
+
+instance Prim () where
+  type PrimBase () = ()
+  type SizeOf () = 0
+  type Alignment () = 0
+  sizeOf# _ = 0#
+  {-# INLINE sizeOf# #-}
+  alignment# _ = 0#
+  {-# INLINE alignment# #-}
+  indexByteOffByteArray# _ _ = ()
+  {-# INLINE indexByteOffByteArray# #-}
+  indexByteArray# _ _ = ()
+  {-# INLINE indexByteArray# #-}
+  indexOffAddr# _ _ = ()
+  {-# INLINE indexOffAddr# #-}
+  readByteOffMutableByteArray# _ _ s = (# s, () #)
+  {-# INLINE readByteOffMutableByteArray# #-}
+  readMutableByteArray# _ _ s = (# s, () #)
+  {-# INLINE readMutableByteArray# #-}
+  readOffAddr# _ _ s = (# s, () #)
+  {-# INLINE readOffAddr# #-}
+  writeByteOffMutableByteArray# _ _ () s = s
+  {-# INLINE writeByteOffMutableByteArray# #-}
+  writeMutableByteArray# _ _ () s = s
+  {-# INLINE writeMutableByteArray# #-}
+  writeOffAddr# _ _ () s = s
+  {-# INLINE writeOffAddr# #-}
+  setMutableByteArray# _ _ _ () s = s
+  {-# INLINE setMutableByteArray# #-}
+  setOffAddr# _ _ _ () s = s
+  {-# INLINE setOffAddr# #-}
+
+instance a ~ b => Prim (a :~: b) where
+  type PrimBase (a :~: b) = ()
+  toPrimBase Refl = ()
+  fromPrimBase () = Refl
+
+
+instance Prim Int where
+  type PrimBase Int = Int
+  type SizeOf Int = SIZEOF_HSINT
+  type Alignment Int = ALIGNMENT_HSINT
+  sizeOf# _ = SIZEOF_HSINT#
+  {-# INLINE sizeOf# #-}
+  alignment# _ = ALIGNMENT_HSINT#
+  {-# INLINE alignment# #-}
+  indexByteOffByteArray# ba# i# = I# (indexWord8ArrayAsInt# ba# i#)
+  {-# INLINE indexByteOffByteArray# #-}
+  indexByteArray# ba# i# = I# (indexIntArray# ba# i#)
+  {-# INLINE indexByteArray# #-}
+  indexOffAddr# addr# i# = I# (indexIntOffAddr# addr# i#)
+  {-# INLINE indexOffAddr# #-}
+  readByteOffMutableByteArray# mba# i# s = case readWord8ArrayAsInt# mba# i# s of
+                                             (# s', a# #) -> (# s', I# a# #)
+  {-# INLINE readByteOffMutableByteArray# #-}
+  readMutableByteArray# mba# i# s = case readIntArray# mba# i# s of
+                                      (# s', a# #) -> (# s', I# a# #)
+  {-# INLINE readMutableByteArray# #-}
+  readOffAddr# mba# i# s = case readIntOffAddr# mba# i# s of
+                             (# s', a# #) -> (# s', I# a# #)
+  {-# INLINE readOffAddr# #-}
+  writeByteOffMutableByteArray# mba# i# (I# a#) = writeWord8ArrayAsInt# mba# i# a#
+  {-# INLINE writeByteOffMutableByteArray# #-}
+  writeMutableByteArray# mba# i# (I# a#) = writeIntArray# mba# i# a#
+  {-# INLINE writeMutableByteArray# #-}
+  writeOffAddr# mba# i# (I# a#) = writeIntOffAddr# mba# i# a#
+  {-# INLINE writeOffAddr# #-}
+#if WORD_SIZE_IN_BITS >= 64
+  setMutableByteArray# mba# o# n# (I# a#) = setMutableByteArray# mba# o# n# (I64# a#)
+  setOffAddr# addr# o# n# (I# a#) = setOffAddr# addr# o# n# (I64# a#)
+#else
+  setMutableByteArray# mba# o# n# (I# a#) = setMutableByteArray# mba# o# n# (I32# a#)
+  setOffAddr# addr# o# n# (I# a#) = setOffAddr# addr# o# n# (I32# a#)
+#endif
+  {-# INLINE setMutableByteArray# #-}
+  {-# INLINE setOffAddr# #-}
+
+instance Prim Int8 where
+  type PrimBase Int8 = Int8
+  type SizeOf Int8 = SIZEOF_INT8
+  type Alignment Int8 = ALIGNMENT_INT8
+  sizeOf# _ = SIZEOF_INT8#
+  {-# INLINE sizeOf# #-}
+  alignment# _ = ALIGNMENT_INT8#
+  {-# INLINE alignment# #-}
+  indexByteOffByteArray# ba# i# = I8# (indexInt8Array# ba# i#)
+  {-# INLINE indexByteOffByteArray# #-}
+  indexByteArray# ba# i# = I8# (indexInt8Array# ba# i#)
+  {-# INLINE indexByteArray# #-}
+  indexOffAddr# addr# i# = I8# (indexInt8OffAddr# addr# i#)
+  {-# INLINE indexOffAddr# #-}
+  readByteOffMutableByteArray# mba# i# s = case readInt8Array# mba# i# s of
+                                             (# s', a# #) -> (# s', I8# a# #)
+  {-# INLINE readByteOffMutableByteArray# #-}
+  readMutableByteArray# mba# i# s = case readInt8Array# mba# i# s of
+                                      (# s', a# #) -> (# s', I8# a# #)
+  {-# INLINE readMutableByteArray# #-}
+  readOffAddr# mba# i# s = case readInt8OffAddr# mba# i# s of
+                             (# s', a# #) -> (# s', I8# a# #)
+  {-# INLINE readOffAddr# #-}
+  writeByteOffMutableByteArray# mba# i# (I8# a#) = writeInt8Array# mba# i# a#
+  {-# INLINE writeByteOffMutableByteArray# #-}
+  writeMutableByteArray# mba# i# (I8# a#) = writeInt8Array# mba# i# a#
+  {-# INLINE writeMutableByteArray# #-}
+  writeOffAddr# mba# i# (I8# a#) = writeInt8OffAddr# mba# i# a#
+  {-# INLINE writeOffAddr# #-}
+  setMutableByteArray# mba# i# n# (I8# a#) = setByteArray# mba# i# n# a#
+  {-# INLINE setMutableByteArray# #-}
+  setOffAddr# addr# o# n# a = unsafePrimBase_ (memsetInt8Addr# addr# o# n# a)
+  {-# INLINE setOffAddr# #-}
+
+instance Prim Int16 where
+  type PrimBase Int16 = Int16
+  type SizeOf Int16 = SIZEOF_INT16
+  type Alignment Int16 = ALIGNMENT_INT16
+  sizeOf# _ = SIZEOF_INT16#
+  {-# INLINE sizeOf# #-}
+  alignment# _ = ALIGNMENT_INT16#
+  {-# INLINE alignment# #-}
+  indexByteOffByteArray# ba# i# = I16# (indexWord8ArrayAsInt16# ba# i#)
+  {-# INLINE indexByteOffByteArray# #-}
+  indexByteArray# ba# i# = I16# (indexInt16Array# ba# i#)
+  {-# INLINE indexByteArray# #-}
+  indexOffAddr# addr# i# = I16# (indexInt16OffAddr# addr# i#)
+  {-# INLINE indexOffAddr# #-}
+  readByteOffMutableByteArray# mba# i# s = case readWord8ArrayAsInt16# mba# i# s of
+                                             (# s', a# #) -> (# s', I16# a# #)
+  {-# INLINE readByteOffMutableByteArray# #-}
+  readMutableByteArray# mba# i# s = case readInt16Array# mba# i# s of
+                                      (# s', a# #) -> (# s', I16# a# #)
+  {-# INLINE readMutableByteArray# #-}
+  readOffAddr# mba# i# s = case readInt16OffAddr# mba# i# s of
+                             (# s', a# #) -> (# s', I16# a# #)
+  {-# INLINE readOffAddr# #-}
+  writeByteOffMutableByteArray# mba# i# (I16# a#) = writeWord8ArrayAsInt16# mba# i# a#
+  {-# INLINE writeByteOffMutableByteArray# #-}
+  writeMutableByteArray# mba# i# (I16# a#) = writeInt16Array# mba# i# a#
+  {-# INLINE writeMutableByteArray# #-}
+  writeOffAddr# mba# i# (I16# a#) = writeInt16OffAddr# mba# i# a#
+  {-# INLINE writeOffAddr# #-}
+  setMutableByteArray# mba# o# n# a = unsafePrimBase_ (memsetInt16MutableByteArray# mba# o# n# a)
+  {-# INLINE setMutableByteArray# #-}
+  setOffAddr# addr# o# n# a = unsafePrimBase_ (memsetInt16Addr# addr# o# n# a)
+  {-# INLINE setOffAddr# #-}
+
+instance Prim Int32 where
+  type PrimBase Int32 = Int32
+  type SizeOf Int32 = SIZEOF_INT32
+  type Alignment Int32 = ALIGNMENT_INT32
+  sizeOf# _ = SIZEOF_INT32#
+  {-# INLINE sizeOf# #-}
+  alignment# _ = ALIGNMENT_INT32#
+  {-# INLINE alignment# #-}
+  indexByteOffByteArray# ba# i# = I32# (indexWord8ArrayAsInt32# ba# i#)
+  {-# INLINE indexByteOffByteArray# #-}
+  indexByteArray# ba# i# = I32# (indexInt32Array# ba# i#)
+  {-# INLINE indexByteArray# #-}
+  indexOffAddr# addr# i# = I32# (indexInt32OffAddr# addr# i#)
+  {-# INLINE indexOffAddr# #-}
+  readByteOffMutableByteArray# mba# i# s = case readWord8ArrayAsInt32# mba# i# s of
+                                             (# s', a# #) -> (# s', I32# a# #)
+  {-# INLINE readByteOffMutableByteArray# #-}
+  readMutableByteArray# mba# i# s = case readInt32Array# mba# i# s of
+                                      (# s', a# #) -> (# s', I32# a# #)
+  {-# INLINE readMutableByteArray# #-}
+  readOffAddr# mba# i# s = case readInt32OffAddr# mba# i# s of
+                             (# s', a# #) -> (# s', I32# a# #)
+  {-# INLINE readOffAddr# #-}
+  writeByteOffMutableByteArray# mba# i# (I32# a#) = writeWord8ArrayAsInt32# mba# i# a#
+  {-# INLINE writeByteOffMutableByteArray# #-}
+  writeMutableByteArray# mba# i# (I32# a#) = writeInt32Array# mba# i# a#
+  {-# INLINE writeMutableByteArray# #-}
+  writeOffAddr# mba# i# (I32# a#) = writeInt32OffAddr# mba# i# a#
+  {-# INLINE writeOffAddr# #-}
+  setMutableByteArray# mba# o# n# a = unsafePrimBase_ (memsetInt32MutableByteArray# mba# o# n# a)
+  {-# INLINE setMutableByteArray# #-}
+  setOffAddr# addr# o# n# a = unsafePrimBase_ (memsetInt32Addr# addr# o# n# a)
+  {-# INLINE setOffAddr# #-}
+
+instance Prim Int64 where
+  type PrimBase Int64 = Int64
+  type SizeOf Int64 = SIZEOF_INT64
+  type Alignment Int64 = ALIGNMENT_INT64
+  sizeOf# _ = SIZEOF_INT64#
+  {-# INLINE sizeOf# #-}
+  alignment# _ = ALIGNMENT_INT64#
+  {-# INLINE alignment# #-}
+  indexByteOffByteArray# ba# i# = I64# (indexWord8ArrayAsInt64# ba# i#)
+  {-# INLINE indexByteOffByteArray# #-}
+  indexByteArray# ba# i# = I64# (indexInt64Array# ba# i#)
+  {-# INLINE indexByteArray# #-}
+  indexOffAddr# addr# i# = I64# (indexInt64OffAddr# addr# i#)
+  {-# INLINE indexOffAddr# #-}
+  readByteOffMutableByteArray# mba# i# s = case readWord8ArrayAsInt64# mba# i# s of
+                                             (# s', a# #) -> (# s', I64# a# #)
+  {-# INLINE readByteOffMutableByteArray# #-}
+  readMutableByteArray# mba# i# s = case readInt64Array# mba# i# s of
+                                      (# s', a# #) -> (# s', I64# a# #)
+  {-# INLINE readMutableByteArray# #-}
+  readOffAddr# mba# i# s = case readInt64OffAddr# mba# i# s of
+                             (# s', a# #) -> (# s', I64# a# #)
+  {-# INLINE readOffAddr# #-}
+  writeByteOffMutableByteArray# mba# i# (I64# a#) = writeWord8ArrayAsInt64# mba# i# a#
+  {-# INLINE writeByteOffMutableByteArray# #-}
+  writeMutableByteArray# mba# i# (I64# a#) = writeInt64Array# mba# i# a#
+  {-# INLINE writeMutableByteArray# #-}
+  writeOffAddr# mba# i# (I64# a#) = writeInt64OffAddr# mba# i# a#
+  {-# INLINE writeOffAddr# #-}
+  setMutableByteArray# mba# o# n# a = unsafePrimBase_ (memsetInt64MutableByteArray# mba# o# n# a)
+  {-# INLINE setMutableByteArray# #-}
+  setOffAddr# addr# o# n# a = unsafePrimBase_ (memsetInt64Addr# addr# o# n# a)
+  {-# INLINE setOffAddr# #-}
+
+
+instance Prim Word where
+  type PrimBase Word = Word
+  type SizeOf Word = SIZEOF_HSWORD
+  type Alignment Word = ALIGNMENT_HSWORD
+  sizeOf# _ = SIZEOF_HSWORD#
+  {-# INLINE sizeOf# #-}
+  alignment# _ = ALIGNMENT_HSWORD#
+  {-# INLINE alignment# #-}
+  indexByteOffByteArray# ba# i# = W# (indexWord8ArrayAsWord# ba# i#)
+  {-# INLINE indexByteOffByteArray# #-}
+  indexByteArray# ba# i# = W# (indexWordArray# ba# i#)
+  {-# INLINE indexByteArray# #-}
+  indexOffAddr# addr# i# = W# (indexWordOffAddr# addr# i#)
+  {-# INLINE indexOffAddr# #-}
+  readByteOffMutableByteArray# mba# i# s = case readWord8ArrayAsWord# mba# i# s of
+                                             (# s', a# #) -> (# s', W# a# #)
+  {-# INLINE readByteOffMutableByteArray# #-}
+  readMutableByteArray# mba# i# s = case readWordArray# mba# i# s of
+                                      (# s', a# #) -> (# s', W# a# #)
+  {-# INLINE readMutableByteArray# #-}
+  readOffAddr# mba# i# s = case readWordOffAddr# mba# i# s of
+                             (# s', a# #) -> (# s', W# a# #)
+  {-# INLINE readOffAddr# #-}
+  writeByteOffMutableByteArray# mba# i# (W# a#) = writeWord8ArrayAsWord# mba# i# a#
+  {-# INLINE writeByteOffMutableByteArray# #-}
+  writeMutableByteArray# mba# i# (W# a#) = writeWordArray# mba# i# a#
+  {-# INLINE writeMutableByteArray# #-}
+  writeOffAddr# mba# i# (W# a#) = writeWordOffAddr# mba# i# a#
+  {-# INLINE writeOffAddr# #-}
+#if WORD_SIZE_IN_BITS >= 64
+  setMutableByteArray# mba# o# n# (W# a#) = setMutableByteArray# mba# o# n# (W64# a#)
+  setOffAddr# addr# o# n# (W# a#) = setOffAddr# addr# o# n# (W64# a#)
+#else
+  setMutableByteArray# mba# o# n# (W# a#) = setMutableByteArray# mba# o# n# (W32# a#)
+  setOffAddr# addr# o# n# (W# a#) = setOffAddr# addr# o# n# (W32# a#)
+#endif
+  {-# INLINE setMutableByteArray# #-}
+  {-# INLINE setOffAddr# #-}
+
+instance Prim Word8 where
+  type PrimBase Word8 = Word8
+  type SizeOf Word8 = SIZEOF_WORD8
+  type Alignment Word8 = ALIGNMENT_WORD8
+  sizeOf# _ = SIZEOF_WORD8#
+  {-# INLINE sizeOf# #-}
+  alignment# _ = ALIGNMENT_WORD8#
+  {-# INLINE alignment# #-}
+  indexByteOffByteArray# ba# i# = W8# (indexWord8Array# ba# i#)
+  {-# INLINE indexByteOffByteArray# #-}
+  indexByteArray# ba# i# = W8# (indexWord8Array# ba# i#)
+  {-# INLINE indexByteArray# #-}
+  indexOffAddr# addr# i# = W8# (indexWord8OffAddr# addr# i#)
+  {-# INLINE indexOffAddr# #-}
+  readByteOffMutableByteArray# mba# i# s = case readWord8Array# mba# i# s of
+                                             (# s', a# #) -> (# s', W8# a# #)
+  {-# INLINE readByteOffMutableByteArray# #-}
+  readMutableByteArray# mba# i# s = case readWord8Array# mba# i# s of
+                                      (# s', a# #) -> (# s', W8# a# #)
+  {-# INLINE readMutableByteArray# #-}
+  readOffAddr# mba# i# s = case readWord8OffAddr# mba# i# s of
+                             (# s', a# #) -> (# s', W8# a# #)
+  {-# INLINE readOffAddr# #-}
+  writeByteOffMutableByteArray# mba# i# (W8# a#) = writeWord8Array# mba# i# a#
+  {-# INLINE writeByteOffMutableByteArray# #-}
+  writeMutableByteArray# mba# i# (W8# a#) = writeWord8Array# mba# i# a#
+  {-# INLINE writeMutableByteArray# #-}
+  writeOffAddr# mba# i# (W8# a#) = writeWord8OffAddr# mba# i# a#
+  {-# INLINE writeOffAddr# #-}
+  setMutableByteArray# mba# i# n# (W8# a#) = setByteArray# mba# i# n# (word2Int# a#)
+  {-# INLINE setMutableByteArray# #-}
+  setOffAddr# addr# o# n# a = unsafePrimBase_ (memsetWord8Addr# addr# o# n# a)
+  {-# INLINE setOffAddr# #-}
+
+instance Prim Word16 where
+  type PrimBase Word16 = Word16
+  type SizeOf Word16 = SIZEOF_WORD16
+  type Alignment Word16 = ALIGNMENT_WORD16
+  sizeOf# _ = SIZEOF_WORD16#
+  {-# INLINE sizeOf# #-}
+  alignment# _ = ALIGNMENT_WORD16#
+  {-# INLINE alignment# #-}
+  indexByteOffByteArray# ba# i# = W16# (indexWord8ArrayAsWord16# ba# i#)
+  {-# INLINE indexByteOffByteArray# #-}
+  indexByteArray# ba# i# = W16# (indexWord16Array# ba# i#)
+  {-# INLINE indexByteArray# #-}
+  indexOffAddr# addr# i# = W16# (indexWord16OffAddr# addr# i#)
+  {-# INLINE indexOffAddr# #-}
+  readByteOffMutableByteArray# mba# i# s = case readWord8ArrayAsWord16# mba# i# s of
+                                             (# s', a# #) -> (# s', W16# a# #)
+  {-# INLINE readByteOffMutableByteArray# #-}
+  readMutableByteArray# mba# i# s = case readWord16Array# mba# i# s of
+                                      (# s', a# #) -> (# s', W16# a# #)
+  {-# INLINE readMutableByteArray# #-}
+  readOffAddr# mba# i# s = case readWord16OffAddr# mba# i# s of
+                             (# s', a# #) -> (# s', W16# a# #)
+  {-# INLINE readOffAddr# #-}
+  writeByteOffMutableByteArray# mba# i# (W16# a#) = writeWord8ArrayAsWord16# mba# i# a#
+  {-# INLINE writeByteOffMutableByteArray# #-}
+  writeMutableByteArray# mba# i# (W16# a#) = writeWord16Array# mba# i# a#
+  {-# INLINE writeMutableByteArray# #-}
+  writeOffAddr# mba# i# (W16# a#) = writeWord16OffAddr# mba# i# a#
+  {-# INLINE writeOffAddr# #-}
+  setMutableByteArray# mba# o# n# a =
+    unsafePrimBase_ (memsetWord16MutableByteArray# mba# o# n# a)
+  {-# INLINE setMutableByteArray# #-}
+  setOffAddr# addr# o# n# a = unsafePrimBase_ (memsetWord16Addr# addr# o# n# a)
+  {-# INLINE setOffAddr# #-}
+
+instance Prim Word32 where
+  type PrimBase Word32 = Word32
+  type SizeOf Word32 = SIZEOF_WORD32
+  type Alignment Word32 = ALIGNMENT_WORD32
+  sizeOf# _ = SIZEOF_WORD32#
+  {-# INLINE sizeOf# #-}
+  alignment# _ = ALIGNMENT_WORD32#
+  {-# INLINE alignment# #-}
+  indexByteOffByteArray# ba# i# = W32# (indexWord8ArrayAsWord32# ba# i#)
+  {-# INLINE indexByteOffByteArray# #-}
+  indexByteArray# ba# i# = W32# (indexWord32Array# ba# i#)
+  {-# INLINE indexByteArray# #-}
+  indexOffAddr# addr# i# = W32# (indexWord32OffAddr# addr# i#)
+  {-# INLINE indexOffAddr# #-}
+  readByteOffMutableByteArray# mba# i# s = case readWord8ArrayAsWord32# mba# i# s of
+                                             (# s', a# #) -> (# s', W32# a# #)
+  {-# INLINE readByteOffMutableByteArray# #-}
+  readMutableByteArray# mba# i# s = case readWord32Array# mba# i# s of
+                                      (# s', a# #) -> (# s', W32# a# #)
+  {-# INLINE readMutableByteArray# #-}
+  readOffAddr# mba# i# s = case readWord32OffAddr# mba# i# s of
+                             (# s', a# #) -> (# s', W32# a# #)
+  {-# INLINE readOffAddr# #-}
+  writeByteOffMutableByteArray# mba# i# (W32# a#) = writeWord8ArrayAsWord32# mba# i# a#
+  {-# INLINE writeByteOffMutableByteArray# #-}
+  writeMutableByteArray# mba# i# (W32# a#) = writeWord32Array# mba# i# a#
+  {-# INLINE writeMutableByteArray# #-}
+  writeOffAddr# mba# i# (W32# a#) = writeWord32OffAddr# mba# i# a#
+  {-# INLINE writeOffAddr# #-}
+  setMutableByteArray# mba# o# n# a = unsafePrimBase_ (memsetWord32MutableByteArray# mba# o# n# a)
+  {-# INLINE setMutableByteArray# #-}
+  setOffAddr# addr# o# n# a = unsafePrimBase_ (memsetWord32Addr# addr# o# n# a)
+  {-# INLINE setOffAddr# #-}
+
+instance Prim Word64 where
+  type PrimBase Word64 = Word64
+  type SizeOf Word64 = SIZEOF_WORD64
+  type Alignment Word64 = ALIGNMENT_WORD64
+  sizeOf# _ = SIZEOF_WORD64#
+  {-# INLINE sizeOf# #-}
+  alignment# _ = ALIGNMENT_WORD64#
+  {-# INLINE alignment# #-}
+  indexByteOffByteArray# ba# i# = W64# (indexWord8ArrayAsWord64# ba# i#)
+  {-# INLINE indexByteOffByteArray# #-}
+  indexByteArray# ba# i# = W64# (indexWord64Array# ba# i#)
+  {-# INLINE indexByteArray# #-}
+  indexOffAddr# addr# i# = W64# (indexWord64OffAddr# addr# i#)
+  {-# INLINE indexOffAddr# #-}
+  readByteOffMutableByteArray# mba# i# s = case readWord8ArrayAsWord64# mba# i# s of
+                                             (# s', a# #) -> (# s', W64# a# #)
+  {-# INLINE readByteOffMutableByteArray# #-}
+  readMutableByteArray# mba# i# s = case readWord64Array# mba# i# s of
+                                      (# s', a# #) -> (# s', W64# a# #)
+  {-# INLINE readMutableByteArray# #-}
+  readOffAddr# mba# i# s = case readWord64OffAddr# mba# i# s of
+                             (# s', a# #) -> (# s', W64# a# #)
+  {-# INLINE readOffAddr# #-}
+  writeByteOffMutableByteArray# mba# i# (W64# a#) = writeWord8ArrayAsWord64# mba# i# a#
+  {-# INLINE writeByteOffMutableByteArray# #-}
+  writeMutableByteArray# mba# i# (W64# a#) = writeWord64Array# mba# i# a#
+  {-# INLINE writeMutableByteArray# #-}
+  writeOffAddr# mba# i# (W64# a#) = writeWord64OffAddr# mba# i# a#
+  {-# INLINE writeOffAddr# #-}
+  setMutableByteArray# mba# o# n# a = unsafePrimBase_ (memsetWord64MutableByteArray# mba# o# n# a)
+  {-# INLINE setMutableByteArray# #-}
+  setOffAddr# addr# o# n# a = unsafePrimBase_ (memsetWord64Addr# addr# o# n# a)
+  {-# INLINE setOffAddr# #-}
+
+
+instance Prim Float where
+  type PrimBase Float = Float
+  type SizeOf Float = SIZEOF_FLOAT
+  type Alignment Float = ALIGNMENT_FLOAT
+  sizeOf# _ = SIZEOF_FLOAT#
+  {-# INLINE sizeOf# #-}
+  alignment# _ = ALIGNMENT_FLOAT#
+  {-# INLINE alignment# #-}
+  indexByteOffByteArray# ba# i# = F# (indexWord8ArrayAsFloat# ba# i#)
+  {-# INLINE indexByteOffByteArray# #-}
+  indexByteArray# ba# i# = F# (indexFloatArray# ba# i#)
+  {-# INLINE indexByteArray# #-}
+  indexOffAddr# addr# i# = F# (indexFloatOffAddr# addr# i#)
+  {-# INLINE indexOffAddr# #-}
+  readByteOffMutableByteArray# mba# i# s = case readWord8ArrayAsFloat# mba# i# s of
+                                             (# s', a# #) -> (# s', F# a# #)
+  {-# INLINE readByteOffMutableByteArray# #-}
+  readMutableByteArray# mba# i# s = case readFloatArray# mba# i# s of
+                                      (# s', a# #) -> (# s', F# a# #)
+  {-# INLINE readMutableByteArray# #-}
+  readOffAddr# mba# i# s = case readFloatOffAddr# mba# i# s of
+                             (# s', a# #) -> (# s', F# a# #)
+  {-# INLINE readOffAddr# #-}
+  writeByteOffMutableByteArray# mba# i# (F# a#) = writeWord8ArrayAsFloat# mba# i# a#
+  {-# INLINE writeByteOffMutableByteArray# #-}
+  writeMutableByteArray# mba# i# (F# a#) = writeFloatArray# mba# i# a#
+  {-# INLINE writeMutableByteArray# #-}
+  writeOffAddr# mba# i# (F# a#) = writeFloatOffAddr# mba# i# a#
+  {-# INLINE writeOffAddr# #-}
+  setMutableByteArray# mba# o# n# (F# f#) =
+    unsafePrimBase_ (memsetWord32MutableByteArray# mba# o# n# (W32# (floatToWord32# f#)))
+  {-# INLINE setMutableByteArray# #-}
+  setOffAddr# addr# o# n# (F# f#) =
+    unsafePrimBase_ (memsetWord32Addr# addr# o# n# (W32# (floatToWord32# f#)))
+
+instance Prim Double where
+  type PrimBase Double = Double
+  type SizeOf Double = SIZEOF_DOUBLE
+  type Alignment Double = ALIGNMENT_DOUBLE
+  sizeOf# _ = SIZEOF_DOUBLE#
+  {-# INLINE sizeOf# #-}
+  alignment# _ = ALIGNMENT_DOUBLE#
+  {-# INLINE alignment# #-}
+  indexByteOffByteArray# ba# i# = D# (indexWord8ArrayAsDouble# ba# i#)
+  {-# INLINE indexByteOffByteArray# #-}
+  indexByteArray# ba# i# = D# (indexDoubleArray# ba# i#)
+  {-# INLINE indexByteArray# #-}
+  indexOffAddr# addr# i# = D# (indexDoubleOffAddr# addr# i#)
+  {-# INLINE indexOffAddr# #-}
+  readByteOffMutableByteArray# mba# i# s = case readWord8ArrayAsDouble# mba# i# s of
+                                             (# s', a# #) -> (# s', D# a# #)
+  {-# INLINE readByteOffMutableByteArray# #-}
+  readMutableByteArray# mba# i# s = case readDoubleArray# mba# i# s of
+                                      (# s', a# #) -> (# s', D# a# #)
+  {-# INLINE readMutableByteArray# #-}
+  readOffAddr# mba# i# s = case readDoubleOffAddr# mba# i# s of
+                             (# s', a# #) -> (# s', D# a# #)
+  {-# INLINE readOffAddr# #-}
+  writeByteOffMutableByteArray# mba# i# (D# a#) = writeWord8ArrayAsDouble# mba# i# a#
+  {-# INLINE writeByteOffMutableByteArray# #-}
+  writeMutableByteArray# mba# i# (D# a#) = writeDoubleArray# mba# i# a#
+  {-# INLINE writeMutableByteArray# #-}
+  writeOffAddr# mba# i# (D# a#) = writeDoubleOffAddr# mba# i# a#
+  {-# INLINE writeOffAddr# #-}
+  setMutableByteArray# mba# o# n# (D# d#) =
+    unsafePrimBase_ (memsetWord64MutableByteArray# mba# o# n# (W64# (doubleToWord64# d#)))
+  {-# INLINE setMutableByteArray# #-}
+  setOffAddr# addr# o# n# (D# d#) =
+    unsafePrimBase_ (memsetWord64Addr# addr# o# n# (W64# (doubleToWord64# d#)))
+  {-# INLINE setOffAddr# #-}
+
+bool2Int# :: Bool -> Int#
+bool2Int# b = if b then 1# else 0#
+{-# INLINE bool2Int# #-}
+
+int2Bool# :: Int# -> Bool
+int2Bool# i# = isTrue# (i# /=# 0#) -- tagToEnum# (i# /=# 0#) -- (andI# i# 1#)
+{-# INLINE int2Bool# #-}
+
+instance Prim Bool where
+  type PrimBase Bool = Int8
+  fromPrimBase (I8# i#) = int2Bool# i#
+  {-# INLINE fromPrimBase #-}
+  toPrimBase b = I8# (bool2Int# b)
+  {-# INLINE toPrimBase #-}
+
+instance Prim Char where
+  type PrimBase Char = Char
+  type SizeOf Char = SIZEOF_HSCHAR
+  type Alignment Char = ALIGNMENT_HSCHAR
+  sizeOf# _ = SIZEOF_HSCHAR#
+  {-# INLINE sizeOf# #-}
+  alignment# _ = ALIGNMENT_HSCHAR#
+  {-# INLINE alignment# #-}
+  indexByteOffByteArray# ba# i# = C# (indexWord8ArrayAsWideChar# ba# i#)
+  {-# INLINE indexByteOffByteArray# #-}
+  indexByteArray# ba# i# = C# (indexWideCharArray# ba# i#)
+  {-# INLINE indexByteArray# #-}
+  indexOffAddr# addr# i# = C# (indexWideCharOffAddr# addr# i#)
+  {-# INLINE indexOffAddr# #-}
+  readByteOffMutableByteArray# mba# i# s = case readWord8ArrayAsWideChar# mba# i# s of
+                                             (# s', a# #) -> (# s', C# a# #)
+  {-# INLINE readByteOffMutableByteArray# #-}
+  readMutableByteArray# mba# i# s = case readWideCharArray# mba# i# s of
+                                      (# s', a# #) -> (# s', C# a# #)
+  {-# INLINE readMutableByteArray# #-}
+  readOffAddr# mba# i# s = case readWideCharOffAddr# mba# i# s of
+                             (# s', a# #) -> (# s', C# a# #)
+  {-# INLINE readOffAddr# #-}
+  writeByteOffMutableByteArray# mba# i# (C# a#) = writeWord8ArrayAsWideChar# mba# i# a#
+  {-# INLINE writeByteOffMutableByteArray# #-}
+  writeMutableByteArray# mba# i# (C# a#) = writeWideCharArray# mba# i# a#
+  {-# INLINE writeMutableByteArray# #-}
+  writeOffAddr# mba# i# (C# a#) = writeWideCharOffAddr# mba# i# a#
+  {-# INLINE writeOffAddr# #-}
+  setMutableByteArray# mba# o# n# (C# a#) = setMutableByteArray# mba# o# n# (I32# (ord# a#))
+  {-# INLINE setMutableByteArray# #-}
+  setOffAddr# addr# o# n# (C# a#) = setOffAddr# addr# o# n# (I32# (ord# a#))
+  {-# INLINE setOffAddr# #-}
+
+instance Prim (Ptr a) where
+  type PrimBase (Ptr a) = Ptr a
+  type SizeOf (Ptr a) = SIZEOF_HSPTR
+  type Alignment (Ptr a) = ALIGNMENT_HSPTR
+  sizeOf# _ = SIZEOF_HSINT#
+  {-# INLINE sizeOf# #-}
+  alignment# _ = ALIGNMENT_HSINT#
+  {-# INLINE alignment# #-}
+  indexByteOffByteArray# ba# i# = Ptr (indexWord8ArrayAsAddr# ba# i#)
+  {-# INLINE indexByteOffByteArray# #-}
+  indexByteArray# ba# i# = Ptr (indexAddrArray# ba# i#)
+  {-# INLINE indexByteArray# #-}
+  indexOffAddr# addr# i# = Ptr (indexAddrOffAddr# addr# i#)
+  {-# INLINE indexOffAddr# #-}
+  readByteOffMutableByteArray# mba# i# s = case readWord8ArrayAsAddr# mba# i# s of
+                                             (# s', a# #) -> (# s', Ptr a# #)
+  {-# INLINE readByteOffMutableByteArray# #-}
+  readMutableByteArray# mba# i# s = case readAddrArray# mba# i# s of
+                                      (# s', a# #) -> (# s', Ptr a# #)
+  {-# INLINE readMutableByteArray# #-}
+  readOffAddr# mba# i# s = case readAddrOffAddr# mba# i# s of
+                             (# s', a# #) -> (# s', Ptr a# #)
+  {-# INLINE readOffAddr# #-}
+  writeByteOffMutableByteArray# mba# i# (Ptr a#) = writeWord8ArrayAsAddr# mba# i# a#
+  {-# INLINE writeByteOffMutableByteArray# #-}
+  writeMutableByteArray# mba# i# (Ptr a#) = writeAddrArray# mba# i# a#
+  {-# INLINE writeMutableByteArray# #-}
+  writeOffAddr# mba# i# (Ptr a#) = writeAddrOffAddr# mba# i# a#
+  {-# INLINE writeOffAddr# #-}
+#if SIZEOF_HSPTR == SIZEOF_INT64
+  setMutableByteArray# mba# o# n# (Ptr a#) = setMutableByteArray# mba# o# n# (I64# (addr2Int# a#))
+  setOffAddr# addr# o# n# (Ptr a#) = setOffAddr# addr# o# n# (I64# (addr2Int# a#))
+#elif SIZEOF_HSPTR == SIZEOF_INT32
+  setMutableByteArray# mba# o# n# (Ptr a#) = setMutableByteArray# mba# o# n# (I32# (addr2Int# a#))
+  setOffAddr# addr# o# n# (Ptr a#) = setOffAddr# addr# o# n# (I32# (addr2Int# a#))
+#else
+#error Ptr is of unsupported size SIZEOF_HSPTR
+#endif
+  {-# INLINE setMutableByteArray# #-}
+  {-# INLINE setOffAddr# #-}
+
+instance Prim (FunPtr a) where
+  type PrimBase (FunPtr a) = Ptr a
+  toPrimBase (FunPtr addr#) = Ptr addr#
+  fromPrimBase (Ptr addr#) = FunPtr addr#
+
+
+instance Prim (StablePtr a) where
+  type PrimBase (StablePtr a) = StablePtr a
+  type SizeOf (StablePtr a) = SIZEOF_HSSTABLEPTR
+  type Alignment (StablePtr a) = ALIGNMENT_HSSTABLEPTR
+  sizeOf# _ = SIZEOF_HSINT#
+  {-# INLINE sizeOf# #-}
+  alignment# _ = ALIGNMENT_HSINT#
+  {-# INLINE alignment# #-}
+  indexByteOffByteArray# ba# i# = StablePtr (indexWord8ArrayAsStablePtr# ba# i#)
+  {-# INLINE indexByteOffByteArray# #-}
+  indexByteArray# ba# i# = StablePtr (indexStablePtrArray# ba# i#)
+  {-# INLINE indexByteArray# #-}
+  indexOffAddr# addr# i# = StablePtr (indexStablePtrOffAddr# addr# i#)
+  {-# INLINE indexOffAddr# #-}
+  readByteOffMutableByteArray# mba# i# s = case readWord8ArrayAsStablePtr# mba# i# s of
+                                             (# s', a# #) -> (# s', StablePtr a# #)
+  {-# INLINE readByteOffMutableByteArray# #-}
+  readMutableByteArray# mba# i# s = case readStablePtrArray# mba# i# s of
+                                      (# s', a# #) -> (# s', StablePtr a# #)
+  {-# INLINE readMutableByteArray# #-}
+  readOffAddr# mba# i# s = case readStablePtrOffAddr# mba# i# s of
+                             (# s', a# #) -> (# s', StablePtr a# #)
+  {-# INLINE readOffAddr# #-}
+  writeByteOffMutableByteArray# mba# i# (StablePtr a#) = writeWord8ArrayAsStablePtr# mba# i# a#
+  {-# INLINE writeByteOffMutableByteArray# #-}
+  writeMutableByteArray# mba# i# (StablePtr a#) = writeStablePtrArray# mba# i# a#
+  {-# INLINE writeMutableByteArray# #-}
+  writeOffAddr# mba# i# (StablePtr a#) = writeStablePtrOffAddr# mba# i# a#
+  {-# INLINE writeOffAddr# #-}
+#if SIZEOF_HSSTABLEPTR == SIZEOF_INT64
+  setMutableByteArray# mba# o# n# (StablePtr a#) = setMutableByteArray# mba# o# n# (I64# (unsafeCoerce# a#))
+  setOffAddr# addr# o# n# (StablePtr a#) = setOffAddr# addr# o# n# (I64# (unsafeCoerce# a#))
+#elif SIZEOF_HSSTABLEPTR == SIZEOF_INT32
+  setMutableByteArray# mba# o# n# (StablePtr a#) = setMutableByteArray# mba# o# n# (I32# (unsafeCoerce# a#))
+  setOffAddr# addr# o# n# (StablePtr a#) = setOffAddr# addr# o# n# (I32# (unsafeCoerce# a#))
+#else
+#error StablePtr is of unsupported size SIZEOF_HSSTABLEPTR
+#endif
+  {-# INLINE setMutableByteArray# #-}
+  {-# INLINE setOffAddr# #-}
+
+
+instance Prim IntPtr where
+  type PrimBase IntPtr = Int
+
+instance Prim WordPtr where
+  type PrimBase WordPtr = Word
+
+instance Prim CBool where
+  type PrimBase CBool = HTYPE_BOOL
+
+instance Prim CChar where
+  type PrimBase CChar = HTYPE_CHAR
+
+instance Prim CSChar where
+  type PrimBase CSChar = HTYPE_SIGNED_CHAR
+
+instance Prim CUChar where
+  type PrimBase CUChar = HTYPE_UNSIGNED_CHAR
+
+instance Prim CShort where
+  type PrimBase CShort = HTYPE_SHORT
+
+instance Prim CUShort where
+  type PrimBase CUShort = HTYPE_UNSIGNED_SHORT
+
+instance Prim CInt where
+  type PrimBase CInt = HTYPE_INT
+
+instance Prim CUInt where
+  type PrimBase CUInt = HTYPE_UNSIGNED_INT
+
+instance Prim CLong where
+  type PrimBase CLong = HTYPE_LONG
+
+instance Prim CULong where
+  type PrimBase CULong = HTYPE_UNSIGNED_LONG
+
+instance Prim CLLong where
+  type PrimBase CLLong = HTYPE_LONG_LONG
+
+instance Prim CULLong where
+  type PrimBase CULLong = HTYPE_UNSIGNED_LONG_LONG
+
+instance Prim CPtrdiff where
+  type PrimBase CPtrdiff = HTYPE_PTRDIFF_T
+
+instance Prim CSize where
+  type PrimBase CSize = HTYPE_SIZE_T
+
+instance Prim CWchar where
+  type PrimBase CWchar = HTYPE_WCHAR_T
+
+instance Prim CSigAtomic where
+  type PrimBase CSigAtomic = HTYPE_SIG_ATOMIC_T
+
+instance Prim CIntPtr where
+  type PrimBase CIntPtr = HTYPE_INTPTR_T
+
+instance Prim CUIntPtr where
+  type PrimBase CUIntPtr = HTYPE_UINTPTR_T
+
+instance Prim CIntMax where
+  type PrimBase CIntMax = HTYPE_INTMAX_T
+
+instance Prim CUIntMax where
+  type PrimBase CUIntMax = HTYPE_UINTMAX_T
+
+instance Prim CFloat where
+  type PrimBase CFloat = HTYPE_FLOAT
+
+instance Prim CDouble where
+  type PrimBase CDouble = HTYPE_DOUBLE
+
+
+instance Prim Fd where
+  type PrimBase Fd = CInt
+
+instance Prim Errno where
+  type PrimBase Errno = CInt
+
+
+#if defined(HTYPE_DEV_T)
+instance Prim CDev where
+  type PrimBase CDev = HTYPE_DEV_T
+#endif
+#if defined(HTYPE_INO_T)
+instance Prim CIno where
+  type PrimBase CIno = HTYPE_INO_T
+#endif
+#if defined(HTYPE_MODE_T)
+instance Prim CMode where
+  type PrimBase CMode = HTYPE_MODE_T
+#endif
+#if defined(HTYPE_OFF_T)
+instance Prim COff where
+  type PrimBase COff = HTYPE_OFF_T
+#endif
+#if defined(HTYPE_PID_T)
+instance Prim CPid where
+  type PrimBase CPid = HTYPE_PID_T
+#endif
+#if defined(HTYPE_SSIZE_T)
+instance Prim CSsize where
+  type PrimBase CSsize = HTYPE_SSIZE_T
+#endif
+#if defined(HTYPE_GID_T)
+instance Prim CGid where
+  type PrimBase CGid = HTYPE_GID_T
+#endif
+#if defined(HTYPE_NLINK_T)
+instance Prim CNlink where
+  type PrimBase CNlink = HTYPE_NLINK_T
+#endif
+#if defined(HTYPE_UID_T)
+instance Prim CUid where
+  type PrimBase CUid = HTYPE_UID_T
+#endif
+#if defined(HTYPE_CC_T)
+instance Prim CCc where
+  type PrimBase CCc = HTYPE_CC_T
+#endif
+#if defined(HTYPE_SPEED_T)
+instance Prim CSpeed where
+  type PrimBase CSpeed = HTYPE_SPEED_T
+#endif
+#if defined(HTYPE_TCFLAG_T)
+instance Prim CTcflag where
+  type PrimBase CTcflag = HTYPE_TCFLAG_T
+#endif
+#if defined(HTYPE_RLIM_T)
+instance Prim CRLim where
+  type PrimBase CRLim = HTYPE_RLIM_T
+#endif
+
+#if __GLASGOW_HASKELL__ >= 800
+
+
+instance Prim a => Prim (Max a) where
+  type PrimBase (Max a) = a
+instance Prim a => Prim (Min a) where
+  type PrimBase (Min a) = a
+instance Prim a => Prim (Data.Semigroup.First a) where
+  type PrimBase (Data.Semigroup.First a) = a
+instance Prim a => Prim (Data.Semigroup.Last a) where
+  type PrimBase (Data.Semigroup.Last a) = a
+instance (Prim a, Prim b) => Prim (Arg a b) where
+  type PrimBase (Arg a b) = (a, b)
+  toPrimBase (Arg a b) = (a, b)
+  fromPrimBase (a, b) = Arg a b
+
+instance Prim a => Prim (Const a b) where
+  type PrimBase (Const a b) = a
+
+#if __GLASGOW_HASKELL__ >= 802
+
+instance a ~ b => Prim (a :~~: b) where
+  type PrimBase (a :~~: b) = ()
+  toPrimBase HRefl = ()
+  fromPrimBase () = HRefl
+
+#if defined(HTYPE_BLKSIZE_T)
+instance Prim CBlkSize where
+  type PrimBase CBlkSize = HTYPE_BLKSIZE_T
+#endif
+#if defined(HTYPE_BLKCNT_T)
+instance Prim CBlkCnt where
+  type PrimBase CBlkCnt = HTYPE_BLKCNT_T
+#endif
+#if defined(HTYPE_CLOCKID_T)
+instance Prim CClockId where
+  type PrimBase CClockId = HTYPE_CLOCKID_T
+#endif
+#if defined(HTYPE_FSBLKCNT_T)
+instance Prim CFsBlkCnt where
+  type PrimBase CFsBlkCnt = HTYPE_FSBLKCNT_T
+#endif
+#if defined(HTYPE_FSFILCNT_T)
+instance Prim CFsFilCnt where
+  type PrimBase CFsFilCnt = HTYPE_FSFILCNT_T
+#endif
+#if defined(HTYPE_ID_T)
+instance Prim CId where
+  type PrimBase CId = HTYPE_ID_T
+#endif
+#if defined(HTYPE_KEY_T)
+instance Prim CKey where
+  type PrimBase CKey = HTYPE_KEY_T
+#endif
+#if defined(HTYPE_TIMER_T)
+instance Prim CTimer where
+  type PrimBase CTimer = HTYPE_TIMER_T
+#endif
+
+#if __GLASGOW_HASKELL__ >= 810
+
+#if defined(HTYPE_SOCKLEN_T)
+instance Prim CSocklen where
+  type PrimBase CSocklen = HTYPE_SOCKLEN_T
+#endif
+#if defined(HTYPE_NFDS_T)
+instance Prim CNfds where
+  type PrimBase CNfds = HTYPE_NFDS_T
+#endif
+
+#endif /* __GLASGOW_HASKELL__ >= 810 */
+
+#if __GLASGOW_HASKELL__ >= 806
+instance Prim (f a) => Prim (Ap f a) where
+  type PrimBase (Ap f a) = f a
+#endif /* __GLASGOW_HASKELL__ >= 806 */
+
+
+#endif /* __GLASGOW_HASKELL__ >= 802 */
+
+
+#endif /* __GLASGOW_HASKELL__ >= 800 */
+
+instance (Prim (f a), Prim (g a)) => Prim (Functor.Product f g a) where
+  type PrimBase (Functor.Product f g a) = (f a, g a)
+  toPrimBase (Functor.Pair fa ga) = (fa, ga)
+  {-# INLINE toPrimBase #-}
+  fromPrimBase (fa, ga) = Functor.Pair fa ga
+  {-# INLINE fromPrimBase #-}
+
+
+instance Prim (f (g a)) => Prim (Compose f g a) where
+  type PrimBase (Compose f g a) = f (g a)
+
+instance Prim a => Prim (Identity a) where
+  type PrimBase (Identity a) = a
+
+instance Prim (f a) => Prim (Alt f a) where
+  type PrimBase (Alt f a) = f a
+
+instance Prim Ordering where
+  type PrimBase Ordering = Int8
+  toPrimBase o = I8# (fromOrdering# o)
+  {-# INLINE toPrimBase #-}
+  fromPrimBase (I8# i#) = toOrdering# i#
+  {-# INLINE fromPrimBase #-}
+
+instance Prim IODeviceType where
+  type PrimBase IODeviceType = Int8
+  toPrimBase =
+    \case
+      Directory -> 0
+      Stream -> 1
+      RegularFile -> 2
+      RawDevice -> 3
+  {-# INLINE toPrimBase #-}
+  fromPrimBase =
+    \case
+      0 -> Directory
+      1 -> Stream
+      2 -> RegularFile
+      _ -> RawDevice
+  {-# INLINE fromPrimBase #-}
+
+instance Prim SeekMode where
+  type PrimBase SeekMode = Int8
+  toPrimBase = \case
+    AbsoluteSeek -> 0
+    RelativeSeek -> 1
+    SeekFromEnd  -> 2
+  {-# INLINE toPrimBase #-}
+  fromPrimBase = \case
+    0 -> AbsoluteSeek
+    1 -> RelativeSeek
+    _ -> SeekFromEnd
+  {-# INLINE fromPrimBase #-}
+
+instance Prim BlockReason where
+  type PrimBase BlockReason = Int8
+  toPrimBase =
+    \case
+      BlockedOnMVar -> 0
+      BlockedOnBlackHole -> 1
+      BlockedOnException -> 2
+      BlockedOnSTM -> 3
+      BlockedOnForeignCall -> 4
+      BlockedOnOther -> 5
+  {-# INLINE toPrimBase #-}
+  fromPrimBase =
+    \case
+      0 -> BlockedOnMVar
+      1 -> BlockedOnBlackHole
+      2 -> BlockedOnException
+      3 -> BlockedOnSTM
+      4 -> BlockedOnForeignCall
+      _ -> BlockedOnOther
+  {-# INLINE fromPrimBase #-}
+
+
+instance Prim ThreadStatus where
+  type PrimBase ThreadStatus = Int8
+  toPrimBase =
+    \case
+      ThreadRunning -> 0x00
+      ThreadFinished -> 0x10
+      ThreadBlocked br -> 0x20 .|. toPrimBase br
+      ThreadDied -> 0x30
+  {-# INLINE toPrimBase #-}
+  fromPrimBase =
+    \case
+      0x00 -> ThreadRunning
+      0x10 -> ThreadFinished
+      0x30 -> ThreadDied
+      x -> ThreadBlocked $ fromPrimBase (x .&. 0xf)
+  {-# INLINE fromPrimBase #-}
+
+instance Prim IOMode where
+  type PrimBase IOMode = Int8
+  toPrimBase =
+    \case
+      ReadMode -> 0
+      WriteMode -> 1
+      AppendMode -> 2
+      ReadWriteMode -> 3
+  {-# INLINE toPrimBase #-}
+  fromPrimBase =
+    \case
+      0 -> ReadMode
+      1 -> WriteMode
+      2 -> AppendMode
+      _ -> ReadWriteMode
+  {-# INLINE fromPrimBase #-}
+
+instance Prim BufferMode where
+  type PrimBase BufferMode = (Int8, Maybe Int)
+  toPrimBase =
+    \case
+      NoBuffering -> (0, Nothing)
+      LineBuffering -> (1, Nothing)
+      BlockBuffering mb -> (2, mb)
+  {-# INLINE toPrimBase #-}
+  fromPrimBase =
+    \case
+      (0, _) -> NoBuffering
+      (1, _) -> LineBuffering
+      (_, mb) -> BlockBuffering mb
+  {-# INLINE fromPrimBase #-}
+
+instance Prim Newline where
+  type PrimBase Newline = Int8
+  toPrimBase =
+    \case
+      LF -> 0
+      CRLF -> 1
+  {-# INLINE toPrimBase #-}
+  fromPrimBase =
+    \case
+      0 -> LF
+      _ -> CRLF
+  {-# INLINE fromPrimBase #-}
+
+instance Prim NewlineMode where
+  type PrimBase NewlineMode = Int8
+  toPrimBase (NewlineMode i o) =
+    (toPrimBase i `unsafeShiftL` 1) .|. toPrimBase o
+  {-# INLINE toPrimBase #-}
+  fromPrimBase p =
+    NewlineMode
+      (fromPrimBase ((p `unsafeShiftR` 1) .&. 1))
+      (fromPrimBase (p .&. 1))
+  {-# INLINE fromPrimBase #-}
+
+instance Prim GeneralCategory where
+  type PrimBase GeneralCategory = Word8
+  toPrimBase = fromIntegral . fromEnum
+  {-# INLINE toPrimBase #-}
+  fromPrimBase p
+    | ip > fromEnum (maxBound :: GeneralCategory) = NotAssigned
+    | otherwise = toEnum ip
+    where
+      ip = fromIntegral p
+  {-# INLINE fromPrimBase #-}
+
+
+instance Prim a => Prim (Down a) where
+  type PrimBase (Down a) = a
+
+instance Prim a => Prim (Dual a) where
+  type PrimBase (Dual a) = a
+
+instance Prim a => Prim (Sum a) where
+  type PrimBase (Sum a) = a
+
+instance Prim a => Prim (Product a) where
+  type PrimBase (Product a) = a
+
+instance Prim All where
+  type PrimBase All = Bool
+
+instance Prim Any where
+  type PrimBase Any = Bool
+
+instance Prim Fingerprint where
+  type PrimBase Fingerprint = (Word64, Word64)
+  toPrimBase (Fingerprint a b) = (a, b)
+  fromPrimBase (a, b) = Fingerprint a b
+
+instance Prim a => Prim (Ratio a) where
+  type PrimBase (Ratio a) = (a, a)
+  toPrimBase (a :% b) = (a, b)
+  fromPrimBase (a, b) = a :% b
+
+instance Prim a => Prim (Complex a) where
+  type PrimBase (Complex a) = (a, a)
+  toPrimBase (a :+ b) = (a, b)
+  fromPrimBase (a, b) = a :+ b
+
+instance (Prim a, Prim b) => Prim (a, b) where
+  type PrimBase (a, b) = (a, b)
+  type SizeOf (a, b) = SizeOf a + SizeOf b
+  type Alignment (a, b) = Alignment a + Alignment b
+  sizeOf# _ = sizeOf# (proxy# :: Proxy# a) +# sizeOf# (proxy# :: Proxy# b)
+  {-# INLINE sizeOf# #-}
+  alignment# _ =
+    alignment# (proxy# :: Proxy# a) +# alignment# (proxy# :: Proxy# b)
+  {-# INLINE alignment# #-}
+  indexByteArray# ba# i# =
+    let i0# = i# *# sizeOf# (proxy# :: Proxy# (a, b))
+     in indexByteOffByteArray# ba# i0#
+  {-# INLINE indexByteArray# #-}
+  indexByteOffByteArray# ba# i0# =
+    let i1# = i0# +# sizeOf# (proxy# :: Proxy# a)
+     in (indexByteOffByteArray# ba# i0#, indexByteOffByteArray# ba# i1#)
+  {-# INLINE indexByteOffByteArray# #-}
+  indexOffAddr# addr# i# =
+    let addr0# = addr# `plusAddr#` (i# *# sizeOf# (proxy# :: Proxy# (a, b)))
+        addr1# = addr0# `plusAddr#` sizeOf# (proxy# :: Proxy# a)
+     in ( indexOffAddr# addr0# 0#, indexOffAddr# addr1# 0#)
+  {-# INLINE indexOffAddr# #-}
+  readMutableByteArray# mba# i# =
+    let i0# = i# *# sizeOf# (proxy# :: Proxy# (a, b))
+     in readByteOffMutableByteArray# mba# i0#
+  {-# INLINE readMutableByteArray# #-}
+  readByteOffMutableByteArray# mba# i0# s =
+    let i1# = i0# +# sizeOf# (proxy# :: Proxy# a)
+     in case readByteOffMutableByteArray# mba# i0# s of
+          (# s', a0 #) ->
+            case readByteOffMutableByteArray# mba# i1# s' of
+              (# s'', a1 #) -> (# s'', (a0, a1) #)
+  {-# INLINE readByteOffMutableByteArray# #-}
+  readOffAddr# addr# i# s =
+    let addr0# = addr# `plusAddr#` (i# *# sizeOf# (proxy# :: Proxy# (a, b)))
+        addr1# = addr# `plusAddr#` sizeOf# (proxy# :: Proxy# a)
+    in case readOffAddr# addr0# 0# s of
+         (# s', a0 #) ->
+           case readOffAddr# addr1# 0# s' of
+             (# s'', a1 #) -> (# s'', (a0, a1) #)
+  {-# INLINE readOffAddr# #-}
+  writeByteOffMutableByteArray# mba# i0# (a0, a1) s =
+    let i1# = i0# +# sizeOf# (proxy# :: Proxy# a)
+    in writeByteOffMutableByteArray# mba# i1# a1 (writeByteOffMutableByteArray# mba# i0# a0 s)
+  {-# INLINE writeByteOffMutableByteArray# #-}
+  writeMutableByteArray# mba# i# a =
+    let i0# = i# *# sizeOf# (proxy# :: Proxy# (a, b))
+    in writeByteOffMutableByteArray# mba# i0# a
+  {-# INLINE writeMutableByteArray# #-}
+  writeOffAddr# addr# i# (a0, a1) s =
+    let addr0# = addr# `plusAddr#` (i# *# sizeOf# (proxy# :: Proxy# (a, b)))
+        addr1# = addr0# `plusAddr#` sizeOf# (proxy# :: Proxy# a)
+    in writeOffAddr# addr0# 0# a1 (writeOffAddr# addr1# 0# a0 s)
+  {-# INLINE writeOffAddr# #-}
+  setMutableByteArray# = setMutableByteArrayLoop#
+    -- TODO: optimize with rewrite rules?
+    --  | a0 == a1 = setMutableByteArray# mba# (o# *# 2#) (n# *# 2#) a0 s
+  {-# INLINE setMutableByteArray# #-}
+  setOffAddr# = setOffAddrLoop#
+  {-# INLINE setOffAddr# #-}
+  --   | a0 == a1 = setOffAddr# addr# (o# *# 2#) (n# *# 2#) a0 s
+
+
+instance (Prim a, Prim b, Prim c) => Prim (a, b, c) where
+  type PrimBase (a, b, c) = (a, b, c)
+  type SizeOf (a, b, c) = SizeOf a + SizeOf b + SizeOf c
+  type Alignment (a, b, c) = Alignment a + Alignment b + Alignment c
+  sizeOf# _ = sizeOf# (proxy# :: Proxy# a)
+           +# sizeOf# (proxy# :: Proxy# b)
+           +# sizeOf# (proxy# :: Proxy# c)
+  {-# INLINE sizeOf# #-}
+  alignment# _ = alignment# (proxy# :: Proxy# a)
+              +# alignment# (proxy# :: Proxy# b)
+              +# alignment# (proxy# :: Proxy# c)
+  {-# INLINE alignment# #-}
+  indexByteOffByteArray# ba# i0# =
+    let i1# = i0# +# sizeOf# (proxy# :: Proxy# a)
+        i2# = i1# +# sizeOf# (proxy# :: Proxy# b)
+    in ( indexByteOffByteArray# ba# i0#
+       , indexByteOffByteArray# ba# i1#
+       , indexByteOffByteArray# ba# i2#
+       )
+  {-# INLINE indexByteOffByteArray# #-}
+  indexByteArray# ba# i# =
+    let i0# = i# *# sizeOf# (proxy# :: Proxy# (a, b, c))
+    in indexByteOffByteArray# ba# i0#
+  {-# INLINE indexByteArray# #-}
+  indexOffAddr# addr# i# =
+    let i0# = i# *# sizeOf# (proxy# :: Proxy# (a, b, c))
+        i1# = i0# +# sizeOf# (proxy# :: Proxy# a)
+        i2# = i1# +# sizeOf# (proxy# :: Proxy# b)
+    in ( indexOffAddr# (addr# `plusAddr#` i0#) 0#
+       , indexOffAddr# (addr# `plusAddr#` i1#) 0#
+       , indexOffAddr# (addr# `plusAddr#` i2#) 0#
+       )
+  {-# INLINE indexOffAddr# #-}
+  readMutableByteArray# mba# i# =
+    let i0# = i# *# sizeOf# (proxy# :: Proxy# (a, b, c))
+    in readByteOffMutableByteArray# mba# i0#
+  {-# INLINE readMutableByteArray# #-}
+  readByteOffMutableByteArray# mba# i0# s =
+    let i1# = i0# +# sizeOf# (proxy# :: Proxy# a)
+        i2# = i1# +# sizeOf# (proxy# :: Proxy# b)
+    in case readByteOffMutableByteArray# mba# i0# s  of { (# s0, a0 #) ->
+       case readByteOffMutableByteArray# mba# i1# s0 of { (# s1, a1 #) ->
+       case readByteOffMutableByteArray# mba# i2# s1 of { (# s2, a2 #) ->
+         (# s2, (a0, a1, a2) #)
+       }}}
+  {-# INLINE readByteOffMutableByteArray# #-}
+  readOffAddr# addr# i# s =
+    let addr0# = addr#  `plusAddr#` (i# *# sizeOf# (proxy# :: Proxy# (a, b, c)))
+        addr1# = addr0# `plusAddr#` sizeOf# (proxy# :: Proxy# a)
+        addr2# = addr0# `plusAddr#` sizeOf# (proxy# :: Proxy# b)
+    in case readOffAddr# addr0# 0# s  of { (# s0, a0 #) ->
+       case readOffAddr# addr1# 0# s0 of { (# s1, a1 #) ->
+       case readOffAddr# addr2# 0# s1 of { (# s2, a2 #) ->
+         (# s2, (a0, a1, a2) #)
+       }}}
+  {-# INLINE readOffAddr# #-}
+  writeByteOffMutableByteArray# mba# i0# (a0, a1, a2) s =
+    let i1# = i0# +# sizeOf# (proxy# :: Proxy# a)
+        i2# = i1# +# sizeOf# (proxy# :: Proxy# b)
+    in writeByteOffMutableByteArray# mba# i2# a2
+       (writeByteOffMutableByteArray# mba# i1# a1
+        (writeByteOffMutableByteArray# mba# i0# a0 s))
+  {-# INLINE writeByteOffMutableByteArray# #-}
+  writeMutableByteArray# mba# i# a s =
+    let i0# = i# *# sizeOf# (proxy# :: Proxy# (a, b, c))
+    in writeByteOffMutableByteArray# mba# i0# a s
+  {-# INLINE writeMutableByteArray# #-}
+  writeOffAddr# addr# i# (a0, a1, a2) s =
+    let addr0# = addr#  `plusAddr#` (i# *# sizeOf# (proxy# :: Proxy# (a, b, c)))
+        addr1# = addr0# `plusAddr#` sizeOf# (proxy# :: Proxy# a)
+        addr2# = addr0# `plusAddr#` sizeOf# (proxy# :: Proxy# b)
+    in writeOffAddr# addr0# 0# a2
+       (writeOffAddr# addr1# 0# a1
+        (writeOffAddr# addr2# 0# a0 s))
+  {-# INLINE writeOffAddr# #-}
+  setMutableByteArray# = setMutableByteArrayLoop#
+    --  | a0 == a1 && a1 == a2 = setMutableByteArray# mba# (o# *# 3#) (n# *# 3#) a0 s
+  {-# INLINE setMutableByteArray# #-}
+  setOffAddr# = setOffAddrLoop#
+    --  | a0 == a1 && a1 == a2 = setOffAddr# addr# (o# *# 3#) (n# *# 3#) a0 s
+  {-# INLINE setOffAddr# #-}
+
+-- TODO: Write optimized versions for higher tuples
+instance (Prim a, Prim b, Prim c, Prim d) => Prim (a, b, c, d) where
+  type PrimBase (a, b, c, d) = ((a, b), (c, d))
+  toPrimBase (a, b, c, d) = ((a, b), (c, d))
+  {-# INLINE toPrimBase #-}
+  fromPrimBase ((a, b), (c, d)) = (a, b, c, d)
+  {-# INLINE fromPrimBase #-}
+
+instance (Prim a, Prim b, Prim c, Prim d, Prim e) => Prim (a, b, c, d, e) where
+  type PrimBase (a, b, c, d, e) = ((a, b), (c, d), e)
+  toPrimBase (a, b, c, d, e) = ((a, b), (c, d), e)
+  {-# INLINE toPrimBase #-}
+  fromPrimBase ((a, b), (c, d), e) = (a, b, c, d, e)
+  {-# INLINE fromPrimBase #-}
+
+instance (Prim a, Prim b, Prim c, Prim d, Prim e, Prim f) => Prim (a, b, c, d, e, f) where
+  type PrimBase (a, b, c, d, e, f) = ((a, b), (c, d), (e, f))
+  toPrimBase (a, b, c, d, e, f) = ((a, b), (c, d), (e, f))
+  {-# INLINE toPrimBase #-}
+  fromPrimBase ((a, b), (c, d), (e, f)) = (a, b, c, d, e, f)
+  {-# INLINE fromPrimBase #-}
+
+instance (Prim a, Prim b, Prim c, Prim d, Prim e, Prim f, Prim g) => Prim (a, b, c, d, e, f, g) where
+  type PrimBase (a, b, c, d, e, f, g) = ((a, b, c), (d, e, f), g)
+  toPrimBase (a, b, c, d, e, f, g) = ((a, b, c), (d, e, f), g)
+  {-# INLINE toPrimBase #-}
+  fromPrimBase ((a, b, c), (d, e, f), g) = (a, b, c, d, e, f, g)
+  {-# INLINE fromPrimBase #-}
+
+instance (Prim a, Prim b, Prim c, Prim d, Prim e, Prim f, Prim g, Prim h) =>
+  Prim (a, b, c, d, e, f, g, h) where
+  type PrimBase (a, b, c, d, e, f, g, h) = ((a, b, c), (d, e, f), (g, h))
+  toPrimBase (a, b, c, d, e, f, g, h) = ((a, b, c), (d, e, f), (g, h))
+  {-# INLINE toPrimBase #-}
+  fromPrimBase ((a, b, c), (d, e, f), (g, h)) = (a, b, c, d, e, f, g, h)
+  {-# INLINE fromPrimBase #-}
+
+instance (Prim a, Prim b, Prim c, Prim d, Prim e, Prim f, Prim g, Prim h, Prim i) =>
+  Prim (a, b, c, d, e, f, g, h, i) where
+  type PrimBase (a, b, c, d, e, f, g, h, i) = ((a, b, c), (d, e, f), (g, h, i))
+  toPrimBase (a, b, c, d, e, f, g, h, i) = ((a, b, c), (d, e, f), (g, h, i))
+  {-# INLINE toPrimBase #-}
+  fromPrimBase ((a, b, c), (d, e, f), (g, h, i)) = (a, b, c, d, e, f, g, h, i)
+  {-# INLINE fromPrimBase #-}
+
+
+instance Prim a => Prim (Maybe a) where
+  type PrimBase (Maybe a) = Maybe a
+  type SizeOf (Maybe a) = 1 + SizeOf a
+  type Alignment (Maybe a) = 1 + Alignment a
+  sizeOf# _ = 1# +# sizeOf# (proxy# :: Proxy# a)
+  {-# INLINE sizeOf# #-}
+  alignment# _ = 1# +# alignment# (proxy# :: Proxy# a)
+  {-# INLINE alignment# #-}
+  indexByteOffByteArray# ba# i# =
+    case indexInt8Array# ba# i# of
+      0# -> Nothing
+      _  -> Just (indexByteOffByteArray# ba# (i# +# 1#))
+  {-# INLINE indexByteOffByteArray# #-}
+  indexByteArray# ba# i# =
+    indexByteOffByteArray# ba# (i# *# sizeOf# (proxy# :: Proxy# (Maybe a)))
+  {-# INLINE indexByteArray# #-}
+  indexOffAddr# addr# i# =
+    let addr0# = addr# `plusAddr#` (i# *# sizeOf# (proxy# :: Proxy# (Maybe a)))
+    in case indexInt8OffAddr# addr0# 0# of
+      0# -> Nothing
+      _  -> Just (indexOffAddr# (addr0# `plusAddr#` 1#) 0#)
+  {-# INLINE indexOffAddr# #-}
+  readByteOffMutableByteArray# mba# i# s =
+    case readInt8Array# mba# i# s of
+      (# s', 0# #) -> (# s', Nothing #)
+      (# s', _  #) -> case readByteOffMutableByteArray# mba# (i# +# 1#) s' of
+                        (# s'', a #) -> (# s'', Just a #)
+  {-# INLINE readByteOffMutableByteArray# #-}
+  readMutableByteArray# mba# i# =
+    let i0# = i# *# sizeOf# (proxy# :: Proxy# (Maybe a))
+     in readByteOffMutableByteArray# mba# i0#
+  {-# INLINE readMutableByteArray# #-}
+  readOffAddr# addr# i# s =
+    let addr0# = addr# `plusAddr#` (i# *# sizeOf# (proxy# :: Proxy# (Maybe a)))
+    in case readInt8OffAddr# addr0# 0# s of
+         (# s', 0# #) -> (# s', Nothing #)
+         (# s', _  #) -> case readOffAddr# (addr0# `plusAddr#` 1#) 0# s' of
+                           (# s'', a #) -> (# s'', Just a #)
+  {-# INLINE readOffAddr# #-}
+  writeByteOffMutableByteArray# mba# i# mVal s =
+    case mVal of
+      Nothing -> setByteArray# mba# i# (sizeOf# (proxy# :: Proxy# (Maybe a))) 0# s
+      Just a  -> writeByteOffMutableByteArray# mba# (i# +# 1#) a (writeInt8Array# mba# i# 1# s)
+  {-# INLINE writeByteOffMutableByteArray# #-}
+  writeMutableByteArray# mba# i# mVal s =
+    let k# = sizeOf# (proxy# :: Proxy# (Maybe a))
+        i0# = i# *# k# -- Not using writeByteOffMutableByteArray# to avoid k# recomputation
+    in case mVal of
+         Nothing -> setByteArray# mba# i0# k# 0# s
+         Just a  -> writeByteOffMutableByteArray# mba# (i0# +# 1#) a (writeInt8Array# mba# i0# 1# s)
+  {-# INLINE writeMutableByteArray# #-}
+  writeOffAddr# addr# i# mVal s =
+    let k# = sizeOf# (proxy# :: Proxy# (Maybe a))
+        i0# = i# *# k#
+    in case mVal of
+         Nothing -> setOffAddr# addr# i0# k# (I8# 0#) s
+         Just a  ->
+           writeOffAddr# (addr# `plusAddr#` (i0# +# 1#)) 0# a (writeInt8OffAddr# addr# i0# 1# s)
+  {-# INLINE writeOffAddr# #-}
+  setMutableByteArray# mba# o# n# mVal s =
+    case mVal of
+      Nothing ->
+        let k# = sizeOf# (proxy# :: Proxy# (Maybe a))
+        in setByteArray# mba# (o# *# k#) (n# *# k#) 0# s
+      _       -> setMutableByteArrayLoop# mba# o# n# mVal s
+  {-# INLINE setMutableByteArray# #-}
+  setOffAddr# addr# o# n# mVal s =
+    case mVal of
+      Nothing ->
+        let k# = sizeOf# (proxy# :: Proxy# (Maybe a))
+        in setOffAddr# addr# (o# *# k#) (n# *# k#) (I8# 0#) s
+      _       ->  setOffAddrLoop# addr# o# n# mVal s
+  {-# INLINE setOffAddr# #-}
+
+max# :: Int# -> Int# -> Int#
+max# x# y# =
+  case x# <# y# of
+    0# -> x#
+    _  -> y#
+{-# INLINE max# #-}
+
+type family MaxOrdering (o :: Ordering) (x :: Nat) (y :: Nat) where
+  MaxOrdering 'LT x y = y
+  MaxOrdering o  x y = x
+
+type MaxOf (x :: Nat) (y :: Nat) = MaxOrdering (CmpNat x y) x y
+
+instance (Prim a, Prim b) => Prim (Either a b) where
+  type PrimBase (Either a b) = Either a b
+  type SizeOf (Either a b) = 1 + MaxOf (SizeOf a) (SizeOf b)
+  type Alignment (Either a b) = 1 + MaxOf (Alignment a) (Alignment b)
+  sizeOf# _ = 1# +# max# (sizeOf# (proxy# :: Proxy# a)) (sizeOf# (proxy# :: Proxy# b))
+  {-# INLINE sizeOf# #-}
+  alignment# _ = 1# +# max# (alignment# (proxy# :: Proxy# a)) (alignment# (proxy# :: Proxy# b))
+  {-# INLINE alignment# #-}
+  indexByteOffByteArray# ba# i# =
+    case indexInt8Array# ba# i# of
+      0# -> Left (indexByteOffByteArray# ba# (i# +# 1#))
+      _  -> Right (indexByteOffByteArray# ba# (i# +# 1#))
+  {-# INLINE indexByteOffByteArray# #-}
+  indexByteArray# ba# i# =
+    indexByteOffByteArray# ba# (i# *# sizeOf# (proxy# :: Proxy# (Either a b)))
+  {-# INLINE indexByteArray# #-}
+  indexOffAddr# addr# i# =
+    let addr0# = addr# `plusAddr#` (i# *# sizeOf# (proxy# :: Proxy# (Either a b)))
+    in case indexInt8OffAddr# addr0# 0# of
+      0# -> Left (indexOffAddr# (addr0# `plusAddr#` 1#) 0#)
+      _  -> Right (indexOffAddr# (addr0# `plusAddr#` 1#) 0#)
+  {-# INLINE indexOffAddr# #-}
+  readByteOffMutableByteArray# mba# i# s =
+    case readInt8Array# mba# i# s of
+      (# s', 0# #) -> case readByteOffMutableByteArray# mba# (i# +# 1#) s' of
+                        (# s'', a #) -> (# s'', Left a #)
+      (# s', _  #) -> case readByteOffMutableByteArray# mba# (i# +# 1#) s' of
+                        (# s'', a #) -> (# s'', Right a #)
+  {-# INLINE readByteOffMutableByteArray# #-}
+  readMutableByteArray# mba# i# =
+    let i0# = i# *# sizeOf# (proxy# :: Proxy# (Either a b))
+     in readByteOffMutableByteArray# mba# i0#
+  {-# INLINE readMutableByteArray# #-}
+  readOffAddr# addr# i# s =
+    let addr0# = addr# `plusAddr#` (i# *# sizeOf# (proxy# :: Proxy# (Either a b)))
+    in case readInt8OffAddr# addr0# 0# s of
+         (# s', 0# #) -> case readOffAddr# (addr0# `plusAddr#` 1#) 0# s' of
+                           (# s'', a #) -> (# s'', Left a #)
+         (# s', _  #) -> case readOffAddr# (addr0# `plusAddr#` 1#) 0# s' of
+                           (# s'', a #) -> (# s'', Right a #)
+  {-# INLINE readOffAddr# #-}
+  writeByteOffMutableByteArray# mba# i# eVal s =
+    let a# = sizeOf# (proxy# :: Proxy# a)
+        b# = sizeOf# (proxy# :: Proxy# b)
+        i1# = i# +# 1#
+    in case eVal of
+         Left a -> -- TODO: Optimize duplication away
+           setByteArray# mba# (i1# +# a#) (max# 0# (b# -# a#)) 0#
+           (writeByteOffMutableByteArray# mba# i1# a (writeInt8Array# mba# i# 0# s))
+         Right b ->
+           setByteArray# mba# (i1# +# b#) (max# 0# (a# -# b#)) 0#
+           (writeByteOffMutableByteArray# mba# i1# b (writeInt8Array# mba# i# 1# s))
+  {-# INLINE writeByteOffMutableByteArray# #-}
+  writeMutableByteArray# mba# i# eVal s =
+    let k# = sizeOf# (proxy# :: Proxy# (Either a b))
+        i0# = i# *# k#
+    in writeByteOffMutableByteArray# mba# i0# eVal s
+  {-# INLINE writeMutableByteArray# #-}
+  writeOffAddr# addr# i# eVal s =
+    let a# = sizeOf# (proxy# :: Proxy# a)
+        b# = sizeOf# (proxy# :: Proxy# b)
+        addr0# = addr# `plusAddr#` (i# *# (1# +# a# +# b#))
+        addr1# = addr0# `plusAddr#` 1#
+    in case eVal of
+         Left a  ->
+           setOffAddr# addr1# a# (max# 0# (b# -# a#)) (I8# 0#)
+           (writeOffAddr# addr1# 0# a (writeInt8OffAddr# addr0# 0# 0# s))
+         Right b ->
+           setOffAddr# addr1# b# (max# 0# (a# -# b#)) (I8# 0#)
+           (writeOffAddr# addr1# 0# b (writeInt8OffAddr# addr0# 0# 1# s))
+  {-# INLINE writeOffAddr# #-}
+  setMutableByteArray# = setMutableByteArrayLoop#
+  {-# INLINE setMutableByteArray# #-}
+  setOffAddr# = setOffAddrLoop#
+  {-# INLINE setOffAddr# #-}
+
+
+-- | A loop that uses `writeMutableByteArray#` to set the values in the region. It is a
+-- suboptimal way to fill the memory with a single value that is why it is only provided
+-- here for convenience
+setMutableByteArrayLoop# ::
+     Prim a => MutableByteArray# s -> Int# -> Int# -> a -> State# s -> State# s
+setMutableByteArrayLoop# mba# o# n# a = go o#
+  where
+    k# = o# +# n#
+    go i# s
+      | isTrue# (i# <# k#) = go (i# +# 1#) (writeMutableByteArray# mba# i# a s)
+      | otherwise = s
+{-# INLINE setMutableByteArrayLoop# #-}
+
+setOffAddrLoop# :: Prim a => Addr# -> Int# -> Int# -> a -> State# s -> State# s
+setOffAddrLoop# addr# o# n# a = go o#
+  where
+    k# = o# +# n#
+    go i# s
+      | isTrue# (i# <# k#) = go (i# +# 1#) (writeOffAddr# addr# i# a s)
+      | otherwise = s
+{-# INLINE setOffAddrLoop# #-}
+
+
+errorImpossible :: String -> String -> a
+errorImpossible fname msg =
+#if __GLASGOW_HASKELL__ < 800
+  error
+#else
+  errorWithoutStackTrace
+#endif
+  $ "Impossible <" ++ fname ++ ">:" ++ msg
+{-# NOINLINE errorImpossible #-}
diff --git a/src/Data/Prim/StableName.hs b/src/Data/Prim/StableName.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Prim/StableName.hs
@@ -0,0 +1,88 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE UnboxedTuples #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+-- |
+-- Module      : Data.Prim.StableName
+-- Copyright   : (c) Alexey Kuleshevich 2020
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Data.Prim.StableName
+  ( StableName(..)
+  , makeStableName
+  , makeAnyStableName
+  , hashStableName
+  , eqStableName
+  ) where
+
+import Control.Prim.Monad
+import GHC.Exts
+#if MIN_VERSION_base(4,12,0)
+import GHC.StableName (StableName(..), eqStableName, hashStableName)
+
+-- | Orphan instance defined in "Data.Prim.StableName"
+instance Show (StableName a) where
+  showsPrec = showPrecStableName
+
+#else
+
+-- | For compatibility with newer ghc versions this is a redifined version of
+-- `System.Mem.StableName.StableName`. Prior to @base-4.12.0.0@ constructor was not
+-- exported, hence this definition, starting with GHC-8.6 @StableName@ is re-exported from
+-- @GHC.StableName@
+data StableName a = StableName (StableName# a)
+
+instance Eq (StableName a) where
+  (==) = eqStableName
+
+instance Show (StableName a) where
+  showsPrec = showPrecStableName
+
+-- | Convert a 'StableName' to an 'Int'.  The 'Int' returned is not
+-- necessarily unique; several 'StableName's may map to the same 'Int'
+-- (in practice however, the chances of this are small, so the result
+-- of 'hashStableName' makes a good hash key).
+hashStableName :: StableName a -> Int
+hashStableName (StableName sn) = I# (stableNameToInt# sn)
+
+-- | Equality on 'StableName' that does not require that the types of
+-- the arguments match.
+--
+-- @since 0.1.0
+eqStableName :: StableName a -> StableName b -> Bool
+eqStableName (StableName sn1) (StableName sn2) =
+  case eqStableName# sn1 sn2 of
+    0# -> False
+    _  -> True
+#endif
+
+showPrecStableName :: Int -> StableName a -> ShowS
+showPrecStableName n sname =
+  case n of
+    0 -> inner
+    _ -> ('(' :) . inner . (')' :)
+  where
+    inner = ("StableName " ++) . shows (hashStableName sname)
+
+-- | Makes a 'StableName' for an arbitrary object.  The object passed as
+-- the first argument is not evaluated by 'makeStableName'.
+makeStableName :: MonadPrim RW m => a -> m (StableName a)
+makeStableName a =
+  prim $ \s ->
+    case makeStableName# a s of
+      (# s', sn #) -> (# s', StableName sn #)
+
+-- | Similar to
+-- [`makeDynamicStableName`](http://hackage.haskell.org/package/stable-maps/docs/System-Mem-StableName-Dynamic.html),
+-- but returns `StableName` `Any` and is generalized to `MonadPrim`
+makeAnyStableName :: MonadPrim RW m => a -> m (StableName Any)
+makeAnyStableName a =
+  prim $ \s ->
+    case makeStableName# a s of
+      (# s', sn# #) -> (# s', StableName (unsafeCoerce# sn#) #)
+
+
diff --git a/src/Foreign/Prim.hs b/src/Foreign/Prim.hs
new file mode 100644
--- /dev/null
+++ b/src/Foreign/Prim.hs
@@ -0,0 +1,71 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE UnboxedTuples #-}
+-- |
+-- Module      : Foreign.Prim
+-- Copyright   : (c) Alexey Kuleshevich 2020
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Foreign.Prim
+  ( -- * Missing primitives
+    unsafeThawByteArray#
+  , mutableByteArrayContents#
+  , unsafeThawArrayArray#
+  , unInt#
+  , unWord#
+    -- * Primitive
+  , module Foreign.Prim.C
+  , module Foreign.Prim.Cmm
+    -- * Re-exports
+  , module Foreign.C.Types
+  , module System.Posix.Types
+  , module GHC.Exts
+#if __GLASGOW_HASKELL__ < 804
+  , module GHC.Prim
+#endif
+  , module GHC.Int
+  , module GHC.Word
+  ) where
+
+import Foreign.Prim.C
+import Foreign.Prim.Cmm
+import Foreign.C.Types
+import System.Posix.Types
+import GHC.Exts
+import GHC.Int
+import GHC.Word
+#if __GLASGOW_HASKELL__ < 804
+import GHC.Prim
+  ( addCFinalizerToWeak#
+  , deRefWeak#
+  , finalizeWeak#
+  , mkWeak#
+  , mkWeakNoFinalizer#
+  )
+#endif
+
+unsafeThawByteArray# :: ByteArray# -> State# s -> (# State# s, MutableByteArray# s #)
+unsafeThawByteArray# ba# s = (# s, unsafeCoerce# ba# #)
+{-# INLINE unsafeThawByteArray# #-}
+
+mutableByteArrayContents# :: MutableByteArray# s -> Addr#
+mutableByteArrayContents# mba# = byteArrayContents# (unsafeCoerce# mba#)
+{-# INLINE mutableByteArrayContents# #-}
+
+
+unsafeThawArrayArray# :: ArrayArray# -> State# s -> (# State# s, MutableArrayArray# s #)
+unsafeThawArrayArray# ba# s = (# s, unsafeCoerce# ba# #)
+{-# INLINE unsafeThawArrayArray# #-}
+
+
+
+unInt# :: Int -> Int#
+unInt# (I# i#) = i#
+{-# INLINE unInt# #-}
+
+unWord# :: Word -> Word#
+unWord# (W# w#) = w#
+{-# INLINE unWord# #-}
diff --git a/src/Foreign/Prim/C.hs b/src/Foreign/Prim/C.hs
new file mode 100644
--- /dev/null
+++ b/src/Foreign/Prim/C.hs
@@ -0,0 +1,179 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE UnliftedFFITypes #-}
+-- |
+-- Module      : Foreign.Prim.C
+-- Copyright   : (c) Alexey Kuleshevich 2020
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Foreign.Prim.C
+  ( -- * Backwards compatibility
+    --
+    -- Functions introduced in older versions that have backwards compatible
+    -- implementations here. Section names are ghc versions in which exported
+    -- functions and types were introduced.
+    module Foreign.Prim.C.LtGHC806
+  -- * Forward compatibility
+  -- * Extra functionality
+  -- ** Atomic
+  , module Foreign.Prim.C.Atomic
+  -- ** Comparison
+  , isSameByteArray#
+  , isSameMutableByteArray#
+  , toOrdering#
+  , fromOrdering#
+  , memcmpAddr#
+  , memcmpAddrByteArray#
+  , memcmpByteArray#
+  , memcmpByteArrayAddr#
+  -- ** Setting memory
+  , memsetWord8MutableByteArray#
+  , memsetWord8Addr#
+  , memsetInt8MutableByteArray#
+  , memsetInt8Addr#
+  , memsetWord16MutableByteArray#
+  , memsetWord16Addr#
+  , memsetInt16MutableByteArray#
+  , memsetInt16Addr#
+  , memsetWord32MutableByteArray#
+  , memsetWord32Addr#
+  , memsetInt32MutableByteArray#
+  , memsetInt32Addr#
+  , memsetWord64MutableByteArray#
+  , memsetWord64Addr#
+  , memsetInt64MutableByteArray#
+  , memsetInt64Addr#
+
+  -- ** Moving memory
+  , memmoveAddr#
+  , memmoveMutableByteArray#
+  , memmoveMutableByteArrayToAddr#
+  , memmoveMutableByteArrayFromAddr#
+  ) where
+
+import GHC.Exts
+import GHC.Int
+import GHC.Word
+import Foreign.Prim.C.Atomic
+import Foreign.Prim.C.LtGHC806
+
+-- | Because GC is guaranteed not to move unpinned memory during the unsafe FFI call we
+-- can compare memory pointers on the C side. Because the addresses cannot change
+-- underneath us we can safely guarantee pointer equality for the same pinned or unpinned
+-- arrays
+
+foreign import ccall unsafe "primal.c primal_ptreq"
+  isSameByteArray# :: ByteArray# -> ByteArray# -> Int#
+
+foreign import ccall unsafe "primal.c primal_ptreq"
+  isSameMutableByteArray# :: MutableByteArray# s -> MutableByteArray# s -> Int#
+
+-- | Convert memcmp result into an ordering
+toOrdering# :: Int# -> Ordering
+toOrdering# =
+  \case
+    0# -> EQ
+    n# ->
+      if isTrue# (n# <# 0#)
+        then LT
+        else GT
+
+fromOrdering# :: Ordering -> Int#
+fromOrdering# =
+  \case
+    EQ -> 0#
+    LT -> -1#
+    GT -> 1#
+
+foreign import ccall unsafe "primal.c primal_memcmp"
+  memcmpAddr# :: Addr# -> Int# -> Addr# -> Int# -> Int# -> Int#
+foreign import ccall unsafe "primal.c primal_memcmp"
+  memcmpAddrByteArray# :: Addr# -> Int# -> ByteArray# -> Int# -> Int# -> Int#
+foreign import ccall unsafe "primal.c primal_memcmp"
+  memcmpByteArray# :: ByteArray# -> Int# -> ByteArray# -> Int# -> Int# -> Int#
+foreign import ccall unsafe "primal.c primal_memcmp"
+  memcmpByteArrayAddr# :: ByteArray# -> Int# -> Addr# -> Int# -> Int# -> Int#
+
+foreign import ccall unsafe "primal.c primal_memset8"
+  memsetInt8MutableByteArray# :: MutableByteArray# s -> Int# -> Int# -> Int8 -> IO ()
+
+foreign import ccall unsafe "primal.c primal_memset8"
+  memsetInt8Addr# :: Addr# -> Int# -> Int# -> Int8 -> IO ()
+
+foreign import ccall unsafe "primal.c primal_memset8"
+  memsetWord8MutableByteArray# :: MutableByteArray# s -> Int# -> Int# -> Word8 -> IO ()
+
+foreign import ccall unsafe "primal.c primal_memset8"
+  memsetWord8Addr# :: Addr# -> Int# -> Int# -> Word8 -> IO ()
+
+foreign import ccall unsafe "primal.c primal_memset16"
+  memsetInt16MutableByteArray# :: MutableByteArray# s -> Int# -> Int# -> Int16 -> IO ()
+
+foreign import ccall unsafe "primal.c primal_memset16"
+  memsetInt16Addr# :: Addr# -> Int# -> Int# -> Int16 -> IO ()
+
+foreign import ccall unsafe "primal.c primal_memset16"
+  memsetWord16MutableByteArray# :: MutableByteArray# s -> Int# -> Int# -> Word16 -> IO ()
+
+foreign import ccall unsafe "primal.c primal_memset16"
+  memsetWord16Addr# :: Addr# -> Int# -> Int# -> Word16 -> IO ()
+
+
+foreign import ccall unsafe "primal.c primal_memset32"
+  memsetInt32MutableByteArray# :: MutableByteArray# s -> Int# -> Int# -> Int32 -> IO ()
+
+foreign import ccall unsafe "primal.c primal_memset32"
+  memsetInt32Addr# :: Addr# -> Int# -> Int# -> Int32 -> IO ()
+
+foreign import ccall unsafe "primal.c primal_memset32"
+  memsetWord32MutableByteArray# :: MutableByteArray# s -> Int# -> Int# -> Word32 -> IO ()
+
+foreign import ccall unsafe "primal.c primal_memset32"
+  memsetWord32Addr# :: Addr# -> Int# -> Int# -> Word32 -> IO ()
+
+
+foreign import ccall unsafe "primal.c primal_memset64"
+  memsetInt64MutableByteArray# :: MutableByteArray# s -> Int# -> Int# -> Int64 -> IO ()
+
+foreign import ccall unsafe "primal.c primal_memset64"
+  memsetInt64Addr# :: Addr# -> Int# -> Int# -> Int64 -> IO ()
+
+foreign import ccall unsafe "primal.c primal_memset64"
+  memsetWord64MutableByteArray# :: MutableByteArray# s -> Int# -> Int# -> Word64 -> IO ()
+
+foreign import ccall unsafe "primal.c primal_memset64"
+  memsetWord64Addr# :: Addr# -> Int# -> Int# -> Word64 -> IO ()
+
+foreign import ccall unsafe "primal.c primal_memmove"
+  memmoveAddr# :: Addr# -- ^ Source ptr
+               -> Int# -- ^ Offset in bytes into source array
+               -> Addr# -- ^ Destination ptr
+               -> Int# -- ^ Offset in bytes into destination
+               -> Int# -- ^ Number of bytes to copy
+               -> IO ()
+foreign import ccall unsafe "primal.c primal_memmove"
+  memmoveMutableByteArray# :: MutableByteArray# s -- ^ Source array
+                           -> Int# -- ^ Offset in bytes into source array
+                           -> MutableByteArray# s -- ^ Destination
+                           -> Int# -- ^ Offset in bytes into destination
+                           -> Int# -- ^ Number of bytes to copy
+                           -> IO ()
+foreign import ccall unsafe "primal.c primal_memmove"
+  memmoveMutableByteArrayToAddr# :: MutableByteArray# s -- ^ Source array
+                                 -> Int# -- ^ Offset in bytes into source array
+                                 -> Addr# -- ^ Destination ptr
+                                 -> Int# -- ^ Offset in bytes into destination
+                                 -> Int# -- ^ Number of bytes to copy
+                                 -> IO ()
+foreign import ccall unsafe "primal.c primal_memmove"
+  memmoveMutableByteArrayFromAddr# :: Addr# -- ^ Source Ptr
+                                   -> Int# -- ^ Offset in bytes into source array
+                                   -> MutableByteArray# s -- ^ Destination
+                                   -> Int# -- ^ Offset in bytes into destination
+                                   -> Int# -- ^ Number of bytes to copy
+                                   -> IO ()
+
diff --git a/src/Foreign/Prim/C/Atomic.hs b/src/Foreign/Prim/C/Atomic.hs
new file mode 100644
--- /dev/null
+++ b/src/Foreign/Prim/C/Atomic.hs
@@ -0,0 +1,739 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE ForeignFunctionInterface #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE UnliftedFFITypes #-}
+-- |
+-- Module      : Foreign.Prim.C.Atomic
+-- Copyright   : (c) Alexey Kuleshevich 2020
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Foreign.Prim.C.Atomic
+  ( module Foreign.Prim.C.Atomic
+  ) where
+
+import Control.Prim.Monad.Unsafe
+import GHC.Exts
+import GHC.Int
+import GHC.Word
+import Foreign.Prim.C.LtGHC802
+
+#include "MachDeps.h"
+
+-- | Helper function for converting casBool IO actions
+ioCBoolToBoolBase :: IO CBool -> State# s -> (# State# s, Bool #)
+ioCBoolToBoolBase m s =
+  case unsafePrimBase m s of
+    (# s', CBool (W8# w#) #) -> (# s', isTrue# (word2Int# w#) #)
+{-# INLINE ioCBoolToBoolBase #-}
+
+
+-- | [Memory barrier](https://en.wikipedia.org/wiki/Memory_barrier). This will
+-- ensure that the cache is fully updated before continuing.
+syncSynchronize# :: State# s -> State# s
+syncSynchronize# = unsafePrimBase_ syncSynchronize
+{-# INLINE syncSynchronize# #-}
+
+withMemBarrier# :: (State# s -> (# State# s, a #)) -> State# s -> (# State# s, a #)
+withMemBarrier# f s = f (syncSynchronize# s)
+{-# INLINE withMemBarrier# #-}
+
+withMemBarrier_# :: (State# s -> State# s) -> State# s -> State# s
+withMemBarrier_# f s = f (syncSynchronize# s)
+{-# INLINE withMemBarrier_# #-}
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_synchronize"
+  syncSynchronize :: IO ()
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync8_lock_test_set"
+  syncLockTestSetInt8ArrayIO :: MutableByteArray# s -> Int# -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_lock_test_set"
+  syncLockTestSetInt8AddrIO :: Addr# -> Int# -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_lock_release"
+  syncLockReleaseInt8ArrayIO :: MutableByteArray# s -> Int# -> IO ()
+foreign import ccall unsafe "primal_atomic.c primal_sync8_lock_release"
+  syncLockReleaseInt8AddrIO :: Addr# -> Int# -> IO ()
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync8_cas_bool"
+  syncCasInt8BoolAddrIO :: Addr# -> Int# -> Int8 -> Int8 -> IO CBool
+foreign import ccall unsafe "primal_atomic.c primal_sync8_cas_bool"
+  syncCasInt8BoolArrayIO :: MutableByteArray# s -> Int# -> Int8 -> Int8 -> IO CBool
+foreign import ccall unsafe "primal_atomic.c primal_sync8_cas_bool"
+  syncCasWord8BoolAddrIO :: Addr# -> Int# -> Word8 -> Word8 -> IO CBool
+foreign import ccall unsafe "primal_atomic.c primal_sync8_cas_bool"
+  syncCasWord8BoolArrayIO :: MutableByteArray# s -> Int# -> Word8 -> Word8 -> IO CBool
+
+foreign import ccall unsafe "primal_atomic.c primal_sync8_cas"
+  syncCasInt8AddrIO :: Addr# -> Int# -> Int8 -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_cas"
+  syncCasInt8ArrayIO :: MutableByteArray# s -> Int# -> Int8 -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_cas"
+  syncCasWord8AddrIO :: Addr# -> Int# -> Word8 -> Word8 -> IO Word8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_cas"
+  syncCasWord8ArrayIO :: MutableByteArray# s -> Int# -> Word8 -> Word8 -> IO Word8
+
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_add"
+  syncAddFetchOldInt8AddrIO :: Addr# -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_add"
+  syncAddFetchOldInt8ArrayIO :: MutableByteArray# s -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_add"
+  syncAddFetchOldWord8AddrIO :: Addr# -> Int# -> Word8 -> IO Word8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_add"
+  syncAddFetchOldWord8ArrayIO :: MutableByteArray# s -> Int# -> Word8 -> IO Word8
+
+foreign import ccall unsafe "primal_atomic.c primal_sync8_add_fetch"
+  syncAddFetchNewInt8AddrIO :: Addr# -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_add_fetch"
+  syncAddFetchNewInt8ArrayIO :: MutableByteArray# s -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_add_fetch"
+  syncAddFetchNewWord8AddrIO :: Addr# -> Int# -> Word8 -> IO Word8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_add_fetch"
+  syncAddFetchNewWord8ArrayIO :: MutableByteArray# s -> Int# -> Word8 -> IO Word8
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_sub"
+  syncSubFetchOldInt8AddrIO :: Addr# -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_sub"
+  syncSubFetchOldInt8ArrayIO :: MutableByteArray# s -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_sub"
+  syncSubFetchOldWord8AddrIO :: Addr# -> Int# -> Word8 -> IO Word8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_sub"
+  syncSubFetchOldWord8ArrayIO :: MutableByteArray# s -> Int# -> Word8 -> IO Word8
+
+foreign import ccall unsafe "primal_atomic.c primal_sync8_sub_fetch"
+  syncSubFetchNewInt8AddrIO :: Addr# -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_sub_fetch"
+  syncSubFetchNewInt8ArrayIO :: MutableByteArray# s -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_sub_fetch"
+  syncSubFetchNewWord8AddrIO :: Addr# -> Int# -> Word8 -> IO Word8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_sub_fetch"
+  syncSubFetchNewWord8ArrayIO :: MutableByteArray# s -> Int# -> Word8 -> IO Word8
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_and"
+  syncAndFetchOldInt8AddrIO :: Addr# -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_and"
+  syncAndFetchOldInt8ArrayIO :: MutableByteArray# s -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_and"
+  syncAndFetchOldWord8AddrIO :: Addr# -> Int# -> Word8 -> IO Word8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_and"
+  syncAndFetchOldWord8ArrayIO :: MutableByteArray# s -> Int# -> Word8 -> IO Word8
+
+foreign import ccall unsafe "primal_atomic.c primal_sync8_and_fetch"
+  syncAndFetchNewInt8AddrIO :: Addr# -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_and_fetch"
+  syncAndFetchNewInt8ArrayIO :: MutableByteArray# s -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_and_fetch"
+  syncAndFetchNewWord8AddrIO :: Addr# -> Int# -> Word8 -> IO Word8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_and_fetch"
+  syncAndFetchNewWord8ArrayIO :: MutableByteArray# s -> Int# -> Word8 -> IO Word8
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_nand"
+  syncNandFetchOldInt8AddrIO :: Addr# -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_nand"
+  syncNandFetchOldInt8ArrayIO :: MutableByteArray# s -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_nand"
+  syncNandFetchOldWord8AddrIO :: Addr# -> Int# -> Word8 -> IO Word8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_nand"
+  syncNandFetchOldWord8ArrayIO :: MutableByteArray# s -> Int# -> Word8 -> IO Word8
+
+foreign import ccall unsafe "primal_atomic.c primal_sync8_nand_fetch"
+  syncNandFetchNewInt8AddrIO :: Addr# -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_nand_fetch"
+  syncNandFetchNewInt8ArrayIO :: MutableByteArray# s -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_nand_fetch"
+  syncNandFetchNewWord8AddrIO :: Addr# -> Int# -> Word8 -> IO Word8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_nand_fetch"
+  syncNandFetchNewWord8ArrayIO :: MutableByteArray# s -> Int# -> Word8 -> IO Word8
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_or"
+  syncOrFetchOldInt8AddrIO :: Addr# -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_or"
+  syncOrFetchOldInt8ArrayIO :: MutableByteArray# s -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_or"
+  syncOrFetchOldWord8AddrIO :: Addr# -> Int# -> Word8 -> IO Word8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_or"
+  syncOrFetchOldWord8ArrayIO :: MutableByteArray# s -> Int# -> Word8 -> IO Word8
+
+foreign import ccall unsafe "primal_atomic.c primal_sync8_or_fetch"
+  syncOrFetchNewInt8AddrIO :: Addr# -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_or_fetch"
+  syncOrFetchNewInt8ArrayIO :: MutableByteArray# s -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_or_fetch"
+  syncOrFetchNewWord8AddrIO :: Addr# -> Int# -> Word8 -> IO Word8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_or_fetch"
+  syncOrFetchNewWord8ArrayIO :: MutableByteArray# s -> Int# -> Word8 -> IO Word8
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_xor"
+  syncXorFetchOldInt8AddrIO :: Addr# -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_xor"
+  syncXorFetchOldInt8ArrayIO :: MutableByteArray# s -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_xor"
+  syncXorFetchOldWord8AddrIO :: Addr# -> Int# -> Word8 -> IO Word8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_fetch_xor"
+  syncXorFetchOldWord8ArrayIO :: MutableByteArray# s -> Int# -> Word8 -> IO Word8
+
+foreign import ccall unsafe "primal_atomic.c primal_sync8_xor_fetch"
+  syncXorFetchNewInt8AddrIO :: Addr# -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_xor_fetch"
+  syncXorFetchNewInt8ArrayIO :: MutableByteArray# s -> Int# -> Int8 -> IO Int8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_xor_fetch"
+  syncXorFetchNewWord8AddrIO :: Addr# -> Int# -> Word8 -> IO Word8
+foreign import ccall unsafe "primal_atomic.c primal_sync8_xor_fetch"
+  syncXorFetchNewWord8ArrayIO :: MutableByteArray# s -> Int# -> Word8 -> IO Word8
+
+
+
+
+
+
+
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync16_cas_bool"
+  syncCasInt16BoolAddrIO :: Addr# -> Int# -> Int16 -> Int16 -> IO CBool
+foreign import ccall unsafe "primal_atomic.c primal_sync16_cas_bool"
+  syncCasInt16BoolArrayIO :: MutableByteArray# s -> Int# -> Int16 -> Int16 -> IO CBool
+foreign import ccall unsafe "primal_atomic.c primal_sync16_cas_bool"
+  syncCasWord16BoolAddrIO :: Addr# -> Int# -> Word16 -> Word16 -> IO CBool
+foreign import ccall unsafe "primal_atomic.c primal_sync16_cas_bool"
+  syncCasWord16BoolArrayIO :: MutableByteArray# s -> Int# -> Word16 -> Word16 -> IO CBool
+
+foreign import ccall unsafe "primal_atomic.c primal_sync16_cas"
+  syncCasInt16AddrIO :: Addr# -> Int# -> Int16 -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_cas"
+  syncCasInt16ArrayIO :: MutableByteArray# s -> Int# -> Int16 -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_cas"
+  syncCasWord16AddrIO :: Addr# -> Int# -> Word16 -> Word16 -> IO Word16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_cas"
+  syncCasWord16ArrayIO :: MutableByteArray# s -> Int# -> Word16 -> Word16 -> IO Word16
+
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_add"
+  syncAddFetchOldInt16AddrIO :: Addr# -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_add"
+  syncAddFetchOldInt16ArrayIO :: MutableByteArray# s -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_add"
+  syncAddFetchOldWord16AddrIO :: Addr# -> Int# -> Word16 -> IO Word16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_add"
+  syncAddFetchOldWord16ArrayIO :: MutableByteArray# s -> Int# -> Word16 -> IO Word16
+
+foreign import ccall unsafe "primal_atomic.c primal_sync16_add_fetch"
+  syncAddFetchNewInt16AddrIO :: Addr# -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_add_fetch"
+  syncAddFetchNewInt16ArrayIO :: MutableByteArray# s -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_add_fetch"
+  syncAddFetchNewWord16AddrIO :: Addr# -> Int# -> Word16 -> IO Word16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_add_fetch"
+  syncAddFetchNewWord16ArrayIO :: MutableByteArray# s -> Int# -> Word16 -> IO Word16
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_sub"
+  syncSubFetchOldInt16AddrIO :: Addr# -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_sub"
+  syncSubFetchOldInt16ArrayIO :: MutableByteArray# s -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_sub"
+  syncSubFetchOldWord16AddrIO :: Addr# -> Int# -> Word16 -> IO Word16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_sub"
+  syncSubFetchOldWord16ArrayIO :: MutableByteArray# s -> Int# -> Word16 -> IO Word16
+
+foreign import ccall unsafe "primal_atomic.c primal_sync16_sub_fetch"
+  syncSubFetchNewInt16AddrIO :: Addr# -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_sub_fetch"
+  syncSubFetchNewInt16ArrayIO :: MutableByteArray# s -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_sub_fetch"
+  syncSubFetchNewWord16AddrIO :: Addr# -> Int# -> Word16 -> IO Word16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_sub_fetch"
+  syncSubFetchNewWord16ArrayIO :: MutableByteArray# s -> Int# -> Word16 -> IO Word16
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_and"
+  syncAndFetchOldInt16AddrIO :: Addr# -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_and"
+  syncAndFetchOldInt16ArrayIO :: MutableByteArray# s -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_and"
+  syncAndFetchOldWord16AddrIO :: Addr# -> Int# -> Word16 -> IO Word16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_and"
+  syncAndFetchOldWord16ArrayIO :: MutableByteArray# s -> Int# -> Word16 -> IO Word16
+
+foreign import ccall unsafe "primal_atomic.c primal_sync16_and_fetch"
+  syncAndFetchNewInt16AddrIO :: Addr# -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_and_fetch"
+  syncAndFetchNewInt16ArrayIO :: MutableByteArray# s -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_and_fetch"
+  syncAndFetchNewWord16AddrIO :: Addr# -> Int# -> Word16 -> IO Word16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_and_fetch"
+  syncAndFetchNewWord16ArrayIO :: MutableByteArray# s -> Int# -> Word16 -> IO Word16
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_nand"
+  syncNandFetchOldInt16AddrIO :: Addr# -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_nand"
+  syncNandFetchOldInt16ArrayIO :: MutableByteArray# s -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_nand"
+  syncNandFetchOldWord16AddrIO :: Addr# -> Int# -> Word16 -> IO Word16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_nand"
+  syncNandFetchOldWord16ArrayIO :: MutableByteArray# s -> Int# -> Word16 -> IO Word16
+
+foreign import ccall unsafe "primal_atomic.c primal_sync16_nand_fetch"
+  syncNandFetchNewInt16AddrIO :: Addr# -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_nand_fetch"
+  syncNandFetchNewInt16ArrayIO :: MutableByteArray# s -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_nand_fetch"
+  syncNandFetchNewWord16AddrIO :: Addr# -> Int# -> Word16 -> IO Word16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_nand_fetch"
+  syncNandFetchNewWord16ArrayIO :: MutableByteArray# s -> Int# -> Word16 -> IO Word16
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_or"
+  syncOrFetchOldInt16AddrIO :: Addr# -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_or"
+  syncOrFetchOldInt16ArrayIO :: MutableByteArray# s -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_or"
+  syncOrFetchOldWord16AddrIO :: Addr# -> Int# -> Word16 -> IO Word16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_or"
+  syncOrFetchOldWord16ArrayIO :: MutableByteArray# s -> Int# -> Word16 -> IO Word16
+
+foreign import ccall unsafe "primal_atomic.c primal_sync16_or_fetch"
+  syncOrFetchNewInt16AddrIO :: Addr# -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_or_fetch"
+  syncOrFetchNewInt16ArrayIO :: MutableByteArray# s -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_or_fetch"
+  syncOrFetchNewWord16AddrIO :: Addr# -> Int# -> Word16 -> IO Word16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_or_fetch"
+  syncOrFetchNewWord16ArrayIO :: MutableByteArray# s -> Int# -> Word16 -> IO Word16
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_xor"
+  syncXorFetchOldInt16AddrIO :: Addr# -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_xor"
+  syncXorFetchOldInt16ArrayIO :: MutableByteArray# s -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_xor"
+  syncXorFetchOldWord16AddrIO :: Addr# -> Int# -> Word16 -> IO Word16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_fetch_xor"
+  syncXorFetchOldWord16ArrayIO :: MutableByteArray# s -> Int# -> Word16 -> IO Word16
+
+foreign import ccall unsafe "primal_atomic.c primal_sync16_xor_fetch"
+  syncXorFetchNewInt16AddrIO :: Addr# -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_xor_fetch"
+  syncXorFetchNewInt16ArrayIO :: MutableByteArray# s -> Int# -> Int16 -> IO Int16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_xor_fetch"
+  syncXorFetchNewWord16AddrIO :: Addr# -> Int# -> Word16 -> IO Word16
+foreign import ccall unsafe "primal_atomic.c primal_sync16_xor_fetch"
+  syncXorFetchNewWord16ArrayIO :: MutableByteArray# s -> Int# -> Word16 -> IO Word16
+
+
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync32_cas_bool"
+  syncCasInt32BoolAddrIO :: Addr# -> Int# -> Int32 -> Int32 -> IO CBool
+foreign import ccall unsafe "primal_atomic.c primal_sync32_cas_bool"
+  syncCasInt32BoolArrayIO :: MutableByteArray# s -> Int# -> Int32 -> Int32 -> IO CBool
+foreign import ccall unsafe "primal_atomic.c primal_sync32_cas_bool"
+  syncCasWord32BoolAddrIO :: Addr# -> Int# -> Word32 -> Word32 -> IO CBool
+foreign import ccall unsafe "primal_atomic.c primal_sync32_cas_bool"
+  syncCasWord32BoolArrayIO :: MutableByteArray# s -> Int# -> Word32 -> Word32 -> IO CBool
+
+foreign import ccall unsafe "primal_atomic.c primal_sync32_cas"
+  syncCasInt32AddrIO :: Addr# -> Int# -> Int32 -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_cas"
+  syncCasInt32ArrayIO :: MutableByteArray# s -> Int# -> Int32 -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_cas"
+  syncCasWord32AddrIO :: Addr# -> Int# -> Word32 -> Word32 -> IO Word32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_cas"
+  syncCasWord32ArrayIO :: MutableByteArray# s -> Int# -> Word32 -> Word32 -> IO Word32
+
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_add"
+  syncAddFetchOldInt32AddrIO :: Addr# -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_add"
+  syncAddFetchOldInt32ArrayIO :: MutableByteArray# s -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_add"
+  syncAddFetchOldWord32AddrIO :: Addr# -> Int# -> Word32 -> IO Word32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_add"
+  syncAddFetchOldWord32ArrayIO :: MutableByteArray# s -> Int# -> Word32 -> IO Word32
+
+foreign import ccall unsafe "primal_atomic.c primal_sync32_add_fetch"
+  syncAddFetchNewInt32AddrIO :: Addr# -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_add_fetch"
+  syncAddFetchNewInt32ArrayIO :: MutableByteArray# s -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_add_fetch"
+  syncAddFetchNewWord32AddrIO :: Addr# -> Int# -> Word32 -> IO Word32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_add_fetch"
+  syncAddFetchNewWord32ArrayIO :: MutableByteArray# s -> Int# -> Word32 -> IO Word32
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_sub"
+  syncSubFetchOldInt32AddrIO :: Addr# -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_sub"
+  syncSubFetchOldInt32ArrayIO :: MutableByteArray# s -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_sub"
+  syncSubFetchOldWord32AddrIO :: Addr# -> Int# -> Word32 -> IO Word32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_sub"
+  syncSubFetchOldWord32ArrayIO :: MutableByteArray# s -> Int# -> Word32 -> IO Word32
+
+foreign import ccall unsafe "primal_atomic.c primal_sync32_sub_fetch"
+  syncSubFetchNewInt32AddrIO :: Addr# -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_sub_fetch"
+  syncSubFetchNewInt32ArrayIO :: MutableByteArray# s -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_sub_fetch"
+  syncSubFetchNewWord32AddrIO :: Addr# -> Int# -> Word32 -> IO Word32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_sub_fetch"
+  syncSubFetchNewWord32ArrayIO :: MutableByteArray# s -> Int# -> Word32 -> IO Word32
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_and"
+  syncAndFetchOldInt32AddrIO :: Addr# -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_and"
+  syncAndFetchOldInt32ArrayIO :: MutableByteArray# s -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_and"
+  syncAndFetchOldWord32AddrIO :: Addr# -> Int# -> Word32 -> IO Word32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_and"
+  syncAndFetchOldWord32ArrayIO :: MutableByteArray# s -> Int# -> Word32 -> IO Word32
+
+foreign import ccall unsafe "primal_atomic.c primal_sync32_and_fetch"
+  syncAndFetchNewInt32AddrIO :: Addr# -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_and_fetch"
+  syncAndFetchNewInt32ArrayIO :: MutableByteArray# s -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_and_fetch"
+  syncAndFetchNewWord32AddrIO :: Addr# -> Int# -> Word32 -> IO Word32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_and_fetch"
+  syncAndFetchNewWord32ArrayIO :: MutableByteArray# s -> Int# -> Word32 -> IO Word32
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_nand"
+  syncNandFetchOldInt32AddrIO :: Addr# -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_nand"
+  syncNandFetchOldInt32ArrayIO :: MutableByteArray# s -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_nand"
+  syncNandFetchOldWord32AddrIO :: Addr# -> Int# -> Word32 -> IO Word32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_nand"
+  syncNandFetchOldWord32ArrayIO :: MutableByteArray# s -> Int# -> Word32 -> IO Word32
+
+foreign import ccall unsafe "primal_atomic.c primal_sync32_nand_fetch"
+  syncNandFetchNewInt32AddrIO :: Addr# -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_nand_fetch"
+  syncNandFetchNewInt32ArrayIO :: MutableByteArray# s -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_nand_fetch"
+  syncNandFetchNewWord32AddrIO :: Addr# -> Int# -> Word32 -> IO Word32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_nand_fetch"
+  syncNandFetchNewWord32ArrayIO :: MutableByteArray# s -> Int# -> Word32 -> IO Word32
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_or"
+  syncOrFetchOldInt32AddrIO :: Addr# -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_or"
+  syncOrFetchOldInt32ArrayIO :: MutableByteArray# s -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_or"
+  syncOrFetchOldWord32AddrIO :: Addr# -> Int# -> Word32 -> IO Word32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_or"
+  syncOrFetchOldWord32ArrayIO :: MutableByteArray# s -> Int# -> Word32 -> IO Word32
+
+foreign import ccall unsafe "primal_atomic.c primal_sync32_or_fetch"
+  syncOrFetchNewInt32AddrIO :: Addr# -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_or_fetch"
+  syncOrFetchNewInt32ArrayIO :: MutableByteArray# s -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_or_fetch"
+  syncOrFetchNewWord32AddrIO :: Addr# -> Int# -> Word32 -> IO Word32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_or_fetch"
+  syncOrFetchNewWord32ArrayIO :: MutableByteArray# s -> Int# -> Word32 -> IO Word32
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_xor"
+  syncXorFetchOldInt32AddrIO :: Addr# -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_xor"
+  syncXorFetchOldInt32ArrayIO :: MutableByteArray# s -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_xor"
+  syncXorFetchOldWord32AddrIO :: Addr# -> Int# -> Word32 -> IO Word32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_fetch_xor"
+  syncXorFetchOldWord32ArrayIO :: MutableByteArray# s -> Int# -> Word32 -> IO Word32
+
+foreign import ccall unsafe "primal_atomic.c primal_sync32_xor_fetch"
+  syncXorFetchNewInt32AddrIO :: Addr# -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_xor_fetch"
+  syncXorFetchNewInt32ArrayIO :: MutableByteArray# s -> Int# -> Int32 -> IO Int32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_xor_fetch"
+  syncXorFetchNewWord32AddrIO :: Addr# -> Int# -> Word32 -> IO Word32
+foreign import ccall unsafe "primal_atomic.c primal_sync32_xor_fetch"
+  syncXorFetchNewWord32ArrayIO :: MutableByteArray# s -> Int# -> Word32 -> IO Word32
+
+
+
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_cas_bool"
+  syncCasIntBoolAddrIO :: Addr# -> Int# -> Int -> Int -> IO CBool
+foreign import ccall unsafe "primal_atomic.c primal_sync_cas_bool"
+  syncCasIntBoolArrayIO :: MutableByteArray# s -> Int# -> Int -> Int -> IO CBool
+foreign import ccall unsafe "primal_atomic.c primal_sync_cas_bool"
+  syncCasWordBoolAddrIO :: Addr# -> Int# -> Word -> Word -> IO CBool
+foreign import ccall unsafe "primal_atomic.c primal_sync_cas_bool"
+  syncCasWordBoolArrayIO :: MutableByteArray# s -> Int# -> Word -> Word -> IO CBool
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_cas"
+  syncCasIntAddrIO :: Addr# -> Int# -> Int -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_cas"
+  syncCasIntArrayIO :: MutableByteArray# s -> Int# -> Int -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_cas"
+  syncCasWordAddrIO :: Addr# -> Int# -> Word -> Word -> IO Word
+foreign import ccall unsafe "primal_atomic.c primal_sync_cas"
+  syncCasWordArrayIO :: MutableByteArray# s -> Int# -> Word -> Word -> IO Word
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_add"
+  syncAddFetchOldIntAddrIO :: Addr# -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_add"
+  syncAddFetchOldIntArrayIO :: MutableByteArray# s -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_add"
+  syncAddFetchOldWordAddrIO :: Addr# -> Int# -> Word -> IO Word
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_add"
+  syncAddFetchOldWordArrayIO :: MutableByteArray# s -> Int# -> Word -> IO Word
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_add_fetch"
+  syncAddFetchNewIntAddrIO :: Addr# -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_add_fetch"
+  syncAddFetchNewIntArrayIO :: MutableByteArray# s -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_add_fetch"
+  syncAddFetchNewWordAddrIO :: Addr# -> Int# -> Word -> IO Word
+foreign import ccall unsafe "primal_atomic.c primal_sync_add_fetch"
+  syncAddFetchNewWordArrayIO :: MutableByteArray# s -> Int# -> Word -> IO Word
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_sub"
+  syncSubFetchOldIntAddrIO :: Addr# -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_sub"
+  syncSubFetchOldIntArrayIO :: MutableByteArray# s -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_sub"
+  syncSubFetchOldWordAddrIO :: Addr# -> Int# -> Word -> IO Word
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_sub"
+  syncSubFetchOldWordArrayIO :: MutableByteArray# s -> Int# -> Word -> IO Word
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_sub_fetch"
+  syncSubFetchNewIntAddrIO :: Addr# -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_sub_fetch"
+  syncSubFetchNewIntArrayIO :: MutableByteArray# s -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_sub_fetch"
+  syncSubFetchNewWordAddrIO :: Addr# -> Int# -> Word -> IO Word
+foreign import ccall unsafe "primal_atomic.c primal_sync_sub_fetch"
+  syncSubFetchNewWordArrayIO :: MutableByteArray# s -> Int# -> Word -> IO Word
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_and"
+  syncAndFetchOldIntAddrIO :: Addr# -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_and"
+  syncAndFetchOldIntArrayIO :: MutableByteArray# s -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_and"
+  syncAndFetchOldWordAddrIO :: Addr# -> Int# -> Word -> IO Word
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_and"
+  syncAndFetchOldWordArrayIO :: MutableByteArray# s -> Int# -> Word -> IO Word
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_and_fetch"
+  syncAndFetchNewIntAddrIO :: Addr# -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_and_fetch"
+  syncAndFetchNewIntArrayIO :: MutableByteArray# s -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_and_fetch"
+  syncAndFetchNewWordAddrIO :: Addr# -> Int# -> Word -> IO Word
+foreign import ccall unsafe "primal_atomic.c primal_sync_and_fetch"
+  syncAndFetchNewWordArrayIO :: MutableByteArray# s -> Int# -> Word -> IO Word
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_nand"
+  syncNandFetchOldIntAddrIO :: Addr# -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_nand"
+  syncNandFetchOldIntArrayIO :: MutableByteArray# s -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_nand"
+  syncNandFetchOldWordAddrIO :: Addr# -> Int# -> Word -> IO Word
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_nand"
+  syncNandFetchOldWordArrayIO :: MutableByteArray# s -> Int# -> Word -> IO Word
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_nand_fetch"
+  syncNandFetchNewIntAddrIO :: Addr# -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_nand_fetch"
+  syncNandFetchNewIntArrayIO :: MutableByteArray# s -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_nand_fetch"
+  syncNandFetchNewWordAddrIO :: Addr# -> Int# -> Word -> IO Word
+foreign import ccall unsafe "primal_atomic.c primal_sync_nand_fetch"
+  syncNandFetchNewWordArrayIO :: MutableByteArray# s -> Int# -> Word -> IO Word
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_or"
+  syncOrFetchOldIntAddrIO :: Addr# -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_or"
+  syncOrFetchOldIntArrayIO :: MutableByteArray# s -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_or"
+  syncOrFetchOldWordAddrIO :: Addr# -> Int# -> Word -> IO Word
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_or"
+  syncOrFetchOldWordArrayIO :: MutableByteArray# s -> Int# -> Word -> IO Word
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_or_fetch"
+  syncOrFetchNewIntAddrIO :: Addr# -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_or_fetch"
+  syncOrFetchNewIntArrayIO :: MutableByteArray# s -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_or_fetch"
+  syncOrFetchNewWordAddrIO :: Addr# -> Int# -> Word -> IO Word
+foreign import ccall unsafe "primal_atomic.c primal_sync_or_fetch"
+  syncOrFetchNewWordArrayIO :: MutableByteArray# s -> Int# -> Word -> IO Word
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_xor"
+  syncXorFetchOldIntAddrIO :: Addr# -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_xor"
+  syncXorFetchOldIntArrayIO :: MutableByteArray# s -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_xor"
+  syncXorFetchOldWordAddrIO :: Addr# -> Int# -> Word -> IO Word
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_xor"
+  syncXorFetchOldWordArrayIO :: MutableByteArray# s -> Int# -> Word -> IO Word
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_xor_fetch"
+  syncXorFetchNewIntAddrIO :: Addr# -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_xor_fetch"
+  syncXorFetchNewIntArrayIO :: MutableByteArray# s -> Int# -> Int -> IO Int
+foreign import ccall unsafe "primal_atomic.c primal_sync_xor_fetch"
+  syncXorFetchNewWordAddrIO :: Addr# -> Int# -> Word -> IO Word
+foreign import ccall unsafe "primal_atomic.c primal_sync_xor_fetch"
+  syncXorFetchNewWordArrayIO :: MutableByteArray# s -> Int# -> Word -> IO Word
+
+
+
+
+#if WORD_SIZE_IN_BITS >= 64
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_cas_bool"
+  syncCasInt64BoolAddrIO :: Addr# -> Int# -> Int64 -> Int64 -> IO CBool
+foreign import ccall unsafe "primal_atomic.c primal_sync_cas_bool"
+  syncCasInt64BoolArrayIO :: MutableByteArray# s -> Int# -> Int64 -> Int64 -> IO CBool
+foreign import ccall unsafe "primal_atomic.c primal_sync_cas_bool"
+  syncCasWord64BoolAddrIO :: Addr# -> Int# -> Word64 -> Word64 -> IO CBool
+foreign import ccall unsafe "primal_atomic.c primal_sync_cas_bool"
+  syncCasWord64BoolArrayIO :: MutableByteArray# s -> Int# -> Word64 -> Word64 -> IO CBool
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_cas"
+  syncCasInt64AddrIO :: Addr# -> Int# -> Int64 -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_cas"
+  syncCasInt64ArrayIO :: MutableByteArray# s -> Int# -> Int64 -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_cas"
+  syncCasWord64AddrIO :: Addr# -> Int# -> Word64 -> Word64 -> IO Word64
+foreign import ccall unsafe "primal_atomic.c primal_sync_cas"
+  syncCasWord64ArrayIO :: MutableByteArray# s -> Int# -> Word64 -> Word64 -> IO Word64
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_add"
+  syncAddFetchOldInt64AddrIO :: Addr# -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_add"
+  syncAddFetchOldInt64ArrayIO :: MutableByteArray# s -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_add"
+  syncAddFetchOldWord64AddrIO :: Addr# -> Int# -> Word64 -> IO Word64
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_add"
+  syncAddFetchOldWord64ArrayIO :: MutableByteArray# s -> Int# -> Word64 -> IO Word64
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_add_fetch"
+  syncAddFetchNewInt64AddrIO :: Addr# -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_add_fetch"
+  syncAddFetchNewInt64ArrayIO :: MutableByteArray# s -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_add_fetch"
+  syncAddFetchNewWord64AddrIO :: Addr# -> Int# -> Word64 -> IO Word64
+foreign import ccall unsafe "primal_atomic.c primal_sync_add_fetch"
+  syncAddFetchNewWord64ArrayIO :: MutableByteArray# s -> Int# -> Word64 -> IO Word64
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_sub"
+  syncSubFetchOldInt64AddrIO :: Addr# -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_sub"
+  syncSubFetchOldInt64ArrayIO :: MutableByteArray# s -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_sub"
+  syncSubFetchOldWord64AddrIO :: Addr# -> Int# -> Word64 -> IO Word64
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_sub"
+  syncSubFetchOldWord64ArrayIO :: MutableByteArray# s -> Int# -> Word64 -> IO Word64
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_sub_fetch"
+  syncSubFetchNewInt64AddrIO :: Addr# -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_sub_fetch"
+  syncSubFetchNewInt64ArrayIO :: MutableByteArray# s -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_sub_fetch"
+  syncSubFetchNewWord64AddrIO :: Addr# -> Int# -> Word64 -> IO Word64
+foreign import ccall unsafe "primal_atomic.c primal_sync_sub_fetch"
+  syncSubFetchNewWord64ArrayIO :: MutableByteArray# s -> Int# -> Word64 -> IO Word64
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_and"
+  syncAndFetchOldInt64AddrIO :: Addr# -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_and"
+  syncAndFetchOldInt64ArrayIO :: MutableByteArray# s -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_and"
+  syncAndFetchOldWord64AddrIO :: Addr# -> Int# -> Word64 -> IO Word64
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_and"
+  syncAndFetchOldWord64ArrayIO :: MutableByteArray# s -> Int# -> Word64 -> IO Word64
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_and_fetch"
+  syncAndFetchNewInt64AddrIO :: Addr# -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_and_fetch"
+  syncAndFetchNewInt64ArrayIO :: MutableByteArray# s -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_and_fetch"
+  syncAndFetchNewWord64AddrIO :: Addr# -> Int# -> Word64 -> IO Word64
+foreign import ccall unsafe "primal_atomic.c primal_sync_and_fetch"
+  syncAndFetchNewWord64ArrayIO :: MutableByteArray# s -> Int# -> Word64 -> IO Word64
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_nand"
+  syncNandFetchOldInt64AddrIO :: Addr# -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_nand"
+  syncNandFetchOldInt64ArrayIO :: MutableByteArray# s -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_nand"
+  syncNandFetchOldWord64AddrIO :: Addr# -> Int# -> Word64 -> IO Word64
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_nand"
+  syncNandFetchOldWord64ArrayIO :: MutableByteArray# s -> Int# -> Word64 -> IO Word64
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_nand_fetch"
+  syncNandFetchNewInt64AddrIO :: Addr# -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_nand_fetch"
+  syncNandFetchNewInt64ArrayIO :: MutableByteArray# s -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_nand_fetch"
+  syncNandFetchNewWord64AddrIO :: Addr# -> Int# -> Word64 -> IO Word64
+foreign import ccall unsafe "primal_atomic.c primal_sync_nand_fetch"
+  syncNandFetchNewWord64ArrayIO :: MutableByteArray# s -> Int# -> Word64 -> IO Word64
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_or"
+  syncOrFetchOldInt64AddrIO :: Addr# -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_or"
+  syncOrFetchOldInt64ArrayIO :: MutableByteArray# s -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_or"
+  syncOrFetchOldWord64AddrIO :: Addr# -> Int# -> Word64 -> IO Word64
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_or"
+  syncOrFetchOldWord64ArrayIO :: MutableByteArray# s -> Int# -> Word64 -> IO Word64
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_or_fetch"
+  syncOrFetchNewInt64AddrIO :: Addr# -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_or_fetch"
+  syncOrFetchNewInt64ArrayIO :: MutableByteArray# s -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_or_fetch"
+  syncOrFetchNewWord64AddrIO :: Addr# -> Int# -> Word64 -> IO Word64
+foreign import ccall unsafe "primal_atomic.c primal_sync_or_fetch"
+  syncOrFetchNewWord64ArrayIO :: MutableByteArray# s -> Int# -> Word64 -> IO Word64
+
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_xor"
+  syncXorFetchOldInt64AddrIO :: Addr# -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_xor"
+  syncXorFetchOldInt64ArrayIO :: MutableByteArray# s -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_xor"
+  syncXorFetchOldWord64AddrIO :: Addr# -> Int# -> Word64 -> IO Word64
+foreign import ccall unsafe "primal_atomic.c primal_sync_fetch_xor"
+  syncXorFetchOldWord64ArrayIO :: MutableByteArray# s -> Int# -> Word64 -> IO Word64
+
+foreign import ccall unsafe "primal_atomic.c primal_sync_xor_fetch"
+  syncXorFetchNewInt64AddrIO :: Addr# -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_xor_fetch"
+  syncXorFetchNewInt64ArrayIO :: MutableByteArray# s -> Int# -> Int64 -> IO Int64
+foreign import ccall unsafe "primal_atomic.c primal_sync_xor_fetch"
+  syncXorFetchNewWord64AddrIO :: Addr# -> Int# -> Word64 -> IO Word64
+foreign import ccall unsafe "primal_atomic.c primal_sync_xor_fetch"
+  syncXorFetchNewWord64ArrayIO :: MutableByteArray# s -> Int# -> Word64 -> IO Word64
+
+#endif
diff --git a/src/Foreign/Prim/C/LtGHC802.hs b/src/Foreign/Prim/C/LtGHC802.hs
new file mode 100644
--- /dev/null
+++ b/src/Foreign/Prim/C/LtGHC802.hs
@@ -0,0 +1,68 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE ForeignFunctionInterface #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE UnliftedFFITypes #-}
+-- |
+-- Module      : Foreign.Prim.C.LtGHC802
+-- Copyright   : (c) Alexey Kuleshevich 2020
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Foreign.Prim.C.LtGHC802
+  (
+  -- ** GHC-8.2
+    CBool(..)
+  , isByteArrayPinned#
+  , isMutableByteArrayPinned#
+  -- ** GHC-8.0
+  , compareByteArrays#
+  , getSizeofMutableByteArray#
+  ) where
+
+import GHC.Exts
+
+#if __GLASGOW_HASKELL__ < 802
+
+import Data.Bits (Bits, FiniteBits)
+import Data.Word
+import Foreign.Storable (Storable)
+import Control.DeepSeq
+
+#include "MachDeps.h"
+#include "HsBaseConfig.h"
+#include "primal_compat.h"
+
+
+-- | This type was added in base-4.10 and is provided from here for backwards compatibility
+newtype {-# CTYPE "bool" #-} CBool = CBool HTYPE_BOOL
+  deriving (Eq, Ord, Num, Enum, Storable, Real, Bounded, Integral, Bits, FiniteBits, NFData, Read, Show)
+
+-- | Determine whether a `ByteArray#` is guaranteed not to move during GC.
+foreign import ccall unsafe "primal_compat.c primal_is_byte_array_pinned"
+  isByteArrayPinned# :: ByteArray# -> Int#
+
+-- | Determine whether a `MutableByteArray#` is guaranteed not to move during GC.
+foreign import ccall unsafe "primal_compat.c primal_is_byte_array_pinned"
+  isMutableByteArrayPinned# :: MutableByteArray# s -> Int#
+
+-- | This is equivalent to @memcmp@ in C
+foreign import ccall unsafe "primal.c primal_memcmp"
+  compareByteArrays# :: ByteArray# -> Int# -> ByteArray# -> Int# -> Int# -> Int#
+
+#if __GLASGOW_HASKELL__ < 800
+-- | Compatibility function for ghc-7.10 version
+getSizeofMutableByteArray# :: MutableByteArray# s -> State# s -> (# State# s, Int# #)
+getSizeofMutableByteArray# mba# s = (# s, sizeofMutableByteArray# mba# #)
+{-# INLINE getSizeofMutableByteArray# #-}
+
+#endif /* __GLASGOW_HASKELL__ < 800 */
+
+#else
+
+import Foreign.C.Types (CBool(..))
+
+#endif /* __GLASGOW_HASKELL__ < 802 */
diff --git a/src/Foreign/Prim/C/LtGHC806.hs b/src/Foreign/Prim/C/LtGHC806.hs
new file mode 100644
--- /dev/null
+++ b/src/Foreign/Prim/C/LtGHC806.hs
@@ -0,0 +1,439 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE ForeignFunctionInterface #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE UnboxedTuples #-}
+{-# LANGUAGE UnliftedFFITypes #-}
+-- |
+-- Module      : Foreign.Prim.C.LtGHC806
+-- Copyright   : (c) Alexey Kuleshevich 2020
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Foreign.Prim.C.LtGHC806
+  (
+  -- ** GHC 8.6
+    indexWord8ArrayAsChar#
+  , readWord8ArrayAsChar#
+  , writeWord8ArrayAsChar#
+  , indexWord8ArrayAsWideChar#
+  , readWord8ArrayAsWideChar#
+  , writeWord8ArrayAsWideChar#
+  , indexWord8ArrayAsAddr#
+  , readWord8ArrayAsAddr#
+  , writeWord8ArrayAsAddr#
+  , indexWord8ArrayAsStablePtr#
+  , readWord8ArrayAsStablePtr#
+  , writeWord8ArrayAsStablePtr#
+  , indexWord8ArrayAsFloat#
+  , readWord8ArrayAsFloat#
+  , writeWord8ArrayAsFloat#
+  , indexWord8ArrayAsDouble#
+  , readWord8ArrayAsDouble#
+  , writeWord8ArrayAsDouble#
+  , indexWord8ArrayAsInt16#
+  , readWord8ArrayAsInt16#
+  , writeWord8ArrayAsInt16#
+  , indexWord8ArrayAsInt32#
+  , readWord8ArrayAsInt32#
+  , writeWord8ArrayAsInt32#
+  , indexWord8ArrayAsInt64#
+  , readWord8ArrayAsInt64#
+  , writeWord8ArrayAsInt64#
+  , indexWord8ArrayAsInt#
+  , readWord8ArrayAsInt#
+  , writeWord8ArrayAsInt#
+  , indexWord8ArrayAsWord16#
+  , readWord8ArrayAsWord16#
+  , writeWord8ArrayAsWord16#
+  , indexWord8ArrayAsWord32#
+  , readWord8ArrayAsWord32#
+  , writeWord8ArrayAsWord32#
+  , indexWord8ArrayAsWord64#
+  , readWord8ArrayAsWord64#
+  , writeWord8ArrayAsWord64#
+  , indexWord8ArrayAsWord#
+  , readWord8ArrayAsWord#
+  , writeWord8ArrayAsWord#
+
+  , atomicModifyMutVar_#
+  , atomicModifyMutVar2#
+  , module Foreign.Prim.C.LtGHC802
+  ) where
+
+import GHC.Exts
+import Foreign.Prim.C.LtGHC802
+#if __GLASGOW_HASKELL__ < 806
+
+import GHC.Int
+import GHC.Word
+import Foreign.Prim.StablePtr
+import Control.Prim.Monad.Unsafe
+
+#include "MachDeps.h"
+#endif
+
+
+#if __GLASGOW_HASKELL__ <= 806
+
+-- | Slightly slower reimplementation of newer primops using the old `atomicModifyMutVar#`
+--
+-- Modify the contents of a `MutVar#`, returning the previous contents and the result of
+-- applying the given function to the previous contents.
+--
+-- /__Warning:__/ this can fail with an unchecked exception.
+atomicModifyMutVar_# :: MutVar# s a -> (a -> a) -> State# s -> (# State# s, a, a #)
+atomicModifyMutVar_# ref# f s =
+  case atomicModifyMutVar# ref# (\a -> let a' = f a in (a', (a', a))) s of
+    (# s', (prev, cur) #) -> (# s', prev, cur #)
+{-# INLINE atomicModifyMutVar_# #-}
+
+-- | Slightly slower reimplementation of newer primops using the old `atomicModifyMutVar#`
+--
+-- Modify the contents of a `MutVar#`, returning the previous contents and the result of
+-- applying the given function to the previous contents.
+--
+-- /__Warning:__/ this can fail with an unchecked exception.
+atomicModifyMutVar2# :: MutVar# s a -> (a -> (a, b)) -> State# s -> (# State# s, a, (a, b) #)
+atomicModifyMutVar2# ref# f s =
+  case atomicModifyMutVar# ref# (\a -> let (a', b) = f a in (a', (a', a, b))) s of
+    (# s', (prev, cur, artifact) #) -> (# s', prev, (cur, artifact) #)
+{-# INLINE atomicModifyMutVar2# #-}
+
+#endif
+
+-- ghc-8.6 (i.e. 806 version) introduced these new functions, for versions before we
+-- use their re-implementations in C:
+#if __GLASGOW_HASKELL__ < 806
+
+indexWord8ArrayAsChar# :: ByteArray# -> Int# -> Char#
+indexWord8ArrayAsChar# = indexCharArray#
+
+readWord8ArrayAsChar# :: MutableByteArray# d -> Int# -> State# d -> (# State# d, Char# #)
+readWord8ArrayAsChar# = readCharArray#
+
+writeWord8ArrayAsChar# :: MutableByteArray# d -> Int# -> Char# -> State# d -> State# d
+writeWord8ArrayAsChar# = writeCharArray#
+
+foreign import ccall unsafe "primal_compat.c primal_memread32"
+  indexWord8ArrayAsWideChar# :: ByteArray# -> Int# -> Char#
+
+foreign import ccall unsafe "primal_compat.c primal_memread32"
+  readWord8ArrayAsWideCharIO# :: MutableByteArray# d -> Int# -> IO Char
+
+readWord8ArrayAsWideChar# :: MutableByteArray# d -> Int# -> State# d -> (# State# d, Char# #)
+readWord8ArrayAsWideChar# mb# i# s =
+  case unsafePrimBase (readWord8ArrayAsWideCharIO# mb# i#) s of
+    (# s', C# c# #) -> (# s', c# #)
+
+foreign import ccall unsafe "primal_compat.c primal_memwrite32"
+  writeWord8ArrayAsWideCharIO# :: MutableByteArray# d -> Int# -> Char# -> IO ()
+
+writeWord8ArrayAsWideChar# :: MutableByteArray# d -> Int# -> Char# -> State# d -> State# d
+writeWord8ArrayAsWideChar# mb# i# c# = unsafePrimBase_ (writeWord8ArrayAsWideCharIO# mb# i# c#)
+
+-- Addr#
+
+#if SIZEOF_HSPTR == SIZEOF_INT64
+foreign import ccall unsafe "primal_compat.c primal_memread64"
+  indexWord8ArrayAsAddr# :: ByteArray# -> Int# -> Addr#
+
+foreign import ccall unsafe "primal_compat.c primal_memread64"
+  readWord8ArrayAsPtrIO# :: MutableByteArray# d -> Int# -> IO (Ptr a)
+
+foreign import ccall unsafe "primal_compat.c primal_memwrite64"
+  writeWord8ArrayAsAddrIO# :: MutableByteArray# d -> Int# -> Addr# -> IO ()
+
+
+#elif SIZEOF_HSPTR == SIZEOF_INT32
+foreign import ccall unsafe "primal_compat.c primal_memread32"
+  indexWord8ArrayAsAddr# :: ByteArray# -> Int# -> Addr#
+
+foreign import ccall unsafe "primal_compat.c primal_memread32"
+  readWord8ArrayAsPtrIO# :: MutableByteArray# d -> Int# -> IO (Ptr a)
+
+foreign import ccall unsafe "primal_compat.c primal_memwrite32
+  writeWord8ArrayAsAddrIO# :: MutableByteArray# d -> Int# -> Addr# -> IO ()
+#else
+#error Ptr is of unsupported size SIZEOF_HSPTR
+#endif
+
+readWord8ArrayAsAddr# :: MutableByteArray# d -> Int# -> State# d -> (# State# d, Addr# #)
+readWord8ArrayAsAddr# mb# i# s =
+  case unsafePrimBase (readWord8ArrayAsPtrIO# mb# i#) s of
+    (# s', Ptr addr# #) -> (# s', addr# #)
+
+writeWord8ArrayAsAddr# :: MutableByteArray# d -> Int# -> Addr# -> State# d -> State# d
+writeWord8ArrayAsAddr# mb# i# addr# = unsafePrimBase_ (writeWord8ArrayAsAddrIO# mb# i# addr#)
+
+-- StablePtr#
+
+#if SIZEOF_HSSTABLEPTR == SIZEOF_INT64
+foreign import ccall unsafe "primal_compat.c primal_memread64"
+  indexWord8ArrayAsStablePtr# :: ByteArray# -> Int# -> StablePtr# a
+
+foreign import ccall unsafe "primal_compat.c primal_memread64"
+  readWord8ArrayAsStablePtrIO# :: MutableByteArray# d -> Int# -> IO (StablePtr a)
+
+foreign import ccall unsafe "primal_compat.c primal_memwrite64"
+  writeWord8ArrayAsStablePtrIO# :: MutableByteArray# d -> Int# -> StablePtr# a -> IO ()
+#elif SIZEOF_HSSTABLEPTR == SIZEOF_INT32
+foreign import ccall unsafe "primal_compat.c primal_memread32"
+  indexWord8ArrayAsStablePtr# :: ByteArray# -> Int# -> StablePtr# a
+
+foreign import ccall unsafe "primal_compat.c primal_memread32"
+  readWord8ArrayAsStablePtrIO# :: MutableByteArray# d -> Int# -> IO (StablePtr a)
+
+foreign import ccall unsafe "primal_compat.c primal_memwrite32
+  writeWord8ArrayAsStablePtrIO# :: MutableByteArray# d -> Int# -> StablePtr# a -> IO ()
+#else
+#error StablePtr is of unsupported size SIZEOF_HSPTR
+#endif
+
+readWord8ArrayAsStablePtr# :: MutableByteArray# d -> Int# -> State# d -> (# State# d, StablePtr# a #)
+readWord8ArrayAsStablePtr# mb# i# s =
+  case unsafePrimBase (readWord8ArrayAsStablePtrIO# mb# i#) s of
+    (# s', StablePtr addr# #) -> (# s', addr# #)
+
+writeWord8ArrayAsStablePtr# :: MutableByteArray# d -> Int# -> StablePtr# a -> State# d -> State# d
+writeWord8ArrayAsStablePtr# mb# i# addr# = unsafePrimBase_ (writeWord8ArrayAsStablePtrIO# mb# i# addr#)
+
+
+-- Float#
+
+foreign import ccall unsafe "primal_compat.c primal_memread32"
+  indexWord8ArrayAsFloat# :: ByteArray# -> Int# -> Float#
+
+foreign import ccall unsafe "primal_compat.c primal_memread32"
+  readWord8ArrayAsFloatIO# :: MutableByteArray# d -> Int# -> IO Float
+
+readWord8ArrayAsFloat# :: MutableByteArray# d -> Int# -> State# d -> (# State# d, Float# #)
+readWord8ArrayAsFloat# mb# i# s =
+  case unsafePrimBase (readWord8ArrayAsFloatIO# mb# i#) s of
+    (# s', F# a# #) -> (# s', a# #)
+
+foreign import ccall unsafe "primal_compat.c primal_memwrite32"
+  writeWord8ArrayAsFloatIO# :: MutableByteArray# d -> Int# -> Float# -> IO ()
+
+writeWord8ArrayAsFloat# :: MutableByteArray# d -> Int# -> Float# -> State# d -> State# d
+writeWord8ArrayAsFloat# mb# i# a# = unsafePrimBase_ (writeWord8ArrayAsFloatIO# mb# i# a#)
+
+-- Double#
+
+foreign import ccall unsafe "primal_compat.c primal_memread64"
+  indexWord8ArrayAsDouble# :: ByteArray# -> Int# -> Double#
+
+foreign import ccall unsafe "primal_compat.c primal_memread64"
+  readWord8ArrayAsDoubleIO# :: MutableByteArray# d -> Int# -> IO Double
+
+readWord8ArrayAsDouble# :: MutableByteArray# d -> Int# -> State# d -> (# State# d, Double# #)
+readWord8ArrayAsDouble# mb# i# s =
+  case unsafePrimBase (readWord8ArrayAsDoubleIO# mb# i#) s of
+    (# s', D# a# #) -> (# s', a# #)
+
+foreign import ccall unsafe "primal_compat.c primal_memwrite64"
+  writeWord8ArrayAsDoubleIO# :: MutableByteArray# d -> Int# -> Double# -> IO ()
+
+writeWord8ArrayAsDouble# :: MutableByteArray# d -> Int# -> Double# -> State# d -> State# d
+writeWord8ArrayAsDouble# mb# i# a# = unsafePrimBase_ (writeWord8ArrayAsDoubleIO# mb# i# a#)
+
+-- Int16#
+
+foreign import ccall unsafe "primal_compat.c primal_memread16"
+  indexWord8ArrayAsInt16# :: ByteArray# -> Int# -> Int#
+
+foreign import ccall unsafe "primal_compat.c primal_memread16"
+  readWord8ArrayAsInt16IO# :: MutableByteArray# d -> Int# -> IO Int16
+
+readWord8ArrayAsInt16# :: MutableByteArray# d -> Int# -> State# d -> (# State# d, Int# #)
+readWord8ArrayAsInt16# mb# i# s =
+  case unsafePrimBase (readWord8ArrayAsInt16IO# mb# i#) s of
+    (# s', I16# a# #) -> (# s', a# #)
+
+foreign import ccall unsafe "primal_compat.c primal_memwrite16"
+  writeWord8ArrayAsInt16IO# :: MutableByteArray# d -> Int# -> Int# -> IO ()
+
+writeWord8ArrayAsInt16# :: MutableByteArray# d -> Int# -> Int# -> State# d -> State# d
+writeWord8ArrayAsInt16# mb# i# a# = unsafePrimBase_ (writeWord8ArrayAsInt16IO# mb# i# a#)
+
+
+-- Int32#
+
+foreign import ccall unsafe "primal_compat.c primal_memread32"
+  indexWord8ArrayAsInt32# :: ByteArray# -> Int# -> Int#
+
+foreign import ccall unsafe "primal_compat.c primal_memread32"
+  readWord8ArrayAsInt32IO# :: MutableByteArray# d -> Int# -> IO Int32
+
+readWord8ArrayAsInt32# :: MutableByteArray# d -> Int# -> State# d -> (# State# d, Int# #)
+readWord8ArrayAsInt32# mb# i# s =
+  case unsafePrimBase (readWord8ArrayAsInt32IO# mb# i#) s of
+    (# s', I32# a# #) -> (# s', a# #)
+
+foreign import ccall unsafe "primal_compat.c primal_memwrite32"
+  writeWord8ArrayAsInt32IO# :: MutableByteArray# d -> Int# -> Int# -> IO ()
+
+writeWord8ArrayAsInt32# :: MutableByteArray# d -> Int# -> Int# -> State# d -> State# d
+writeWord8ArrayAsInt32# mb# i# a# = unsafePrimBase_ (writeWord8ArrayAsInt32IO# mb# i# a#)
+
+
+-- Int64#
+
+foreign import ccall unsafe "primal_compat.c primal_memread64"
+  readWord8ArrayAsInt64IO# :: MutableByteArray# d -> Int# -> IO Int64
+
+#if WORD_SIZE_IN_BITS >= 64
+foreign import ccall unsafe "primal_compat.c primal_memread64"
+  indexWord8ArrayAsInt64# :: ByteArray# -> Int# -> Int#
+foreign import ccall unsafe "primal_compat.c primal_memwrite64"
+  writeWord8ArrayAsInt64IO# :: MutableByteArray# d -> Int# -> Int# -> IO ()
+
+readWord8ArrayAsInt64# :: MutableByteArray# d -> Int# -> State# d -> (# State# d, Int# #)
+writeWord8ArrayAsInt64# :: MutableByteArray# d -> Int# -> Int# -> State# d -> State# d
+
+#else
+foreign import ccall unsafe "primal_compat.c primal_memread64"
+  indexWord8ArrayAsInt64# :: ByteArray# -> Int# -> Int64#
+foreign import ccall unsafe "primal_compat.c primal_memwrite64"
+  writeWord8ArrayAsInt64IO# :: MutableByteArray# d -> Int# -> Int64# -> IO ()
+
+readWord8ArrayAsInt64# :: MutableByteArray# d -> Int# -> State# d -> (# State# d, Int64# #)
+writeWord8ArrayAsInt64# :: MutableByteArray# d -> Int# -> Int64# -> State# d -> State# d
+#endif
+
+readWord8ArrayAsInt64# mb# i# s =
+  case unsafePrimBase (readWord8ArrayAsInt64IO# mb# i#) s of
+    (# s', I64# a# #) -> (# s', a# #)
+writeWord8ArrayAsInt64# mb# i# a# = unsafePrimBase_ (writeWord8ArrayAsInt64IO# mb# i# a#)
+
+-- Int#
+
+#if WORD_SIZE_IN_BITS >= 64
+foreign import ccall unsafe "primal_compat.c primal_memread64"
+  indexWord8ArrayAsInt# :: ByteArray# -> Int# -> Int#
+
+foreign import ccall unsafe "primal_compat.c primal_memread64"
+  readWord8ArrayAsIntIO# :: MutableByteArray# d -> Int# -> IO Int
+
+foreign import ccall unsafe "primal_compat.c primal_memwrite64"
+  writeWord8ArrayAsIntIO# :: MutableByteArray# d -> Int# -> Int# -> IO ()
+#else
+foreign import ccall unsafe "primal_compat.c primal_memread32"
+  indexWord8ArrayAsInt# :: ByteArray# -> Int# -> Int#
+
+foreign import ccall unsafe "primal_compat.c primal_memread32"
+  readWord8ArrayAsIntIO# :: MutableByteArray# d -> Int# -> IO Int64
+
+foreign import ccall unsafe "primal_compat.c primal_memwrite32"
+  writeWord8ArrayAsIntIO# :: MutableByteArray# d -> Int# -> Int# -> IO ()
+#endif
+
+readWord8ArrayAsInt# :: MutableByteArray# d -> Int# -> State# d -> (# State# d, Int# #)
+readWord8ArrayAsInt# mb# i# s =
+  case unsafePrimBase (readWord8ArrayAsIntIO# mb# i#) s of
+    (# s', I# a# #) -> (# s', a# #)
+
+writeWord8ArrayAsInt# :: MutableByteArray# d -> Int# -> Int# -> State# d -> State# d
+writeWord8ArrayAsInt# mb# i# a# = unsafePrimBase_ (writeWord8ArrayAsIntIO# mb# i# a#)
+
+-- Word16#
+
+foreign import ccall unsafe "primal_compat.c primal_memread16"
+  indexWord8ArrayAsWord16# :: ByteArray# -> Int# -> Word#
+
+foreign import ccall unsafe "primal_compat.c primal_memread16"
+  readWord8ArrayAsWord16IO# :: MutableByteArray# d -> Int# -> IO Word16
+
+readWord8ArrayAsWord16# :: MutableByteArray# d -> Int# -> State# d -> (# State# d, Word# #)
+readWord8ArrayAsWord16# mb# i# s =
+  case unsafePrimBase (readWord8ArrayAsWord16IO# mb# i#) s of
+    (# s', W16# a# #) -> (# s', a# #)
+
+foreign import ccall unsafe "primal_compat.c primal_memwrite16"
+  writeWord8ArrayAsWord16IO# :: MutableByteArray# d -> Int# -> Word# -> IO ()
+
+writeWord8ArrayAsWord16# :: MutableByteArray# d -> Int# -> Word# -> State# d -> State# d
+writeWord8ArrayAsWord16# mb# i# a# = unsafePrimBase_ (writeWord8ArrayAsWord16IO# mb# i# a#)
+
+
+-- Word32#
+
+foreign import ccall unsafe "primal_compat.c primal_memread32"
+  indexWord8ArrayAsWord32# :: ByteArray# -> Int# -> Word#
+
+foreign import ccall unsafe "primal_compat.c primal_memread32"
+  readWord8ArrayAsWord32IO# :: MutableByteArray# d -> Int# -> IO Word32
+
+readWord8ArrayAsWord32# :: MutableByteArray# d -> Int# -> State# d -> (# State# d, Word# #)
+readWord8ArrayAsWord32# mb# i# s =
+  case unsafePrimBase (readWord8ArrayAsWord32IO# mb# i#) s of
+    (# s', W32# a# #) -> (# s', a# #)
+
+foreign import ccall unsafe "primal_compat.c primal_memwrite32"
+  writeWord8ArrayAsWord32IO# :: MutableByteArray# d -> Int# -> Word# -> IO ()
+
+writeWord8ArrayAsWord32# :: MutableByteArray# d -> Int# -> Word# -> State# d -> State# d
+writeWord8ArrayAsWord32# mb# i# a# = unsafePrimBase_ (writeWord8ArrayAsWord32IO# mb# i# a#)
+
+
+-- Word64#
+
+foreign import ccall unsafe "primal_compat.c primal_memread64"
+  readWord8ArrayAsWord64IO# :: MutableByteArray# d -> Int# -> IO Word64
+
+#if WORD_SIZE_IN_BITS >= 64
+foreign import ccall unsafe "primal_compat.c primal_memread64"
+  indexWord8ArrayAsWord64# :: ByteArray# -> Int# -> Word#
+foreign import ccall unsafe "primal_compat.c primal_memwrite64"
+  writeWord8ArrayAsWord64IO# :: MutableByteArray# d -> Int# -> Word# -> IO ()
+
+readWord8ArrayAsWord64# :: MutableByteArray# d -> Int# -> State# d -> (# State# d, Word# #)
+writeWord8ArrayAsWord64# :: MutableByteArray# d -> Int# -> Word# -> State# d -> State# d
+
+#else
+foreign import ccall unsafe "primal_compat.c primal_memread64"
+  indexWord8ArrayAsWord64# :: ByteArray# -> Int# -> Word64#
+foreign import ccall unsafe "primal_compat.c primal_memwrite64"
+  writeWord8ArrayAsWord64IO# :: MutableByteArray# d -> Int# -> Word64# -> IO ()
+
+readWord8ArrayAsWord64# :: MutableByteArray# d -> Int# -> State# d -> (# State# d, Word64# #)
+writeWord8ArrayAsWord64# :: MutableByteArray# d -> Int# -> Word64# -> State# d -> State# d
+#endif
+
+readWord8ArrayAsWord64# mb# i# s =
+  case unsafePrimBase (readWord8ArrayAsWord64IO# mb# i#) s of
+    (# s', W64# a# #) -> (# s', a# #)
+writeWord8ArrayAsWord64# mb# i# a# = unsafePrimBase_ (writeWord8ArrayAsWord64IO# mb# i# a#)
+
+-- Word#
+
+#if WORD_SIZE_IN_BITS >= 64
+foreign import ccall unsafe "primal_compat.c primal_memread64"
+  indexWord8ArrayAsWord# :: ByteArray# -> Int# -> Word#
+
+foreign import ccall unsafe "primal_compat.c primal_memread64"
+  readWord8ArrayAsWordIO# :: MutableByteArray# d -> Int# -> IO Word
+
+foreign import ccall unsafe "primal_compat.c primal_memwrite64"
+  writeWord8ArrayAsWordIO# :: MutableByteArray# d -> Int# -> Word# -> IO ()
+#else
+foreign import ccall unsafe "primal_compat.c primal_memread32"
+  indexWord8ArrayAsWord# :: ByteArray# -> Int# -> Word#
+
+foreign import ccall unsafe "primal_compat.c primal_memread32"
+  readWord8ArrayAsWordIO# :: MutableByteArray# d -> Int# -> IO Word64
+
+foreign import ccall unsafe "primal_compat.c primal_memwrite32"
+  writeWord8ArrayAsWordIO# :: MutableByteArray# d -> Int# -> Word# -> IO ()
+#endif
+
+readWord8ArrayAsWord# :: MutableByteArray# d -> Int# -> State# d -> (# State# d, Word# #)
+readWord8ArrayAsWord# mb# i# s =
+  case unsafePrimBase (readWord8ArrayAsWordIO# mb# i#) s of
+    (# s', W# a# #) -> (# s', a# #)
+
+writeWord8ArrayAsWord# :: MutableByteArray# d -> Int# -> Word# -> State# d -> State# d
+writeWord8ArrayAsWord# mb# i# a# = unsafePrimBase_ (writeWord8ArrayAsWordIO# mb# i# a#)
+
+#endif /* __GLASGOW_HASKELL__ < 806 */
diff --git a/src/Foreign/Prim/Cmm.hs b/src/Foreign/Prim/Cmm.hs
new file mode 100644
--- /dev/null
+++ b/src/Foreign/Prim/Cmm.hs
@@ -0,0 +1,48 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE ForeignFunctionInterface #-}
+{-# LANGUAGE GHCForeignImportPrim #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE UnliftedFFITypes #-}
+-- |
+-- Module      : Foreign.Prim.Cmm
+-- Copyright   : (c) Alexey Kuleshevich 2020
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Foreign.Prim.Cmm
+  ( word32ToFloat#
+  , floatToWord32#
+  , word64ToDouble#
+  , doubleToWord64#
+  ) where
+
+
+import GHC.Exts
+
+#include "MachDeps.h"
+
+-- | Cast a 32bit Word into a Float
+foreign import prim "primal_stg_word32ToFloatzh"
+  word32ToFloat# :: Word# -> Float#
+
+-- | Cast a Float into a 32bit Word
+foreign import prim "primal_stg_floatToWord32zh"
+  floatToWord32# :: Float# -> Word#
+
+-- | Cast a 64bit Word into a Double
+foreign import prim "primal_stg_word64ToDoublezh"
+#if WORD_SIZE_IN_BITS == 64
+  word64ToDouble# :: Word# -> Double#
+#else
+  word64ToDouble# :: Word64# -> Double#
+#endif
+
+-- | Cast a Double into a 64bit Word
+foreign import prim "primal_stg_doubleToWord64zh"
+#if WORD_SIZE_IN_BITS == 64
+  doubleToWord64# :: Double# -> Word#
+#else
+  doubleToWord64# :: Double# -> Word64#
+#endif
diff --git a/src/Foreign/Prim/Ptr.hs b/src/Foreign/Prim/Ptr.hs
new file mode 100644
--- /dev/null
+++ b/src/Foreign/Prim/Ptr.hs
@@ -0,0 +1,605 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE UnboxedTuples #-}
+-- |
+-- Module      : Foreign.Prim.Ptr
+-- Copyright   : (c) Alexey Kuleshevich 2020
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Foreign.Prim.Ptr
+  ( module GHC.Ptr
+  , plusOffPtr
+  , plusByteOffPtr
+  , minusOffPtr
+  , minusOffRemPtr
+  , minusByteOffPtr
+  , readPtr
+  , readOffPtr
+  , readByteOffPtr
+  , writePtr
+  , writeOffPtr
+  , writeByteOffPtr
+  , setOffPtr
+  , copyPtrToPtr
+  , copyByteOffPtrToPtr
+  , movePtrToPtr
+  , moveByteOffPtrToPtr
+  , comparePtrToPtr
+  , compareByteOffPtrToPtr
+  , freeHaskellFunPtr
+  , module X
+  , WordPtr(..)
+  , ptrToWordPtr
+  , wordPtrToPtr
+  , IntPtr(..)
+  , ptrToIntPtr
+  , intPtrToPtr
+  -- * Atomic
+  , casOffPtr
+  , atomicModifyOffPtr
+  , atomicModifyOffPtr_
+  , atomicModifyFetchOldOffPtr
+  , atomicModifyFetchNewOffPtr
+  -- ** Numeric
+  , atomicAddFetchOldOffPtr
+  , atomicAddFetchNewOffPtr
+  , atomicSubFetchOldOffPtr
+  , atomicSubFetchNewOffPtr
+  -- ** Binary
+  , atomicAndFetchOldOffPtr
+  , atomicAndFetchNewOffPtr
+  , atomicNandFetchOldOffPtr
+  , atomicNandFetchNewOffPtr
+  , atomicOrFetchOldOffPtr
+  , atomicOrFetchNewOffPtr
+  , atomicXorFetchOldOffPtr
+  , atomicXorFetchNewOffPtr
+  , atomicNotFetchOldOffPtr
+  , atomicNotFetchNewOffPtr
+  -- * Prefetch
+  , prefetchPtr0
+  , prefetchPtr1
+  , prefetchPtr2
+  , prefetchPtr3
+  , prefetchOffPtr0
+  , prefetchOffPtr1
+  , prefetchOffPtr2
+  , prefetchOffPtr3
+  ) where
+
+import Control.Prim.Monad
+import Control.Prim.Monad.Unsafe
+import Data.Prim
+import Data.Prim.Atomic
+import Data.Prim.Class
+import Foreign.Marshal.Utils (copyBytes)
+import Foreign.Prim
+import qualified Foreign.Ptr as GHC (freeHaskellFunPtr)
+import Foreign.Ptr as X hiding (IntPtr, WordPtr, freeHaskellFunPtr, intPtrToPtr,
+                         ptrToIntPtr, ptrToWordPtr, wordPtrToPtr)
+import GHC.Ptr
+
+setOffPtr ::
+     (MonadPrim s m, Prim e)
+  => Ptr e -- ^ Chunk of memory to fill
+  -> Off e -- ^ Offset in number of elements
+  -> Count e -- ^ Number of cells to fill
+  -> e -- ^ A value to fill the cells with
+  -> m ()
+setOffPtr (Ptr addr#) (Off (I# o#)) (Count (I# n#)) a = prim_ (setOffAddr# addr# o# n# a)
+{-# INLINE setOffPtr #-}
+
+
+readOffPtr :: (MonadPrim s m, Prim e) => Ptr e -> Off e -> m e
+readOffPtr (Ptr addr#) (Off (I# i#)) = prim (readOffAddr# addr# i#)
+{-# INLINE readOffPtr #-}
+
+
+readByteOffPtr :: (MonadPrim s m, Prim e) => Ptr e -> Off Word8 -> m e
+readByteOffPtr ptr (Off i) =
+  case ptr `plusPtr` i of
+    Ptr addr# -> prim (readOffAddr# addr# 0#)
+{-# INLINE readByteOffPtr #-}
+
+writeOffPtr :: (MonadPrim s m, Prim e) => Ptr e -> Off e -> e -> m ()
+writeOffPtr (Ptr addr#) (Off (I# i#)) a = prim_ (writeOffAddr# addr# i# a)
+{-# INLINE writeOffPtr #-}
+
+writeByteOffPtr :: (MonadPrim s m, Prim e) => Ptr e -> Off Word8 -> e -> m ()
+writeByteOffPtr ptr (Off i) a =
+  case ptr `plusPtr` i of
+    Ptr addr# -> prim_ (writeOffAddr# addr# 0# a)
+{-# INLINE writeByteOffPtr #-}
+
+readPtr :: (MonadPrim s m, Prim e) => Ptr e -> m e
+readPtr (Ptr addr#) = prim (readOffAddr# addr# 0#)
+{-# INLINE readPtr #-}
+
+writePtr :: (MonadPrim s m, Prim e) => Ptr e -> e -> m ()
+writePtr (Ptr addr#) a = prim_ (writeOffAddr# addr# 0# a)
+{-# INLINE writePtr #-}
+
+plusByteOffPtr :: Ptr e -> Off Word8 -> Ptr e
+plusByteOffPtr (Ptr addr#) (Off (I# off#)) = Ptr (addr# `plusAddr#` off#)
+{-# INLINE plusByteOffPtr #-}
+
+
+plusOffPtr :: Prim e => Ptr e -> Off e -> Ptr e
+plusOffPtr (Ptr addr#) off = Ptr (addr# `plusAddr#` fromOff# off)
+{-# INLINE plusOffPtr #-}
+
+-- | Find the offset in bytes that is between the two pointers by subtracting one address
+-- from another.
+--
+-- @since 0.1.0
+minusByteOffPtr :: Ptr e -> Ptr e -> Off Word8
+minusByteOffPtr (Ptr xaddr#) (Ptr yaddr#) = Off (I# (xaddr# `minusAddr#` yaddr#))
+{-# INLINE minusByteOffPtr #-}
+
+-- | Find the offset in number of elements that is between the two pointers by subtracting
+-- one address from another and dividing the result by the size of an element.
+--
+-- @since 0.1.0
+minusOffPtr :: Prim e => Ptr e -> Ptr e -> Off e
+minusOffPtr (Ptr xaddr#) (Ptr yaddr#) =
+  fromByteOff (Off (I# (xaddr# `minusAddr#` yaddr#)))
+{-# INLINE minusOffPtr #-}
+
+-- | Same as `minusOffPtr`, but will also return the remainder in bytes that is left over.
+--
+-- @since 0.1.0
+minusOffRemPtr :: Prim e => Ptr e -> Ptr e -> (Off e, Off Word8)
+minusOffRemPtr (Ptr xaddr#) (Ptr yaddr#) =
+  fromByteOffRem (Off (I# (xaddr# `minusAddr#` yaddr#)))
+{-# INLINE minusOffRemPtr #-}
+
+copyPtrToPtr :: (MonadPrim s m, Prim e) => Ptr e -> Off e -> Ptr e -> Off e -> Count e -> m ()
+copyPtrToPtr srcPtr srcOff dstPtr dstOff c =
+  unsafeIOToPrim $
+  copyBytes
+    (dstPtr `plusOffPtr` dstOff)
+    (srcPtr `plusOffPtr` srcOff)
+    (fromCount c)
+{-# INLINE copyPtrToPtr #-}
+
+copyByteOffPtrToPtr ::
+     (MonadPrim s m, Prim e)
+  => Ptr e
+  -> Off Word8
+  -> Ptr e
+  -> Off Word8
+  -> Count e
+  -> m ()
+copyByteOffPtrToPtr srcPtr (Off srcOff) dstPtr (Off dstOff) c =
+  unsafeIOToPrim $
+  copyBytes
+    (dstPtr `plusPtr` dstOff)
+    (srcPtr `plusPtr` srcOff)
+    (fromCount c)
+{-# INLINE copyByteOffPtrToPtr #-}
+
+movePtrToPtr :: (MonadPrim s m, Prim e) => Ptr e -> Off e -> Ptr e -> Off e -> Count e -> m ()
+movePtrToPtr src srcOff dst dstOff =
+  moveByteOffPtrToPtr src (toByteOff srcOff) dst (toByteOff dstOff)
+{-# INLINE movePtrToPtr #-}
+
+moveByteOffPtrToPtr ::
+     (MonadPrim s m, Prim e)
+  => Ptr e
+  -> Off Word8
+  -> Ptr e
+  -> Off Word8
+  -> Count e
+  -> m ()
+moveByteOffPtrToPtr (Ptr srcAddr#) (Off (I# srcOff#)) (Ptr dstAddr#) (Off (I# dstOff#)) c =
+  unsafeIOToPrim $ memmoveAddr# srcAddr# srcOff# dstAddr# dstOff# (fromCount# c)
+{-# INLINE moveByteOffPtrToPtr #-}
+
+-- | Compare memory between two pointers. Offsets and count is in number of elements,
+-- instead of byte count. Use `compareByteOffPtrToPtr` when offset in bytes is required.
+comparePtrToPtr :: Prim e => Ptr e -> Off e -> Ptr e -> Off e -> Count e -> Ordering
+comparePtrToPtr (Ptr addr1#) off1 (Ptr addr2#) off2 c =
+  toOrdering# (memcmpAddr# addr1# (fromOff# off1) addr2# (fromOff# off2) (fromCount# c))
+{-# INLINE comparePtrToPtr #-}
+
+-- | Same as `comparePtrToPtr`, except offset is in bytes instead of number of elements.
+compareByteOffPtrToPtr ::
+     Prim e => Ptr e -> Off Word8 -> Ptr e -> Off Word8 -> Count e -> Ordering
+compareByteOffPtrToPtr (Ptr addr1#) (Off (I# off1#)) (Ptr addr2#) (Off (I# off2#)) c =
+  toOrdering# (memcmpAddr# addr1# off1# addr2# off2# (fromCount# c))
+{-# INLINE compareByteOffPtrToPtr #-}
+
+
+
+
+-- | Perform atomic modification of an element in the `Ptr` at the supplied
+-- index. Returns the artifact of computation @__b__@.  Offset is in number of elements,
+-- rather than bytes. Implies a full memory barrier.
+--
+-- /Note/ - Bounds are not checked, therefore this function is unsafe.
+--
+-- @since 0.1.0
+casOffPtr ::
+     (MonadPrim s m, Atomic e)
+  => Ptr e -- ^ Array to be mutated
+  -> Off e -- ^ Index is in elements of @__a__@, rather than bytes.
+  -> e -- ^ Expected old value
+  -> e -- ^ New value
+  -> m e
+casOffPtr (Ptr addr#) (Off (I# i#)) old new = prim $ casOffAddr# addr# i# old new
+{-# INLINE casOffPtr #-}
+
+-- | Perform atomic modification of an element in the `Ptr` at the supplied
+-- index. Returns the artifact of computation @__b__@.  Offset is in number of elements,
+-- rather than bytes. Implies a full memory barrier.
+--
+-- /Note/ - Bounds are not checked, therefore this function is unsafe.
+--
+-- @since 0.1.0
+atomicModifyOffPtr ::
+     (MonadPrim s m, Atomic e)
+  => Ptr e -- ^ Array to be mutated
+  -> Off e -- ^ Index is in elements of @__a__@, rather than bytes.
+  -> (e -> (e, b)) -- ^ Function that is applied to the old value and returns new value
+                   -- and some artifact of computation @__b__@
+  -> m b
+atomicModifyOffPtr (Ptr addr#) (Off (I# i#)) f =
+  prim $
+  atomicModifyOffAddr# addr# i# $ \a ->
+    case f a of
+      (a', b) -> (# a', b #)
+{-# INLINE atomicModifyOffPtr #-}
+
+-- | Perform atomic modification of an element in the `Ptr` at the supplied
+-- index.  Offset is in number of elements, rather than bytes. Implies a full memory
+-- barrier.
+--
+-- /Note/ - Bounds are not checked, therefore this function is unsafe.
+--
+-- @since 0.1.0
+atomicModifyOffPtr_ ::
+     (MonadPrim s m, Atomic e)
+  => Ptr e -- ^ Array to be mutated
+  -> Off e -- ^ Index is in elements of @__a__@, rather than bytes.
+  -> (e -> e) -- ^ Function that is applied to the old value and returns new value.
+  -> m ()
+atomicModifyOffPtr_ (Ptr addr#) (Off (I# i#)) f =
+  prim_ $ atomicModifyOffAddr_# addr# i# f
+{-# INLINE atomicModifyOffPtr_ #-}
+
+
+-- | Perform atomic modification of an element in the `Ptr` at the supplied
+-- index. Returns the previous value.  Offset is in number of elements, rather than
+-- bytes. Implies a full memory barrier.
+--
+-- /Note/ - Bounds are not checked, therefore this function is unsafe.
+--
+-- @since 0.1.0
+atomicModifyFetchOldOffPtr ::
+     (MonadPrim s m, Atomic e)
+  => Ptr e -- ^ Array to be mutated
+  -> Off e -- ^ Index is in elements of @__a__@, rather than bytes.
+  -> (e -> e) -- ^ Function that is applied to the old value and returns the new value
+  -> m e
+atomicModifyFetchOldOffPtr (Ptr addr#) (Off (I# i#)) f =
+  prim $ atomicModifyFetchOldOffAddr# addr# i# f
+{-# INLINE atomicModifyFetchOldOffPtr #-}
+
+
+-- | Perform atomic modification of an element in the `Ptr` at the supplied
+-- index.  Offset is in number of elements, rather than bytes. Implies a full memory
+-- barrier.
+--
+-- /Note/ - Bounds are not checked, therefore this function is unsafe.
+--
+-- @since 0.1.0
+atomicModifyFetchNewOffPtr ::
+     (MonadPrim s m, Atomic e)
+  => Ptr e -- ^ Array to be mutated
+  -> Off e -- ^ Index is in elements of @__a__@, rather than bytes.
+  -> (e -> e) -- ^ Function that is applied to the old value and returns the new value
+  -> m e
+atomicModifyFetchNewOffPtr (Ptr addr#) (Off (I# i#)) f =
+  prim $ atomicModifyFetchNewOffAddr# addr# i# f
+{-# INLINE atomicModifyFetchNewOffPtr #-}
+
+
+
+-- | Add a numeric value to an element of a `Ptr`, corresponds to @(`+`)@ done
+-- atomically. Returns the previous value.  Offset is in number of elements, rather
+-- than bytes. Implies a full memory barrier.
+--
+-- /Note/ - Bounds are not checked, therefore this function is unsafe.
+--
+-- @since 0.1.0
+atomicAddFetchOldOffPtr ::
+     (MonadPrim s m, AtomicCount e)
+  => Ptr e
+  -> Off e
+  -> e
+  -> m e
+atomicAddFetchOldOffPtr (Ptr addr#) (Off (I# i#)) a =
+  prim (atomicAddFetchOldOffAddr# addr# i# a)
+{-# INLINE atomicAddFetchOldOffPtr #-}
+
+-- | Add a numeric value to an element of a `Ptr`, corresponds to @(`+`)@ done
+-- atomically. Returns the new value.  Offset is in number of elements, rather
+-- than bytes. Implies a full memory barrier.
+--
+-- /Note/ - Bounds are not checked, therefore this function is unsafe.
+--
+-- @since 0.1.0
+atomicAddFetchNewOffPtr ::
+     (MonadPrim s m, AtomicCount e)
+  => Ptr e
+  -> Off e
+  -> e
+  -> m e
+atomicAddFetchNewOffPtr (Ptr addr#) (Off (I# i#)) a =
+  prim (atomicAddFetchNewOffAddr# addr# i# a)
+{-# INLINE atomicAddFetchNewOffPtr #-}
+
+
+
+-- | Subtract a numeric value from an element of a `Ptr`, corresponds to
+-- @(`-`)@ done atomically. Returns the previous value.  Offset is in number of elements, rather
+-- than bytes. Implies a full memory barrier.
+--
+-- /Note/ - Bounds are not checked, therefore this function is unsafe.
+--
+-- @since 0.1.0
+atomicSubFetchOldOffPtr ::
+     (MonadPrim s m, AtomicCount e)
+  => Ptr e
+  -> Off e
+  -> e
+  -> m e
+atomicSubFetchOldOffPtr (Ptr addr#) (Off (I# i#)) a =
+  prim (atomicSubFetchOldOffAddr# addr# i# a)
+{-# INLINE atomicSubFetchOldOffPtr #-}
+
+-- | Subtract a numeric value from an element of a `Ptr`, corresponds to
+-- @(`-`)@ done atomically. Returns the new value. Offset is in number of elements, rather
+-- than bytes. Implies a full memory barrier.
+--
+-- /Note/ - Bounds are not checked, therefore this function is unsafe.
+--
+-- @since 0.1.0
+atomicSubFetchNewOffPtr ::
+     (MonadPrim s m, AtomicCount e)
+  => Ptr e
+  -> Off e
+  -> e
+  -> m e
+atomicSubFetchNewOffPtr (Ptr addr#) (Off (I# i#)) a =
+  prim (atomicSubFetchNewOffAddr# addr# i# a)
+{-# INLINE atomicSubFetchNewOffPtr #-}
+
+
+
+-- | Binary conjunction (AND) of an element of a `Ptr` with the supplied value,
+-- corresponds to @(`Data.Bits..&.`)@ done atomically. Returns the previous value. Offset
+-- is in number of elements, rather than bytes. Implies a full memory barrier.
+--
+-- /Note/ - Bounds are not checked, therefore this function is unsafe.
+--
+-- @since 0.1.0
+atomicAndFetchOldOffPtr ::
+     (MonadPrim s m, AtomicBits e)
+  => Ptr e
+  -> Off e
+  -> e
+  -> m e
+atomicAndFetchOldOffPtr (Ptr addr#) (Off (I# i#)) a =
+  prim (atomicAndFetchOldOffAddr# addr# i# a)
+{-# INLINE atomicAndFetchOldOffPtr #-}
+
+-- | Binary conjunction (AND) of an element of a `Ptr` with the supplied value,
+-- corresponds to @(`Data.Bits..&.`)@ done atomically. Returns the new value. Offset is
+-- in number of elements, rather than bytes. Implies a full memory barrier.
+--
+-- /Note/ - Bounds are not checked, therefore this function is unsafe.
+--
+-- @since 0.1.0
+atomicAndFetchNewOffPtr ::
+     (MonadPrim s m, AtomicBits e)
+  => Ptr e
+  -> Off e
+  -> e
+  -> m e
+atomicAndFetchNewOffPtr (Ptr addr#) (Off (I# i#)) a =
+  prim (atomicAndFetchNewOffAddr# addr# i# a)
+{-# INLINE atomicAndFetchNewOffPtr #-}
+
+
+
+-- | Negation of binary conjunction (NAND) of an element of a `Ptr` with the
+-- supplied value, corresponds to @\\x y -> `Data.Bits.complement` (x `Data.Bits..&.` y)@
+-- done atomically. Returns the previous value. Offset is in number of elements, rather
+-- than bytes. Implies a full memory barrier.
+--
+-- /Note/ - Bounds are not checked, therefore this function is unsafe.
+--
+-- @since 0.1.0
+atomicNandFetchOldOffPtr ::
+     (MonadPrim s m, AtomicBits e)
+  => Ptr e
+  -> Off e
+  -> e
+  -> m e
+atomicNandFetchOldOffPtr (Ptr addr#) (Off (I# i#)) a =
+  prim (atomicNandFetchOldOffAddr# addr# i# a)
+{-# INLINE atomicNandFetchOldOffPtr #-}
+
+-- | Negation of binary conjunction (NAND)  of an element of a `Ptr` with the supplied
+-- value, corresponds to @\\x y -> `Data.Bits.complement` (x `Data.Bits..&.` y)@ done
+-- atomically. Returns the new value. Offset is in number of elements, rather than
+-- bytes. Implies a full memory barrier.
+--
+-- /Note/ - Bounds are not checked, therefore this function is unsafe.
+--
+-- @since 0.1.0
+atomicNandFetchNewOffPtr ::
+     (MonadPrim s m, AtomicBits e)
+  => Ptr e
+  -> Off e
+  -> e
+  -> m e
+atomicNandFetchNewOffPtr (Ptr addr#) (Off (I# i#)) a =
+  prim (atomicNandFetchNewOffAddr# addr# i# a)
+{-# INLINE atomicNandFetchNewOffPtr #-}
+
+
+
+
+-- | Binary disjunction (OR) of an element of a `Ptr` with the supplied value,
+-- corresponds to @(`Data.Bits..|.`)@ done atomically. Returns the previous value. Offset
+-- is in number of elements, rather than bytes. Implies a full memory barrier.
+--
+-- /Note/ - Bounds are not checked, therefore this function is unsafe.
+--
+-- @since 0.1.0
+atomicOrFetchOldOffPtr ::
+     (MonadPrim s m, AtomicBits e)
+  => Ptr e
+  -> Off e
+  -> e
+  -> m e
+atomicOrFetchOldOffPtr (Ptr addr#) (Off (I# i#)) a =
+  prim (atomicOrFetchOldOffAddr# addr# i# a)
+{-# INLINE atomicOrFetchOldOffPtr #-}
+
+-- | Binary disjunction (OR) of an element of a `Ptr` with the supplied value,
+-- corresponds to @(`Data.Bits..|.`)@ done atomically. Returns the new value. Offset is
+-- in number of elements, rather than bytes. Implies a full memory barrier.
+--
+-- /Note/ - Bounds are not checked, therefore this function is unsafe.
+--
+-- @since 0.1.0
+atomicOrFetchNewOffPtr ::
+     (MonadPrim s m, AtomicBits e)
+  => Ptr e
+  -> Off e
+  -> e
+  -> m e
+atomicOrFetchNewOffPtr (Ptr addr#) (Off (I# i#)) a =
+  prim (atomicOrFetchNewOffAddr# addr# i# a)
+{-# INLINE atomicOrFetchNewOffPtr #-}
+
+
+
+-- | Binary exclusive disjunction (XOR) of an element of a `Ptr` with the supplied value,
+-- corresponds to @`Data.Bits.xor`@ done atomically. Returns the previous value. Offset
+-- is in number of elements, rather than bytes. Implies a full memory barrier.
+--
+-- /Note/ - Bounds are not checked, therefore this function is unsafe.
+--
+-- @since 0.1.0
+atomicXorFetchOldOffPtr ::
+     (MonadPrim s m, AtomicBits e)
+  => Ptr e
+  -> Off e
+  -> e
+  -> m e
+atomicXorFetchOldOffPtr (Ptr addr#) (Off (I# i#)) a =
+  prim (atomicXorFetchOldOffAddr# addr# i# a)
+{-# INLINE atomicXorFetchOldOffPtr #-}
+
+-- | Binary exclusive disjunction (XOR) of an element of a `Ptr` with the supplied value,
+-- corresponds to @`Data.Bits.xor`@ done atomically. Returns the new value. Offset is
+-- in number of elements, rather than bytes. Implies a full memory barrier.
+--
+-- /Note/ - Bounds are not checked, therefore this function is unsafe.
+--
+-- @since 0.1.0
+atomicXorFetchNewOffPtr ::
+     (MonadPrim s m, AtomicBits e)
+  => Ptr e
+  -> Off e
+  -> e
+  -> m e
+atomicXorFetchNewOffPtr (Ptr addr#) (Off (I# i#)) a =
+  prim (atomicXorFetchNewOffAddr# addr# i# a)
+{-# INLINE atomicXorFetchNewOffPtr #-}
+
+
+
+
+
+-- | Binary negation (NOT) of an element of a `Ptr`, corresponds to
+-- @(`Data.Bits.complement`)@ done atomically. Returns the previous value. Offset is in
+-- number of elements, rather than bytes. Implies a full memory barrier.
+--
+-- /Note/ - Bounds are not checked, therefore this function is unsafe.
+--
+-- @since 0.1.0
+atomicNotFetchOldOffPtr ::
+     (MonadPrim s m, AtomicBits e)
+  => Ptr e
+  -> Off e
+  -> m e
+atomicNotFetchOldOffPtr (Ptr addr#) (Off (I# i#)) =
+  prim (atomicNotFetchOldOffAddr# addr# i#)
+{-# INLINE atomicNotFetchOldOffPtr #-}
+
+-- | Binary negation (NOT) of an element of a `Ptr`, corresponds to
+-- @(`Data.Bits.complement`)@ done atomically. Returns the new value. Offset is in number
+-- of elements, rather than bytes. Implies a full memory barrier.
+--
+-- /Note/ - Bounds are not checked, therefore this function is unsafe.
+--
+-- @since 0.1.0
+atomicNotFetchNewOffPtr ::
+     (MonadPrim s m, AtomicBits e)
+  => Ptr e
+  -> Off e
+  -> m e
+atomicNotFetchNewOffPtr (Ptr addr#) (Off (I# i#)) =
+  prim (atomicNotFetchNewOffAddr# addr# i#)
+{-# INLINE atomicNotFetchNewOffPtr #-}
+
+
+
+
+
+prefetchPtr0 :: MonadPrim s m => Ptr e -> m ()
+prefetchPtr0 (Ptr b#) = prim_ (prefetchAddr0# b# 0#)
+{-# INLINE prefetchPtr0 #-}
+
+prefetchPtr1 :: MonadPrim s m => Ptr a -> m ()
+prefetchPtr1 (Ptr b#) = prim_ (prefetchAddr1# b# 0#)
+{-# INLINE prefetchPtr1 #-}
+
+prefetchPtr2 :: MonadPrim s m => Ptr e -> m ()
+prefetchPtr2 (Ptr b#) = prim_ (prefetchAddr2# b# 0#)
+{-# INLINE prefetchPtr2 #-}
+
+prefetchPtr3 :: MonadPrim s m => Ptr e -> m ()
+prefetchPtr3 (Ptr b#) = prim_ (prefetchAddr3# b# 0#)
+{-# INLINE prefetchPtr3 #-}
+
+prefetchOffPtr0 :: (MonadPrim s m, Prim e) => Ptr e -> Off e -> m ()
+prefetchOffPtr0 (Ptr b#) off = prim_ (prefetchAddr0# b# (fromOff# off))
+{-# INLINE prefetchOffPtr0 #-}
+
+prefetchOffPtr1 :: (MonadPrim s m, Prim e) => Ptr e -> Off e -> m ()
+prefetchOffPtr1 (Ptr b#) off = prim_ (prefetchAddr1# b# (fromOff# off))
+{-# INLINE prefetchOffPtr1 #-}
+
+prefetchOffPtr2 :: (MonadPrim s m, Prim e) => Ptr e -> Off e -> m ()
+prefetchOffPtr2 (Ptr b#) off = prim_ (prefetchAddr2# b# (fromOff# off))
+{-# INLINE prefetchOffPtr2 #-}
+
+prefetchOffPtr3 :: (MonadPrim s m, Prim e) => Ptr e -> Off e -> m ()
+prefetchOffPtr3 (Ptr b#) off = prim_ (prefetchAddr3# b# (fromOff# off))
+{-# INLINE prefetchOffPtr3 #-}
+
+-- | Same as `GHC.freeHaskellFunPtr`
+--
+-- @since 0.1.0
+freeHaskellFunPtr :: MonadPrim s m => FunPtr a -> m ()
+freeHaskellFunPtr = unsafeIOToPrim . GHC.freeHaskellFunPtr
diff --git a/src/Foreign/Prim/StablePtr.hs b/src/Foreign/Prim/StablePtr.hs
new file mode 100644
--- /dev/null
+++ b/src/Foreign/Prim/StablePtr.hs
@@ -0,0 +1,41 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+-- |
+-- Module      : Foreign.Prim.StablePtr
+-- Copyright   : (c) Alexey Kuleshevich 2020
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Foreign.Prim.StablePtr
+  ( GHC.StablePtr(..)
+  , newStablePtr
+  , deRefStablePtr
+  , freeStablePtr
+  , GHC.castStablePtrToPtr
+  , GHC.castPtrToStablePtr
+  ) where
+
+import Control.DeepSeq
+import Control.Prim.Monad
+import qualified GHC.Stable as GHC
+
+instance NFData (GHC.StablePtr a) where
+  rnf (GHC.StablePtr _) = ()
+
+instance Show (GHC.StablePtr a) where
+  show = show . GHC.castStablePtrToPtr
+
+
+-- | Same as `GHC.newStablePtr`, but generalized to `MonadPrim`
+newStablePtr :: MonadPrim RW m => a -> m (GHC.StablePtr a)
+newStablePtr = liftPrimBase . GHC.newStablePtr
+
+-- | Same as `GHC.deRefStablePtr`, but generalized to `MonadPrim`
+deRefStablePtr :: MonadPrim RW m => GHC.StablePtr a -> m a
+deRefStablePtr = liftPrimBase . GHC.deRefStablePtr
+
+-- | Same as `GHC.freeStablePtr`, but generalized to `MonadPrim`
+freeStablePtr :: MonadPrim RW m => GHC.StablePtr a -> m ()
+freeStablePtr = liftPrimBase . GHC.freeStablePtr
diff --git a/src/Foreign/Prim/WeakPtr.hs b/src/Foreign/Prim/WeakPtr.hs
new file mode 100644
--- /dev/null
+++ b/src/Foreign/Prim/WeakPtr.hs
@@ -0,0 +1,104 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE UnboxedTuples #-}
+-- |
+-- Module      : Foreign.Prim.WeakPtr
+-- Copyright   : (c) Alexey Kuleshevich 2020
+-- License     : BSD3
+-- Maintainer  : Alexey Kuleshevich <alexey@kuleshevi.ch>
+-- Stability   : experimental
+-- Portability : non-portable
+--
+module Foreign.Prim.WeakPtr
+  ( Weak(..)
+  , mkWeak -- TODO: validate pre ghc-8.2 mkWeak#
+  , mkWeakNoFinalizer
+  , mkWeakPtr
+  , mkWeakPtrNoFinalizer
+  , addFinalizer
+  , addCFinalizer
+  , addCFinalizerEnv
+  , deRefWeak
+  , finalizeWeak
+  ) where
+
+import Control.Monad
+import Control.Prim.Monad
+import GHC.Weak (Weak(..))
+import Foreign.Prim
+
+-- | Same as `System.Mem.Weak.mkWeak`, except it requires a finalizer to be
+-- supplied. For a version without finalizers use `mkWeakNoFinalizer`
+mkWeak :: MonadUnliftPrim RW m => a -> v -> m b -> m (Weak v)
+mkWeak key val finalizer =
+  runInPrimBase finalizer $ \f s ->
+    case mkWeak# key val f s of
+      (# s', w #) -> (# s', Weak w #)
+
+-- | Similar to `mkWeak`, except it does not require a finalizer.
+mkWeakNoFinalizer :: MonadPrim RW m => a -> v -> m (Weak v)
+mkWeakNoFinalizer key val =
+  prim $ \s ->
+    case mkWeakNoFinalizer# key val s of
+      (# s', w #) -> (# s', Weak w #)
+
+-- | Same as `System.Mem.Weak.mkWeakPtr`, except it requires a finalizer to be
+-- supplied. For a version without finalizers use `mkWeakPtrNoFinalizer`
+mkWeakPtr :: MonadUnliftPrim RW m => k -> m b -> m (Weak k)
+mkWeakPtr key = mkWeak key key
+
+-- | Similar to `mkWeakPtr`, except it does not require a finalizer.
+mkWeakPtrNoFinalizer :: MonadPrim RW m => k -> m (Weak k)
+mkWeakPtrNoFinalizer key = mkWeakNoFinalizer key key
+
+
+-- | Same as `System.Mem.Weak.addFinalizer`.
+addFinalizer :: MonadUnliftPrim RW m => k -> m b -> m ()
+addFinalizer key = void . mkWeakPtr key
+
+-- | Add a foreign function finalizer with a single argument
+addCFinalizer ::
+     MonadPrim RW m
+  => FunPtr (Ptr a -> IO ())
+     -- ^ Pointer to the C function to be called when finalizers are being invoked
+  -> Ptr a
+     -- ^ Argument that will be supplied to the finalizer function
+  -> Weak v
+  -> m Bool
+addCFinalizer (FunPtr faddr#) (Ptr addr#) (Weak weak#) =
+  prim $ \s ->
+    case addCFinalizerToWeak# faddr# addr# 0# nullAddr# weak# s of
+      (# s', i# #) -> (# s', isTrue# i# #)
+
+-- | Add a foreign function finalizer with two arguments
+addCFinalizerEnv ::
+     MonadPrim RW m
+  => FunPtr (Ptr env -> Ptr a -> IO ())
+     -- ^ Pointer to the C function to be called when finalizers are being invoked
+  -> Ptr env
+     -- ^ First argument that will be supplied to the finalizer function
+  -> Ptr a
+     -- ^ Second argument that will be supplied to the finalizer function
+  -> Weak v
+  -> m Bool
+addCFinalizerEnv (FunPtr faddr#) (Ptr envAddr#) (Ptr addr#) (Weak weak#) =
+  prim $ \s ->
+    case addCFinalizerToWeak# faddr# addr# 1# envAddr# weak# s of
+      (# s', i# #) -> (# s', isTrue# i# #)
+
+-- | Similar to `System.Mem.Weak.deRefWeak`
+deRefWeak :: MonadPrim RW m => Weak v -> m (Maybe v)
+deRefWeak (Weak weak#) =
+  prim $ \s ->
+    case deRefWeak# weak# s of
+      (# s', 0#, _ #) -> (# s', Nothing #)
+      (# s', _, a #) -> (# s', Just a #)
+
+
+-- | Similar to `System.Mem.Weak.finalize`
+finalizeWeak :: MonadPrim RW m => Weak v -> m ()
+finalizeWeak (Weak w) =
+  prim $ \s ->
+    case finalizeWeak# w s of
+      (# s1, 0#, _ #) -> (# s1, () #)
+      (# s1, _, f #) -> f s1
diff --git a/tests/doctests.hs b/tests/doctests.hs
new file mode 100644
--- /dev/null
+++ b/tests/doctests.hs
@@ -0,0 +1,6 @@
+module Main where
+
+import Test.DocTest (doctest)
+
+main :: IO ()
+main = doctest ["src", "-fobject-code"]
