diff --git a/Control/Monad/Primitive.hs b/Control/Monad/Primitive.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/Primitive.hs
@@ -0,0 +1,41 @@
+{-# LANGUAGE MagicHash, UnboxedTuples, TypeFamilies #-}
+
+-- |
+-- Module      : Control.Monad.Primitive
+-- Copyright   : (c) Roman Leshchinskiy 2009
+-- License     : BSD-style
+--
+-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
+-- Portability : non-portable
+-- 
+-- Primitive state-transformer monads
+--
+
+module Control.Monad.Primitive ( PrimMonad(..), primitive_ ) where
+
+import GHC.Prim   ( State#, RealWorld )
+import GHC.IOBase ( IO(..) )
+import GHC.ST     ( ST(..) )
+
+-- | Class of primitive state-transformer monads
+class Monad m => PrimMonad m where
+  -- | State token type
+  type PrimState m
+
+  -- | Execute a primitive operation
+  primitive :: (State# (PrimState m) -> (# State# (PrimState m), a #)) -> m a
+
+-- | Execute a primitive operation with no result
+primitive_ :: PrimMonad m
+              => (State# (PrimState m) -> State# (PrimState m)) -> m ()
+{-# INLINE primitive_ #-}
+primitive_ f = primitive (\s# -> (# f s#, () #))
+
+instance PrimMonad IO where
+  type PrimState IO = RealWorld
+  primitive = IO
+
+instance PrimMonad (ST s) where
+  type PrimState (ST s) = s
+  primitive = ST
+
diff --git a/Data/Primitive.hs b/Data/Primitive.hs
new file mode 100644
--- /dev/null
+++ b/Data/Primitive.hs
@@ -0,0 +1,36 @@
+{-# LANGUAGE MagicHash #-}
+{-# OPTIONS_GHC -fno-warn-duplicate-exports #-}
+-- |
+-- Module      : Data.Primitive
+-- Copyright   : (c) Roman Leshchinskiy 2009
+-- License     : BSD-style
+--
+-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
+-- Portability : non-portable
+-- 
+-- Reexports all primitive operations
+--
+module Data.Primitive (
+  module Data.Primitive.Types,
+  module Data.Primitive.Array,
+  module Data.Primitive.ByteArray,
+  module Data.Primitive.Addr,
+
+  sizeOf, alignment
+) where
+
+import Data.Primitive.Types
+import Data.Primitive.Array
+import Data.Primitive.ByteArray
+import Data.Primitive.Addr
+
+import GHC.Base ( Int(..) )
+
+-- | Size of values of type @a@. The argument is not used.
+sizeOf :: Prim a => a -> Int
+sizeOf x = I# (sizeOf# x)
+
+-- | Alignment of values of type @a@. The argument is not used.
+alignment :: Prim a => a -> Int
+alignment x = I# (alignment# x)
+
diff --git a/Data/Primitive/Addr.hs b/Data/Primitive/Addr.hs
new file mode 100644
--- /dev/null
+++ b/Data/Primitive/Addr.hs
@@ -0,0 +1,74 @@
+{-# LANGUAGE MagicHash, UnboxedTuples #-}
+
+-- |
+-- Module      : Data.Primitive.Addr
+-- Copyright   : (c) Roman Leshchinskiy 2009
+-- License     : BSD-style
+--
+-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
+-- Portability : non-portable
+-- 
+-- Primitive operations on machine addresses
+--
+
+module Data.Primitive.Addr (
+  Addr(..),
+
+  nullAddr, plusAddr, minusAddr, remAddr,
+  indexOffAddr, readOffAddr, writeOffAddr
+) where
+
+import Control.Monad.Primitive
+import Data.Primitive.Types
+
+import GHC.Base ( Int(..) )
+import GHC.Prim
+
+instance Eq Addr where
+  Addr a# == Addr b# = eqAddr# a# b#
+  Addr a# /= Addr b# = neAddr# a# b#
+
+instance Ord Addr where
+  Addr a# > Addr b# = gtAddr# a# b#
+  Addr a# >= Addr b# = geAddr# a# b#
+  Addr a# < Addr b# = ltAddr# a# b#
+  Addr a# <= Addr b# = leAddr# a# b#
+
+-- | The null address
+nullAddr :: Addr
+nullAddr = Addr nullAddr#
+
+infixl 6 `plusAddr`, `minusAddr`
+infixl 7 `remAddr`
+
+-- | Offset an address by the given number of bytes
+plusAddr :: Addr -> Int -> Addr
+plusAddr (Addr a#) (I# i#) = Addr (plusAddr# a# i#)
+
+-- | Distance in bytes between two addresses. The result is only valid if the
+-- difference fits in an 'Int'.
+minusAddr :: Addr -> Addr -> Int
+minusAddr (Addr a#) (Addr b#) = I# (minusAddr# a# b#)
+
+remAddr :: Addr -> Int -> Int
+remAddr (Addr a#) (I# i#) = I# (remAddr# a# i#)
+
+-- | Read a value from a memory position given by an address and an offset.
+-- The memory block the address refers to must be immutable. The offset is in
+-- elements of type @a@ rather than in bytes.
+indexOffAddr :: Prim a => Addr -> Int -> a
+{-# INLINE indexOffAddr #-}
+indexOffAddr (Addr addr#) (I# i#) = indexOffAddr# addr# i#
+
+-- | Read a value from a memory position given by an address and an offset.
+-- The offset is in elements of type @a@ rather than in bytes.
+readOffAddr :: (Prim a, PrimMonad m) => Addr -> Int -> m a
+{-# INLINE readOffAddr #-}
+readOffAddr (Addr addr#) (I# i#) = primitive (readOffAddr# addr# i#)
+
+-- | Write a value to a memory position given by an address and an offset.
+-- The offset is in elements of type @a@ rather than in bytes.
+writeOffAddr :: (Prim a, PrimMonad m) => Addr -> Int -> a -> m ()
+{-# INLINE writeOffAddr #-}
+writeOffAddr (Addr addr#) (I# i#) x = primitive_ (writeOffAddr# addr# i# x)
+
diff --git a/Data/Primitive/Array.hs b/Data/Primitive/Array.hs
new file mode 100644
--- /dev/null
+++ b/Data/Primitive/Array.hs
@@ -0,0 +1,104 @@
+{-# LANGUAGE MagicHash, UnboxedTuples #-}
+
+-- |
+-- Module      : Data.Primitive.Array
+-- Copyright   : (c) Roman Leshchinskiy 2009
+-- License     : BSD-style
+--
+-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
+-- Portability : non-portable
+-- 
+-- Primitive boxed arrays
+--
+
+module Data.Primitive.Array (
+  Array(..), MutableArray(..),
+
+  newArray, readArray, writeArray, indexArray, indexArrayM,
+  unsafeFreezeArray, unsafeThawArray, sameMutableArray
+) where
+
+import Control.Monad.Primitive
+
+import GHC.Base  ( Int(..) )
+import GHC.Prim
+
+-- | Boxed arrays
+data Array a = Array (Array# a)
+
+-- | Mutable boxed arrays associated with a primitive state token.
+data MutableArray m a = MutableArray (MutableArray# (PrimState m) a)
+
+-- | Create a new mutable array of the specified size and initialise all
+-- elements with the given value.
+newArray :: PrimMonad m => Int -> a -> m (MutableArray m a)
+{-# INLINE newArray #-}
+newArray (I# n#) x = primitive
+   (\s# -> case newArray# n# x s# of
+             (# s'#, arr# #) -> (# s'#, MutableArray arr# #))
+
+-- | Read a value from the array at the given index.
+readArray :: PrimMonad m => MutableArray m a -> Int -> m a
+{-# INLINE readArray #-}
+readArray (MutableArray arr#) (I# i#) = primitive (readArray# arr# i#)
+
+-- | Write a value to the array at the given index.
+writeArray :: PrimMonad m => MutableArray m a -> Int -> a -> m ()
+{-# INLINE writeArray #-}
+writeArray (MutableArray arr#) (I# i#) x = primitive_ (writeArray# arr# i# x)
+
+-- | Read a value from the immutable array at the given index.
+indexArray :: Array a -> Int -> a
+{-# INLINE indexArray #-}
+indexArray (Array arr#) (I# i#) = case indexArray# arr# i# of (# x #) -> x
+
+-- | Monadically read a value from the immutable array at the given index.
+-- This allows us to be strict in the array while remaining lazy in the read
+-- element which is very useful for collective operations. Suppose we want to
+-- copy an array. We could do something like this:
+--
+-- > copy marr arr ... = do ...
+-- >                        writeArray marr i (indexArray arr i) ...
+-- >                        ...
+--
+-- But since primitive arrays are lazy, the calls to 'indexArray' will not be
+-- evaluated. Rather, @marr@ will be filled with thunks each of which would
+-- retain a reference to @arr@. This is definitely not what we want!
+--
+-- With 'indexArrayM', we can instead write
+--
+-- > copy marr arr ... = do ...
+-- >                        x <- indexArrayM arr i
+-- >                        writeArray marr i x
+-- >                        ...
+--
+-- Now, indexing is executed immediately although the returned element is
+-- still not evaluated.
+--
+indexArrayM :: Monad m => Array a -> Int -> m a 
+{-# INLINE indexArrayM #-}
+indexArrayM (Array arr#) (I# i#)
+  = case indexArray# arr# i# of (# x #) -> return x
+
+-- | Convert a mutable array to an immutable one without copying. The
+-- array should not be modified after the conversion.
+unsafeFreezeArray :: PrimMonad m => MutableArray m a -> m (Array a)
+{-# INLINE unsafeFreezeArray #-}
+unsafeFreezeArray (MutableArray arr#)
+  = primitive (\s# -> case unsafeFreezeArray# arr# s# of
+                        (# s'#, arr'# #) -> (# s'#, Array arr'# #))
+
+-- | Convert an immutable array to an mutable one without copying. The
+-- immutable array should not be used after the conversion.
+unsafeThawArray :: PrimMonad m => Array a -> m (MutableArray m a)
+{-# INLINE unsafeThawArray #-}
+unsafeThawArray (Array arr#)
+  = primitive (\s# -> case unsafeThawArray# arr# s# of
+                        (# s'#, arr'# #) -> (# s'#, MutableArray arr'# #))
+
+-- | Check whether the two arrays refer to the same memory block.
+sameMutableArray :: MutableArray s a -> MutableArray s a -> Bool
+{-# INLINE sameMutableArray #-}
+sameMutableArray (MutableArray arr#) (MutableArray brr#)
+  = sameMutableArray# arr# brr#
+
diff --git a/Data/Primitive/ByteArray.hs b/Data/Primitive/ByteArray.hs
new file mode 100644
--- /dev/null
+++ b/Data/Primitive/ByteArray.hs
@@ -0,0 +1,110 @@
+{-# LANGUAGE MagicHash, UnboxedTuples #-}
+
+-- |
+-- Module      : Data.Primitive.ByteArray
+-- Copyright   : (c) Roman Leshchinskiy 2009
+-- License     : BSD-style
+--
+-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
+-- Portability : non-portable
+-- 
+-- Primitive operations on ByteArrays
+--
+
+module Data.Primitive.ByteArray (
+  ByteArray(..), MutableByteArray(..),
+
+  newByteArray, newPinnedByteArray, newAlignedPinnedByteArray,
+  readByteArray, writeByteArray, indexByteArray,
+  unsafeFreezeByteArray,
+  sizeofByteArray, sizeofMutableByteArray, sameMutableByteArray,
+  byteArrayContents
+) where
+
+import Control.Monad.Primitive
+import Data.Primitive.Types
+
+import GHC.Base ( Int(..) )
+import GHC.Prim
+
+-- | Byte arrays
+data ByteArray = ByteArray ByteArray#
+
+-- | Mutable byte arrays associated with a primitive state token
+data MutableByteArray m = MutableByteArray (MutableByteArray# (PrimState m))
+
+-- | Create a new mutable byte array of the specified size.
+newByteArray :: PrimMonad m => Int -> m (MutableByteArray m)
+{-# INLINE newByteArray #-}
+newByteArray (I# n#)
+  = primitive (\s# -> case newByteArray# n# s# of
+                        (# s'#, arr# #) -> (# s'#, MutableByteArray arr# #))
+
+-- | Create a /pinned/ byte array of the specified size. The garbage collector
+-- is guaranteed not to move it.
+newPinnedByteArray :: PrimMonad m => Int -> m (MutableByteArray m)
+{-# INLINE newPinnedByteArray #-}
+newPinnedByteArray (I# n#)
+  = primitive (\s# -> case newPinnedByteArray# n# s# of
+                        (# s'#, arr# #) -> (# s'#, MutableByteArray arr# #))
+
+-- | Create a /pinned/ byte array of the specified size and with the give
+-- alignment. The garbage collector is guaranteed not to move it.
+newAlignedPinnedByteArray :: PrimMonad m => Int -> Int -> m (MutableByteArray m)
+{-# INLINE newAlignedPinnedByteArray #-}
+newAlignedPinnedByteArray (I# n#) (I# k#)
+  = primitive (\s# -> case newAlignedPinnedByteArray# n# k# s# of
+                        (# s'#, arr# #) -> (# s'#, MutableByteArray arr# #))
+
+-- | Yield a pointer to the array's data. This operation is only safe on
+-- /pinned/ byte arrays allocated by 'newPinnedByteArray' or
+-- 'newAlignedPinnedByteArray'.
+byteArrayContents :: ByteArray -> Addr
+{-# INLINE byteArrayContents #-}
+byteArrayContents (ByteArray arr#) = Addr (byteArrayContents# arr#)
+
+-- | Check if the two arrays refer to the same memory block.
+sameMutableByteArray :: MutableByteArray s -> MutableByteArray s -> Bool
+{-# INLINE sameMutableByteArray #-}
+sameMutableByteArray (MutableByteArray arr#) (MutableByteArray brr#)
+  = sameMutableByteArray# arr# brr#
+
+-- | Convert a mutable byte array to an immutable one without copying. The
+-- array should not be modified after the conversion.
+unsafeFreezeByteArray :: PrimMonad m => MutableByteArray m -> m ByteArray
+{-# INLINE unsafeFreezeByteArray #-}
+unsafeFreezeByteArray (MutableByteArray arr#)
+  = primitive (\s# -> case unsafeFreezeByteArray# arr# s# of
+                        (# s'#, arr'# #) -> (# s'#, ByteArray arr'# #))
+
+-- | Size of the byte array.
+sizeofByteArray :: ByteArray -> Int
+{-# INLINE sizeofByteArray #-}
+sizeofByteArray (ByteArray arr#) = I# (sizeofByteArray# arr#)
+
+-- | Size of the mutable byte array.
+sizeofMutableByteArray :: MutableByteArray s -> Int
+{-# INLINE sizeofMutableByteArray #-}
+sizeofMutableByteArray (MutableByteArray arr#) = I# (sizeofMutableByteArray# arr#)
+
+-- | Read a primitive value from the byte array. The offset is given in
+-- elements of type @a@ rather than in bytes.
+indexByteArray :: Prim a => ByteArray -> Int -> a
+{-# INLINE indexByteArray #-}
+indexByteArray (ByteArray arr#) (I# i#) = indexByteArray# arr# i#
+
+-- | Read a primitive value from the byte array. The offset is given in
+-- elements of type @a@ rather than in bytes.
+readByteArray :: (Prim a, PrimMonad m) => MutableByteArray m -> Int -> m a
+{-# INLINE readByteArray #-}
+readByteArray (MutableByteArray arr#) (I# i#)
+  = primitive (readByteArray# arr# i#)
+
+-- | Write a primitive value to the byte array. The offset is given in
+-- elements of type @a@ rather than in bytes.
+writeByteArray
+  :: (Prim a, PrimMonad m) => MutableByteArray m -> Int -> a -> m ()
+{-# INLINE writeByteArray #-}
+writeByteArray (MutableByteArray arr#) (I# i#) x
+  = primitive_ (writeByteArray# arr# i# x)
+
diff --git a/Data/Primitive/MachDeps.hs b/Data/Primitive/MachDeps.hs
new file mode 100644
--- /dev/null
+++ b/Data/Primitive/MachDeps.hs
@@ -0,0 +1,114 @@
+{-# LANGUAGE CPP #-}
+
+-- |
+-- Module      : Data.Primitive.MachDeps
+-- Copyright   : (c) Roman Leshchinskiy 2009
+-- License     : BSD-style
+--
+-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
+-- Portability : non-portable
+-- 
+-- Machine-dependent constants
+--
+
+module Data.Primitive.MachDeps where
+
+#include "MachDeps.h"
+
+sIZEOF_CHAR,
+ aLIGNMENT_CHAR,
+
+ sIZEOF_INT,
+ aLIGNMENT_INT,
+
+ sIZEOF_WORD,
+ aLIGNMENT_WORD,
+
+ sIZEOF_DOUBLE,
+ aLIGNMENT_DOUBLE,
+
+ sIZEOF_FLOAT,
+ aLIGNMENT_FLOAT,
+
+ sIZEOF_PTR,
+ aLIGNMENT_PTR,
+
+ sIZEOF_FUNPTR,
+ aLIGNMENT_FUNPTR,
+
+ sIZEOF_STABLEPTR,
+ aLIGNMENT_STABLEPTR,
+
+ sIZEOF_INT8,
+ aLIGNMENT_INT8,
+
+ sIZEOF_WORD8,
+ aLIGNMENT_WORD8,
+
+ sIZEOF_INT16,
+ aLIGNMENT_INT16,
+
+ sIZEOF_WORD16,
+ aLIGNMENT_WORD16,
+
+ sIZEOF_INT32,
+ aLIGNMENT_INT32,
+
+ sIZEOF_WORD32,
+ aLIGNMENT_WORD32,
+
+ sIZEOF_INT64,
+ aLIGNMENT_INT64,
+
+ sIZEOF_WORD64,
+ aLIGNMENT_WORD64 :: Int
+
+
+sIZEOF_CHAR = SIZEOF_HSCHAR
+aLIGNMENT_CHAR = ALIGNMENT_HSCHAR
+
+sIZEOF_INT = SIZEOF_HSINT
+aLIGNMENT_INT = ALIGNMENT_HSINT
+
+sIZEOF_WORD = SIZEOF_HSWORD
+aLIGNMENT_WORD = ALIGNMENT_HSWORD
+
+sIZEOF_DOUBLE = SIZEOF_HSDOUBLE
+aLIGNMENT_DOUBLE = ALIGNMENT_HSDOUBLE
+
+sIZEOF_FLOAT = SIZEOF_HSFLOAT
+aLIGNMENT_FLOAT = ALIGNMENT_HSFLOAT
+
+sIZEOF_PTR = SIZEOF_HSPTR
+aLIGNMENT_PTR = ALIGNMENT_HSPTR
+
+sIZEOF_FUNPTR = SIZEOF_HSFUNPTR
+aLIGNMENT_FUNPTR = ALIGNMENT_HSFUNPTR
+
+sIZEOF_STABLEPTR = SIZEOF_HSSTABLEPTR
+aLIGNMENT_STABLEPTR = ALIGNMENT_HSSTABLEPTR
+
+sIZEOF_INT8 = SIZEOF_INT8
+aLIGNMENT_INT8 = ALIGNMENT_INT8
+
+sIZEOF_WORD8 = SIZEOF_WORD8
+aLIGNMENT_WORD8 = ALIGNMENT_WORD8
+
+sIZEOF_INT16 = SIZEOF_INT16
+aLIGNMENT_INT16 = ALIGNMENT_INT16
+
+sIZEOF_WORD16 = SIZEOF_WORD16
+aLIGNMENT_WORD16 = ALIGNMENT_WORD16
+
+sIZEOF_INT32 = SIZEOF_INT32
+aLIGNMENT_INT32 = ALIGNMENT_INT32
+
+sIZEOF_WORD32 = SIZEOF_WORD32
+aLIGNMENT_WORD32 = ALIGNMENT_WORD32
+
+sIZEOF_INT64 = SIZEOF_INT64
+aLIGNMENT_INT64 = ALIGNMENT_INT64
+
+sIZEOF_WORD64 = SIZEOF_WORD64
+aLIGNMENT_WORD64 = ALIGNMENT_WORD64
+
diff --git a/Data/Primitive/Types.hs b/Data/Primitive/Types.hs
new file mode 100644
--- /dev/null
+++ b/Data/Primitive/Types.hs
@@ -0,0 +1,134 @@
+{-# LANGUAGE UnboxedTuples, MagicHash, CPP #-}
+
+-- |
+-- Module      : Data.Primitive.Types
+-- Copyright   : (c) Roman Leshchinskiy 2009
+-- License     : BSD-style
+--
+-- Maintainer  : Roman Leshchinskiy <rl@cse.unsw.edu.au>
+-- Portability : non-portable
+-- 
+-- Basic types and classes for primitive array operations
+--
+
+module Data.Primitive.Types (
+  Prim(..),
+
+  Addr(..),
+) where
+
+import Control.Monad.Primitive
+import Data.Primitive.MachDeps
+
+import GHC.Base (
+    Int(..), Char(..),
+  )
+import GHC.Float (
+    Float(..), Double(..)
+  )
+import GHC.Word (
+    Word(..), Word8(..), Word16(..), Word32(..), Word64(..)
+  )
+import GHC.Int (
+    Int8(..), Int16(..), Int32(..), Int64(..)
+  )
+
+import GHC.Prim
+
+-- | A machine address
+data Addr = Addr Addr#
+
+-- | Class of types supporting primitive array operations
+class Prim a where
+
+  -- | Size of values of type @a@. The argument is not used.
+  sizeOf#    :: a -> Int#
+
+  -- | Alignment of values of type @a@. The argument is not used.
+  alignment# :: a -> Int#
+
+  -- | Read a value from the array. The offset is in elements of type
+  -- @a@ rather than in bytes.
+  indexByteArray# :: ByteArray# -> Int# -> a
+
+  -- | Read a value from the mutable array. The offset is in elements of type
+  -- @a@ rather than in bytes.
+  readByteArray# :: MutableByteArray# s -> Int# -> State# s -> (# State# s, a #)
+
+  -- | Write a value to the mutable array. The offset is in elements of type
+  -- @a@ rather than in bytes.
+  writeByteArray# :: MutableByteArray# s -> Int# -> a -> State# s -> State# s
+
+  -- | Read a value from a memory position given by an address and an offset.
+  -- The memory block the address refers to must be immutable. The offset is in
+  -- elements of type @a@ rather than in bytes.
+  indexOffAddr# :: Addr# -> Int# -> a
+
+  -- | Read a value from a memory position given by an address and an offset.
+  -- The offset is in elements of type @a@ rather than in bytes.
+  readOffAddr# :: Addr# -> Int# -> State# s -> (# State# s, a #)
+
+  -- | Write a value to a memory position given by an address and an offset.
+  -- The offset is in elements of type @a@ rather than in bytes.
+  writeOffAddr# :: Addr# -> Int# -> a -> State# s -> State# s
+
+#define derivePrim(ty, ctr, sz, align, idx_arr, rd_arr, wr_arr, idx_addr, rd_addr, wr_addr) \
+instance Prim ty where {                                        \
+  sizeOf# _ = unI# sz                                           \
+; alignment# _ = unI# align                                     \
+; indexByteArray# arr# i# = ctr (idx_arr arr# i#)               \
+; readByteArray#  arr# i# s# = case rd_arr arr# i# s# of        \
+                        { (# s1#, x# #) -> (# s1#, ctr x# #) }  \
+; writeByteArray# arr# i# (ctr x#) s# = wr_arr arr# i# x# s#    \
+                                                                \
+; indexOffAddr# addr# i# = ctr (idx_addr addr# i#)              \
+; readOffAddr#  addr# i# s# = case rd_addr addr# i# s# of       \
+                        { (# s1#, x# #) -> (# s1#, ctr x# #) }  \
+; writeOffAddr# addr# i# (ctr x#) s# = wr_addr addr# i# x# s#   }
+
+unI# :: Int -> Int#
+unI# (I# n#) = n#
+
+derivePrim(Word, W#, sIZEOF_WORD, aLIGNMENT_WORD,
+           indexWordArray#, readWordArray#, writeWordArray#,
+           indexWordOffAddr#, readWordOffAddr#, writeWordOffAddr#)
+derivePrim(Word8, W8#, sIZEOF_WORD8, aLIGNMENT_WORD8,
+           indexWord8Array#, readWord8Array#, writeWord8Array#,
+           indexWord8OffAddr#, readWord8OffAddr#, writeWord8OffAddr#)
+derivePrim(Word16, W16#, sIZEOF_WORD16, aLIGNMENT_WORD16,
+           indexWord16Array#, readWord16Array#, writeWord16Array#,
+           indexWord16OffAddr#, readWord16OffAddr#, writeWord16OffAddr#)
+derivePrim(Word32, W32#, sIZEOF_WORD32, aLIGNMENT_WORD32,
+           indexWord32Array#, readWord32Array#, writeWord32Array#,
+           indexWord32OffAddr#, readWord32OffAddr#, writeWord32OffAddr#)
+derivePrim(Word64, W64#, sIZEOF_WORD64, aLIGNMENT_WORD64,
+           indexWord64Array#, readWord64Array#, writeWord64Array#,
+           indexWord64OffAddr#, readWord64OffAddr#, writeWord64OffAddr#)
+derivePrim(Int, I#, sIZEOF_INT, aLIGNMENT_INT,
+           indexIntArray#, readIntArray#, writeIntArray#,
+           indexIntOffAddr#, readIntOffAddr#, writeIntOffAddr#)
+derivePrim(Int8, I8#, sIZEOF_INT8, aLIGNMENT_INT8,
+           indexInt8Array#, readInt8Array#, writeInt8Array#,
+           indexInt8OffAddr#, readInt8OffAddr#, writeInt8OffAddr#)
+derivePrim(Int16, I16#, sIZEOF_INT16, aLIGNMENT_INT16,
+           indexInt16Array#, readInt16Array#, writeInt16Array#,
+           indexInt16OffAddr#, readInt16OffAddr#, writeInt16OffAddr#)
+derivePrim(Int32, I32#, sIZEOF_INT32, aLIGNMENT_INT32,
+           indexInt32Array#, readInt32Array#, writeInt32Array#,
+           indexInt32OffAddr#, readInt32OffAddr#, writeInt32OffAddr#)
+derivePrim(Int64, I64#, sIZEOF_INT64, aLIGNMENT_INT64,
+           indexInt64Array#, readInt64Array#, writeInt64Array#,
+           indexInt64OffAddr#, readInt64OffAddr#, writeInt64OffAddr#)
+derivePrim(Float, F#, sIZEOF_FLOAT, aLIGNMENT_FLOAT,
+           indexFloatArray#, readFloatArray#, writeFloatArray#,
+           indexFloatOffAddr#, readFloatOffAddr#, writeFloatOffAddr#)
+derivePrim(Double, D#, sIZEOF_DOUBLE, aLIGNMENT_DOUBLE,
+           indexDoubleArray#, readDoubleArray#, writeDoubleArray#,
+           indexDoubleOffAddr#, readDoubleOffAddr#, writeDoubleOffAddr#)
+derivePrim(Char, C#, sIZEOF_CHAR, aLIGNMENT_CHAR,
+           indexWideCharArray#, readWideCharArray#, writeWideCharArray#,
+           indexWideCharOffAddr#, readWideCharOffAddr#, writeWideCharOffAddr#)
+derivePrim(Addr, Addr, sIZEOF_PTR, aLIGNMENT_PTR,
+           indexAddrArray#, readAddrArray#, writeAddrArray#,
+           indexAddrOffAddr#, readAddrOffAddr#, writeAddrOffAddr#)
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2008-2009, Roman Leshchinskiy
+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 name of the University nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission. 
+
+THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY COURT OF THE UNIVERSITY OF
+GLASGOW AND THE 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
+UNIVERSITY COURT OF THE UNIVERSITY OF GLASGOW OR THE 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/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,3 @@
+import Distribution.Simple
+main = defaultMain
+
diff --git a/primitive.cabal b/primitive.cabal
new file mode 100644
--- /dev/null
+++ b/primitive.cabal
@@ -0,0 +1,30 @@
+Name:           primitive
+Version:        0.1
+License:        BSD3
+License-File:   LICENSE
+Author:         Roman Leshchinskiy <rl@cse.unsw.edu.au>
+Maintainer:     Roman Leshchinskiy <rl@cse.unsw.edu.au>
+Copyright:      (c) Roman Leshchinskiy 2009
+Category:       Data
+Synopsis:       Wrappers for primitive operations
+Description:
+        .
+        This package provides wrappers for primitive array operations from
+        GHC.Prim.
+        .
+
+Cabal-Version:  >= 1.2
+Build-Type:     Simple
+
+Library
+  Exposed-Modules:
+        Control.Monad.Primitive
+        Data.Primitive
+        Data.Primitive.MachDeps
+        Data.Primitive.Types
+        Data.Primitive.Array
+        Data.Primitive.ByteArray
+        Data.Primitive.Addr
+
+  Build-Depends: base >= 2 && < 5, ghc-prim
+
