diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,22 @@
+# PRIM
+This library reorganizes `ghc-prim` in a sane but conservative way
+, without adding any fancy tricks like overloading or extra functions.
+It's meant as a foundation for low-level programming in haskell, as well as (eventually),
+a comprehensive home for documentation on ghc magic.
+
+# Module Structure
+
+  Modules live at the toplevel and do not consider the global package ecosystem, for modularity.
+It is intended to use cabal mixins or PackageImports to appropriately avoid collisions downstream.
+Modules are granular, intending to represent a particular usable component such as a single datatype or class.
+Modules for internal types are nested under the module they group closest with,
+while modules for common types like Refs and Arrays are anti-nested with the root exposing their types.
+
+# Export Structure
+
+  Types and constructors with the same name as the module, as well as all operators are meant to be imported unqualified.
+All other identifiers are meant to be imported qualified. The common pattern is: 
+
+```haskell
+import Compact (Compact)
+import Compact qualified
diff --git a/prim.cabal b/prim.cabal
new file mode 100644
--- /dev/null
+++ b/prim.cabal
@@ -0,0 +1,73 @@
+cabal-version: 2.4
+name: prim
+homepage: https://github.com/daig/prim#readme
+version: 0.1.0.0
+category: Prelude
+synopsis: An ergonomic but conservative interface to ghc-prim
+description: 
+      This library reorganizes @ghc-prim@ in a sane but conservative way 
+  , without adding any fancy tricks like overloading or extra functions.
+  It's meant as a foundation for low-level programming in haskell, as well as (eventually),
+  a comprehensive home for documentation on ghc magic.
+
+stability: cursed
+bug-reports: https://github.com/daig/prim/issues
+author: Dai
+maintainer: daig@sodality.cc
+copyright: 2020 Sodality
+license: MIT
+
+extra-source-files:
+  README.md
+  CHANGELOG.md
+
+source-repository head
+  type: git
+  location: https://github.com/daig/prim
+
+
+library 
+  default-language: Haskell2010
+  default-extensions: MagicHash, UnboxedTuples
+                    , KindSignatures, PolyKinds, ConstraintKinds, TypeOperators, RankNTypes
+                    , BlockArguments
+  hs-source-dirs: src
+  other-modules: Prelude
+  reexported-modules: GHC.Tuple as Tuple
+  exposed-modules: Char
+                 , I64, I32, I16, I8
+                 , U64, U32, U16, U8
+                 , B8, B16, B32, B64
+                 , F64, F32
+                 , ST,ST.IO, ST.IO.STM
+                 , Ref
+                 , Ref.Weak, Ref.Stable, Ref.Stable.Name, Ref.Byte
+                 , Ref.Char8, Ref.Char
+                 , Ref.I64, Ref.I32, Ref.I16, Ref.I8
+                 , Ref.U64, Ref.U32, Ref.U16, Ref.U8
+                 , Ref.F32, Ref.F64
+                 , Ref.Ref.Byte, Ref.Ref.Stable
+                 , Ref.Boxed, Ref.STM, Ref.Lock
+                 , Array, Array.Small, Array.Boxed
+                 , Array.Byte, Array.Byte.Pinned, Array.Byte.Unpinned
+                 , Array.Char, Array.Char8
+                 , Array.F32, Array.F64
+                 , Array.I64, Array.I32, Array.I16, Array.I8
+                 , Array.U64, Array.U32, Array.U16, Array.U8
+                 , Array.Ref.Stable
+                 , Array.Array, Array.Array.Byte, Array.Array.Array
+                 , Thread
+                 , Compact
+                 , Proxy
+                 , Coerce
+                 , Exception, Exception.Mask
+                 , Spark
+                 , Enum
+                 , Any, BCO
+                 , RTS.Block, Optimizer
+                 , RTS.Prefetch.Any, RTS.Prefetch.Ref, RTS.Prefetch.Array, RTS.Prefetch.Array.M
+                 , String, String.C, String.C.Latin, String.C.UTF8, String.List
+                 , Nat
+                 , Stock
+                 , Syntax.ImplicitParam
+  build-depends: ghc-prim ^>= 0.6.1, microbase
diff --git a/src/Any.hs b/src/Any.hs
new file mode 100644
--- /dev/null
+++ b/src/Any.hs
@@ -0,0 +1,20 @@
+module Any (module Any, Any, seq) where
+import qualified Ref
+import qualified Array
+import GHC.Types as X (Any)
+
+eq# :: a -> a -> B
+eq# = reallyUnsafePtrEquality#
+
+fromRef :: Ref.Byte -> (# a #)
+fromRef = addrToAny#
+
+-- | Must be run on an evaluated value, not a thunk
+toRef# :: a -> IO Ref.Byte
+toRef# = anyToAddr#
+
+unpackClosure :: a -> (# Ref.Byte, Array.Byte, Array.Boxed b #)
+unpackClosure = unpackClosure# 
+
+getApStackVal :: a -> I64 -> (# I64, b #)
+getApStackVal = getApStackVal#
diff --git a/src/Array.hs b/src/Array.hs
new file mode 100644
--- /dev/null
+++ b/src/Array.hs
@@ -0,0 +1,24 @@
+-- | Types for arrays
+{-# language NoImplicitPrelude #-}
+module Array where
+import GHC.Prim
+
+type Boxed = Array#
+type Unlifted = ArrayArray#
+type Small = SmallArray#
+type Byte = ByteArray#
+
+type I64 = ByteArray#
+type I32 = ByteArray#
+type I16 = ByteArray#
+type I8 = ByteArray#
+
+type U64 = ByteArray#
+type U32 = ByteArray#
+type U16 = ByteArray#
+type U8 = ByteArray#
+
+type F32 = ByteArray#
+type F64 = ByteArray#
+
+type StablePtr = ByteArray#
diff --git a/src/Array/Array.hs b/src/Array/Array.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/Array.hs
@@ -0,0 +1,29 @@
+-- | /Unlifted/ arrays, containing strictly evaluated pointers.
+-- Unlike "Array.Byte", these store pointers, but like it, they're guarenteed not to be bottom.
+-- Eg. We cannot store an 'Addr', because it might be null, but we can store "Array.Byte.Array",
+-- and more "Array.Array"
+module Array.Array where
+
+type A = ArrayArray#
+type M = MutableArrayArray#
+
+new :: I64 -> ST s (M s)
+new = newArrayArray#
+
+eq :: M s -> M s -> B
+eq = sameMutableArrayArray#
+
+freeze## :: M s -> ST s A
+freeze## = unsafeFreezeArrayArray#
+
+size :: A -> I64
+size = sizeofArrayArray#
+
+sizeM :: M s -> I64
+sizeM = sizeofMutableArrayArray#
+
+copy# :: A -> I64 -> M s -> I64 -> I64 -> ST_ s
+copy# = copyArrayArray#
+
+copyM# :: M s -> I64 -> M s -> I64 -> I64 -> ST_ s
+copyM# = copyMutableArrayArray#
diff --git a/src/Array/Array/Array.hs b/src/Array/Array/Array.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/Array/Array.hs
@@ -0,0 +1,12 @@
+module Array.Array.Array where
+import qualified Array
+import Array.Array
+
+index# :: A -> I64 -> Array.Unlifted
+index# = indexArrayArrayArray#
+
+read# :: M s -> I64 -> ST s Array.Unlifted
+read# = readArrayArrayArray#
+
+write# :: M s -> I64 -> Array.Unlifted -> ST_ s
+write# = writeArrayArrayArray#
diff --git a/src/Array/Array/Byte.hs b/src/Array/Array/Byte.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/Array/Byte.hs
@@ -0,0 +1,12 @@
+module Array.Array.Byte where
+import qualified Array
+import Array.Array
+
+index# :: A -> I64 -> Array.Byte
+index# = indexByteArrayArray#
+
+read# :: M s -> I64 -> ST s Array.Byte
+read# = readByteArrayArray#
+
+write# :: M s -> I64 -> Array.Byte -> ST_ s
+write# = writeByteArrayArray#
diff --git a/src/Array/Boxed.hs b/src/Array/Boxed.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/Boxed.hs
@@ -0,0 +1,106 @@
+module Array.Boxed where
+import qualified Array
+
+type A = Array#
+type M = MutableArray#
+
+
+new :: I64 -> a -> ST s (M s a)
+new = newArray#
+
+eq :: M s a -> M s a -> B
+eq = sameMutableArray#
+
+read :: M s a -> I64 -> ST s a
+read = readArray#
+
+write :: M s a -> I64 -> a -> ST_ s
+write = writeArray#
+
+-- | Number of elements
+size :: A a -> I64
+size = sizeofArray#
+
+-- | Read from the specified index of an immutable array.
+-- The result is packaged into an unboxed unary tuple; the result itself is not yet evaluated.
+-- Pattern matching on the tuple forces the indexing of the array to happen
+-- but does not evaluate the element itself. Evaluating the thunk prevents
+-- additional thunks from building up on the heap. Avoiding these thunks, in turn,
+-- reduces references to the argument array, allowing it to be garbage collected more promptly.
+-- Warning: this can fail with an unchecked exception.
+index# :: A a -> I64 -> (# a #)
+index# = indexArray#
+
+-- | Make a mutable array immutable, without copying.
+freeze## :: M s a -> ST s (A a)
+freeze## = unsafeFreezeArray#
+
+-- | Make an immutable array mutable, without copying.
+thaw## :: A a -> ST s (M s a)
+thaw## = unsafeThawArray#
+
+-- | Copy the elements from the source array to the destination array.
+-- Both arrays must fully contain the specified ranges, but this is not checked.
+-- The two arrays must not be the same array in different states, but this is not checked either.
+--
+-- Warning: this can fail with an unchecked exception.
+copy# :: A a -- ^ source
+      -> I64 -- ^ source offset
+      -> M s a -- ^ destination
+      -> I64 -- ^ destination offset
+      -> I64 -- ^ number of elements to copy
+      -> ST_ s
+copy# = copyArray#
+
+-- | Copy the elements from the source array to the destination array.
+-- Both arrays must fully contain the specified ranges, but this is not checked.
+-- The two arrays must not be the same array in different states, but this is not checked either.
+--
+-- Warning: this can fail with an unchecked exception.
+copyM# :: M s a -- ^ source
+       -> I64 -- ^ source offset
+       -> M s a -- ^ destination
+       -> I64 -- ^ destination offset
+       -> I64 -- ^ number of elements to copy
+       -> ST_ s
+copyM# = copyMutableArray#
+
+-- | Create a new array with the elements from the source array.
+-- The provided array must fully contain the specified range, but this is not checked.
+--
+-- Warning: this can fail with an unchecked exception.
+clone# :: A a
+       -> I64 -- ^ Source offset
+       -> I64 -- ^ number of elements to copy
+       -> A a
+clone# = cloneArray#
+
+-- | Create a new array with the elements from the source array.
+-- The provided array must fully contain the specified range, but this is not checked.
+--
+-- Warning: this can fail with an unchecked exception.
+cloneM# :: M s a
+        -> I64 -- ^ Source offset
+        -> I64 -- ^ number of elements to copy
+        -> ST s (M s a)
+cloneM# = cloneMutableArray#
+
+freeze# :: M s a
+        -> I64 -- ^ Source offset
+        -> I64 -- ^ number of elements to copy
+        -> ST s (A a)
+freeze# = freezeArray#
+
+thaw# ::  A a
+        -> I64 -- ^ Source offset
+        -> I64 -- ^ number of elements to copy
+        -> ST s (M s a)
+thaw# = thawArray#
+
+cas# :: M s a
+    -> I64 -- ^ Source offset
+    -> a -- ^ Expected old value
+    -> a -- ^ New value
+    -> ST s (# B, a #) -- ^ Whether the swap failed, and the actual new value
+cas# as o a0 a1 s0 = case casArray# as o a0 a1 s0 of
+  (# s1, failed', a #) -> (# s1, (# failed', a #) #)
diff --git a/src/Array/Byte.hs b/src/Array/Byte.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/Byte.hs
@@ -0,0 +1,113 @@
+module Array.Byte where
+import qualified Array
+import qualified Ref
+
+type A = Array.Byte
+type M = MutableByteArray#
+
+-- | Create a new uninitialized mutable byte array of specified size (in bytes),
+-- in the specified state thread.
+new :: I64 -> ST s (M s)
+new = newByteArray#
+
+eq :: M s -> M s -> B
+eq = sameMutableByteArray#
+
+shrink :: M s -> I64 -> ST_ s
+shrink = shrinkMutableByteArray#
+
+-- | Number of elements
+size :: A -> I64
+size = sizeofByteArray#
+
+-- | Number of elements. Must be in @ST@ because of possible resizes.
+sizeM :: M s -> ST s I64
+sizeM = getSizeofMutableByteArray#
+
+-- | Make a mutable array immutable, without copying.
+freeze## :: M s -> ST s (A)
+freeze## = unsafeFreezeByteArray#
+
+-- | Copy the elements from the source array to the destination array.
+-- Both arrays must fully contain the specified ranges, but this is not checked.
+-- The two arrays must not be the same array in different states, but this is not checked either.
+--
+-- Warning: this can fail with an unchecked exception.
+copy# :: A -- ^ source
+      -> I64 -- ^ source offset
+      -> M s -- ^ destination
+      -> I64 -- ^ destination offset
+      -> I64 -- ^ number of elements to copy
+      -> ST_ s
+copy# = copyByteArray#
+
+-- | Copy the elements from the source array to the destination array.
+-- Both arrays must fully contain the specified ranges, but this is not checked.
+-- The two arrays must not be the same array in different states, but this is not checked either.
+--
+-- Warning: this can fail with an unchecked exception.
+copyM# :: M s -- ^ source
+       -> I64 -- ^ source offset
+       -> M s -- ^ destination
+       -> I64 -- ^ destination offset
+       -> I64 -- ^ number of elements to copy
+       -> ST_ s
+copyM# = copyMutableByteArray#
+
+-- | Copy a range of the @A@ to the memory range starting at the @Ref.Byte@.
+-- The @A@ and the memory region at @Ref.Byte@ must fully contain the specified ranges, but this is not checked.
+-- The @Ref.Byte@ must not point into the @A@ (e.g. if the @A@ were pinned), but this is not checked either. 
+--
+-- Warning: this can fail with an unchecked exception.
+copyToRef# :: A -- ^ source
+            -> I64 -- ^ source offset
+            -> Ref.Byte -- ^ destination
+            -> I64 -- ^ number of elements to copy
+            -> ST_ s
+copyToRef# = copyByteArrayToAddr#
+
+-- | Copy a range of the @A@ to the memory range starting at the @Ref.Byte@.
+-- The @A@ and the memory region at @Ref.Byte@ must fully contain the specified ranges, but this is not checked.
+-- The @Ref.Byte@ must not point into the @A@ (e.g. if the @A@ were pinned), but this is not checked either. 
+--
+-- Warning: this can fail with an unchecked exception.
+copyToRefM# :: M s -- ^ source
+             -> I64 -- ^ source offset
+             -> Ref.Byte -- ^ destination
+             -> I64 -- ^ number of elements to copy
+             -> ST_ s
+copyToRefM# = copyMutableByteArrayToAddr#
+
+-- |Copy a memory range starting at the @Ref.Byte@ to the specified range in the
+--    @Mutable@. The memory region at @Ref.Byte@ and the @A@ must fully
+--    contain the specified ranges, but this is not checked. The @Ref.Byte@ must not
+--    point into the @Mutable@ (e.g. if the @Mutable@ were pinned),
+--    but this is not checked either.
+--
+--    Warning: This can fail with an unchecked exception.
+copyFromRef# :: Ref.Byte -- ^ source
+              -> M s -- ^ destination
+              -> I64 -- ^ destination offset
+              -> I64 -- ^ number of elements to copy
+              -> ST_ s
+copyFromRef# = copyAddrToByteArray#
+
+-- | Set a slice to the specified byte.
+set :: M s
+    -> I64 -- ^ slice start offset
+    -> I64 -- ^ slice length in bytes
+    -> I64 -- ^ the byte to set them to
+    -> ST_ s
+set = setByteArray#
+
+
+
+-- | Lexicographic comparison.
+-- Warning: Both arrays mus fully contain the specified ranges, but this is not checked.
+compare# :: A -- ^ source1
+         -> I64 -- ^ source1 offset
+         -> A -- ^ source2
+         -> I64 -- ^ source2 offset
+         -> I64 -- ^ number of bytes to compare
+         -> I64 -- ^ a number less-than, equal-to, or greater-than @0#@
+compare# = compareByteArrays#
diff --git a/src/Array/Byte/Pinned.hs b/src/Array/Byte/Pinned.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/Byte/Pinned.hs
@@ -0,0 +1,19 @@
+module Array.Byte.Pinned where
+import qualified Ref
+import Array.Byte hiding (new)
+
+new :: I64 -> ST s (M s)
+new = newPinnedByteArray#
+
+-- TODO: add docs for which arg is which
+newAligned :: I64 -> I64 -> ST s (M s)
+newAligned = newAlignedPinnedByteArray#
+
+pinned' :: A -> B
+pinned' = isByteArrayPinned#
+
+pinnedM' :: M s -> B
+pinnedM' = isMutableByteArrayPinned#
+
+contents :: A -> Ref.Byte
+contents = byteArrayContents#
diff --git a/src/Array/Byte/Unpinned.hs b/src/Array/Byte/Unpinned.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/Byte/Unpinned.hs
@@ -0,0 +1,5 @@
+module Array.Byte.Unpinned where
+import Array.Byte
+
+resize :: M s -> I64 -> ST s (M s)
+resize = resizeMutableByteArray#
diff --git a/src/Array/Char.hs b/src/Array/Char.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/Char.hs
@@ -0,0 +1,19 @@
+module Array.Char where
+import Array.Byte
+
+index# :: A
+       -> I64 -- Offset in 4-byte words
+       -> Char
+index# = indexWideCharArray#
+
+index## :: A
+        -> I64 -- Offset in bytes
+        -> Char
+index## = indexWord8ArrayAsWideChar#
+
+
+read# :: M s -> I64 -> ST s Char
+read# = readWideCharArray#
+
+write# :: M s -> I64 -> Char -> ST_ s
+write# = writeWideCharArray#
diff --git a/src/Array/Char8.hs b/src/Array/Char8.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/Char8.hs
@@ -0,0 +1,13 @@
+module Array.Char8 where
+import Array.Byte
+
+index# :: A
+       -> I64 -- ^ offset in bytes
+       -> Char8#
+index# = indexCharArray#
+
+read# :: M s -> I64 -> ST s Char8#
+read# = readCharArray#
+
+write# :: M s -> I64 -> Char8# -> ST_ s
+write# = writeCharArray#
diff --git a/src/Array/F32.hs b/src/Array/F32.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/F32.hs
@@ -0,0 +1,11 @@
+module Array.F32 where
+import Array.Byte
+
+index# :: A -> I64 -> F32
+index# = indexFloatArray#
+
+read# :: M s -> I64 -> ST s F32
+read# = readFloatArray#
+
+write# :: M s -> I64 -> F32 -> ST_ s
+write# = writeFloatArray#
diff --git a/src/Array/F64.hs b/src/Array/F64.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/F64.hs
@@ -0,0 +1,11 @@
+module Array.F64 where
+import Array.Byte
+
+index# :: A -> I64 -> F64
+index# = indexDoubleArray#
+
+read# :: M s -> I64 -> ST s F64
+read# = readDoubleArray#
+
+write# :: M s -> I64 -> F64 -> ST_ s
+write# = writeDoubleArray#
diff --git a/src/Array/I16.hs b/src/Array/I16.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/I16.hs
@@ -0,0 +1,18 @@
+module Array.I16 where
+import Array.Byte
+
+index# :: A
+       -> I64 -- Offset in elments
+       -> I16
+index# = indexInt16Array#
+
+index## :: A
+        -> I64 -- Offset in bytes
+        -> I16
+index## = indexWord8ArrayAsInt16#
+
+read# :: M s -> I64 -> ST s I16
+read# = readInt16Array#
+
+write# :: M s -> I64 -> I16 -> ST_ s
+write# = writeInt16Array#
diff --git a/src/Array/I32.hs b/src/Array/I32.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/I32.hs
@@ -0,0 +1,18 @@
+module Array.I32 where
+import Array.Byte
+
+index# :: A
+       -> I64 -- Offset in elments
+       -> I32
+index# = indexInt32Array#
+
+index## :: A
+        -> I64 -- Offset in bytes
+        -> I32
+index## = indexWord8ArrayAsInt32#
+
+read# :: M s -> I64 -> ST s I32
+read# = readInt32Array#
+
+write# :: M s -> I64 -> I32 -> ST_ s
+write# = writeInt32Array#
diff --git a/src/Array/I64.hs b/src/Array/I64.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/I64.hs
@@ -0,0 +1,63 @@
+module Array.I64 where
+import Array.Byte
+
+index# :: A
+       -> I64 -- Offset in elments
+       -> I64
+index# = indexInt64Array#
+
+index## :: A
+        -> I64 -- Offset in bytes
+        -> I64
+index## = indexWord8ArrayAsInt64#
+
+read#, readA# :: M s -> I64 -> ST s I64
+read# = readIntArray#
+readA# = atomicReadIntArray#
+
+
+write#,writeA# :: M s -> I64 -> I64 -> ST_ s
+write# = writeIntArray#
+writeA# = atomicWriteIntArray#
+
+cas# :: M s
+    -> I64 -- ^ Source offset
+    -> I64 -- ^ Expected old value
+    -> I64 -- ^ New value
+    -> ST s I64 -- ^ The actual old value
+cas# = casIntArray#
+
+fetchAdd :: M s -- ^ Source
+         -> I64 -- ^ Source offset
+         -> I64 -- ^ Value to add
+         -> ST s I64 -- ^ The old value
+fetchAdd = fetchAddIntArray#
+
+fetchSub :: M s -- ^ Source
+         -> I64 -- ^ Source offset
+         -> I64 -- ^ Value to subtract
+         -> ST s I64 -- ^ The old value
+fetchSub = fetchSubIntArray#
+
+fetchAnd :: M s -- ^ Source
+         -> I64 -- ^ Source offset
+         -> I64 -- ^ Value to bitwise @and@
+         -> ST s I64 -- ^ The old value
+fetchAnd = fetchAndIntArray#
+
+fetchNand :: M s -- ^ Source
+          -> I64 -- ^ Source offset
+          -> I64 -- ^ Value to bitwise @nand@
+          -> ST s I64 -- ^ The old value
+fetchNand = fetchNandIntArray#
+fetchOr  :: M s -- ^ Source
+         -> I64 -- ^ Source offset
+         -> I64 -- ^ Value to bitwise @or@
+         -> ST s I64 -- ^ The old value
+fetchOr = fetchOrIntArray#
+
+fetchXor :: M s -- ^ Source
+         -> I64 -- ^ Source offset
+         -> I64 -- ^ Value to bitwise @xor@
+         -> ST s I64 -- ^ The old value
+fetchXor = fetchXorIntArray#
diff --git a/src/Array/I8.hs b/src/Array/I8.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/I8.hs
@@ -0,0 +1,13 @@
+module Array.I8 where
+import Array.Byte
+
+index# :: A
+       -> I64 -- ^ Offset in elments
+       -> I8
+index# = indexInt8Array#
+
+read# :: M s -> I64 -> ST s I8
+read# = readInt8Array#
+
+write# :: M s -> I64 -> I8 -> ST_ s
+write# = writeInt8Array#
diff --git a/src/Array/Ref/Stable.hs b/src/Array/Ref/Stable.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/Ref/Stable.hs
@@ -0,0 +1,19 @@
+module Array.Ref.Stable where
+import Array.Byte
+import qualified Ref
+
+index# :: A
+       -> I64 -- Offset in elments
+       -> Ref.Stable a
+index# = indexStablePtrArray#
+
+index## :: A
+        -> I64 -- Offset in bytes
+        -> Ref.Stable a
+index## = indexWord8ArrayAsStablePtr#
+
+read# :: M s -> I64 -> ST s (Ref.Stable a)
+read# = readStablePtrArray#
+
+write# :: M s -> I64 -> Ref.Stable a -> ST_ s
+write# = writeStablePtrArray#
diff --git a/src/Array/Small.hs b/src/Array/Small.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/Small.hs
@@ -0,0 +1,112 @@
+module Array.Small where
+import Prelude hiding (Array)
+
+type A = SmallArray#
+type M = SmallMutableArray#
+
+new :: I64 -> a -> ST s (M s a)
+new = newSmallArray#
+
+eq :: M s a -> M s a -> B
+eq = sameSmallMutableArray#
+
+shrink :: M s a -> I64 -> ST_ s
+shrink = shrinkSmallMutableArray#
+
+read :: M s a -> I64 -> ST s a
+read = readSmallArray#
+
+write :: M s a -> I64 -> a -> ST_ s
+write = writeSmallArray#
+
+-- | Number of elements
+size :: A a -> I64
+size = sizeofSmallArray#
+
+-- | Number of elements. Must be in @ST@ because of possible resizes.
+sizeM# :: M s a -> ST s I64
+sizeM# = getSizeofSmallMutableArray#
+
+-- | Read from the specified index of an immutable array.
+-- The result is packaged into an unboxed unary tuple; the result itself is not yet evaluated.
+-- Pattern matching on the tuple forces the indexing of the array to happen
+-- but does not evaluate the element itself. Evaluating the thunk prevents
+-- additional thunks from building up on the heap. Avoiding these thunks, in turn,
+-- reduces references to the argument array, allowing it to be garbage collected more promptly.
+-- Warning: this can fail with an unchecked exception.
+index# :: A a -> I64 -> (# a #)
+index# = indexSmallArray#
+
+-- | Make a mutable array immutable, without copying.
+freeze## :: M s a -> ST s (A a)
+freeze## = unsafeFreezeSmallArray#
+
+-- | Make an immutable array mutable, without copying.
+thaw## :: A a -> ST s (M s a)
+thaw## = unsafeThawSmallArray#
+
+-- | Copy the elements from the source array to the destination array.
+-- Both arrays must fully contain the specified ranges, but this is not checked.
+-- The two arrays must not be the same array in different states, but this is not checked either.
+--
+-- Warning: this can fail with an unchecked exception.
+copy# :: A a -- ^ source
+      -> I64 -- ^ source offset
+      -> M s a -- ^ destination
+      -> I64 -- ^ destination offset
+      -> I64 -- ^ number of elements to copy
+      -> ST_ s
+copy# = copySmallArray#
+
+-- | Copy the elements from the source array to the destination array.
+-- Both arrays must fully contain the specified ranges, but this is not checked.
+-- The two arrays must not be the same array in different states, but this is not checked either.
+--
+-- Warning: this can fail with an unchecked exception.
+copyM# :: M s a -- ^ source
+       -> I64 -- ^ source offset
+       -> M s a -- ^ destination
+       -> I64 -- ^ destination offset
+       -> I64 -- ^ number of elements to copy
+       -> ST_ s
+copyM# = copySmallMutableArray#
+
+-- | Create a new array with the elements from the source array.
+-- The provided array must fully contain the specified range, but this is not checked.
+--
+-- Warning: this can fail with an unchecked exception.
+clone# :: A a
+       -> I64 -- ^ Source offset
+       -> I64 -- ^ number of elements to copy
+       -> A a
+clone# = cloneSmallArray#
+
+-- | Create a new array with the elements from the source array.
+-- The provided array must fully contain the specified range, but this is not checked.
+--
+-- Warning: this can fail with an unchecked exception.
+cloneM# :: M s a
+        -> I64 -- ^ Source offset
+        -> I64 -- ^ number of elements to copy
+        -> ST s (M s a)
+cloneM# = cloneSmallMutableArray#
+
+freeze# :: M s a
+        -> I64 -- ^ Source offset
+        -> I64 -- ^ number of elements to copy
+        -> ST s (A a)
+freeze# = freezeSmallArray#
+
+thaw# ::  A a
+        -> I64 -- ^ Source offset
+        -> I64 -- ^ number of elements to copy
+        -> ST s (M s a)
+thaw# = thawSmallArray#
+
+cas :: M s a
+    -> I64 -- ^ Source offset
+    -> a -- ^ Expected old value
+    -> a -- ^ New value
+    -> ST s (# B, a #) -- ^ Whether the swap failed, and the actual new value
+cas as o a0 a1 s0 = case casSmallArray# as o a0 a1 s0 of
+  (# s1, failed', a #) -> (# s1, (# failed', a #) #)
diff --git a/src/Array/U16.hs b/src/Array/U16.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/U16.hs
@@ -0,0 +1,19 @@
+module Array.U16 where
+import Array.Byte
+
+index# :: A
+       -> I64 -- Offset in elments
+       -> U16
+index# = indexWord16Array#
+
+index## :: A
+        -> I64 -- Offset in bytes
+        -> U16
+index## = indexWord8ArrayAsWord16#
+
+
+read# :: M s -> I64 -> ST s U16
+read# = readWord8Array#
+
+write# :: M s -> I64 -> U16 -> ST_ s
+write# = writeWord8Array#
diff --git a/src/Array/U32.hs b/src/Array/U32.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/U32.hs
@@ -0,0 +1,18 @@
+module Array.U32 where
+import Array.Byte
+
+index# :: A
+       -> I64 -- Offset in elments
+       -> U32
+index# = indexWord32Array#
+
+index## :: A
+        -> I64 -- Offset in bytes
+        -> U32
+index## = indexWord8ArrayAsWord32#
+
+read# :: M s -> I64 -> ST s U32
+read# = readWord32Array#
+
+write# :: M s -> I64 -> U32 -> ST_ s
+write# = writeWord32Array#
diff --git a/src/Array/U64.hs b/src/Array/U64.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/U64.hs
@@ -0,0 +1,18 @@
+module Array.U64 where
+import Array.Byte
+
+index# :: A
+       -> I64 -- Offset in elments
+       -> U64
+index# = indexWord64Array#
+
+index## :: A
+        -> I64 -- Offset in bytes
+        -> U64
+index## = indexWord8ArrayAsWord64#
+
+read# :: M s -> I64 -> ST s U64
+read# = readWord8Array#
+
+write# :: M s -> I64 -> U64 -> ST_ s
+write# = writeWord8Array#
diff --git a/src/Array/U8.hs b/src/Array/U8.hs
new file mode 100644
--- /dev/null
+++ b/src/Array/U8.hs
@@ -0,0 +1,11 @@
+module Array.U8 where
+import Array.Byte
+
+index# :: A -> I64 -> U8
+index# = indexWord8Array#
+
+read# :: M s -> I64 -> ST s U8
+read# = readWord8Array#
+
+write# :: M s -> I64 -> U8 -> ST_ s
+write# = writeWord8Array#
diff --git a/src/B16.hs b/src/B16.hs
new file mode 100644
--- /dev/null
+++ b/src/B16.hs
@@ -0,0 +1,19 @@
+module B16 (B16, module B16) where
+
+fromU64 :: U64 -> B16
+fromU64 = narrow16Word#
+
+-- | Count the number of set bits
+popCnt,clz,ctz :: B16 -> B16
+popCnt = popCnt16#; clz = clz16#; ctz = ctz16#
+
+byteSwap :: B16 -> B16
+byteSwap = byteSwap16#
+pext :: B16 -> U64 -> B16
+pext y x = pext16# x y
+pdep :: B16 -> U64 -> U64
+pdep y x = pdep16# x y
+
+-- | Reverse the order of the bits.
+reverse :: B16 -> B16
+reverse = bitReverse16#
diff --git a/src/B32.hs b/src/B32.hs
new file mode 100644
--- /dev/null
+++ b/src/B32.hs
@@ -0,0 +1,20 @@
+module B32 (B32, module B32) where
+
+fromU64 :: U64 -> B32
+fromU64 = narrow32Word#
+
+-- | Count the number of set bits
+popCnt,clz,ctz :: B32 -> B32
+popCnt = popCnt32#; clz = clz32#; ctz = ctz32#
+
+byteSwap :: B32 -> B32
+byteSwap = byteSwap32#
+
+pext :: B32 -> U64 -> B32
+pext y x = pext32# x y
+pdep :: B32 -> U64 -> U64
+pdep y x = pdep32# x y
+
+-- | Reverse the order of the bits.
+reverse :: B32 -> B32
+reverse = bitReverse32#
diff --git a/src/B64.hs b/src/B64.hs
new file mode 100644
--- /dev/null
+++ b/src/B64.hs
@@ -0,0 +1,59 @@
+module B64 (B64, module B64) where
+import qualified GHC.Types as GHC
+
+eq, ne :: B64 -> B64 -> B
+eq x y = eqWord# x y
+ne x y = neWord# x y
+
+fromInt :: Int -> B64
+fromInt = int2Word#
+toInt :: B64 -> Int
+toInt = word2Int#
+
+toF32 :: B64 -> F32
+toF32 = word2Float#
+toF64 :: B64 -> F64
+toF64 = word2Double#
+
+toU8 :: B64 -> U8
+toU8 = narrow8Word#
+toU16 :: B64 -> U16
+toU16 = narrow16Word#
+toU32 :: B64 -> U32
+toU32 = narrow32Word#
+
+toB8 :: B64 -> B8
+toB8 = narrow8Word#
+toB16 :: B64 -> B16
+toB16 = narrow16Word#
+toB32 :: B64 -> B32
+toB32 = narrow32Word#
+
+and,or,xor :: B64 -> B64 -> B64
+and = and#
+or = or#
+xor = xor#
+not :: B64 -> B64
+not = not#
+
+-- | Shift left.  Result undefined if shift amount is not
+--           in the range 0 to word size - 1 inclusive.
+shiftL#, shiftRL# :: Int -> B64 -> B64
+shiftL# i w = uncheckedShiftL# w i
+
+-- |Shift right logical.  Result undefined if shift amount is not
+--           in the range 0 to word size - 1 inclusive.
+shiftRL# i w = uncheckedShiftRL# w i
+
+-- | Count the number of set bits
+popCnt,clz,ctz :: B64 -> U8
+popCnt = popCnt#; clz = clz#; ctz = ctz#
+
+byteSwap :: B64 -> B64
+byteSwap = byteSwap#
+pdep, pext :: B64 -> B64 -> B64
+pdep y x = pdep# x y; pext y x = pext# x y
+
+-- | Reverse the order of the bits.
+reverse :: B64 -> B64
+reverse = bitReverse#
diff --git a/src/B8.hs b/src/B8.hs
new file mode 100644
--- /dev/null
+++ b/src/B8.hs
@@ -0,0 +1,17 @@
+module B8 (B8, module B8) where
+
+fromU64 :: U64 -> B8
+fromU64 = narrow8Word#
+
+-- | Count the number of set bits
+popCnt,clz,ctz :: B8 -> B8
+popCnt = popCnt8#; clz = clz8#; ctz = ctz8#
+
+pext :: B8 -> U64 -> B8
+pext y x = pext8# x y
+pdep :: B8 -> U64 -> U64
+pdep y x = pdep8# x y
+
+-- | Reverse the order of the bits.
+reverse :: B8 -> B8
+reverse = bitReverse8#
diff --git a/src/BCO.hs b/src/BCO.hs
new file mode 100644
--- /dev/null
+++ b/src/BCO.hs
@@ -0,0 +1,10 @@
+module BCO where
+import qualified Array
+
+type BCO = BCO#
+
+mkApUpd0 :: BCO -> (# a #)
+mkApUpd0 = mkApUpd0#
+
+new :: Array.Byte -> Array.Byte -> Array.Boxed a -> I64 -> Array.Byte -> ST s BCO
+new = newBCO#
diff --git a/src/Char.hs b/src/Char.hs
new file mode 100644
--- /dev/null
+++ b/src/Char.hs
@@ -0,0 +1,13 @@
+module Char where
+
+gt y x = gtChar# x y
+ge y x = geChar# x y
+lt y x = ltChar# x y
+le y x = leChar# x y
+eq x y = eqChar# x y
+ne x y = neChar# x y
+
+fromInt :: Int -> Char
+fromInt = chr#
+toInt :: Char -> Int
+toInt = ord#
diff --git a/src/Coerce.hs b/src/Coerce.hs
new file mode 100644
--- /dev/null
+++ b/src/Coerce.hs
@@ -0,0 +1,11 @@
+module Coerce where
+import qualified Prelude as GHC
+import qualified GHC.Types as GHC
+
+type (=#) = GHC.Coercible
+
+coerce :: forall b a. a =# b => a -> b
+coerce = GHC.coerce
+
+coerce# :: forall b a. a -> b
+coerce# = GHC.unsafeCoerce#
diff --git a/src/Compact.hs b/src/Compact.hs
new file mode 100644
--- /dev/null
+++ b/src/Compact.hs
@@ -0,0 +1,39 @@
+module Compact where
+import qualified Ref
+
+type Compact = Compact#
+type Block# = (# Ref.Byte, U64 #)
+
+new :: U64 -> IO Compact
+new = compactNew#
+resize :: Compact -> U64 -> IO_
+resize = compactResize#
+elem' :: a -> Compact -> IO B
+elem' a c = compactContains# c a
+
+elemOfAny' :: a -> IO B
+elemOfAny' = compactContainsAny#
+
+-- | The address and size (in bytes) of the first block of a @Compact@
+head :: Compact -> IO Block#
+head c s0 = case compactGetFirstBlock# c s0 of
+  (# s1, a, n #) -> (# s1, (# a, n #) #)
+
+next :: Compact -> Ref.Byte -> IO Block#
+next c a0 s0 = case compactGetNextBlock# c a0 s0 of
+  (# s1, a1, n #) -> (# s1, (# a1, n #) #)
+
+allocate :: Block# -> IO Ref.Byte
+allocate (# a, n #) = compactAllocateBlock# n a
+
+fixup :: Ref.Byte -> Ref.Byte -> IO (# Compact, Ref.Byte #)
+fixup b0 root s0 = case compactFixupPointers# b0 root s0 of
+  (# s1, c, b1 #) -> (# s1, (# c, b1 #) #)
+
+insert, insertShared :: a -> Compact -> IO a
+insert a c = compactAdd# c a
+insertShared a c = compactAddWithSharing# c a
+
+size :: Compact -> IO U64
+size = compactSize#
+
diff --git a/src/Enum.hs b/src/Enum.hs
new file mode 100644
--- /dev/null
+++ b/src/Enum.hs
@@ -0,0 +1,10 @@
+{-# language ScopedTypeVariables, RankNTypes, TypeApplications #-}
+module Enum
+  (-- | Must be evaluated, not a thunk
+   dataToTag# 
+  -- | @a@ must be an enum type
+  ,tagToEnum#
+  ) where
+
+-- Note we can't fiddle with tagToEnum# eg to rename
+-- because of ghc magic prefenting it used at higher order
diff --git a/src/Exception.hs b/src/Exception.hs
new file mode 100644
--- /dev/null
+++ b/src/Exception.hs
@@ -0,0 +1,12 @@
+module Exception where
+
+-- | Can only catch values with an @Exception@ instance.
+catch# :: IO a -> (e -> IO a) -> IO a
+catch# = Prelude.catch#
+
+-- | Raising values other than type @SomeException@ leads to segfault
+raise# :: e -> a
+raise# = Prelude.raise#
+-- | Raising values other than type @SomeException@ leads to segfault
+raiseIO# :: e -> IO a
+raiseIO# = Prelude.raiseIO#
diff --git a/src/Exception/Mask.hs b/src/Exception/Mask.hs
new file mode 100644
--- /dev/null
+++ b/src/Exception/Mask.hs
@@ -0,0 +1,21 @@
+{-# language PatternSynonyms #-}
+module Exception.Mask where
+import Prelude hiding (State#)
+
+async :: IO a -> IO a
+async = maskAsyncExceptions#
+
+uninterruptible :: IO a -> IO a
+uninterruptible = maskUninterruptible#
+
+state :: IO State#
+state = getMaskingState#
+
+type State# = I64
+
+pattern Unmasked :: State#
+pattern Unmasked = 0#
+pattern Uninterruptible :: State#
+pattern Uninterruptible = 1#
+pattern Interruptible :: State#
+pattern Interruptible = 2#
diff --git a/src/F32.hs b/src/F32.hs
new file mode 100644
--- /dev/null
+++ b/src/F32.hs
@@ -0,0 +1,39 @@
+module F32 (F32, module F32) where
+
+add,sub,mul,div :: F32 -> F32 -> F32
+add y x = plusFloat# x y
+sub y x = minusFloat# x y
+mul y x = timesFloat# x y
+div y x = divideFloat# x y
+
+negate,abs,exp,log,sqrt,sin,cos,tan,asin,acos,atan,sinh,cosh,tanh :: F32 -> F32
+negate = negateFloat#
+abs = fabsFloat#
+exp = expFloat#; log = logFloat#
+sqrt = sqrtFloat#
+sin = sinFloat#; cos = cosFloat#; tan = tanFloat#
+asin = asinFloat#; acos = acosFloat#; atan = atanFloat#
+sinh = sinhFloat#; cosh = coshFloat#; tanh = tanhFloat#
+
+pow :: F32 -> F32 -> F32
+pow y x = powerFloat# x y
+
+gt,ge,lt,le,eq,ne :: F32 -> F32 -> B
+gt y x = gtFloat# x y
+ge y x = geFloat# x y
+lt y x = ltFloat# x y
+le y x = leFloat# x y
+eq x y = eqFloat# x y
+ne x y = neFloat# x y
+
+toInt :: F32 -> I64
+toInt = float2Int#
+fromInt:: I64 -> F32
+fromInt = int2Float#
+toF64 :: F32 -> F64
+toF64 = float2Double#
+fromF64 :: F64 -> F32
+fromF64 = double2Float#
+
+decodeI64 :: F32 -> (# I64, I64 #)
+decodeI64 = decodeFloat_Int#
diff --git a/src/F64.hs b/src/F64.hs
new file mode 100644
--- /dev/null
+++ b/src/F64.hs
@@ -0,0 +1,43 @@
+module F64 (F64, module F64) where
+
+add,sub,mul,div :: F64 -> F64 -> F64
+add y x = x +## y
+sub y x = x -## y
+-- | Low word of signed integer multiply
+mul y x = x *## y
+div y x = x /## y
+negate,abs,exp,log,sqrt,sin,cos,tan,asin,acos,atan,sinh,cosh,tanh :: F64 -> F64
+negate = negateDouble#
+abs = fabsDouble#
+exp = expDouble#; log = logDouble#
+sqrt = sqrtDouble#
+sin = sinDouble#; cos = cosDouble#; tan = tanDouble#
+asin = asinDouble#; acos = acosDouble#; atan = atanDouble#
+sinh = sinhDouble#; cosh = coshDouble#; tanh = tanhDouble#
+
+pow :: F64 -> F64 -> F64
+pow y x = x **## y
+
+decode2Int :: F64 -> (# Int, U64, U64, Int #)
+decode2Int = decodeDouble_2Int#  
+decodeI64 :: F64 -> (# Int, Int #)
+decodeI64 = decodeDouble_Int64#
+
+
+gt y x = x >## y
+ge y x = x >=## y
+lt y x = x <## y
+le y x = x <=## y
+eq x y = x ==## y
+ne x y = x /=## y
+
+fromInt :: Int -> F64
+fromInt = int2Double#
+toInt :: F64 -> Int
+toInt = double2Int#
+fromU64 :: U64 -> F64
+fromU64 = word2Double#
+toF32 :: F64 -> F32
+toF32 = double2Float#
+fromF32 :: F32 -> F64
+fromF32 = float2Double#
diff --git a/src/I16.hs b/src/I16.hs
new file mode 100644
--- /dev/null
+++ b/src/I16.hs
@@ -0,0 +1,1 @@
+module I16 (I16) where
diff --git a/src/I32.hs b/src/I32.hs
new file mode 100644
--- /dev/null
+++ b/src/I32.hs
@@ -0,0 +1,1 @@
+module I32 (I32) where
diff --git a/src/I64.hs b/src/I64.hs
new file mode 100644
--- /dev/null
+++ b/src/I64.hs
@@ -0,0 +1,109 @@
+module I64 (I64, module I64) where
+import qualified GHC.Types 
+
+add,sub,mul, quot, rem :: I64 -> I64 -> I64
+add y x = x +# y
+sub y x = x -# y
+-- | Low word of signed integer multiply
+mul y x = x *# y
+-- |Return non-zero if there is any possibility that the upper word of a
+--     signed integer multiply might contain useful information.  Return
+--     zero only if you are completely sure that no overflow can occur.
+--     On a 32-bit platform, the recommended implementation is to do a
+--     32 x 32 -> 64 signed multiply, and subtract result[63:32] from
+--     (result[31] >>signed 31).  If this is zero, meaning that the
+--     upper word is merely a sign extension of the lower one, no
+--     overflow can occur.
+--
+--     On a 64-bit platform it is not always possible to
+--     acquire the top 64 bits of the result.  Therefore, a recommended
+--     implementation is to take the absolute value of both operands, and
+--     return 0 iff bits[63:31] of them are zero, since that means that their
+--     magnitudes fit within 31 bits, so the magnitude of the product must fit
+--     into 62 bits.
+--
+--     If in doubt, return non-zero, but do make an effort to create the
+--     correct answer for small args, since otherwise the performance of
+--     @(*) :: I64eger -> I64eger -> I64eger@ will be poor.
+mulMayOflo :: I64 -> I64 -> B
+mulMayOflo x y = mulIntMayOflo# x y
+negate :: I64 -> I64
+negate = negateInt#
+-- | Rounds towards zero. The behavior is undefined if the first argument is zero.
+quot y x = quotInt# x y
+-- |Satisfies @(add (rem y x) (mul y (quot y x)) == x@. The
+--     behavior is undefined if the first argument is zero.
+rem y x = remInt# x y
+quotRem :: I64 -> I64 -> (# I64, I64 #)
+-- | Rounds towards zero
+quotRem y x = quotRemInt# x y
+
+addC, subC :: I64 -> I64 -> (# I64, B #)
+-- |Add signed integers reporting overflow.
+--           First member of result is the sum truncated to an @I64@;
+--           second member is zero if the true sum fits in an @I64@,
+--           nonzero if overflow occurred (the sum is either too large
+--           or too small to fit in an @I64@).
+addC y x = addIntC# x y
+-- |Subtract signed integers reporting overflow.
+--           First member of result is the difference truncated to an @I64@;
+--           second member is zero if the true difference fits in an @I64@,
+--           nonzero if overflow occurred (the difference is either too large
+--           or too small to fit in an @I64@).
+subC y x = subIntC# x y
+
+gt,ge,lt,le,eq,ne :: I64 -> I64 -> B
+gt y x = x ># y
+ge y x = x >=# y
+lt y x = x <# y
+le y x = x <=# y
+eq x y = x ==# y
+ne x y = x /=# y
+
+toU64 :: I64 -> U64
+toU64 = int2Word#
+fromU64 :: U64 -> I64
+fromU64 = word2Int#
+
+toF32 :: I64 -> F32
+toF32 = int2Float#
+toF64 :: I64 -> F64
+toF64 = int2Double#
+
+toI8 :: I64 -> I8
+toI8 = narrow8Int#
+toI16 :: I64 -> I16
+toI16 = narrow16Int#
+toI32 :: I64 -> I32
+toI32 = narrow32Int#
+
+
+
+-- |Shift right arithmetic.  Result undefined if shift amount is not
+--           in the range 0 to word size - 1 inclusive.
+
+shiftRA# :: I64 -> I64 -> I64
+shiftRA# = uncheckedIShiftRA#
+
+
+-- * Bitwise operations included for completeness, but signed bit operations should never be used.
+
+{-# DEPRECATED shiftL#, shiftRL#, and, or, xor "Don't use signed bitwise operations, prefer U64 instead" #-}
+
+-- | Shift left.  Result undefined if shift amount is not
+--           in the range 0 to word size - 1 inclusive.
+shiftL# :: I64 -> I64 -> I64
+shiftL# = uncheckedIShiftL# 
+
+-- |Shift right logical.  Result undefined if shift amount is not
+--           in the range 0 to word size - 1 inclusive.
+
+shiftRL# :: I64 -> I64 -> I64
+shiftRL# = uncheckedIShiftRL#
+and, or, xor :: I64 -> I64 -> I64
+and = andI#
+or = orI#
+xor = xorI#
+
+not :: I64 -> I64
+not = notI#
diff --git a/src/I8.hs b/src/I8.hs
new file mode 100644
--- /dev/null
+++ b/src/I8.hs
@@ -0,0 +1,1 @@
+module I8 (I8) where
diff --git a/src/Nat.hs b/src/Nat.hs
new file mode 100644
--- /dev/null
+++ b/src/Nat.hs
@@ -0,0 +1,2 @@
+module Nat (Nat) where
+import GHC.Types
diff --git a/src/Optimizer.hs b/src/Optimizer.hs
new file mode 100644
--- /dev/null
+++ b/src/Optimizer.hs
@@ -0,0 +1,5 @@
+module Optimizer (module X) where
+import GHC.Magic as X
+import GHC.Types as X (SPEC(..))
+
+
diff --git a/src/Prelude.hs b/src/Prelude.hs
new file mode 100644
--- /dev/null
+++ b/src/Prelude.hs
@@ -0,0 +1,40 @@
+{-# OPTIONS_HADDOCK not-home  #-}
+{-# language TypeOperators #-}
+module Prelude (module Prelude, module X) where
+import GHC.Prim as X
+import           GHC.Types as X (TYPE)
+import qualified GHC.Types as GHC
+import ST as X (ST,ST_)
+import ST.IO as X
+
+-- TODO: use hsboot instead of this file
+-- TODO: add safe versions of the sized numbers
+
+type Char = Char#
+type Char8# = Char#
+
+type Int = Int#
+type I64 = Int#
+type I32 = Int#
+type I16 = Int#
+type I8 = Int#
+
+type U8 = Word#
+type U16 = Word#
+type U32 = Word#
+type U64 = Word#
+
+type B = Int#
+type B8 = Word#
+type B16 = Word#
+type B32 = Word#
+type B64 = Word#
+
+type F32 = Float#
+type F64 = Double#
+
+type Maybe# (a :: TYPE r) = (# B, a #)
+
+
+type T = GHC.Type
+type C = GHC.Constraint
diff --git a/src/Proxy.hs b/src/Proxy.hs
new file mode 100644
--- /dev/null
+++ b/src/Proxy.hs
@@ -0,0 +1,8 @@
+{-# language PatternSynonyms #-}
+module Proxy where
+
+type Proxy = Proxy#
+
+-- | Hack to expose 'proxy#'
+pattern Proxy :: Proxy a
+pattern Proxy <- proxy# where Proxy = proxy#
diff --git a/src/RTS/Block.hs b/src/RTS/Block.hs
new file mode 100644
--- /dev/null
+++ b/src/RTS/Block.hs
@@ -0,0 +1,10 @@
+module RTS.Block where
+
+delay :: I64 {- ^ microseconds to wait -} -> ST_ s
+delay = delay#
+
+-- TODO: use a convenience type for file descriptors once you understand how they work.
+waitRead,waitWrite :: I64 -> ST_ s
+waitRead = waitRead#
+waitWrite = waitWrite#
+
diff --git a/src/RTS/Prefetch/Any.hs b/src/RTS/Prefetch/Any.hs
new file mode 100644
--- /dev/null
+++ b/src/RTS/Prefetch/Any.hs
@@ -0,0 +1,7 @@
+module RTS.Prefetch.Any where
+
+t0, t1, t2, t3 :: a -> ST_ s
+t0 = prefetchValue0#
+t1 = prefetchValue1#
+t2 = prefetchValue2#
+t3 = prefetchValue3#
diff --git a/src/RTS/Prefetch/Array.hs b/src/RTS/Prefetch/Array.hs
new file mode 100644
--- /dev/null
+++ b/src/RTS/Prefetch/Array.hs
@@ -0,0 +1,8 @@
+module RTS.Prefetch.Array where
+import qualified Array
+
+t0, t1, t2, t3 :: Array.Byte -> I64 {- ^ offset -} -> ST_ s
+t0 = prefetchByteArray0#
+t1 = prefetchByteArray1#
+t2 = prefetchByteArray2#
+t3 = prefetchByteArray3#
diff --git a/src/RTS/Prefetch/Array/M.hs b/src/RTS/Prefetch/Array/M.hs
new file mode 100644
--- /dev/null
+++ b/src/RTS/Prefetch/Array/M.hs
@@ -0,0 +1,8 @@
+module RTS.Prefetch.Array.M where
+import qualified Array.Byte
+
+t0, t1, t2, t3 :: Array.Byte.M s -> I64 {- ^ offset -} -> ST_ s
+t0 = prefetchMutableByteArray0#
+t1 = prefetchMutableByteArray1#
+t2 = prefetchMutableByteArray2#
+t3 = prefetchMutableByteArray3#
diff --git a/src/RTS/Prefetch/Ref.hs b/src/RTS/Prefetch/Ref.hs
new file mode 100644
--- /dev/null
+++ b/src/RTS/Prefetch/Ref.hs
@@ -0,0 +1,8 @@
+module RTS.Prefetch.Ref where
+import qualified Ref
+
+t0, t1, t2, t3 :: Ref.Byte -> I64 {- ^ offset -} -> ST_ s
+t0 = prefetchAddr0#
+t1 = prefetchAddr1#
+t2 = prefetchAddr2#
+t3 = prefetchAddr3#
diff --git a/src/Ref.hs b/src/Ref.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref.hs
@@ -0,0 +1,8 @@
+module Ref where
+
+type Byte = Addr#
+type Weak = Weak#
+type Stable = StablePtr#
+type Boxed = MutVar#
+type STM = TVar#
+type Lock = MVar#
diff --git a/src/Ref/Boxed.hs b/src/Ref/Boxed.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/Boxed.hs
@@ -0,0 +1,40 @@
+module Ref.Boxed where
+import qualified Ref
+
+type Ref = MutVar#
+
+new :: a -> ST s (Ref s a)
+new = newMutVar#
+
+read :: Ref s a -> ST s a
+read = readMutVar#
+
+write :: Ref s a -> a -> ST_ s
+write = writeMutVar#
+
+eq :: Ref s a -> Ref s a -> B
+eq = sameMutVar#
+
+-- | Modify the contents of a @Ref.Boxed@, returning the previous contents and the result of applying the given function to the previous contents. Note that this isn't strictly speaking the correct type for this function; it should really be MutVar# s a -> (a -> (a,b)) -> State# s -> (# State# s, a, (a, b) #), but we don't know about pairs here.
+-- 
+-- Warning: this can fail with an unchecked exception.
+
+
+modify :: Ref s a
+       -> (a -> b)
+       -> ST s (# a, b #) -- ^ Previous contents and the result of applying the function
+modify r f s0 = case atomicModifyMutVar2# r f s0 of
+  (# s1, old, new #) -> (# s1, (# old, new #) #)
+
+modify_ :: Ref s a
+        -> (a -> a)
+        -> ST s (# a, a #) -- ^ Previous contents and the result of applying the function
+modify_ r f s0 = case atomicModifyMutVar2# r f s0 of
+  (# s1, old, new #) -> (# s1, (# old, new #) #)
+
+cas :: Ref s a
+    -> a -- ^ expected old value
+    -> a -- ^ new value
+    -> ST s (# B, a #) -- ^ Whether the swap failed, and the actual new value
+cas r old new s0 = case casMutVar# r old new s0 of
+  (# s1, failed', a #) -> (# s1, (# failed', a #) #)
diff --git a/src/Ref/Byte.hs b/src/Ref/Byte.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/Byte.hs
@@ -0,0 +1,38 @@
+{-# language PatternSynonyms #-}
+module Ref.Byte where
+
+type Ref = Addr#
+
+-- | hack to expose nullAddr#
+pattern Null :: Ref
+pattern Null <- nullAddr# where Null = nullAddr#
+
+add :: I64 -> Ref -> Ref
+add i a = plusAddr# a i
+
+sub :: Ref -> Ref -> I64
+sub a0 a1 = minusAddr# a1 a0
+
+rem :: I64 -> Ref -> I64
+rem i a = remAddr# a i
+
+toI64 :: Ref -> I64
+toI64 = addr2Int#
+fromI64 :: I64 -> Ref
+fromI64 = int2Addr#
+{-# DEPRECATED toI64, fromI64 "This operation is strongly deprecated" #-}
+
+gt,ge,lt,le,eq,ne :: Ref -> Ref -> B
+gt y x = gtAddr# x y
+ge y x = geAddr# x y
+lt y x = ltAddr# x y
+le y x = leAddr# x y
+eq x y = eqAddr# x y
+ne x y = neAddr# x y
+
+toAny :: Ref-> (# a #)
+toAny = addrToAny#
+
+-- | Must be run on an evaluated value, not a thunk
+fromAny# :: a -> IO Ref
+fromAny# = anyToAddr#
diff --git a/src/Ref/Char.hs b/src/Ref/Char.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/Char.hs
@@ -0,0 +1,11 @@
+module Ref.Char where
+import Ref.Byte
+
+index# :: Ref -> I64 {- ^ Offset in elments -} -> Char
+index# = indexWideCharOffAddr#
+
+read# :: Ref -> I64 -> ST s Char
+read# = readWideCharOffAddr#
+
+write# :: Ref -> I64 -> Char -> ST_ s
+write# = writeWideCharOffAddr#
diff --git a/src/Ref/Char8.hs b/src/Ref/Char8.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/Char8.hs
@@ -0,0 +1,11 @@
+module Ref.Char8 where
+import Ref.Byte
+
+index# :: Ref -> I64 {- ^ Offset in elments -} -> Char8#
+index# = indexCharOffAddr#
+
+read# :: Ref -> I64 -> ST s Char8#
+read# = readCharOffAddr#
+
+write# :: Ref -> I64 -> Char8# -> ST_ s
+write# = writeCharOffAddr#
diff --git a/src/Ref/F32.hs b/src/Ref/F32.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/F32.hs
@@ -0,0 +1,11 @@
+module Ref.F32 where
+import Ref.Byte
+
+index# :: Ref -> I64 {- ^ Offset in elments -} -> F32
+index# = indexFloatOffAddr#
+
+read# :: Ref -> I64 {- ^ Offset in elements -} -> ST s F32
+read# = readFloatOffAddr#
+
+write# :: Ref -> I64 {- ^ Offset in elements -} -> F32 -> ST_ s
+write# = writeFloatOffAddr#
diff --git a/src/Ref/F64.hs b/src/Ref/F64.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/F64.hs
@@ -0,0 +1,11 @@
+module Ref.F64 where
+import Ref.Byte
+
+index# :: Ref -> I64 {- ^ Offset in elments -} -> F64
+index# = indexDoubleOffAddr#
+
+read# :: Ref -> I64 {- ^ Offset in elements -} -> ST s F64
+read# = readDoubleOffAddr#
+
+write# :: Ref -> I64 {- ^ Offset in elements -} -> F64 -> ST_ s
+write# = writeDoubleOffAddr#
diff --git a/src/Ref/I16.hs b/src/Ref/I16.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/I16.hs
@@ -0,0 +1,11 @@
+module Ref.I16 where
+import Ref.Byte
+
+index# :: Ref -> I64 {- ^ Offset in elments -} -> I16
+index# = indexInt16OffAddr#
+
+read# :: Ref -> I64 {- ^ Offset in elements -} -> ST s I16
+read# = readInt16OffAddr#
+
+write# :: Ref -> I64 {- ^ Offset in elements -} -> I16 -> ST_ s
+write# = writeInt16OffAddr#
diff --git a/src/Ref/I32.hs b/src/Ref/I32.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/I32.hs
@@ -0,0 +1,11 @@
+module Ref.I32 where
+import Ref.Byte
+
+index# :: Ref -> I64 {- ^ Offset in elments -} -> I32
+index# = indexInt32OffAddr#
+
+read# :: Ref -> I64 {- ^ Offset in elements -} -> ST s I32
+read# = readInt32OffAddr#
+
+write# :: Ref -> I64 {- ^ Offset in elements -} -> I32 -> ST_ s
+write# = writeInt32OffAddr#
diff --git a/src/Ref/I64.hs b/src/Ref/I64.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/I64.hs
@@ -0,0 +1,11 @@
+module Ref.I64 where
+import Ref.Byte
+
+index# :: Ref -> I64 {- ^ Offset in elments -} -> I64
+index# = indexInt64OffAddr#
+
+read# :: Ref -> I64 -> ST s I64
+read# = readInt64OffAddr#
+
+write# :: Ref -> I64 -> I64 -> ST_ s
+write# = writeInt64OffAddr#
diff --git a/src/Ref/I8.hs b/src/Ref/I8.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/I8.hs
@@ -0,0 +1,11 @@
+module Ref.I8 where
+import Ref.Byte
+
+index# :: Ref -> I64 {- ^ Offset in elments -} -> I8
+index# = indexInt8OffAddr#
+
+read# :: Ref -> I64 {- ^ Offset in elements -} -> ST s I8
+read# = readInt8OffAddr#
+
+write# :: Ref -> I64 {- ^ Offset in elements -} -> I8 -> ST_ s
+write# = writeInt8OffAddr#
diff --git a/src/Ref/Lock.hs b/src/Ref/Lock.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/Lock.hs
@@ -0,0 +1,37 @@
+module Ref.Lock where
+
+type Ref = MVar#
+
+eq :: Ref s a -> Ref s a -> B
+eq = sameMVar#
+
+empty' :: Ref s a -> ST s B
+empty' = isEmptyMVar#
+
+-- | A new empty @Ref@
+new :: ST s (Ref s a)
+new = newMVar#
+
+-- | Block until the @Ref@ is full/unlocked, then atomically take the value and lock it.
+take :: Ref s a -> ST s a
+take = takeMVar#
+
+-- | Take the current value if it exists and lock the @Ref@
+take' :: Ref s a -> ST s (Maybe# a) {- ^ The value if the @Ref@ was full/unlocked -}
+take' r s0 = case tryTakeMVar# r s0 of
+  (# s1, full', a #) -> (# s1, (# full', a #) #)
+
+-- | Block until the @Ref@ is full/unlocked, then read the value but don't lock it.
+read :: Ref s a -> ST s a
+read = readMVar#
+
+-- | Take the current value if it exists but don't lock the @Ref@
+read' :: Ref s a -> ST s (Maybe# a) {- ^ The value if the @Ref@ was full/unlocked -}
+read' r s0 = case tryReadMVar# r s0 of
+  (# s1, full', a #) -> (# s1, (# full', a #) #)
+
+write :: Ref s a -> a -> ST_ s
+write = putMVar#
+
+write' :: Ref s a -> a -> ST s B {- ^ whether the write succeeded -}
+write' = tryPutMVar#
diff --git a/src/Ref/Ref/Byte.hs b/src/Ref/Ref/Byte.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/Ref/Byte.hs
@@ -0,0 +1,12 @@
+module Ref.Ref.Byte where
+import qualified Ref
+import Ref.Byte
+
+index# :: Ref -> I64 {- ^ Offset in elments -} -> Ref.Byte
+index# = indexAddrOffAddr#
+
+read# :: Ref -> I64 {- ^ Offset in elements -} -> ST s Ref.Byte
+read# = readAddrOffAddr#
+
+write# :: Ref -> I64 {- ^ Offset in elements -} -> Ref.Byte -> ST_ s
+write# = writeAddrOffAddr#
diff --git a/src/Ref/Ref/Stable.hs b/src/Ref/Ref/Stable.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/Ref/Stable.hs
@@ -0,0 +1,12 @@
+module Ref.Ref.Stable where
+import qualified Ref
+import Ref.Byte
+
+index# :: Ref -> I64 {- ^ Offset in elments -} -> Ref.Stable a
+index# = indexStablePtrOffAddr#
+
+read# :: Ref -> I64 {- ^ Offset in elements -} -> ST s (Ref.Stable a)
+read# = readStablePtrOffAddr#
+
+write# :: Ref -> I64 {- ^ Offset in elements -} -> Ref.Stable a -> ST_ s
+write# = writeStablePtrOffAddr#
diff --git a/src/Ref/STM.hs b/src/Ref/STM.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/STM.hs
@@ -0,0 +1,20 @@
+module Ref.STM where
+
+type Ref = TVar#
+
+eq :: Ref s a -> Ref s a -> B
+eq = sameTVar#
+
+new :: a -> ST s (Ref s a)
+new = newTVar#
+
+read, readIO :: Ref s a -> ST s a
+read = readTVar#
+-- | Read a @Ref.STM@ outside the transaction, without annotating the STM ledger.
+-- Much faster than 'read'.
+readIO = readTVarIO#
+
+write :: Ref s a -> a -> ST_ s
+write = writeTVar#
+
+
diff --git a/src/Ref/Stable.hs b/src/Ref/Stable.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/Stable.hs
@@ -0,0 +1,12 @@
+module Ref.Stable where
+
+type Ref = StablePtr#
+
+new :: a -> IO (Ref a)
+new = makeStablePtr#
+
+deref :: Ref a -> IO a
+deref = deRefStablePtr#
+
+eq :: Ref a -> Ref a -> B
+eq = eqStablePtr#
diff --git a/src/Ref/Stable/Name.hs b/src/Ref/Stable/Name.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/Stable/Name.hs
@@ -0,0 +1,10 @@
+module Ref.Stable.Name where
+
+type Ref = StableName#
+
+new :: a -> IO (Ref a)
+new = makeStableName#
+eq :: Ref a -> Ref a -> B
+eq = eqStableName#
+toInt :: Ref a -> I64
+toInt = stableNameToInt#
diff --git a/src/Ref/U16.hs b/src/Ref/U16.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/U16.hs
@@ -0,0 +1,11 @@
+module Ref.U16 where
+import Ref.Byte
+
+index# :: Ref -> I64 {- ^ Offset in elments -} -> U16
+index# = indexWord16OffAddr#
+
+read# :: Ref -> I64 {- ^ Offset in elements -} -> ST s U16
+read# = readWord16OffAddr#
+
+write# :: Ref -> I64 {- ^ Offset in elements -} -> U16 -> ST_ s
+write# = writeWord16OffAddr#
diff --git a/src/Ref/U32.hs b/src/Ref/U32.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/U32.hs
@@ -0,0 +1,11 @@
+module Ref.U32 where
+import Ref.Byte
+
+index# :: Ref -> I64 {- ^ Offset in elments -} -> U32
+index# = indexWord32OffAddr#
+
+read# :: Ref -> I64 {- ^ Offset in elements -} -> ST s U32
+read# = readWord32OffAddr#
+
+write# :: Ref -> I64 {- ^ Offset in elements -} -> U32 -> ST_ s
+write# = writeWord32OffAddr#
diff --git a/src/Ref/U64.hs b/src/Ref/U64.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/U64.hs
@@ -0,0 +1,11 @@
+module Ref.U64 where
+import Ref.Byte
+
+index# :: Ref -> I64 {- ^ Offset in elments -} -> U64
+index# = indexWord64OffAddr#
+
+read# :: Ref -> I64 {- ^ Offset in elements -} -> ST s U64
+read# = readWord64OffAddr#
+
+write# :: Ref -> I64 {- ^ Offset in elements -} -> U64 -> ST_ s
+write# = writeWord64OffAddr#
diff --git a/src/Ref/U8.hs b/src/Ref/U8.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/U8.hs
@@ -0,0 +1,11 @@
+module Ref.U8 where
+import Ref.Byte
+
+index# :: Ref -> I64 {- ^ Offset in elments -} -> U8
+index# = indexWord8OffAddr#
+
+read# :: Ref -> I64 {- ^ Offset in elements -} -> ST s U8
+read# = readWord8OffAddr#
+
+write# :: Ref -> I64 {- ^ Offset in elements -} -> U8 -> ST_ s
+write# = writeWord8OffAddr#
diff --git a/src/Ref/Weak.hs b/src/Ref/Weak.hs
new file mode 100644
--- /dev/null
+++ b/src/Ref/Weak.hs
@@ -0,0 +1,24 @@
+module Ref.Weak where
+import qualified Ref
+
+type Ref = Weak#
+
+new :: k -> v -> IO x -> IO (Ref v)
+new = mkWeak# 
+
+newNoFinalizer :: k -> v -> IO (Ref v)
+newNoFinalizer = mkWeakNoFinalizer#
+
+addFinalizer :: Ref.Byte -> Ref.Byte -> B -> Ref.Byte -> Ref v -> IO B
+addFinalizer = addCFinalizerToWeak#
+
+deref :: Ref v -> IO (Maybe# v)
+deref w s0 = case deRefWeak# w s0 of
+  (# s1, alive', v #) -> (# s1, (# alive', v #) #)
+
+finalize :: Ref v -> IO (Maybe# (IO x))
+finalize w s0 = case finalizeWeak# w s0 of
+  (# s1, alive', finalizer #) -> (# s1, (# alive', finalizer #) #)
+
+touch :: k -> IO_
+touch = touch#
diff --git a/src/ST.hs b/src/ST.hs
new file mode 100644
--- /dev/null
+++ b/src/ST.hs
@@ -0,0 +1,7 @@
+{-# language NoImplicitPrelude #-}
+module ST ( ST, ST_) where
+import GHC.Prim (State#, TYPE )
+
+type Token = State#
+type ST_ s = Token s -> Token s
+type ST s (a :: TYPE r) = Token s -> (# Token s, a #)
diff --git a/src/ST/IO.hs b/src/ST/IO.hs
new file mode 100644
--- /dev/null
+++ b/src/ST/IO.hs
@@ -0,0 +1,9 @@
+{-# language NoImplicitPrelude #-}
+module ST.IO where
+import GHC.Prim (RealWorld,TYPE)
+import ST (ST,ST_)
+
+
+type (☸) = RealWorld
+type IO (a :: TYPE r) = ST (☸) a
+type IO_ = ST_ (☸)
diff --git a/src/ST/IO/STM.hs b/src/ST/IO/STM.hs
new file mode 100644
--- /dev/null
+++ b/src/ST/IO/STM.hs
@@ -0,0 +1,21 @@
+{-# language NoImplicitPrelude #-}
+module ST.IO.STM where
+import ST.IO
+import GHC.Prim
+
+type STM (a :: TYPE r) = IO a
+type STM_ = IO_
+
+atomically :: STM a -> IO a
+atomically = atomically#
+
+-- | Retry execution of the current memory transaction because it has seen values in TVars which mean that it should not continue (e.g. the TVars represent a shared buffer that is now empty).
+-- The implementation may block the thread until one of the TVars that it has read from has been updated.
+retry :: STM a
+retry = retry#
+
+catch :: STM a -> (e -> STM a) -> STM a
+catch = catchSTM#
+
+catch_ :: STM a -> STM a -> STM a
+catch_ = catchRetry#
diff --git a/src/Spark.hs b/src/Spark.hs
new file mode 100644
--- /dev/null
+++ b/src/Spark.hs
@@ -0,0 +1,16 @@
+module Spark where
+
+par :: a -> I64
+par = par#
+{-# DEPRECATED par "Use 'spark#' instead" #-}
+spark, seq :: a -> ST s a
+spark = spark#
+seq = seq#
+-- | Get the next spark from the job queue and number of remaining(?) sparks
+-- TODO: verify the I64 argument meaning
+get :: ST s (# I64, a #)
+get s0 = case getSpark# s0 of (# s1, n, a #) -> (# s1, (# n, a #) #)
+
+num :: ST s I64
+num = numSparks#
+
diff --git a/src/Stock.hs b/src/Stock.hs
new file mode 100644
--- /dev/null
+++ b/src/Stock.hs
@@ -0,0 +1,4 @@
+{-| Description : Stock datatypes and classes -}
+module Stock (module X) where
+import GHC.Types as X (Bool(..),Char(..),Int(..),Word(..),Float(..),Double(..),IO(..),Ordering(..))
+import GHC.Classes as X (Eq(..),Ord(..))
diff --git a/src/String.hs b/src/String.hs
new file mode 100644
--- /dev/null
+++ b/src/String.hs
@@ -0,0 +1,8 @@
+module String where
+import qualified GHC.Types
+
+-- | Null terminated C-style Strings
+type C# = Addr#
+
+-- | Boxed Linked list of @Char@
+type List = [GHC.Types.Char]
diff --git a/src/String/C.hs b/src/String/C.hs
new file mode 100644
--- /dev/null
+++ b/src/String/C.hs
@@ -0,0 +1,3 @@
+module String.C where
+
+type S = Addr#
diff --git a/src/String/C/Latin.hs b/src/String/C/Latin.hs
new file mode 100644
--- /dev/null
+++ b/src/String/C/Latin.hs
@@ -0,0 +1,115 @@
+{-# language BangPatterns #-}
+module String.C.Latin where
+import qualified String
+import String.C
+import Prelude hiding (Char)
+import GHC.Types (Char(..),isTrue#,Bool(..))
+
+--------------------------------------------------------------------------
+-- Unpacking C strings
+-----------------------------------------------------------------------------
+
+-- This code is needed for virtually all programs, since it's used for
+-- unpacking the strings of error messages.
+
+-- Used to be in GHC.Base, but was moved to ghc-prim because the new generics
+-- stuff uses Strings in the representation, so to give representations for
+-- ghc-prim types we need unpack#
+
+{- Note [Inlining unpack#]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+There's really no point in ever inlining things like unpack# as the loop
+doesn't specialise in an interesting way and we can't deforest the list
+constructors (we'd want to use foldr# for this). Moreover, it's
+pretty small, so there's a danger that it'll be inlined at every literal, which
+is a waste.
+
+Moreover, inlining early may interfere with a variety of rules that are supposed
+to match unpack#,
+
+ * BuiltInRules in PrelRules.hs; e.g.
+       eqString (unpack# (Lit s1)) (unpack# (Lit s2)
+          = s1 == s2
+
+ * unpacking rules; e.g. in GHC.Base,
+       unpack# a
+          = build (foldr# a)
+
+ * stream fusion rules; e.g. in the `text` library,
+       unstream (S.map safe (S.streamList (GHC.unpack# a)))
+          = unpack# a
+
+Moreover, we want to make it CONLIKE, so that:
+
+* the rules in PrelRules will fire when the string is let-bound.
+  E.g. the eqString rule in PrelRules
+   eqString (unpack# (Lit s1)) (unpack# (Lit s2) = s1==s2
+
+* exprIsConApp_maybe will see the string when we have
+     let x = unpack# "foo"#
+     ...(case x of algs)...
+
+All of this goes for unpackUtf8# too.
+-}
+
+
+unpack# :: S -> String.List
+{-# NOINLINE CONLIKE unpack# #-}
+unpack# addr
+  = unpack 0#
+  where
+    unpack nh
+      | isTrue# (ch `eqChar#` '\0'#) = []
+      | True                         = C# ch : unpack (nh +# 1#)
+      where
+        !ch = indexCharOffAddr# addr nh
+
+unpackAppend# :: S -> String.List -> String.List
+{-# NOINLINE unpackAppend# #-}
+     -- See the NOINLINE note on unpack#
+unpackAppend# addr rest
+  = unpack 0#
+  where
+    unpack nh
+      | isTrue# (ch `eqChar#` '\0'#) = rest
+      | True                         = C# ch : unpack (nh +# 1#)
+      where
+        !ch = indexCharOffAddr# addr nh
+
+foldr# :: S -> (Char  -> a -> a) -> a -> a
+
+-- Usually the unpack-list rule turns foldr# into unpack#
+
+-- It also has a BuiltInRule in PrelRules.hs:
+--      foldr# "foo" c (foldr# "baz" c n)
+--        =  foldr# "foobaz" c n
+
+{-# NOINLINE foldr# #-}
+-- At one stage I had NOINLINE [0] on the grounds that, unlike
+-- unpack#, there *is* some point in inlining
+-- foldr#, because we get better code for the
+-- higher-order function call.  BUT there may be a lot of
+-- literal strings, and making a separate 'unpack' loop for
+-- each is highly gratuitous.  See nofib/real/anna/PrettyPrint.
+
+foldr# addr f z
+  = unpack 0#
+  where
+    unpack nh
+      | isTrue# (ch `eqChar#` '\0'#) = z
+      | True                         = C# ch `f` unpack (nh +# 1#)
+      where
+        !ch = indexCharOffAddr# addr nh
+
+-- There's really no point in inlining this for the same reasons as
+-- unpack. See Note [Inlining unpack#] above for details.
+unpackN# :: S -> Int# -> String.List
+{-# NOINLINE unpackN# #-}
+unpackN# _addr 0#   = []
+unpackN#  addr len# = unpack [] (len# -# 1#)
+    where
+     unpack acc i#
+      | isTrue# (i# <# 0#)  = acc
+      | True                =
+         case indexCharOffAddr# addr i# of
+            ch -> unpack (C# ch : acc) (i# -# 1#)
diff --git a/src/String/C/UTF8.hs b/src/String/C/UTF8.hs
new file mode 100644
--- /dev/null
+++ b/src/String/C/UTF8.hs
@@ -0,0 +1,39 @@
+{-# language BangPatterns #-}
+module String.C.UTF8 where
+import qualified String
+import String.C
+import Prelude hiding (Char)
+import GHC.Types (Char(..),isTrue#,Bool(..))
+
+-- There's really no point in inlining this for the same reasons as
+-- unpack. See Note [Inlining unpack#] above for details.
+unpack# :: S -> String.List
+{-# NOINLINE CONLIKE unpack# #-}
+unpack# addr
+  = unpack 0#
+  where
+    -- We take care to strictly evaluate the character decoding as
+    -- indexCharOffAddr# is marked with the can_fail flag and
+    -- consequently GHC won't evaluate the expression unless it is absolutely
+    -- needed.
+    unpack nh
+      | isTrue# (ch `eqChar#` '\0'#  ) = []
+      | isTrue# (ch `leChar#` '\x7F'#) = C# ch : unpack (nh +# 1#)
+      | isTrue# (ch `leChar#` '\xDF'#) =
+          let !c = C# (chr# (((ord# ch                                  -# 0xC0#) `uncheckedIShiftL#`  6#) +#
+                              (ord# (indexCharOffAddr# addr (nh +# 1#)) -# 0x80#)))
+          in c : unpack (nh +# 2#)
+      | isTrue# (ch `leChar#` '\xEF'#) =
+          let !c = C# (chr# (((ord# ch                                  -# 0xE0#) `uncheckedIShiftL#` 12#) +#
+                             ((ord# (indexCharOffAddr# addr (nh +# 1#)) -# 0x80#) `uncheckedIShiftL#`  6#) +#
+                              (ord# (indexCharOffAddr# addr (nh +# 2#)) -# 0x80#)))
+          in c : unpack (nh +# 3#)
+      | True                           =
+          let !c = C# (chr# (((ord# ch                                  -# 0xF0#) `uncheckedIShiftL#` 18#) +#
+                             ((ord# (indexCharOffAddr# addr (nh +# 1#)) -# 0x80#) `uncheckedIShiftL#` 12#) +#
+                             ((ord# (indexCharOffAddr# addr (nh +# 2#)) -# 0x80#) `uncheckedIShiftL#`  6#) +#
+                              (ord# (indexCharOffAddr# addr (nh +# 3#)) -# 0x80#)))
+          in c : unpack (nh +# 4#)
+      where
+        !ch = indexCharOffAddr# addr nh
+
diff --git a/src/String/List.hs b/src/String/List.hs
new file mode 100644
--- /dev/null
+++ b/src/String/List.hs
@@ -0,0 +1,43 @@
+{-# language UnliftedFFITypes #-}
+module String.List where
+import qualified GHC.Types
+
+type S = [GHC.Types.Char]
+
+debugLn :: S -> GHC.Types.IO ()
+debugLn xs = GHC.Types.IO (\s0 ->
+                 case mkMBA xs s0 of
+                 (# s1, mba #) ->
+                     case c_debugLn mba of
+                     GHC.Types.IO f -> f s1)
+
+debugErrLn :: S -> GHC.Types.IO ()
+debugErrLn xs = GHC.Types.IO (\s0 ->
+                    case mkMBA xs s0 of
+                    (# s1, mba #) ->
+                        case c_debugErrLn mba of
+                        GHC.Types.IO f -> f s1)
+
+foreign import ccall unsafe "debugLn"
+    c_debugLn :: MutableByteArray# RealWorld -> GHC.Types.IO ()
+
+foreign import ccall unsafe "debugErrLn"
+    c_debugErrLn :: MutableByteArray# RealWorld -> GHC.Types.IO ()
+
+mkMBA :: S -> IO (MutableByteArray# RealWorld)
+mkMBA xs s0 = -- Start with 1 so that we have space to put in a \0 at
+              -- the end
+              case len 1# xs of
+              l ->
+                  case newByteArray# l s0 of
+                  (# s1, mba #) ->
+                      case write mba 0# xs s1 of
+                      s2 -> (# s2, mba #)
+    where len l [] = l
+          len l (_ : xs') = len (l +# 1#) xs'
+
+          write mba offset [] s = writeCharArray# mba offset '\0'# s
+          write mba offset (GHC.Types.C# x : xs') s
+              = case writeCharArray# mba offset x s of
+                s' ->
+                    write mba (offset +# 1#) xs' s'
diff --git a/src/Syntax/ImplicitParam.hs b/src/Syntax/ImplicitParam.hs
new file mode 100644
--- /dev/null
+++ b/src/Syntax/ImplicitParam.hs
@@ -0,0 +1,2 @@
+module Syntax.ImplicitParam (module X) where
+import GHC.Classes as X (IP(..))
diff --git a/src/Thread.hs b/src/Thread.hs
new file mode 100644
--- /dev/null
+++ b/src/Thread.hs
@@ -0,0 +1,59 @@
+{-# language PatternSynonyms #-}
+module Thread where
+import qualified Ref
+
+type Id = ThreadId#
+
+-- | The physical capability (Hardware thread) a 'Thread' is running on
+type Cap = I64
+
+fork :: a -> IO Id
+fork = fork#
+forkOn :: Cap -> a -> IO Id
+forkOn u = forkOn# u
+-- | Kill a thread with the given exception (toException)
+kill# :: Id -> a -> IO_
+kill# = killThread#
+yield :: IO_
+yield = yield#
+here :: IO Id
+here = myThreadId#
+-- | Label a thread with the given cstring pointer
+label# :: Id -> Ref.Byte -> IO_
+label# = labelThread#
+bound' :: IO B
+bound' = isCurrentThreadBound#
+-- TODO: put this somewhere else
+noDuplicate :: ST_ s
+noDuplicate = noDuplicate#
+status :: Id -> IO (# Status, Cap, B #)
+status n s = case threadStatus# n s of
+  (# s', status, cap, bound' #) -> (# s', (# status, cap, bound' #) #)
+
+-- * Constants for why_blocked field of a TSO from rts/Constants.h
+type Status = Int#
+pattern Running = 0#
+pattern BlockedOnMVar = 1#
+pattern BlockedOnBlackHole = 2#
+pattern BlockedOnRead = 3#
+pattern BlockedOnWrite = 4#
+pattern BlockedOnDelay = 5#
+pattern BlockedOnSTM = 6#
+-- | Win32 only
+pattern BlockedOnDoProc = 7#
+
+-- | Only relevant for THREADED_RTS
+pattern BlockedOnCCall = 10#
+-- | Same as @BlockedOnCCall@ but permit killing the worker thread.
+-- Only relevant for THREADED_RTS
+pattern BlockedOnCCall_Interruptible = 11#
+
+-- | Involved in a message tsent to tso->msg_cap
+pattern BlockedOnMsgThrowTo = 12#
+
+-- | The thread is not on any run queues, but can be woken up by @tryWakeupThread()@
+pattern ThreadMigrating = 13#
+
+-- TODO: There should be more here, like ThreadFinished. Figure out the numbering
+
+
diff --git a/src/U16.hs b/src/U16.hs
new file mode 100644
--- /dev/null
+++ b/src/U16.hs
@@ -0,0 +1,1 @@
+module U16 (U16) where
diff --git a/src/U32.hs b/src/U32.hs
new file mode 100644
--- /dev/null
+++ b/src/U32.hs
@@ -0,0 +1,2 @@
+module U32 (U32) where
+
diff --git a/src/U64.hs b/src/U64.hs
new file mode 100644
--- /dev/null
+++ b/src/U64.hs
@@ -0,0 +1,69 @@
+module U64 (U64, module U64) where
+import qualified GHC.Types as GHC
+
+add,sub,mul, quot, rem :: U64 -> U64 -> U64
+add y x = plusWord# x y
+sub y x = minusWord# x y
+mul y x = timesWord# x y
+
+-- |Add unsigned integers, with the high part (carry) in the first
+--           component of the returned pair and the low part in the second
+--           component of the pair. See also @addC@.
+add2 :: U64 -> U64 -> (# U64, U64 #)
+add2 y x = plusWord2# x y
+
+-- | Rounds towards zero. The behavior is undefined if the first argument is zero.
+quot y x = quotWord# x y
+
+-- |Satisfies @(add (rem y x) (mul y (quot y x)) == x@. The
+--     behavior is undefined if the first argument is zero.
+rem y x = remWord# x y
+
+-- | Rounds towards zero
+quotRem :: U64 -> U64 -> (# U64, U64 #)
+quotRem y x = quotRemWord# x y
+-- |Add signed integers reporting overflow.
+--           First member of result is the sum truncated to an @U64@;
+--           second member is zero if the true sum fits in an @U64@,
+--           nonzero if overflow occurred (the sum is either too large
+--           or too small to fit in an @U64@).
+addC, subC :: U64 -> U64 -> (# U64, B #)
+addC y x = addWordC# x y
+-- |Subtract signed integers reporting overflow.
+--           First member of result is the difference truncated to an @U64@;
+--           second member is zero if the true difference fits in an @U64@,
+--           nonzero if overflow occurred (the difference is either too large
+--           or too small to fit in an @U64@).
+subC y x = subWordC# x y
+
+gt,ge,lt,le,eq,ne :: U64 -> U64 -> B
+gt y x = gtWord# x y
+ge y x = geWord# x y
+lt y x = ltWord# x y
+le y x = leWord# x y
+eq x y = eqWord# x y
+ne x y = neWord# x y
+
+fromInt :: Int -> U64
+fromInt = int2Word#
+toInt :: U64 -> Int
+toInt = word2Int#
+
+toF32 :: U64 -> F32
+toF32 = word2Float#
+toF64 :: U64 -> F64
+toF64 = word2Double#
+
+toU8 :: U64 -> U8
+toU8 = narrow8Word#
+toU16 :: U64 -> U16
+toU16 = narrow16Word#
+toU32 :: U64 -> U32
+toU32 = narrow32Word#
+
+toB8 :: U64 -> B8
+toB8 = narrow8Word#
+toB16 :: U64 -> B16
+toB16 = narrow16Word#
+toB32 :: U64 -> B32
+toB32 = narrow32Word#
diff --git a/src/U8.hs b/src/U8.hs
new file mode 100644
--- /dev/null
+++ b/src/U8.hs
@@ -0,0 +1,1 @@
+module U8 (U8) where
