packages feed

hw-simd 0.1.1.2 → 0.1.1.3

raw patch · 6 files changed

+91/−4 lines, 6 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

+ HaskellWorks.Data.Simd.Comparison.Avx2: class CmpEqWord8sPara a where {
+ HaskellWorks.Data.Simd.Comparison.Avx2: cmpEqWord8sPara :: CmpEqWord8sPara a => Vector Word8 -> a -> CmpEqWord8sParaTarget a
+ HaskellWorks.Data.Simd.Comparison.Avx2: instance HaskellWorks.Data.Simd.Comparison.Avx2.CmpEqWord8sPara (Data.Vector.Storable.Vector GHC.Word.Word64)
+ HaskellWorks.Data.Simd.Internal.Foreign: avx2Cmpeq8Para :: Ptr UInt8 -> Size -> Ptr (Ptr UInt8) -> Size -> Ptr UInt8 -> IO ()
+ HaskellWorks.Data.Simd.Internal.Foreign: c_cmpeq8_para :: Ptr CUChar -> CULong -> Ptr (Ptr CUChar) -> CULong -> Ptr CUChar -> IO ()
- HaskellWorks.Data.Simd.Comparison.Avx2: type family Target a;
+ HaskellWorks.Data.Simd.Comparison.Avx2: type family CmpEqWord8sParaTarget a;
- HaskellWorks.Data.Simd.Internal.Foreign: c_avx2_and_bits :: ((Ptr CUChar) -> (CULong -> ((Ptr CUChar) -> ((Ptr CUChar) -> (IO ())))))
+ HaskellWorks.Data.Simd.Internal.Foreign: c_avx2_and_bits :: Ptr CUChar -> CULong -> Ptr CUChar -> Ptr CUChar -> IO ()
- HaskellWorks.Data.Simd.Internal.Foreign: c_avx2_and_not_bits :: ((Ptr CUChar) -> (CULong -> ((Ptr CUChar) -> ((Ptr CUChar) -> (IO ())))))
+ HaskellWorks.Data.Simd.Internal.Foreign: c_avx2_and_not_bits :: Ptr CUChar -> CULong -> Ptr CUChar -> Ptr CUChar -> IO ()
- HaskellWorks.Data.Simd.Internal.Foreign: c_avx2_not_bits :: ((Ptr CUChar) -> (CULong -> ((Ptr CUChar) -> (IO ()))))
+ HaskellWorks.Data.Simd.Internal.Foreign: c_avx2_not_bits :: Ptr CUChar -> CULong -> Ptr CUChar -> IO ()
- HaskellWorks.Data.Simd.Internal.Foreign: c_avx2_or_bits :: ((Ptr CUChar) -> (CULong -> ((Ptr CUChar) -> ((Ptr CUChar) -> (IO ())))))
+ HaskellWorks.Data.Simd.Internal.Foreign: c_avx2_or_bits :: Ptr CUChar -> CULong -> Ptr CUChar -> Ptr CUChar -> IO ()
- HaskellWorks.Data.Simd.Internal.Foreign: c_avx2_xor_bits :: ((Ptr CUChar) -> (CULong -> ((Ptr CUChar) -> ((Ptr CUChar) -> (IO ())))))
+ HaskellWorks.Data.Simd.Internal.Foreign: c_avx2_xor_bits :: Ptr CUChar -> CULong -> Ptr CUChar -> Ptr CUChar -> IO ()
- HaskellWorks.Data.Simd.Internal.Foreign: c_build_ibs :: ((Ptr CUChar) -> ((Ptr CUChar) -> (CULong -> (IO ()))))
+ HaskellWorks.Data.Simd.Internal.Foreign: c_build_ibs :: Ptr CUChar -> Ptr CUChar -> CULong -> IO ()
- HaskellWorks.Data.Simd.Internal.Foreign: c_cmpeq8 :: (CUChar -> ((Ptr CUChar) -> (CULong -> ((Ptr CUChar) -> (IO ())))))
+ HaskellWorks.Data.Simd.Internal.Foreign: c_cmpeq8 :: CUChar -> Ptr CUChar -> CULong -> Ptr CUChar -> IO ()

Files

cbits/simd.h view
@@ -15,6 +15,13 @@     size_t target_length,     uint8_t *source); +void avx2_cmpeq8_para(+    uint8_t *bytes,+    size_t bytes_length,+    uint8_t **targets,+    size_t targets_length,+    uint8_t *source);+ void avx2_and_bits(     uint8_t *target,     size_t target_length,
cbits/simd_avx2.c view
@@ -54,6 +54,33 @@ #endif } +void avx2_cmpeq8_para(+    uint8_t *bytes,+    size_t bytes_length,+    uint8_t **targets,+    size_t targets_length,+    uint8_t *source) {+#if defined(AVX2_ENABLED)+  size_t i;++  for (i = 0; i < targets_length * 2; ++i) {+    size_t j;++    __m256i v_data_a = *(__m256i *)(source + (i * 32));++    for (j = 0; j < bytes_length; ++j) {+      uint8_t *target     = targets[j];+      uint32_t *target32  = (uint32_t *)target;+      __m256i v_comparand = _mm256_set1_epi8(bytes[j]);+      uint32_t *out_mask  = (uint32_t*)target;+      __m256i v_results_a = _mm256_cmpeq_epi8(v_data_a, v_comparand);+      uint32_t mask       = (uint32_t)_mm256_movemask_epi8(v_results_a);+      target32[i]         = mask;+    }+  }+#endif+}+ void avx2_and_bits(     uint8_t *target,     size_t target_length,
hw-simd.cabal view
@@ -3,7 +3,7 @@ -- see: https://github.com/sol/hpack  name:           hw-simd-version:        0.1.1.2+version:        0.1.1.3 synopsis:       SIMD library description:    Please see the README on Github at <https://github.com/haskell-works/hw-simd#readme> category:       Data, Bit, SIMD
src/HaskellWorks/Data/Simd/Comparison/Avx2.hs view
@@ -1,6 +1,7 @@-{-# LANGUAGE CPP               #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeFamilies      #-}+{-# LANGUAGE CPP                 #-}+{-# LANGUAGE FlexibleInstances   #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeFamilies        #-}  module HaskellWorks.Data.Simd.Comparison.Avx2 where @@ -9,6 +10,7 @@ import Data.Word  import qualified Data.ByteString                         as BS+import qualified Data.Vector                             as DV import qualified Data.Vector.Storable                    as DVS import qualified Foreign.ForeignPtr                      as F import qualified Foreign.Marshal.Unsafe                  as F@@ -87,4 +89,32 @@   cmpEqWord8s w8 = CS.toChunkString . cmpEqWord8s w8 . BS.toByteStrings   {-# INLINE cmpEqWord8s #-} +class CmpEqWord8sPara a where+  type CmpEqWord8sParaTarget a+  cmpEqWord8sPara :: DVS.Vector Word8 -> a -> CmpEqWord8sParaTarget a++instance CmpEqWord8sPara (DVS.Vector Word64) where+  type CmpEqWord8sParaTarget (DVS.Vector Word64) = DV.Vector (DVS.Vector Word64)+  cmpEqWord8sPara w8s v = case DVS.unsafeCast v :: DVS.Vector Word8 of+    u -> case DVS.unsafeToForeignPtr u of+      (srcFptr, srcOffset, srcLength) -> if disalignment == 0+        then F.unsafeLocalState $ do+          tgtFptr <- F.mallocForeignPtrBytes (srcLength * DVS.length w8s)+          F.withForeignPtr srcFptr $ \srcPtr -> do+            F.withForeignPtr tgtFptr $ \tgtPtr -> do+              let tgtsPtrsV :: DVS.Vector (F.Ptr Word8) = DVS.constructN (DVS.length w8s) $ \t ->+                    tgtPtr `F.plusPtr` (DVS.length t * DVS.length v)+              let (w8sFptr, _, w8sLen) = DVS.unsafeToForeignPtr w8s+              let (tgtsPtrsFptr, _, _) = DVS.unsafeToForeignPtr tgtsPtrsV+              F.withForeignPtr w8sFptr $ \w8sPtr -> do+                F.withForeignPtr tgtsPtrsFptr $ \tgtsPtrsPtr -> do+                  F.avx2Cmpeq8Para (F.castPtr w8sPtr) (fromIntegral w8sLen) (F.castPtr tgtsPtrsPtr) (fromIntegral w64sLen) (srcPtr `F.plusPtr` srcOffset)++              let tgtV = DVS.unsafeFromForeignPtr tgtFptr 0 (w64sLen * DVS.length w8s)+              return $ DV.constructN (DVS.length w8s) $ \t -> DVS.take w64sLen (DVS.drop (DV.length t * w64sLen) tgtV)++        else error $ "Unaligned byte string: " <> show disalignment+        where w64sLen       = srcLength `div` 64+              disalignment  = srcLength - w64sLen * 64+  {-# INLINE cmpEqWord8sPara #-} 
src/HaskellWorks/Data/Simd/Internal/Foreign.chs view
@@ -21,6 +21,11 @@   {#call unsafe avx2_cmpeq8 as c_cmpeq8#} byte target targetLength source {-# INLINE avx2Cmpeq8 #-} +avx2Cmpeq8Para :: Ptr UInt8 -> Size -> Ptr (Ptr UInt8) -> Size -> Ptr UInt8 -> IO ()+avx2Cmpeq8Para bytes bytes_length target targetLength source = requireAvx2 $ do+  {#call unsafe avx2_cmpeq8_para as c_cmpeq8_para#} bytes bytes_length target targetLength source+{-# INLINE avx2Cmpeq8Para #-}+ avx2AndBits :: Ptr UInt8 -> Size -> Ptr UInt8 -> Ptr UInt8 -> IO () avx2AndBits target targetLength source_a source_b = requireAvx2 $ do   {#call unsafe avx2_and_bits as c_avx2_and_bits#} target targetLength source_a source_b
test/HaskellWorks/Data/Simd/ComparisonSpec.hs view
@@ -11,6 +11,7 @@ import Hedgehog import Test.Hspec +import qualified Data.Vector                             as DV import qualified Data.Vector.Storable                    as DVS import qualified HaskellWorks.Data.Simd.Comparison.Avx2  as AVX import qualified HaskellWorks.Data.Simd.Comparison.Stock as STK@@ -35,3 +36,20 @@           $ G.word8x8 (G.choice [pure w, G.word8 R.constantBounded])         AVX.cmpEqWord8s w vs === STK.cmpEqWord8s w vs         vs === vs+      it "AVX2 Para 1" $ requireProperty $ do+        w <- forAll $ G.word8 R.constantBounded+        vs :: DVS.Vector Word64 <- forAll+          $ G.storableVector (R.singleton 8)+          $ G.word8x8 (G.choice [pure w, G.word8 R.constantBounded])+        DV.head (AVX.cmpEqWord8sPara (DVS.singleton w) vs) === AVX.cmpEqWord8s w vs+      it "AVX2 Para 2" $ requireProperty $ do+        len <- forAll $ (* 8) <$> G.int (R.linear 0 8)+        w0  <- forAll $ G.word8 R.constantBounded+        w1  <- forAll $ G.word8 R.constantBounded+        vs :: DVS.Vector Word64 <- forAll+          $ G.storableVector (R.singleton len)+          $ G.word8x8 (G.choice [pure w0, pure w1, G.word8 R.constantBounded])+        let actual = AVX.cmpEqWord8sPara (DVS.fromList [w0, w1]) vs+        (actual DV.! 0) === AVX.cmpEqWord8s w0 vs+        (actual DV.! 1) === AVX.cmpEqWord8s w1 vs+