diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,3 @@
+# Changelog for bits-extra
+
+## Unreleased changes
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Author name here (c) 2018
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Author name here nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,257 @@
+# bits-extra
+
+Useful bitwise operations.
+
+This library exposes support for some BMI2 CPU instructions on some x86 based
+CPUs.
+
+Currently support operations include:
+
+* `pdep` - Parallel Deposit
+* `pext` - Parallel Extract
+
+These operations are useful for high performance bit manipulation for
+applications such as succinct data structures.
+
+In the case where the target CPU architectures do not support these
+instruction set, a very slow emulated version of these operations is
+provided instead.
+
+## Compilation
+
+It is sufficient to build, test and benchmark the library as follows
+for emulated behaviour:
+
+```text
+stack build
+stack test
+stack bench
+```
+
+To target the BMI2 instruction set, add the `bmi2` flag:
+
+```text
+stack build --flag bits-extra:bmi2
+stack test  --flag bits-extra:bmi2
+stack bench --flag bits-extra:bmi2
+```
+
+## Benchmark results
+
+Benchmarks with `bmi2` flag defined on `ghc-8.4.1` on `Intel Core i7 2.9 GHz`
+
+```text
+Benchmark bench: RUNNING...
+Fast pdep enabled: True
+Fast pext enabled: True
+benchmarking popCount-single/popCount64
+time                 6.698 ns   (6.634 ns .. 6.766 ns)
+                     0.999 R²   (0.999 R² .. 1.000 R²)
+mean                 6.750 ns   (6.692 ns .. 6.841 ns)
+std dev              243.5 ps   (195.3 ps .. 347.1 ps)
+variance introduced by outliers: 60% (severely inflated)
+
+benchmarking popCount-single/popCount32
+time                 5.543 ns   (5.511 ns .. 5.574 ns)
+                     1.000 R²   (0.999 R² .. 1.000 R²)
+mean                 5.596 ns   (5.546 ns .. 5.650 ns)
+std dev              177.0 ps   (144.8 ps .. 215.8 ps)
+variance introduced by outliers: 54% (severely inflated)
+
+benchmarking pdep-vector/popCount64
+time                 1.083 μs   (1.074 μs .. 1.097 μs)
+                     0.998 R²   (0.997 R² .. 1.000 R²)
+mean                 1.089 μs   (1.075 μs .. 1.104 μs)
+std dev              50.20 ns   (37.87 ns .. 70.22 ns)
+variance introduced by outliers: 62% (severely inflated)
+
+benchmarking pdep-vector/popCount32
+time                 1.074 μs   (1.065 μs .. 1.083 μs)
+                     0.999 R²   (0.999 R² .. 1.000 R²)
+mean                 1.079 μs   (1.071 μs .. 1.090 μs)
+std dev              31.57 ns   (23.09 ns .. 49.88 ns)
+variance introduced by outliers: 40% (moderately inflated)
+
+benchmarking pdep-single/pdep64
+time                 4.920 ns   (4.856 ns .. 5.007 ns)
+                     0.996 R²   (0.990 R² .. 1.000 R²)
+mean                 4.945 ns   (4.874 ns .. 5.125 ns)
+std dev              361.5 ps   (150.9 ps .. 703.7 ps)
+variance introduced by outliers: 86% (severely inflated)
+
+benchmarking pdep-single/pdep32
+time                 5.203 ns   (5.163 ns .. 5.244 ns)
+                     1.000 R²   (0.999 R² .. 1.000 R²)
+mean                 5.229 ns   (5.193 ns .. 5.268 ns)
+std dev              126.2 ps   (109.9 ps .. 148.6 ps)
+variance introduced by outliers: 41% (moderately inflated)
+
+benchmarking pdep-vector/pdep64
+time                 1.627 μs   (1.617 μs .. 1.641 μs)
+                     0.999 R²   (0.998 R² .. 0.999 R²)
+mean                 1.679 μs   (1.652 μs .. 1.723 μs)
+std dev              107.2 ns   (74.61 ns .. 155.4 ns)
+variance introduced by outliers: 75% (severely inflated)
+
+benchmarking pdep-vector/pdep32
+time                 1.626 μs   (1.621 μs .. 1.634 μs)
+                     1.000 R²   (0.999 R² .. 1.000 R²)
+mean                 1.637 μs   (1.624 μs .. 1.651 μs)
+std dev              44.27 ns   (35.00 ns .. 58.61 ns)
+variance introduced by outliers: 35% (moderately inflated)
+
+benchmarking pext-single/pext64
+time                 5.182 ns   (5.133 ns .. 5.239 ns)
+                     0.999 R²   (0.998 R² .. 0.999 R²)
+mean                 5.255 ns   (5.181 ns .. 5.371 ns)
+std dev              314.1 ps   (211.7 ps .. 441.7 ps)
+variance introduced by outliers: 81% (severely inflated)
+
+benchmarking pext-single/pext32
+time                 5.269 ns   (5.222 ns .. 5.340 ns)
+                     0.997 R²   (0.993 R² .. 1.000 R²)
+mean                 5.315 ns   (5.248 ns .. 5.513 ns)
+std dev              388.9 ps   (145.5 ps .. 713.4 ps)
+variance introduced by outliers: 86% (severely inflated)
+
+benchmarking pext-vector/pext64
+time                 1.647 μs   (1.632 μs .. 1.667 μs)
+                     0.998 R²   (0.996 R² .. 0.999 R²)
+mean                 1.673 μs   (1.649 μs .. 1.719 μs)
+std dev              107.5 ns   (67.19 ns .. 171.9 ns)
+variance introduced by outliers: 76% (severely inflated)
+
+benchmarking pext-vector/pext32
+time                 1.626 μs   (1.616 μs .. 1.637 μs)
+                     1.000 R²   (0.999 R² .. 1.000 R²)
+mean                 1.630 μs   (1.617 μs .. 1.649 μs)
+std dev              53.18 ns   (33.93 ns .. 80.86 ns)
+variance introduced by outliers: 44% (moderately inflated)
+
+benchmarking plus-vector/plus64
+time                 1.641 μs   (1.628 μs .. 1.657 μs)
+                     0.999 R²   (0.999 R² .. 1.000 R²)
+mean                 1.647 μs   (1.635 μs .. 1.666 μs)
+std dev              50.67 ns   (38.54 ns .. 76.92 ns)
+variance introduced by outliers: 41% (moderately inflated)
+
+benchmarking plus-vector/plus32
+time                 1.943 μs   (1.932 μs .. 1.953 μs)
+                     1.000 R²   (0.999 R² .. 1.000 R²)
+mean                 1.948 μs   (1.934 μs .. 1.961 μs)
+std dev              45.86 ns   (37.10 ns .. 59.21 ns)
+variance introduced by outliers: 29% (moderately inflated)
+
+Benchmark bench: FINISH
+```
+
+Benchmarks with `bmi2` flag NOT defined on `ghc-8.4.1` on `Intel Core i7 2.9 GHz`
+
+```
+Benchmark bench: RUNNING...
+Fast pdep enabled: False
+Fast pext enabled: False
+benchmarking popCount-single/popCount64
+time                 6.572 ns   (6.433 ns .. 6.765 ns)
+                     0.996 R²   (0.992 R² .. 0.999 R²)
+mean                 6.637 ns   (6.551 ns .. 6.758 ns)
+std dev              346.9 ps   (252.8 ps .. 542.9 ps)
+variance introduced by outliers: 76% (severely inflated)
+
+benchmarking popCount-single/popCount32
+time                 5.196 ns   (5.152 ns .. 5.253 ns)
+                     0.999 R²   (0.999 R² .. 1.000 R²)
+mean                 5.232 ns   (5.186 ns .. 5.293 ns)
+std dev              186.6 ps   (152.8 ps .. 237.0 ps)
+variance introduced by outliers: 60% (severely inflated)
+
+benchmarking pdep-vector/popCount64
+time                 5.409 μs   (5.344 μs .. 5.476 μs)
+                     0.998 R²   (0.997 R² .. 0.999 R²)
+mean                 5.458 μs   (5.391 μs .. 5.549 μs)
+std dev              258.1 ns   (193.1 ns .. 374.6 ns)
+variance introduced by outliers: 60% (severely inflated)
+
+benchmarking pdep-vector/popCount32
+time                 3.849 μs   (3.814 μs .. 3.885 μs)
+                     0.999 R²   (0.999 R² .. 0.999 R²)
+mean                 3.860 μs   (3.818 μs .. 3.919 μs)
+std dev              166.6 ns   (131.0 ns .. 236.7 ns)
+variance introduced by outliers: 56% (severely inflated)
+
+benchmarking pdep-single/pdep64
+time                 10.46 ns   (10.35 ns .. 10.58 ns)
+                     0.999 R²   (0.999 R² .. 0.999 R²)
+mean                 10.53 ns   (10.42 ns .. 10.65 ns)
+std dev              385.2 ps   (321.8 ps .. 480.9 ps)
+variance introduced by outliers: 60% (severely inflated)
+
+benchmarking pdep-single/pdep32
+time                 10.57 ns   (10.49 ns .. 10.68 ns)
+                     0.999 R²   (0.999 R² .. 1.000 R²)
+mean                 10.69 ns   (10.57 ns .. 10.80 ns)
+std dev              404.1 ps   (341.0 ps .. 501.8 ps)
+variance introduced by outliers: 62% (severely inflated)
+
+benchmarking pdep-vector/pdep64
+time                 3.113 μs   (3.091 μs .. 3.140 μs)
+                     0.999 R²   (0.999 R² .. 1.000 R²)
+mean                 3.130 μs   (3.106 μs .. 3.158 μs)
+std dev              82.60 ns   (65.72 ns .. 103.1 ns)
+variance introduced by outliers: 32% (moderately inflated)
+
+benchmarking pdep-vector/pdep32
+time                 3.096 μs   (3.070 μs .. 3.125 μs)
+                     0.999 R²   (0.999 R² .. 1.000 R²)
+mean                 3.086 μs   (3.059 μs .. 3.114 μs)
+std dev              91.30 ns   (77.41 ns .. 110.3 ns)
+variance introduced by outliers: 37% (moderately inflated)
+
+benchmarking pext-single/pext64
+time                 73.06 ns   (72.35 ns .. 73.84 ns)
+                     0.999 R²   (0.999 R² .. 1.000 R²)
+mean                 73.65 ns   (73.02 ns .. 74.35 ns)
+std dev              2.368 ns   (1.974 ns .. 2.918 ns)
+variance introduced by outliers: 50% (severely inflated)
+
+benchmarking pext-single/pext32
+time                 74.07 ns   (73.46 ns .. 74.62 ns)
+                     0.999 R²   (0.999 R² .. 1.000 R²)
+mean                 74.18 ns   (73.41 ns .. 74.83 ns)
+std dev              2.550 ns   (2.161 ns .. 3.134 ns)
+variance introduced by outliers: 54% (severely inflated)
+
+benchmarking pext-vector/pext64
+time                 72.78 μs   (71.21 μs .. 74.87 μs)
+                     0.996 R²   (0.993 R² .. 0.999 R²)
+mean                 72.17 μs   (71.38 μs .. 73.41 μs)
+std dev              3.105 μs   (2.302 μs .. 4.741 μs)
+variance introduced by outliers: 46% (moderately inflated)
+
+benchmarking pext-vector/pext32
+time                 72.69 μs   (72.04 μs .. 73.28 μs)
+                     0.999 R²   (0.999 R² .. 0.999 R²)
+mean                 73.00 μs   (72.25 μs .. 73.85 μs)
+std dev              2.634 μs   (2.237 μs .. 3.137 μs)
+variance introduced by outliers: 37% (moderately inflated)
+
+benchmarking plus-vector/plus64
+time                 1.856 μs   (1.833 μs .. 1.876 μs)
+                     0.999 R²   (0.999 R² .. 0.999 R²)
+mean                 1.861 μs   (1.844 μs .. 1.880 μs)
+std dev              63.39 ns   (54.74 ns .. 75.83 ns)
+variance introduced by outliers: 46% (moderately inflated)
+
+benchmarking plus-vector/plus32
+time                 1.547 μs   (1.532 μs .. 1.562 μs)
+                     0.999 R²   (0.998 R² .. 0.999 R²)
+mean                 1.554 μs   (1.538 μs .. 1.578 μs)
+std dev              62.25 ns   (48.22 ns .. 91.40 ns)
+variance introduced by outliers: 54% (severely inflated)
+
+Benchmark bench: FINISH
+```
+
+## Reference
+
+* [Bit Manipulation Instruction Sets (Wikipedia)](https://en.wikipedia.org/wiki/Bit_Manipulation_Instruction_Sets)
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/bench/Main.hs b/bench/Main.hs
new file mode 100644
--- /dev/null
+++ b/bench/Main.hs
@@ -0,0 +1,80 @@
+module Main where
+
+import Criterion.Main
+import Data.Bits
+import Data.Bits.Pdep
+import Data.Bits.Pext
+import Data.Word
+
+import qualified Data.Vector.Storable as DVS
+
+mkVector :: (Num w, DVS.Storable w) => w -> IO (DVS.Vector w)
+mkVector w = return $ DVS.unfoldrN 1024 gen w
+  where gen b = let a = b + 1 in Just (a, a)
+
+benchPopCount :: [Benchmark]
+benchPopCount =
+  [ env (mkVector (0 :: Word64)) $ \_ -> bgroup "popCount-single"
+    [ bench "popCount64"  (whnf popCount (0 :: Word64))
+    ]
+  , env (mkVector (0 :: Word32)) $ \_ -> bgroup "popCount-single"
+    [ bench "popCount32"  (whnf popCount (0 :: Word32))
+    ]
+  , env (mkVector (0 :: Word64)) $ \v -> bgroup "pdep-vector"
+    [ bench "popCount64"  (whnf (DVS.map popCount) v)
+    ]
+  , env (mkVector (0 :: Word32)) $ \v -> bgroup "pdep-vector"
+    [ bench "popCount32"  (whnf (DVS.map popCount) v)
+    ]
+  ]
+
+benchPlus :: [Benchmark]
+benchPlus =
+  [ env (mkVector (0 :: Word64)) $ \v -> bgroup "plus-vector"
+    [ bench "plus64"    (whnf (DVS.foldr (\a b -> (+) a 0 + b) 0) v)
+    ]
+  , env (mkVector (0 :: Word32)) $ \v -> bgroup "plus-vector"
+    [ bench "plus32"    (whnf (DVS.foldr (\a b -> (+) a 0 + b) 0) v)
+    ]
+  ]
+
+benchPdep :: [Benchmark]
+benchPdep =
+  [ env (mkVector (0 :: Word64)) $ \_ -> bgroup "pdep-single"
+    [ bench "pdep64"    (whnf (pdep 0) (63 :: Word64))
+    ]
+  , env (mkVector (0 :: Word32)) $ \_ -> bgroup "pdep-single"
+    [ bench "pdep32"    (whnf (pdep 0) (63 :: Word32))
+    ]
+  , env (mkVector (0 :: Word64)) $ \v -> bgroup "pdep-vector"
+    [ bench "pdep64"    (whnf (DVS.foldr (\a b -> pdep a 0 + b) 0) v)
+    ]
+  , env (mkVector (0 :: Word32)) $ \v -> bgroup "pdep-vector"
+    [ bench "pdep32"    (whnf (DVS.foldr (\a b -> pdep a 0 + b) 0) v)
+    ]
+  ]
+
+benchPext :: [Benchmark]
+benchPext =
+  [ env (mkVector (0 :: Word64)) $ \_ -> bgroup "pext-single"
+    [ bench "pext64"    (whnf (pext 0) (63 :: Word64))
+    ]
+  , env (mkVector (0 :: Word32)) $ \_ -> bgroup "pext-single"
+    [ bench "pext32"    (whnf (pext 0) (63 :: Word64))
+    ]
+  , env (mkVector (0 :: Word64)) $ \v -> bgroup "pext-vector"
+    [ bench "pext64"    (whnf (DVS.foldr (\a b -> pext a 0 + b) 0) v)
+    ]
+  , env (mkVector (0 :: Word32)) $ \v -> bgroup "pext-vector"
+    [ bench "pext32"    (whnf (DVS.foldr (\a b -> pext a 0 + b) 0) v)
+    ]
+  ]
+
+benchAll :: [Benchmark]
+benchAll = benchPopCount <> benchPdep <> benchPext <> benchPlus
+
+main :: IO ()
+main = do
+  putStrLn $ "Fast pdep enabled: " <> show fastPdepEnabled
+  putStrLn $ "Fast pext enabled: " <> show fastPextEnabled
+  defaultMain benchAll
diff --git a/bits-extra.cabal b/bits-extra.cabal
new file mode 100644
--- /dev/null
+++ b/bits-extra.cabal
@@ -0,0 +1,90 @@
+-- This file has been generated from package.yaml by hpack version 0.20.0.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: 2b16093c79f84feabd7fb8a6c4c36ce7e5cfdcf7aa6a2c48d7d3d84d3166701b
+
+name:           bits-extra
+version:        0.0.0.1
+description:    Please see the README on Github at <https://github.com/haskell-works/bits-extra#readme>
+homepage:       https://github.com/haskell-works/bits-extra#readme
+bug-reports:    https://github.com/haskell-works/bits-extra/issues
+author:         John Ky
+maintainer:     newhoggy@gmail.com
+copyright:      2018 John Ky
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
+cabal-version:  >= 1.10
+
+extra-source-files:
+    ChangeLog.md
+    README.md
+
+source-repository head
+  type: git
+  location: https://github.com/haskell-works/bits-extra
+
+flag bmi2
+  description: Enable bmi2 instruction set
+  manual: False
+  default: False
+
+library
+  hs-source-dirs:
+      src
+  ghc-options: -Wall -O2
+  build-depends:
+      base >=4.11 && <5
+    , ghc-prim
+  if (flag(bmi2)) && (impl(ghc >=8.4.1))
+    ghc-options: -mbmi2 -msse4.2
+    cpp-options: -DBMI2_ENABLED
+  exposed-modules:
+      Data.Bits.Pdep
+      Data.Bits.Pdep.Slow
+      Data.Bits.Pext
+      Data.Bits.Pext.Slow
+  other-modules:
+      Paths_bits_extra
+  default-language: Haskell2010
+
+test-suite bits-extra-test
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
+  hs-source-dirs:
+      test
+  ghc-options: -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      base >=4.11 && <5
+    , bits-extra
+    , ghc-prim
+    , hedgehog
+    , hspec
+    , hw-hedgehog
+    , hw-hspec-hedgehog
+  if (flag(bmi2)) && (impl(ghc >=8.4.1))
+    ghc-options: -mbmi2 -msse4.2
+  other-modules:
+      Data.Bits.PdepSpec
+      Data.Bits.PextSpec
+      Paths_bits_extra
+  default-language: Haskell2010
+
+benchmark bench
+  type: exitcode-stdio-1.0
+  main-is: Main.hs
+  hs-source-dirs:
+      bench
+  ghc-options: -Wall -O2
+  build-depends:
+      base >=4 && <5
+    , bits-extra
+    , criterion
+    , ghc-prim
+    , vector
+  if (flag(bmi2)) && (impl(ghc >=8.4.1))
+    ghc-options: -mbmi2 -msse4.2
+  other-modules:
+      Paths_bits_extra
+  default-language: Haskell2010
diff --git a/src/Data/Bits/Pdep.hs b/src/Data/Bits/Pdep.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Bits/Pdep.hs
@@ -0,0 +1,54 @@
+{-# LANGUAGE CPP       #-}
+{-# LANGUAGE MagicHash #-}
+
+module Data.Bits.Pdep
+  ( Pdep(..)
+  , fastPdepEnabled
+  ) where
+
+import GHC.Prim
+import GHC.Word
+
+-- | Bitwise parallel deposit.  Deposits bits from the source at the locations
+-- described by the mask.
+class Pdep a where
+  pdep :: a -> a -> a
+
+instance Pdep Word where
+  pdep (W#   src#) (W#   mask#) = W#   (pdep#   src# mask#)
+  {-# INLINE pdep #-}
+
+instance Pdep Word8 where
+  pdep src mask = fromIntegral (pdep (fromIntegral src) (fromIntegral mask) :: Word32)
+  {-# INLINE pdep #-}
+
+instance Pdep Word16 where
+  pdep src mask = fromIntegral (pdep (fromIntegral src) (fromIntegral mask) :: Word32)
+  {-# INLINE pdep #-}
+
+#if MIN_VERSION_base(4,11,0)
+instance Pdep Word32 where
+  pdep (W32# src#) (W32# mask#) = W32# (pdep32# src# mask#)
+  {-# INLINE pdep #-}
+
+instance Pdep Word64 where
+  pdep (W64# src#) (W64# mask#) = W64# (pdep64# src# mask#)
+  {-# INLINE pdep #-}
+#else
+instance Pdep Word32 where
+  pdep = slowPdep
+  {-# INLINE pdep #-}
+
+instance Pdep Word64 where
+  pdep = slowPdep
+  {-# INLINE pdep #-}
+#endif
+
+-- | Runtime flag indicating whether the 'pdep' function is using the high-performance.
+-- BMI2 instruction set.  A value of `False` indicates that `pdep` is emulated.
+fastPdepEnabled :: Bool
+#if MIN_VERSION_base(4,11,0) && defined(BMI2_ENABLED)
+fastPdepEnabled = True
+#else
+fastPdepEnabled = False
+#endif
diff --git a/src/Data/Bits/Pdep/Slow.hs b/src/Data/Bits/Pdep/Slow.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Bits/Pdep/Slow.hs
@@ -0,0 +1,40 @@
+module Data.Bits.Pdep.Slow
+  ( SlowPdep(..)
+  ) where
+
+import Data.Bits
+import GHC.Int
+import GHC.Word
+
+slowPdep64 :: Word64 -> Word64 -> Word64
+slowPdep64 = slowPdep64' 0
+
+lsb :: Word64 -> Word64
+lsb src = fromIntegral ((fromIntegral (src `shiftL` 63) :: Int64) `shiftR` 63)
+
+slowPdep64' :: Word64 -> Word64 -> Word64 -> Word64
+slowPdep64' result src mask = if lowest /= 0
+  then slowPdep64' newResult (src `shiftR` 1) (mask .&. complement lowest)
+  else result
+  where lowest    = (-mask) .&. mask
+        newResult = (result .|. ((lsb src) .&. lowest))
+
+-- | Bitwise parallel deposit (emulated).  Deposits bits from the source at the
+-- locations described by the mask.
+class SlowPdep a where
+  slowPdep :: a -> a -> a
+
+instance SlowPdep Word where
+  slowPdep s m = fromIntegral (slowPdep64 (fromIntegral s) (fromIntegral m))
+
+instance SlowPdep Word8 where
+  slowPdep s m = fromIntegral (slowPdep64 (fromIntegral s) (fromIntegral m))
+
+instance SlowPdep Word16 where
+  slowPdep s m = fromIntegral (slowPdep64 (fromIntegral s) (fromIntegral m))
+
+instance SlowPdep Word32 where
+  slowPdep s m = fromIntegral (slowPdep64 (fromIntegral s) (fromIntegral m))
+
+instance SlowPdep Word64 where
+  slowPdep s m = fromIntegral (slowPdep64 (fromIntegral s) (fromIntegral m))
diff --git a/src/Data/Bits/Pext.hs b/src/Data/Bits/Pext.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Bits/Pext.hs
@@ -0,0 +1,54 @@
+{-# LANGUAGE CPP       #-}
+{-# LANGUAGE MagicHash #-}
+
+module Data.Bits.Pext
+  ( Pext(..)
+  , fastPextEnabled
+  ) where
+
+import GHC.Prim
+import GHC.Word
+
+-- | Bitwise parallel extract.  Extract bits from the source at the locations
+-- described by the mask.
+class Pext a where
+  pext :: a -> a -> a
+
+instance Pext Word where
+  pext (W#   src#) (W#   mask#) = W#   (pext#   src# mask#)
+  {-# INLINE pext #-}
+
+instance Pext Word8 where
+  pext src mask = fromIntegral (pext (fromIntegral src) (fromIntegral mask) :: Word32)
+  {-# INLINE pext #-}
+
+instance Pext Word16 where
+  pext src mask = fromIntegral (pext (fromIntegral src) (fromIntegral mask) :: Word32)
+  {-# INLINE pext #-}
+
+#if MIN_VERSION_base(4,11,0)
+instance Pext Word32 where
+  pext (W32# src#) (W32# mask#) = W32# (pext32# src# mask#)
+  {-# INLINE pext #-}
+
+instance Pext Word64 where
+  pext (W64# src#) (W64# mask#) = W64# (pext64# src# mask#)
+  {-# INLINE pext #-}
+#else
+instance Pext Word32 where
+  pext = slowPext
+  {-# INLINE pext #-}
+
+instance Pext Word64 where
+  pext = slowPext
+  {-# INLINE pext #-}
+#endif
+
+-- | Runtime flag indicating whether the 'pext' function is using the high-performance.
+-- BMI2 instruction set.  A value of `False` indicates that `pext` is emulated.
+fastPextEnabled :: Bool
+#if MIN_VERSION_base(4,11,0) && defined(BMI2_ENABLED)
+fastPextEnabled = True
+#else
+fastPextEnabled = False
+#endif
diff --git a/src/Data/Bits/Pext/Slow.hs b/src/Data/Bits/Pext/Slow.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Bits/Pext/Slow.hs
@@ -0,0 +1,39 @@
+module Data.Bits.Pext.Slow
+  ( SlowPext(..)
+  ) where
+
+import Data.Bits
+import GHC.Word
+
+slowPext64 :: Word64 -> Word64 -> Word64
+slowPext64 = slowPext64' 0 0 0
+
+slowPext64' :: Word64 -> Int -> Int -> Word64 -> Word64 -> Word64
+slowPext64' result offset index src mask = if index /= 64
+  then if maskBit /= 0
+          then slowPext64' nextResult (offset + 1) (index + 1) src mask
+          else slowPext64' result      offset      (index + 1) src mask
+  else result
+  where srcBit      = (src  `shiftR` index) .&. 1
+        maskBit     = (mask `shiftR` index) .&. 1
+        nextResult  = result .|. (srcBit `shiftL` offset)
+
+-- | Bitwise parallel extract (emulated).  Extract bits from the source at
+-- the locations described by the mask.
+class SlowPext a where
+  slowPext :: a -> a -> a
+
+instance SlowPext Word where
+  slowPext s m = fromIntegral (slowPext64 (fromIntegral s) (fromIntegral m))
+
+instance SlowPext Word8 where
+  slowPext s m = fromIntegral (slowPext64 (fromIntegral s) (fromIntegral m))
+
+instance SlowPext Word16 where
+  slowPext s m = fromIntegral (slowPext64 (fromIntegral s) (fromIntegral m))
+
+instance SlowPext Word32 where
+  slowPext s m = fromIntegral (slowPext64 (fromIntegral s) (fromIntegral m))
+
+instance SlowPext Word64 where
+  slowPext s m = fromIntegral (slowPext64 (fromIntegral s) (fromIntegral m))
diff --git a/test/Data/Bits/PdepSpec.hs b/test/Data/Bits/PdepSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Data/Bits/PdepSpec.hs
@@ -0,0 +1,42 @@
+
+module Data.Bits.PdepSpec (spec) where
+
+import Data.Bits
+import Data.Bits.Pdep
+import Data.Bits.Pdep.Slow
+import Data.Int
+import Data.Word
+import HaskellWorks.Hspec.Hedgehog
+import Hedgehog
+import Test.Hspec
+
+import qualified Hedgehog.Gen   as G
+import qualified Hedgehog.Range as R
+
+{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{-# ANN module ("HLint: ignore Reduce duplication"  :: String) #-}
+{-# ANN module ("HLint: redundant bracket"          :: String) #-}
+
+spec :: Spec
+spec = describe "Data.Bits.PdepSpec" $ do
+  describe "Emulated pdep and native pdep give the same answer" $ do
+    it "Word64" $ require $ property $ do
+      a <- forAll $ G.word64 R.constantBounded
+      b <- forAll $ G.word64 R.constantBounded
+      pdep a b === slowPdep a b
+    it "Word32" $ require $ property $ do
+      a <- forAll $ G.word32 R.constantBounded
+      b <- forAll $ G.word32 R.constantBounded
+      pdep a b === slowPdep a b
+    it "Word16" $ require $ property $ do
+      a <- forAll $ G.word16 R.constantBounded
+      b <- forAll $ G.word16 R.constantBounded
+      pdep a b === slowPdep a b
+    it "Word8" $ require $ property $ do
+      a <- forAll $ G.word8 R.constantBounded
+      b <- forAll $ G.word8 R.constantBounded
+      pdep a b === slowPdep a b
+    it "Word" $ require $ property $ do
+      a <- forAll $ G.word R.constantBounded
+      b <- forAll $ G.word R.constantBounded
+      pdep a b === slowPdep a b
diff --git a/test/Data/Bits/PextSpec.hs b/test/Data/Bits/PextSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/Data/Bits/PextSpec.hs
@@ -0,0 +1,41 @@
+module Data.Bits.PextSpec (spec) where
+
+import Data.Bits
+import Data.Bits.Pext
+import Data.Bits.Pext.Slow
+import Data.Int
+import Data.Word
+import HaskellWorks.Hspec.Hedgehog
+import Hedgehog
+import Test.Hspec
+
+import qualified Hedgehog.Gen   as G
+import qualified Hedgehog.Range as R
+
+{-# ANN module ("HLint: ignore Redundant do"        :: String) #-}
+{-# ANN module ("HLint: ignore Reduce duplication"  :: String) #-}
+{-# ANN module ("HLint: redundant bracket"          :: String) #-}
+
+spec :: Spec
+spec = describe "Data.Bits.PextSpec" $ do
+  describe "Emulated pext and native pext give the same answer" $ do
+    it "Word64" $ require $ property $ do
+      a <- forAll $ G.word64 R.constantBounded
+      b <- forAll $ G.word64 R.constantBounded
+      pext a b === slowPext a b
+    it "Word32" $ require $ property $ do
+      a <- forAll $ G.word32 R.constantBounded
+      b <- forAll $ G.word32 R.constantBounded
+      pext a b === slowPext a b
+    it "Word16" $ require $ property $ do
+      a <- forAll $ G.word16 R.constantBounded
+      b <- forAll $ G.word16 R.constantBounded
+      pext a b === slowPext a b
+    it "Word8" $ require $ property $ do
+      a <- forAll $ G.word8 R.constantBounded
+      b <- forAll $ G.word8 R.constantBounded
+      pext a b === slowPext a b
+    it "Word" $ require $ property $ do
+      a <- forAll $ G.word R.constantBounded
+      b <- forAll $ G.word R.constantBounded
+      pext a b === slowPext a b
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
