diff --git a/bench/Bench.hs b/bench/Bench.hs
deleted file mode 100644
--- a/bench/Bench.hs
+++ /dev/null
@@ -1,152 +0,0 @@
-module Main (main) where
-
-import Criterion.Main
-import Data.List (unfoldr)
-import Data.Word (Word64)
-
-import qualified Data.Tree as T
-import qualified System.Random as R
-import qualified System.Random.TF as TF
-import qualified System.Random.TF.Instances as TF
-import qualified System.Random.SplitMix as SM
-import qualified System.Random.SplitMix32 as SM32
-
--------------------------------------------------------------------------------
--- List
--------------------------------------------------------------------------------
-
--- infinite list
-genList :: (g -> (Int, g)) -> g -> [Int]
-genList next = unfoldr (Just . next)
-
--- truncated
-genListN :: (g -> (Int, g)) -> g -> [Int]
-genListN next = take 2048 . genList next
-
-randomList :: Int -> [Int]
-randomList = genListN R.random . R.mkStdGen
-
-tfRandomList :: Word64 -> [Int]
-tfRandomList w64 = genListN R.random $ TF.seedTFGen (w64, w64, w64, w64)
-
-splitMixList :: Word64 -> [Int]
-splitMixList w64 = genListN SM.nextInt $ SM.mkSMGen w64
-
-splitMix32List :: Word64 -> [Int]
-splitMix32List w64 = genListN SM32.nextInt $ SM32.mkSMGen $ fromIntegral w64
-
--------------------------------------------------------------------------------
--- Tree
--------------------------------------------------------------------------------
-
-genTree :: (g -> (Int, g)) -> (g -> (g, g)) -> g -> T.Tree Int
-genTree next split = go where
-    go g = case next g of
-        ~(i, g') -> T.Node i $ case split g' of
-            (ga, gb) -> [go ga, go gb]
-
-genTreeN :: (g -> (Int, g)) -> (g -> (g, g)) -> g -> T.Tree Int
-genTreeN next split = cutTree 9 . genTree next split
-  where
-    cutTree :: Int -> T.Tree a -> T.Tree a
-    cutTree n (T.Node x forest)
-        | n <= 0    = T.Node x []
-        | otherwise = T.Node x (map (cutTree (n - 1)) forest)
-
-randomTree :: Int -> T.Tree Int
-randomTree = genTreeN R.next R.split . R.mkStdGen
-
-tfRandomTree :: Word64 -> T.Tree Int
-tfRandomTree w64 = genTreeN R.next R.split $ TF.seedTFGen (w64, w64, w64, w64)
-
-splitMixTree :: Word64 -> T.Tree Int
-splitMixTree w64 = genTreeN SM.nextInt SM.splitSMGen $ SM.mkSMGen w64
-
-splitMix32Tree :: Word64 -> T.Tree Int
-splitMix32Tree w64 = genTreeN SM32.nextInt SM32.splitSMGen $ SM32.mkSMGen $ fromIntegral w64
-
--------------------------------------------------------------------------------
--- List Word64
--------------------------------------------------------------------------------
-
--- infinite list
-genList64 :: (g -> (Word64, g)) -> g -> [Word64]
-genList64 r = unfoldr (Just . r)
-
--- truncated
-genListN64 :: (g -> (Word64, g)) -> g -> [Word64]
-genListN64 r = take 2048 . genList64 r
-
-randomList64 :: Int -> [Word64]
-randomList64 = genListN64 R.random . R.mkStdGen
-
-tfRandomList64 :: Word64 -> [Word64]
-tfRandomList64 w64 = genListN64 TF.random $ TF.seedTFGen (w64, w64, w64, w64)
-
-splitMixList64 :: Word64 -> [Word64]
-splitMixList64 w64 = genListN64 SM.nextWord64 $ SM.mkSMGen w64
-
-splitMix32List64 :: Word64 -> [Word64]
-splitMix32List64 w64 = genListN64 SM32.nextWord64 $ SM32.mkSMGen $ fromIntegral w64
-
--------------------------------------------------------------------------------
--- Tree Word64
--------------------------------------------------------------------------------
-
-genTree64 ::(g -> (Word64, g)) -> (g -> (g, g)) -> g -> T.Tree Word64
-genTree64 r split = go where
-    go g = case r g of
-        ~(i, g') -> T.Node i $ case split g' of
-            (ga, gb) -> [go ga, go gb]
-
-genTreeN64 :: (g -> (Word64, g)) -> (g -> (g, g)) -> g -> T.Tree Word64
-genTreeN64 r split = cutTree 9 . genTree64 r split
-  where
-    cutTree :: Word64 -> T.Tree a -> T.Tree a
-    cutTree n (T.Node x forest)
-        | n <= 0    = T.Node x []
-        | otherwise = T.Node x (map (cutTree (n - 1)) forest)
-
-randomTree64 :: Int -> T.Tree Word64
-randomTree64 = genTreeN64 R.random R.split . R.mkStdGen
-
-tfRandomTree64 :: Word64 -> T.Tree Word64
-tfRandomTree64 w64 = genTreeN64 TF.random R.split $ TF.seedTFGen (w64, w64, w64, w64)
-
-splitMixTree64 :: Word64 -> T.Tree Word64
-splitMixTree64 w64 = genTreeN64 SM.nextWord64 SM.splitSMGen $ SM.mkSMGen w64
-
-splitMix32Tree64 :: Word64 -> T.Tree Word64
-splitMix32Tree64 w64 = genTreeN64 SM32.nextWord64 SM32.splitSMGen $ SM32.mkSMGen $ fromIntegral w64
-
--------------------------------------------------------------------------------
--- Main
--------------------------------------------------------------------------------
-
-main :: IO ()
-main = defaultMain
-    [ bgroup "list"
-        [ bench "random"     $ nf randomList 42
-        , bench "tf-random"  $ nf tfRandomList 42
-        , bench "splitmix"   $ nf splitMixList 42
-        , bench "splitmix32" $ nf splitMix32List 42
-        ]
-    , bgroup "tree"
-        [ bench "random"     $ nf randomTree 42
-        , bench "tf-random"  $ nf tfRandomTree 42
-        , bench "splitmix"   $ nf splitMixTree 42
-        , bench "splitmix32" $ nf splitMix32Tree 42
-        ]
-    , bgroup "list 64"
-        [ bench "random"     $ nf randomList64 42
-        , bench "tf-random"  $ nf tfRandomList64 42
-        , bench "splitmix"   $ nf splitMixList64 42
-        , bench "splitmix32" $ nf splitMix32List64 42
-        ]
-    , bgroup "tree 64"
-        [ bench "random"     $ nf randomTree64 42
-        , bench "tf-random"  $ nf tfRandomTree64 42
-        , bench "splitmix"   $ nf splitMixTree64 42
-        , bench "splitmix32" $ nf splitMix32Tree64 42
-        ]
-    ]
diff --git a/bench/Range.hs b/bench/Range.hs
deleted file mode 100644
--- a/bench/Range.hs
+++ /dev/null
@@ -1,108 +0,0 @@
--- http://www.pcg-random.org/posts/bounded-rands.html
-{-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE CPP          #-}
-module Main where
-
-import Data.Bits
-import Data.Bits.Compat
-import Data.List        (unfoldr)
-import Data.Word        (Word32, Word64)
-
-import qualified System.Random.SplitMix32 as SM
-
-#if defined(__GHCJS__)
-#else
-import System.Clock (Clock (Monotonic), getTime, toNanoSecs)
-import Text.Printf  (printf)
-#endif
-
-main :: IO ()
-main = do
-    gen <- SM.newSMGen
-
-    -- bench gen (\g h -> R (0, pred h) g)
-    bench gen classicMod
-    bench gen intMult
-    bench gen bitmaskWithRejection
-
-bench :: g -> (g -> Word32 -> (Word32, g)) -> IO ()
-bench gen next = do
-    print $ take 70 $ unfoldr (\g -> Just (next g 10)) gen
-    clocked $ do
-        let x = sumOf next gen
-        print x
-
-sumOf :: (g -> Word32 -> (Word32, g)) -> g -> Word32
-sumOf next = go 0 2
-  where
-    go !acc !n g | n > 0xfffff = acc
-                 | otherwise    = let (w, g') = next g n in go (acc + w) (succ n) g'
-
-classicMod :: SM.SMGen -> Word32 -> (Word32, SM.SMGen)
-classicMod g h =
-    let (w32, g') = SM.nextWord32 g in (w32 `mod` h, g')
-
-
--- @
--- uint32_t bounded_rand(rng_t& rng, uint32_t range) {
---     uint32_t x = rng();
---     uint64_t m = uint64_t(x) * uint64_t(range);
---     return m >> 32;
--- }
--- @
---
-intMult :: SM.SMGen -> Word32 -> (Word32, SM.SMGen)
-intMult g h =
-    (fromIntegral $ (fromIntegral w32 * fromIntegral h :: Word64) `shiftR` 32, g')
-  where
-    (w32, g') = SM.nextWord32 g
-
--- @
--- uint32_t bounded_rand(rng_t& rng, uint32_t range) {
---     uint32_t mask = ~uint32_t(0);
---     --range;
---     mask >>= __builtin_clz(range|1);
---     uint32_t x;
---     do {
---         x = rng() & mask;
---     } while (x > range);
---     return x;
--- }
--- @@
-bitmaskWithRejection :: SM.SMGen -> Word32 -> (Word32, SM.SMGen)
-bitmaskWithRejection g0 range = go g0
-  where
-    mask = complement zeroBits `shiftR` countLeadingZeros (range .|. 1)
-    go g = let (x, g') = SM.nextWord32 g
-               x' = x .&. mask
-           in if x' >= range
-              then go g'
-              else (x', g')
-
--------------------------------------------------------------------------------
--- Poor man benchmarking with GHC and GHCJS
--------------------------------------------------------------------------------
-
-clocked :: IO () -> IO ()
-#if defined(__GHCJS__)
-clocked action = do
-    start
-    action
-    stop
-
-foreign import javascript unsafe
-    "console.time('loop');"
-    start :: IO ()
-
-foreign import javascript unsafe
-    "console.timeEnd('loop');"
-    stop :: IO ()
-#else
-clocked action =  do
-    start <- getTime Monotonic
-    action
-    end <- getTime Monotonic
-    printf "loop: %.03fms\n"
-        $ fromIntegral (toNanoSecs (end - start))
-        / (1e6 :: Double)
-#endif
diff --git a/bench/SimpleSum.hs b/bench/SimpleSum.hs
deleted file mode 100644
--- a/bench/SimpleSum.hs
+++ /dev/null
@@ -1,57 +0,0 @@
-{-# LANGUAGE CPP #-}
-module Main (main) where
-
-import System.Environment (getArgs)
-import Data.List (foldl')
-import Data.Word (Word32)
-
-import qualified System.Random as R
-import qualified System.Random.SplitMix as SM
-import qualified System.Random.SplitMix32 as SM32
-
-newGen :: a -> (a -> g) -> IO g -> IO g
-#if 0
-newGen _ _ new = new
-#else
-newGen seed mk _ = return (mk seed)
-#endif
-
-main :: IO ()
-main = do
-    putStrLn "Summing randoms..."
-    getArgs >>= \args -> case args of
-        "splitmix"   : _ -> newGen 33 SM.mkSMGen   SM.newSMGen   >>= \g -> print $ benchSum g SM.nextTwoWord32
-        "splitmix32" : _ -> newGen 33 SM32.mkSMGen SM32.newSMGen >>= \g -> print $ benchSum g SM32.nextTwoWord32
-        "random"     : _ -> R.newStdGen   >>= \g -> print $ benchSum g randomNextTwoWord32
-
-        "sm-integer" : _ -> SM.newSMGen >>= \g -> print $ benchSumInteger g (SM.nextInteger two64 (two64 * 5))
-        "r-integer"  : _ -> R.newStdGen >>= \g -> print $ benchSumInteger g (R.randomR (two64, two64 * 5))
-
-        -- after Closure Compiler getArgs return [] always?
-        -- _ -> newGen 33 SM.mkSMGen   SM.newSMGen   >>= \g -> print $ benchSum g SM.nextTwoWord32
-        _ -> newGen 33 SM32.mkSMGen SM32.newSMGen >>= \g -> print $ benchSum g SM32.nextTwoWord32
-
-
-benchSum :: g -> (g -> (Word32, Word32, g)) -> Word32
-benchSum g next = foldl' (+) 0 $ take 10000000 $ unfoldr2 next g
-
-benchSumInteger :: g -> (g -> (Integer, g)) -> Integer
-benchSumInteger g next = foldl' (+) 0 $ take 10000000 $ unfoldr next g
-
--- | Infinite unfoldr with two element generator
-unfoldr2 :: (s -> (a, a, s)) -> s -> [a]
-unfoldr2 f = go where
-    go s = let (x, y, s') = f s in x : y : go s'
-
--- | Infinite unfoldr with one element generator
-unfoldr :: (s -> (a, s)) -> s -> [a]
-unfoldr f = go where
-    go s = let (x, s') = f s in x : go s'
-
-randomNextTwoWord32 :: R.StdGen -> (Word32, Word32, R.StdGen)
-randomNextTwoWord32 s0 = (x, y, s2) where
-    (x, s1) = R.random s0
-    (y, s2) = R.random s1
-
-two64 :: Integer
-two64 = 2 ^ (64 :: Int)
diff --git a/cbits-unix/init.c b/cbits-unix/init.c
--- a/cbits-unix/init.c
+++ b/cbits-unix/init.c
@@ -1,6 +1,5 @@
 #include <stdint.h>
 #include <unistd.h>
-#include <sys/random.h>
 
 uint64_t splitmix_init() {
 	uint64_t result;
diff --git a/splitmix.cabal b/splitmix.cabal
--- a/splitmix.cabal
+++ b/splitmix.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.4
 name:               splitmix
-version:            0.1.3.1
+version:            0.1.3.2
 synopsis:           Fast Splittable PRNG
 description:
   Pure Haskell implementation of SplitMix described in
@@ -43,6 +43,7 @@
    || ==9.8.4
    || ==9.10.2
    || ==9.12.2
+   || ==9.14.1
 
 extra-doc-files:
   Changelog.md
@@ -60,13 +61,12 @@
 library
   default-language: Haskell2010
   ghc-options:      -Wall
-  hs-source-dirs:   src src-compat
+  hs-source-dirs:   src
   exposed-modules:
     System.Random.SplitMix
     System.Random.SplitMix32
 
   other-modules:
-    Data.Bits.Compat
     System.Random.SplitMix.Init
 
   -- dump-core
@@ -74,7 +74,7 @@
   -- ghc-options: -fplugin=DumpCore -fplugin-opt DumpCore:core-html
 
   build-depends:
-    , base     >=4.12.0.0 && <4.22
+    , base     >=4.12.0.0 && <4.23
     , deepseq  >=1.4.4.0  && <1.6
 
   if flag(optimised-mixer)
@@ -103,138 +103,18 @@
 
     else
       cpp-options:   -DSPLITMIX_INIT_COMPAT=1
-      build-depends: time >=1.2.0.3 && <1.15
+      build-depends: time >=1.2.0.3 && <1.16
 
 source-repository head
   type:     git
   location: https://github.com/haskellari/splitmix.git
 
-benchmark comparison
-  type:             exitcode-stdio-1.0
-  default-language: Haskell2010
-  ghc-options:      -Wall
-  hs-source-dirs:   bench
-  main-is:          Bench.hs
-  build-depends:
-    , base
-    , containers  >=0.6.0.1 && <0.8
-    , criterion   >=1.6.0.0 && <1.7
-    , random
-    , splitmix
-    , tf-random   >=0.5     && <0.6
-
-benchmark simple-sum
-  type:             exitcode-stdio-1.0
-  default-language: Haskell2010
-  ghc-options:      -Wall
-  hs-source-dirs:   bench
-  main-is:          SimpleSum.hs
-  build-depends:
-    , base
-    , random
-    , splitmix
-
-benchmark range
-  type:             exitcode-stdio-1.0
-  default-language: Haskell2010
-  ghc-options:      -Wall
-  hs-source-dirs:   bench src-compat
-  main-is:          Range.hs
-  other-modules:    Data.Bits.Compat
-  build-depends:
-    , base
-    , random
-    , splitmix
-
-test-suite examples
-  type:             exitcode-stdio-1.0
-  default-language: Haskell2010
-  ghc-options:      -Wall
-  hs-source-dirs:   tests
-  main-is:          Examples.hs
-  build-depends:
-    , base
-    , HUnit     >=1.6.0.0 && <1.7
-    , splitmix
-
-test-suite splitmix-tests
-  type:             exitcode-stdio-1.0
-  default-language: Haskell2010
-  ghc-options:      -Wall
-  hs-source-dirs:   tests
-  main-is:          Tests.hs
-  other-modules:
-    MiniQC
-    Uniformity
-
-  build-depends:
-    , base
-    , containers            >=0.4.0.0 && <0.8
-    , HUnit                 >=1.6.0.0 && <1.7
-    , math-functions        >=0.3.3.0 && <0.4
-    , splitmix
-    , test-framework        >=0.8.2.0 && <0.9
-    , test-framework-hunit  >=0.3.0.2 && <0.4
-
-test-suite montecarlo-pi
-  type:             exitcode-stdio-1.0
-  default-language: Haskell2010
-  ghc-options:      -Wall
-  hs-source-dirs:   tests
-  main-is:          SplitMixPi.hs
-  build-depends:
-    , base
-    , splitmix
-
-test-suite montecarlo-pi-32
+test-suite splitmix-examples
   type:             exitcode-stdio-1.0
   default-language: Haskell2010
   ghc-options:      -Wall
   hs-source-dirs:   tests
-  main-is:          SplitMixPi32.hs
-  build-depends:
-    , base
-    , splitmix
-
-test-suite splitmix-dieharder
-  default-language: Haskell2010
-  type:             exitcode-stdio-1.0
-  ghc-options:      -Wall -threaded -rtsopts
-  hs-source-dirs:   tests
-  main-is:          Dieharder.hs
-  build-depends:
-    , async       >=2.2.1    && <2.3
-    , base
-    , bytestring  >=0.10.8.2 && <0.13
-    , deepseq
-    , process     >=1.6.0.0  && <1.7
-    , random
-    , splitmix
-    , tf-random   >=0.5      && <0.6
-    , vector      >=0.13.0.0 && <0.14
-
-test-suite splitmix-testu01
-  if !os(linux)
-    buildable: False
-
-  default-language: Haskell2010
-  type:             exitcode-stdio-1.0
-  ghc-options:      -Wall -threaded -rtsopts
-  hs-source-dirs:   tests
-  main-is:          TestU01.hs
-  c-sources:        tests/cbits/testu01.c
-  extra-libraries:  testu01
-  build-depends:
-    , base
-    , base-compat-batteries  >=0.10.5 && <0.15
-    , splitmix
-
-test-suite initialization
-  default-language: Haskell2010
-  type:             exitcode-stdio-1.0
-  ghc-options:      -Wall -threaded -rtsopts
-  hs-source-dirs:   tests
-  main-is:          Initialization.hs
+  main-is:          splitmix-examples.hs
   build-depends:
     , base
     , HUnit     >=1.6.0.0 && <1.7
diff --git a/src-compat/Data/Bits/Compat.hs b/src-compat/Data/Bits/Compat.hs
deleted file mode 100644
--- a/src-compat/Data/Bits/Compat.hs
+++ /dev/null
@@ -1,9 +0,0 @@
-{-# LANGUAGE CPP #-}
-module Data.Bits.Compat (
-    popCount,
-    zeroBits,
-    finiteBitSize,
-    countLeadingZeros,
-    ) where
-
-import Data.Bits (popCount, zeroBits, finiteBitSize, countLeadingZeros)
diff --git a/src/System/Random/SplitMix.hs b/src/System/Random/SplitMix.hs
--- a/src/System/Random/SplitMix.hs
+++ b/src/System/Random/SplitMix.hs
@@ -49,7 +49,7 @@
     ) where
 
 import Data.Bits             (complement, shiftL, shiftR, xor, (.&.), (.|.))
-import Data.Bits.Compat      (countLeadingZeros, popCount, zeroBits)
+import Data.Bits             (countLeadingZeros, popCount, zeroBits)
 import Data.IORef            (IORef, atomicModifyIORef, newIORef)
 import Data.Word             (Word32, Word64)
 import System.IO.Unsafe      (unsafePerformIO)
diff --git a/src/System/Random/SplitMix32.hs b/src/System/Random/SplitMix32.hs
--- a/src/System/Random/SplitMix32.hs
+++ b/src/System/Random/SplitMix32.hs
@@ -32,7 +32,7 @@
     ) where
 
 import Data.Bits             (complement, shiftL, shiftR, xor, (.&.), (.|.))
-import Data.Bits.Compat
+import Data.Bits
        (countLeadingZeros, finiteBitSize, popCount, zeroBits)
 import Data.IORef            (IORef, atomicModifyIORef, newIORef)
 import Data.Word             (Word32, Word64)
diff --git a/tests/Dieharder.hs b/tests/Dieharder.hs
deleted file mode 100644
--- a/tests/Dieharder.hs
+++ /dev/null
@@ -1,273 +0,0 @@
-{-# LANGUAGE BangPatterns        #-}
-{-# LANGUAGE GADTs               #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-module Main (main) where
-
-import Control.Concurrent.QSem
-import Control.DeepSeq         (force)
-import Control.Monad           (when)
-import Data.Bits               (shiftL, (.|.))
-import Data.Char               (isSpace)
-import Data.List               (isInfixOf, unfoldr)
-import Data.Maybe              (fromMaybe)
-import Data.Word               (Word64)
-import Foreign.C               (Errno (..), ePIPE)
-import Foreign.Ptr             (castPtr)
-import GHC.IO.Exception        (IOErrorType (..), IOException (..))
-import System.Environment      (getArgs)
-import System.IO               (Handle, hGetContents, stdout)
-import Text.Printf             (printf)
-
-import qualified Control.Concurrent.Async     as A
-import qualified Control.Exception            as E
-import qualified Data.ByteString              as BS
-import qualified Data.ByteString.Unsafe       as BS (unsafePackCStringLen)
-import qualified Data.Vector.Storable.Mutable as MSV
-import qualified System.Process               as Proc
-import qualified System.Random.SplitMix       as SM
-import qualified System.Random.SplitMix32     as SM32
-import qualified System.Random.TF             as TF
-import qualified System.Random.TF.Gen         as TF
-import qualified System.Random.TF.Init        as TF
-
-main :: IO ()
-main = do
-    args <- getArgs
-    if null args
-    then return ()
-    else do
-        (cmd, runs, conc, seed, test, raw, _help) <- parseArgsIO args $ (,,,,,,)
-            <$> arg
-            <*> optDef "-n" 1
-            <*> optDef "-j" 1
-            <*> opt "-s"
-            <*> opt "-d"
-            <*> flag "-r"
-            <*> flag "-h"
-
-        let run :: RunType g
-            run | raw       = runRaw
-                | otherwise = runManaged
-
-        case cmd of
-              "splitmix"      -> do
-                  g <- maybe SM.initSMGen (return . SM.mkSMGen) seed
-                  run test runs conc SM.splitSMGen SM.nextWord64 g
-              "splitmix32"      -> do
-                  g <- maybe SM32.initSMGen (return . SM32.mkSMGen) (fmap fromIntegral seed)
-                  run test runs conc SM32.splitSMGen SM32.nextWord64 g
-              "tfrandom"      -> do
-                  g <- TF.initTFGen
-                  run test runs conc TF.split tfNext64 g
-              _               -> return ()
-
-tfNext64 :: TF.TFGen -> (Word64, TF.TFGen)
-tfNext64 g =
-    let (w, g')   = TF.next g
-        (w', g'') = TF.next g'
-    in (fromIntegral w `shiftL` 32 .|. fromIntegral w', g'')
-
--------------------------------------------------------------------------------
--- Dieharder
--------------------------------------------------------------------------------
-
-type RunType g =
-       Maybe Int
-    -> Int
-    -> Int
-    -> (g -> (g, g))
-    -> (g -> (Word64, g))
-    -> g
-    -> IO () 
-
-runRaw :: RunType g
-runRaw _test _runs _conc split word gen =
-    generate word split gen stdout
-
-runManaged :: RunType g
-runManaged test runs conc split word gen = do
-    qsem <- newQSem conc
-
-    rs <- A.forConcurrently (take runs $ unfoldr (Just . split) gen) $ \g ->
-        E.bracket_ (waitQSem qsem) (signalQSem qsem) $
-            dieharder test (generate word split g)
-
-    case mconcat rs of
-        Result p w f -> do
-            let total = fromIntegral (p + w + f) :: Double
-            printf "PASSED %4d %6.02f%%\n" p (fromIntegral p / total * 100)
-            printf "WEAK   %4d %6.02f%%\n" w (fromIntegral w / total * 100)
-            printf "FAILED %4d %6.02f%%\n" f (fromIntegral f / total * 100)
-{-# INLINE runManaged #-}
-
-dieharder :: Maybe Int -> (Handle -> IO ()) -> IO Result
-dieharder test gen = do
-    let proc = Proc.proc "dieharder" $ ["-g", "200"] ++ maybe ["-a"] (\t -> ["-d", show t]) test
-    (Just hin, Just hout, _, ph) <- Proc.createProcess proc
-        { Proc.std_in  = Proc.CreatePipe
-        , Proc.std_out = Proc.CreatePipe
-        }
-
-    out <- hGetContents hout
-    waitOut <- A.async $ E.evaluate $ force out
-
-    E.catch (gen hin) $ \e -> case e of
-        IOError { ioe_type = ResourceVanished , ioe_errno = Just ioe }
-            | Errno ioe == ePIPE -> return ()
-        _ -> E.throwIO e
-
-    res <- A.wait waitOut
-    _ <- Proc.waitForProcess ph
-
-    return $ parseOutput res
-{-# INLINE dieharder #-}
-
-parseOutput :: String -> Result
-parseOutput = foldMap parseLine . lines where
-    parseLine l
-        | any (`isInfixOf` l) doNotUse = mempty
-        | "PASSED" `isInfixOf` l = Result 1 0 0
-        | "WEAK"   `isInfixOf` l = Result 0 1 0
-        | "FAILED" `isInfixOf` l = Result 0 1 0
-        | otherwise = mempty
-
-    doNotUse = ["diehard_opso", "diehard_oqso", "diehard_dna", "diehard_weak"]
-
--------------------------------------------------------------------------------
--- Results
--------------------------------------------------------------------------------
-
-data Result = Result
-    { _passed :: Int
-    , _weak   :: Int
-    , _failed :: Int
-    }
-  deriving Show
-
-instance Semigroup Result where
-    Result p w f <> Result p' w' f' = Result (p + p') (w +  w') (f + f')
-
-instance Monoid Result where
-    mempty = Result 0 0 0
-    mappend = (<>)
-
--------------------------------------------------------------------------------
--- Writer
--------------------------------------------------------------------------------
-
-size :: Int
-size = 512
-
-generate
-    :: forall g. (g -> (Word64, g))
-    -> (g -> (g, g))
-    -> g -> Handle -> IO ()
-generate word split gen0 h = do
-    vec <- MSV.new size
-    go gen0 vec
-  where
-    go :: g -> MSV.IOVector Word64 -> IO ()
-    go gen vec = do
-        let (g1, g2) = split gen
-        write g1 vec 0
-        MSV.unsafeWith vec $ \ptr -> do
-            bs <- BS.unsafePackCStringLen (castPtr ptr, size * 8)
-            BS.hPutStr h bs
-        go g2 vec
-
-    write :: g -> MSV.IOVector Word64 -> Int -> IO ()
-    write !gen !vec !i = do
-        let (w64, gen') = word gen
-        MSV.unsafeWrite vec i w64
-        when (i < size) $
-            write gen' vec (i + 1)
-{-# INLINE generate #-}
-
--------------------------------------------------------------------------------
--- readMaybe
--------------------------------------------------------------------------------
-
-readEither :: Read a => String -> Either String a
-readEither s =
-  case [ x | (x,rest) <- reads s, all isSpace rest ] of
-    [x] -> Right x
-    []  -> Left "Prelude.read: no parse"
-    _   -> Left "Prelude.read: ambiguous parse"
-
-readMaybe :: Read a => String -> Maybe a
-readMaybe s = case readEither s of
-                Left _  -> Nothing
-                Right a -> Just a
-
--------------------------------------------------------------------------------
--- Do it yourself command line parsing
--------------------------------------------------------------------------------
-
--- | 'Parser' is not an 'Alternative', only a *commutative* 'Applicative'.
---
--- Useful for quick cli parsers, like parametrising tests.
-data Parser a where
-    Pure :: a -> Parser a
-    Ap :: Arg b -> Parser (b -> a) -> Parser a
-
-instance Functor Parser where
-    fmap f (Pure a) = Pure (f a)
-    fmap f (Ap x y) = Ap x (fmap (f .) y)
-
-instance  Applicative Parser where
-    pure = Pure
-
-    Pure f <*> z = fmap f z
-    Ap x y <*> z = Ap x (flip <$> y <*> z)
-
-data Arg a where
-    Flag :: String -> Arg Bool
-    Opt  :: String -> (String -> Maybe a) -> Arg (Maybe a)
-    Arg  :: Arg String
-
-arg :: Parser String
-arg = Ap Arg (Pure id)
-
-flag :: String -> Parser Bool
-flag n = Ap (Flag n) (Pure id)
-
-opt :: Read a => String -> Parser (Maybe a)
-opt n = Ap (Opt n readMaybe) (Pure id)
-
-optDef :: Read a => String -> a -> Parser a
-optDef n d = Ap (Opt n readMaybe) (Pure (fromMaybe d))
-
-parseArgsIO :: [String] -> Parser a -> IO a
-parseArgsIO args p = either fail pure (parseArgs args p)
-
-parseArgs :: [String] -> Parser a -> Either String a
-parseArgs []       p = parserToEither p
-parseArgs (x : xs) p = do
-    (xs', p') <- singleArg p x xs
-    parseArgs xs' p'
-
-singleArg :: Parser a -> String -> [String] -> Either String ([String], Parser a)
-singleArg (Pure _)           x _  = Left $ "Extra argument " ++ x
-singleArg (Ap Arg p)         x xs
-    | null x || head x /= '-'     = Right (xs, fmap ($ x) p)
-    | otherwise                   = fmap2 (Ap Arg) (singleArg p x xs)
-singleArg (Ap f@(Flag n) p)  x xs
-    | x == n                      = Right (xs, fmap ($ True) p)
-    | otherwise                   = fmap2 (Ap f) (singleArg p x xs)
-singleArg (Ap o@(Opt n r) p) x xs
-    | x == n                      = case xs of
-        [] -> Left $ "Expected an argument for " ++ n
-        (x' : xs') -> case r x' of
-            Nothing -> Left $ "Cannot read an argument of " ++ n ++ ": " ++ x'
-            Just y  -> Right (xs', fmap ($ Just y) p)
-    | otherwise                   = fmap2 (Ap o) (singleArg p x xs)
-
-fmap2 :: (Functor f, Functor g) => (a -> b) -> f (g a) -> f (g b)
-fmap2 = fmap . fmap
-
--- | Convert parser to 'Right' if there are only defaultable pieces left.
-parserToEither :: Parser a -> Either String a
-parserToEither (Pure x)         = pure x
-parserToEither (Ap (Flag _) p)  = parserToEither $ fmap ($ False) p
-parserToEither (Ap (Opt _ _) p) = parserToEither $ fmap ($ Nothing) p
-parserToEither (Ap Arg _)       = Left "argument required"
diff --git a/tests/Examples.hs b/tests/Examples.hs
deleted file mode 100644
--- a/tests/Examples.hs
+++ /dev/null
@@ -1,15 +0,0 @@
-module Main (main) where
-
-import Test.HUnit ((@?=))
-
-import qualified System.Random.SplitMix32 as SM32
-
-main :: IO ()
-main = do
-    let g = SM32.mkSMGen 42
-    show g @?= "SMGen 142593372 1604540297"
-    print g
-
-    let (w32, g') = SM32.nextWord32 g
-    w32     @?= 1296549791
-    show g' @?= "SMGen 1747133669 1604540297"
diff --git a/tests/Initialization.hs b/tests/Initialization.hs
deleted file mode 100644
--- a/tests/Initialization.hs
+++ /dev/null
@@ -1,28 +0,0 @@
-module Main (main) where
-
-import Control.Monad (forM_, replicateM)
-import Data.List     (tails)
-import Test.HUnit    (assertFailure)
-
-import qualified System.Random.SplitMix   as SM
-import qualified System.Random.SplitMix32 as SM32
-
-main :: IO ()
-main = do
-    g64 <- replicateM 10 (fmap show SM.initSMGen)
-    putStrLn $ unlines g64
-    forM_ (tails g64) $ \xs' -> case xs' of
-        []     -> return ()
-        (x:xs) ->
-            if all (x /=) xs
-            then return ()
-            else assertFailure "ERROR: duplicate"
-
-    g32 <- replicateM 10 (fmap show SM32.initSMGen)
-    putStrLn $ unlines g32
-    forM_ (tails g32) $ \xs' -> case xs' of
-        []     -> return ()
-        (x:xs) ->
-            if all (x /=) xs
-            then return ()
-            else assertFailure "ERROR: duplicate"
diff --git a/tests/MiniQC.hs b/tests/MiniQC.hs
deleted file mode 100644
--- a/tests/MiniQC.hs
+++ /dev/null
@@ -1,81 +0,0 @@
-{-# LANGUAGE DeriveFunctor #-}
--- | This QC doesn't shrink :(
-module MiniQC where
-
-import Control.Monad                  (ap)
-import Data.Int                       (Int32, Int64)
-import Data.Word                      (Word32, Word64)
-import Test.Framework.Providers.API   (Test, TestName)
-import Test.Framework.Providers.HUnit (testCase)
-import Test.HUnit                     (assertFailure)
-
-import System.Random.SplitMix
-
-newtype Gen a = Gen { unGen :: SMGen -> a }
-  deriving (Functor)
-
-instance Applicative Gen where
-    pure x = Gen (const x)
-    (<*>) = ap
-
-instance Monad Gen where
-    return = pure
-
-    m >>= k = Gen $ \g ->
-        let (g1, g2) = splitSMGen g
-        in unGen (k (unGen m g1)) g2
-
-class Arbitrary a where
-    arbitrary :: Gen a
-
-instance Arbitrary Word32 where
-    arbitrary = Gen $ \g -> fst (nextWord32 g)
-instance Arbitrary Word64 where
-    arbitrary = Gen $ \g -> fst (nextWord64 g)
-instance Arbitrary Int32 where
-    arbitrary = Gen $ \g -> fromIntegral (fst (nextWord32 g))
-instance Arbitrary Int64 where
-    arbitrary = Gen $ \g -> fromIntegral (fst (nextWord64 g))
-instance Arbitrary Double where
-    arbitrary = Gen $ \g -> fst (nextDouble g)
-
-newtype Property = Property { unProperty :: Gen ([String], Bool) }
-
-class Testable a where
-    property :: a -> Property
-
-instance Testable Property where
-    property = id
-
-instance Testable Bool where
-    property b = Property $ pure ([show b], b)
-
-instance (Arbitrary a, Show a, Testable b) => Testable (a -> b) where
-    property f = Property $ do
-        x <- arbitrary
-        (xs, b) <- unProperty (property (f x))
-        return (show x : xs, b)
-
-forAllBlind :: Testable prop => Gen a -> (a -> prop) -> Property
-forAllBlind g f = Property $ do
-    x <- g
-    (xs, b) <- unProperty (property (f x))
-    return ("<blind>" : xs, b)
-
-counterexample :: Testable prop => String -> prop -> Property
-counterexample msg prop = Property $ do
-    (xs, b) <- unProperty (property prop)
-    return (msg : xs, b)
-
-testMiniProperty :: Testable prop => TestName -> prop -> Test
-testMiniProperty name prop = testCase name $ do
-    g <- newSMGen
-    go (100 :: Int) g
-  where
-    go n _ | n <= 0  = return ()
-    go n g           = do
-        let (g1, g2) = splitSMGen g
-        case unGen (unProperty (property prop)) g1 of
-            (_, True) -> return ()
-            (xs, False) -> assertFailure (unlines (reverse xs))
-        go (pred n) g2
diff --git a/tests/SplitMixPi.hs b/tests/SplitMixPi.hs
deleted file mode 100644
--- a/tests/SplitMixPi.hs
+++ /dev/null
@@ -1,27 +0,0 @@
-module Main (main) where
-
-import Data.List (unfoldr, foldl')
-import System.Random.SplitMix
-
-doubles :: SMGen -> [Double]
-doubles = unfoldr (Just . nextDouble)
-
-monteCarloPi :: SMGen -> Double
-monteCarloPi = (4 *) . calc . foldl' accum (P 0 0) . take 50000000 . pairs . doubles
-  where
-    calc (P n m) = fromIntegral n / fromIntegral m
-
-    pairs (x : y : xs) = (x, y) : pairs xs
-    pairs _ = []
-
-    accum (P n m) (x, y) | x * x + y * y >= 1 = P n (m + 1)
-                         | otherwise          = P (n + 1) (m + 1)
-
-data P = P !Int !Int
-
-main :: IO ()
-main = do
-    pi' <- fmap monteCarloPi newSMGen
-    print (pi :: Double)
-    print pi'
-    print (pi - pi')
diff --git a/tests/SplitMixPi32.hs b/tests/SplitMixPi32.hs
deleted file mode 100644
--- a/tests/SplitMixPi32.hs
+++ /dev/null
@@ -1,27 +0,0 @@
-module Main (main) where
-
-import Data.List (unfoldr, foldl')
-import System.Random.SplitMix32
-
-doubles :: SMGen -> [Float]
-doubles = unfoldr (Just . nextFloat)
-
-monteCarloPi :: SMGen -> Float
-monteCarloPi = (4 *) . calc . foldl' accum (P 0 0) . take 50000000 . pairs . doubles
-  where
-    calc (P n m) = fromIntegral n / fromIntegral m
-
-    pairs (x : y : xs) = (x, y) : pairs xs
-    pairs _ = []
-
-    accum (P n m) (x, y) | x * x + y * y >= 1 = P n (m + 1)
-                         | otherwise          = P (n + 1) (m + 1)
-
-data P = P !Int !Int
-
-main :: IO ()
-main = do
-    pi' <- fmap monteCarloPi newSMGen
-    print (pi :: Float)
-    print pi'
-    print (pi - pi')
diff --git a/tests/TestU01.hs b/tests/TestU01.hs
deleted file mode 100644
--- a/tests/TestU01.hs
+++ /dev/null
@@ -1,185 +0,0 @@
-{-# LANGUAGE BangPatterns        #-}
-{-# LANGUAGE GADTs               #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-module Main (main) where
-
-import Prelude ()
-import Prelude.Compat
-
-import Data.Char          (isSpace)
-import Data.IORef         (IORef, newIORef, readIORef, writeIORef)
-import Data.Maybe         (fromMaybe)
-import Data.Word          (Word32)
-import System.Environment (getArgs)
-import System.IO.Unsafe   (unsafePerformIO)
-
-import qualified System.Random.SplitMix   as SM64
-import qualified System.Random.SplitMix32 as SM32
-
--------------------------------------------------------------------------------
--- SplitMix32
--------------------------------------------------------------------------------
-
-sm32ref :: IORef SM32.SMGen
-sm32ref = unsafePerformIO $ newIORef $ SM32.mkSMGen 42
-{-# NOINLINE sm32ref #-}
-
-foreign export ccall haskell_splitmix32 :: IO Word32
-foreign export ccall haskell_splitmix32_double :: IO Double
-
-haskell_splitmix32 :: IO Word32
-haskell_splitmix32 = do
-    g <- readIORef sm32ref
-    let !(w32, g') = SM32.nextWord32 g
-    writeIORef sm32ref g'
-    return w32
-
-haskell_splitmix32_double :: IO Double
-haskell_splitmix32_double = do
-    g <- readIORef sm32ref
-    let !(d, g') = SM32.nextDouble g
-    writeIORef sm32ref g'
-    return d
-
--------------------------------------------------------------------------------
--- SplitMix64
--------------------------------------------------------------------------------
-
-sm64ref :: IORef SM64.SMGen
-sm64ref = unsafePerformIO $ newIORef $ SM64.mkSMGen 42
-{-# NOINLINE sm64ref #-}
-
-foreign export ccall haskell_splitmix64 :: IO Word32
-foreign export ccall haskell_splitmix64_double :: IO Double
-
-haskell_splitmix64 :: IO Word32
-haskell_splitmix64 = do
-    g <- readIORef sm64ref
-    let !(w32, g') = SM64.nextWord32 g
-    writeIORef sm64ref g'
-    return w32
-
-haskell_splitmix64_double :: IO Double
-haskell_splitmix64_double = do
-    g <- readIORef sm64ref
-    let !(d, g') = SM64.nextDouble g
-    writeIORef sm64ref g'
-    return d
-
--------------------------------------------------------------------------------
--- Main
--------------------------------------------------------------------------------
-
-foreign import ccall "run_testu01" run_testu01_c :: Int -> Int -> IO ()
-
-main :: IO ()
-main = do
-    args <- getArgs
-    (gen, bat) <- parseArgsIO args $ (,)
-        <$> optDef "-g" SplitMix
-        <*> optDef "-b" SmallCrush
-    run_testu01_c (fromEnum gen) (fromEnum bat)
-
-data Gen
-    = SplitMixDouble
-    | SplitMix
-    | SplitMix32Double
-    | SplitMix32
-    | SplitMix32Native
-  deriving (Read, Enum)
-
-data Bat
-    = SmallCrush
-    | Crush
-    | BigCrush
-    | Sample
-  deriving (Read, Enum)
-
--------------------------------------------------------------------------------
--- readMaybe
--------------------------------------------------------------------------------
-
-readEither :: Read a => String -> Either String a
-readEither s =
-  case [ x | (x,rest) <- reads s, all isSpace rest ] of
-    [x] -> Right x
-    []  -> Left "Prelude.read: no parse"
-    _   -> Left "Prelude.read: ambiguous parse"
-
-readMaybe :: Read a => String -> Maybe a
-readMaybe s = case readEither s of
-                Left _  -> Nothing
-                Right a -> Just a
-
--------------------------------------------------------------------------------
--- Do it yourself command line parsing
--------------------------------------------------------------------------------
-
--- | 'Parser' is not an 'Alternative', only a *commutative* 'Applicative'.
---
--- Useful for quick cli parsers, like parametrising tests.
-data Parser a where
-    Pure :: a -> Parser a
-    Ap :: Arg b -> Parser (b -> a) -> Parser a
-
-instance Functor Parser where
-    fmap f (Pure a) = Pure (f a)
-    fmap f (Ap x y) = Ap x (fmap (f .) y)
-
-instance  Applicative Parser where
-    pure = Pure
-
-    Pure f <*> z = fmap f z
-    Ap x y <*> z = Ap x (flip <$> y <*> z)
-
-data Arg a where
-    Flag :: String -> Arg Bool
-    Opt  :: String -> (String -> Maybe a) -> Arg (Maybe a)
-    Arg  :: Arg String
-
--- arg :: Parser String
--- arg = Ap Arg (Pure id)
---
--- flag :: String -> Parser Bool
--- flag n = Ap (Flag n) (Pure id)
---
--- opt :: Read a => String -> Parser (Maybe a)
--- opt n = Ap (Opt n readMaybe) (Pure id)
-
-optDef :: Read a => String -> a -> Parser a
-optDef n d = Ap (Opt n readMaybe) (Pure (fromMaybe d))
-
-parseArgsIO :: [String] -> Parser a -> IO a
-parseArgsIO args p = either fail pure (parseArgs args p)
-
-parseArgs :: [String] -> Parser a -> Either String a
-parseArgs []       p = parserToEither p
-parseArgs (x : xs) p = do
-    (xs', p') <- singleArg p x xs
-    parseArgs xs' p'
-
-singleArg :: Parser a -> String -> [String] -> Either String ([String], Parser a)
-singleArg (Pure _)           x _  = Left $ "Extra argument " ++ x
-singleArg (Ap Arg p)         x xs
-    | null x || head x /= '-'     = Right (xs, fmap ($ x) p)
-    | otherwise                   = fmap2 (Ap Arg) (singleArg p x xs)
-singleArg (Ap f@(Flag n) p)  x xs
-    | x == n                      = Right (xs, fmap ($ True) p)
-    | otherwise                   = fmap2 (Ap f) (singleArg p x xs)
-singleArg (Ap o@(Opt n r) p) x xs
-    | x == n                      = case xs of
-        [] -> Left $ "Expected an argument for " ++ n
-        (x' : xs') -> case r x' of
-            Nothing -> Left $ "Cannot read an argument of " ++ n ++ ": " ++ x'
-            Just y  -> Right (xs', fmap ($ Just y) p)
-    | otherwise                   = fmap2 (Ap o) (singleArg p x xs)
-
-fmap2 :: (Functor f, Functor g) => (a -> b) -> f (g a) -> f (g b)
-fmap2 = fmap . fmap
-
--- | Convert parser to 'Right' if there are only defaultable pieces left.
-parserToEither :: Parser a -> Either String a
-parserToEither (Pure x)         = pure x
-parserToEither (Ap (Flag _) p)  = parserToEither $ fmap ($ False) p
-parserToEither (Ap (Opt _ _) p) = parserToEither $ fmap ($ Nothing) p
-parserToEither (Ap Arg _)       = Left "argument required"
diff --git a/tests/Tests.hs b/tests/Tests.hs
deleted file mode 100644
--- a/tests/Tests.hs
+++ /dev/null
@@ -1,136 +0,0 @@
-module Main (main) where
-
-import Data.Bits      ((.&.))
-import Data.Int       (Int64)
-import Data.Word      (Word64)
-import Test.Framework (defaultMain, testGroup)
-
-import qualified System.Random.SplitMix   as SM
-import qualified System.Random.SplitMix32 as SM32
-
-import MiniQC     (Arbitrary (..), Gen (..), counterexample, testMiniProperty)
-import Uniformity
-
-main :: IO ()
-main = defaultMain
-    [ testUniformity "SM64 uniformity" (arbitrary :: Gen Word64) (.&. 0xf) 16
-    , testUniformity "SM64 uniformity" (arbitrary :: Gen Word64) (.&. 0xf0) 16
-
-    , testUniformity "bitmaskWithRejection uniformity" (arbitrary :: Gen Word64mod7) id 7
-
-    , testGroup "nextInteger"
-        [ testMiniProperty "valid" $ \a b c d seed -> do
-            let lo' = fromIntegral (a :: Int64) * fromIntegral (b :: Int64)
-                hi' = fromIntegral (c :: Int64) * fromIntegral (d :: Int64)
-
-                lo = min lo' hi'
-                hi = max lo' hi'
-
-            let g = SM.mkSMGen seed
-                (x, _) = SM.nextInteger lo' hi' g
-
-            counterexample (show x) $ lo <= x && x <= hi
-
-        , testMiniProperty "valid small" $ \a b seed -> do
-            let lo' = fromIntegral (a :: Int64) `rem` 10
-                hi' = fromIntegral (b :: Int64) `rem` 10
-
-                lo = min lo' hi'
-                hi = max lo' hi'
-
-            let g = SM.mkSMGen seed
-                (x, _) = SM.nextInteger lo' hi' g
-
-            counterexample (show x) $ lo <= x && x <= hi
-
-        , testMiniProperty "I1 valid" i1valid
-        , testUniformity "I1 uniform" arbitrary (\(I1 w) -> w) 15
-
-        , testMiniProperty "I7 valid" i7valid
-        , testUniformity "I7 uniform" arbitrary (\(I7 w) -> w `mod` 7) 7
-        ]
-
-    , testGroup "SM bitmaskWithRejection"
-        [ testMiniProperty "64" $ \w' seed -> do
-            let w = w' .&. 0xff
-            let w1 = w + 1
-            let g = SM.mkSMGen seed
-            let (x, _) = SM.bitmaskWithRejection64 w1 g
-            counterexample ("64-64 " ++ show x ++ " <= " ++ show w) (x < w1)
-        , testMiniProperty "64'" $ \w' seed -> do
-            let w = w' .&. 0xff
-            let g = SM.mkSMGen seed
-            let (x, _) = SM.bitmaskWithRejection64' w g
-            counterexample ("64-64 " ++ show x ++ " < " ++ show w) (x <= w)
-        , testMiniProperty "32" $ \w' seed -> do
-            let w = w' .&. 0xff
-            let u1 = w'
-            let g = SM.mkSMGen seed
-            let (x, _) = SM.bitmaskWithRejection32 u1 g
-            counterexample ("64-32 " ++ show x ++ " <= " ++ show w) (x < u1)
-        , testMiniProperty "32'" $ \w' seed -> do
-            let w = w' .&. 0xff
-            let u = w
-            let g = SM.mkSMGen seed
-            let (x, _) = SM.bitmaskWithRejection32' u g
-            counterexample ("64-32 " ++ show x ++ " < " ++ show w) (x <= u)
-        ]
-    , testGroup "SM32 bitmaskWithRejection"
-        [ testMiniProperty "64" $ \w' seed -> do
-            let w = w' .&. 0xff
-            let w1 = w + 1
-            let g = SM32.mkSMGen seed
-            let (x, _) = SM32.bitmaskWithRejection64 w1 g
-            counterexample ("64-64 " ++ show x ++ " <= " ++ show w) (x < w1)
-        , testMiniProperty "64'" $ \w' seed -> do
-            let w = w' .&. 0xff
-            let g = SM32.mkSMGen seed
-            let (x, _) = SM32.bitmaskWithRejection64' w g
-            counterexample ("64-64 " ++ show x ++ " < " ++ show w) (x <= w)
-        , testMiniProperty "32" $ \w' seed -> do
-            let w = w' .&. 0xff
-            let u1 = w'
-            let g = SM32.mkSMGen seed
-            let (x, _) = SM32.bitmaskWithRejection32 u1 g
-            counterexample ("64-32 " ++ show x ++ " <= " ++ show w) (x < u1)
-        , testMiniProperty "32'" $ \w' seed -> do
-            let w = w' .&. 0xff
-            let u = w
-            let g = SM32.mkSMGen seed
-            let (x, _) = SM32.bitmaskWithRejection32' u g
-            counterexample ("64-32 " ++ show x ++ " < " ++ show w) (x <= u)
-        ]
-    ]
-
-newtype Word64mod7 = W7 Word64 deriving (Eq, Ord, Show)
-instance Arbitrary Word64mod7 where
-    arbitrary = Gen $ \g -> W7 $ fst $ SM.bitmaskWithRejection64' 6 g
-
-newtype Integer1 = I1 Integer deriving (Eq, Ord, Show)
-instance Arbitrary Integer1 where
-    arbitrary = Gen $ \g -> I1 $ fst $ SM.nextInteger i1min i1max g
-
-i1min :: Integer
-i1min = -7
-
-i1max :: Integer
-i1max = 7
-
-i1valid :: Integer1 -> Bool
-i1valid (I1 i) = i1min <= i && i <= i1max
-
-newtype Integer7 = I7 Integer deriving (Eq, Ord, Show)
-instance Arbitrary Integer7 where
-    arbitrary = Gen $ \g -> I7 $ fst $ SM.nextInteger i7min i7max g
-
-i7min :: Integer
-i7min = negate two64
-
-i7max :: Integer
-i7max = two64 * 6 + 7 * 1234567
-
-i7valid :: Integer7 -> Bool
-i7valid (I7 i) = i7min <= i && i <= i7max
-
-two64 :: Integer
-two64 = 2 ^ (64 :: Int)
diff --git a/tests/Uniformity.hs b/tests/Uniformity.hs
deleted file mode 100644
--- a/tests/Uniformity.hs
+++ /dev/null
@@ -1,134 +0,0 @@
-{-# LANGUAGE BangPatterns        #-}
-{-# LANGUAGE DeriveFunctor       #-}
-{-# LANGUAGE ScopedTypeVariables #-}
--- | Chi-Squared test for uniformity.
-module Uniformity (testUniformity) where
-
-import Data.List                    (intercalate)
-import Data.List                    (foldl')
-import Numeric                      (showFFloat)
-import Numeric.SpecFunctions        (incompleteGamma)
-import Test.Framework.Providers.API (Test, TestName)
-
-import qualified Data.Map as Map
-
-import MiniQC as QC
-
--- | \( \lim_{n\to\infty} \mathrm{Pr}(V \le v) = \ldots \)
-chiDist
-    :: Int     -- ^ k, categories
-    -> Double  -- ^ v, value
-    -> Double
-chiDist k x = incompleteGamma (0.5 * v) (0.5 * x) where
-  v = fromIntegral (k - 1)
-
--- | When the distribution is uniform,
---
--- \[
--- \frac{1}{n} \sum_{s = 1}^k \frac{Y_s^2}{p_s} - n
--- \]
---
--- simplifies to
---
--- \[
--- \frac{k}{n} \sum_{s=1}^k Y_s^2 - n
--- \]
---
--- when \(p_s = \frac{1}{k} \), i.e. \(k\) is the number of buckets.
---
-calculateV :: Int -> Map.Map k Int -> Double
-calculateV k data_ = chiDist k v
-  where
-    v          = fromIntegral k * fromIntegral sumY2 / fromIntegral n - fromIntegral n
-    V2 n sumY2 = foldl' sumF (V2 0 0) (Map.elems data_) where
-        sumF (V2 m m2) x = V2 (m + x) (m2 + x * x)
-
--- Strict pair of 'Int's, used as an accumulator.
-data V2 = V2 !Int !Int
-
-countStream :: Ord a => Stream a -> Int -> Map.Map a Int
-countStream = go Map.empty where
-    go !acc s n
-        | n <= 0    = acc
-        | otherwise = case s of
-            x :> xs -> go (Map.insertWith (+) x 1 acc) xs (pred n)
-
-testUniformityRaw :: forall a. (Ord a, Show a) => Int -> Stream a -> Either String Double
-testUniformityRaw k s
-    | Map.size m > k = Left $ "Got more elements (" ++ show (Map.size m, take 5 $ Map.keys m) ++ " than expected (" ++ show k ++ ")"
-    | p > 0.999999   = Left $
-        "Too impropabable p-value: " ++ show p ++ "\n" ++ table
-        [ [ show x, showFFloat (Just 3) (fromIntegral y / fromIntegral n :: Double) "" ]
-        | (x, y) <- take 20 $ Map.toList m
-        ]
-    | otherwise      = Right p
-  where
-    -- each bucket to have roughly 128 elements
-    n :: Int
-    n = k * 128
-
-    -- buckets from the stream
-    m :: Map.Map a Int
-    m = countStream s n
-
-    -- calculate chi-squared value
-    p :: Double
-    p = calculateV k m
-
-testUniformityQC :: (Ord a, Show a) => Int -> Stream a -> QC.Property
-testUniformityQC k s = case testUniformityRaw k s of
-    Left err -> QC.counterexample err False
-    Right _  -> QC.property True
-
--- | Test that generator produces values uniformly.
---
--- The size is scaled to be at least 20.
---
-testUniformity
-    :: forall a b. (Ord b, Show b)
-    => TestName
-    -> QC.Gen a  -- ^ Generator to test
-    -> (a -> b)    -- ^ Partitioning function
-    -> Int         -- ^ Number of partittions
-    -> Test
-testUniformity name gen f k = QC.testMiniProperty name
-    $ QC.forAllBlind (streamGen gen)
-    $ testUniformityQC k . fmap f
-
--------------------------------------------------------------------------------
--- Infinite stream
--------------------------------------------------------------------------------
-
-data Stream a = a :> Stream a deriving (Functor)
-infixr 5 :>
-
-streamGen :: QC.Gen a -> QC.Gen (Stream a)
-streamGen g = gs where
-    gs = do
-        x <- g
-        xs <- gs
-        return (x :> xs)
-
--------------------------------------------------------------------------------
--- Table
--------------------------------------------------------------------------------
-
-table :: [[String]] -> String
-table cells = unlines rows
-  where
-    cols      :: Int
-    rowWidths :: [Int]
-    rows      :: [String]
-
-    (cols, rowWidths, rows) = foldr go (0, repeat 0, []) cells
-
-    go :: [String] -> (Int, [Int], [String]) -> (Int, [Int], [String])
-    go xs (c, w, yss) =
-        ( max c (length xs)
-        , zipWith max w (map length xs ++ repeat 0)
-        , intercalate "   " (take cols (zipWith fill xs rowWidths))
-          : yss
-        )
-
-    fill :: String -> Int -> String
-    fill s n = s ++ replicate (n - length s) ' '
diff --git a/tests/cbits/testu01.c b/tests/cbits/testu01.c
deleted file mode 100644
--- a/tests/cbits/testu01.c
+++ /dev/null
@@ -1,138 +0,0 @@
-#include "TestU01.h"
-
-#include <stdint.h>
-
-/* Utilities */
-
-inline unsigned int popcount32(uint32_t i) {
-    i = i - ((i >> 1) & 0x55555555);
-    i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
-    return (((i + (i >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
-}
-
-inline uint64_t rotl64(uint64_t value, unsigned int count) {
-    return value << count | value >> (64 - count);
-}
-
-/* For comparison, SplitMix32 generator in C */
-#define GOLDEN_GAMMA 0x9e3779b9U
-
-static uint32_t seed  = 0;
-static uint32_t gamma = 0;
-
-uint32_t mix32(uint32_t z) {
-    z = (z ^ (z >> 16)) * 0x85ebca6b;
-    z = (z ^ (z >> 13)) * 0xc2b2ae35;
-    z = (z ^ (z >> 16));
-    return z;
-}
-
-uint32_t mix32gamma(uint32_t z) {
-    z = (z ^ (z >> 16)) * 0x69ad6ccbU;
-    z = (z ^ (z >> 13)) * 0xcd9ab5b3U;
-    z = (z ^ (z >> 16));
-    return z;
-}
-
-void splitmix32_init(uint32_t s) {
-    seed  = mix32(s);
-    gamma = mix32gamma(s + GOLDEN_GAMMA) | 0x1;
-    if (popcount32(gamma ^ (gamma >> 1)) < 12) {
-        gamma = gamma ^ 0xaaaaaaaa;
-    }
-}
-
-unsigned int splitmix32() {
-    seed = seed + gamma;
-    return mix32(seed);
-}
-
-/* Exported from Haskell */
-uint32_t haskell_splitmix32();
-
-unsigned int exported_splitmix32() {
-    return haskell_splitmix32();
-}
-
-uint32_t haskell_splitmix64();
-
-unsigned int exported_splitmix64() {
-    return haskell_splitmix64();
-}
-
-double haskell_splitmix64_double();
-double haskell_splitmix32_double();
-
-/* Test suite */
-
-int run_testu01(int gen_k, int bat_k) {
-    /* Create TestU01 PRNG object for our generator */
-    unsigned int (*funcBits)() = NULL;
-    double (*func01)() = NULL;
-    unif01_Gen* gen = NULL;
-
-    switch (gen_k) {
-        case 0:
-            func01 = haskell_splitmix64_double;
-            gen = unif01_CreateExternGen01 ("SplitMix (Double)", haskell_splitmix64_double);
-            break;
-
-        case 1:
-            funcBits = exported_splitmix64;
-            gen = unif01_CreateExternGenBits("SplitMix (low 32bit)", exported_splitmix64);
-            break;
-
-        case 2:
-            func01 = haskell_splitmix32_double;
-            gen = unif01_CreateExternGen01("SplitMix32 (Double)", haskell_splitmix32_double);
-            break;
-
-        case 3:
-            funcBits = exported_splitmix32;
-            gen = unif01_CreateExternGenBits("SplitMix32", exported_splitmix32);
-            break;
-
-        default:
-            splitmix32_init(42);
-            printf("Initial state: %u %u\n", seed, gamma);
-
-            funcBits = splitmix32;
-            gen = unif01_CreateExternGenBits("SplitMix32 (C implementation)", splitmix32);
-    }
-
-    /* Run the tests. */
-    switch (bat_k) {
-        case 0:
-            bbattery_SmallCrush(gen);
-            break;
-
-        case 1:
-            bbattery_Crush(gen);
-            break;
-
-        case 2:
-            bbattery_BigCrush(gen);
-            break;
-
-        default:
-            if (funcBits != NULL) {
-                for (int i = 0; i < 32; i++) {
-                    printf("%x\n", funcBits());
-                }
-            }
-
-            if (func01 != NULL) {
-                for (int i = 0; i < 32; i++) {
-                    printf("%.09lf\n", func01());
-                }
-            }
-    }
-
-    if (funcBits != NULL) {
-        unif01_DeleteExternGenBits(gen);
-    } else if (func01 != NULL) {
-        unif01_DeleteExternGen01(gen);
-    }
-
-    return 0;
-}
diff --git a/tests/splitmix-examples.hs b/tests/splitmix-examples.hs
new file mode 100644
--- /dev/null
+++ b/tests/splitmix-examples.hs
@@ -0,0 +1,15 @@
+module Main (main) where
+
+import Test.HUnit ((@?=))
+
+import qualified System.Random.SplitMix32 as SM32
+
+main :: IO ()
+main = do
+    let g = SM32.mkSMGen 42
+    show g @?= "SMGen 142593372 1604540297"
+    print g
+
+    let (w32, g') = SM32.nextWord32 g
+    w32     @?= 1296549791
+    show g' @?= "SMGen 1747133669 1604540297"
