diff --git a/Data/Primitive/Internal/Operations.hs b/Data/Primitive/Internal/Operations.hs index 97bf901..86a9d0a 100644 --- a/Data/Primitive/Internal/Operations.hs +++ b/Data/Primitive/Internal/Operations.hs @@ -56,11 +56,13 @@ foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16" foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32" setWord32Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Word32# -> IO () #else -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word8" +-- Before GHC 9.2 these values use Word#, so the C entry points must take +-- a full machine word and perform the narrowing themselves. +foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word8_compat" setWord8Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Word# -> IO () -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16" +foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16_compat" setWord16Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Word# -> IO () -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32" +foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32_compat" setWord32Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Word# -> IO () #endif @@ -70,19 +72,32 @@ foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word" setWordArray# :: MutableByteArray# s -> CPtrdiff -> CSize -> Word# -> IO () #if __GLASGOW_HASKELL__ >= 902 -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word8" - setInt8Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int8# -> IO () -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16" - setInt16Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int16# -> IO () -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32" - setInt32Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int32# -> IO () +-- The C helpers take unsigned values. Some ABIs, such as RISC-V, require +-- different extension of narrow signed and unsigned arguments. Convert to +-- the C argument type before the FFI call to get the correct upper bits. +setInt8Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int8# -> IO () +{-# INLINE setInt8Array# #-} +setInt8Array# arr off n x = setWord8Array# arr off n (int8ToWord8# x) + +setInt16Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int16# -> IO () +{-# INLINE setInt16Array# #-} +setInt16Array# arr off n x = setWord16Array# arr off n (int16ToWord16# x) + +setInt32Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int32# -> IO () +{-# INLINE setInt32Array# #-} +setInt32Array# arr off n x = setWord32Array# arr off n (int32ToWord32# x) #else -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word8" - setInt8Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int# -> IO () -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16" - setInt16Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int# -> IO () -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32" - setInt32Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int# -> IO () +setInt8Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int# -> IO () +{-# INLINE setInt8Array# #-} +setInt8Array# arr off n x = setWord8Array# arr off n (int2Word# x) + +setInt16Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int# -> IO () +{-# INLINE setInt16Array# #-} +setInt16Array# arr off n x = setWord16Array# arr off n (int2Word# x) + +setInt32Array# :: MutableByteArray# s -> CPtrdiff -> CSize -> Int# -> IO () +{-# INLINE setInt32Array# #-} +setInt32Array# arr off n x = setWord32Array# arr off n (int2Word# x) #endif foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word64" @@ -109,11 +124,11 @@ foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16" foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32" setWord32OffAddr# :: Addr# -> CPtrdiff -> CSize -> Word32# -> IO () #else -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word8" +foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word8_compat" setWord8OffAddr# :: Addr# -> CPtrdiff -> CSize -> Word# -> IO () -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16" +foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16_compat" setWord16OffAddr# :: Addr# -> CPtrdiff -> CSize -> Word# -> IO () -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32" +foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32_compat" setWord32OffAddr# :: Addr# -> CPtrdiff -> CSize -> Word# -> IO () #endif @@ -123,19 +138,29 @@ foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word" setWordOffAddr# :: Addr# -> CPtrdiff -> CSize -> Word# -> IO () #if __GLASGOW_HASKELL__ >= 902 -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word8" - setInt8OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int8# -> IO () -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16" - setInt16OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int16# -> IO () -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32" - setInt32OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int32# -> IO () +setInt8OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int8# -> IO () +{-# INLINE setInt8OffAddr# #-} +setInt8OffAddr# addr off n x = setWord8OffAddr# addr off n (int8ToWord8# x) + +setInt16OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int16# -> IO () +{-# INLINE setInt16OffAddr# #-} +setInt16OffAddr# addr off n x = setWord16OffAddr# addr off n (int16ToWord16# x) + +setInt32OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int32# -> IO () +{-# INLINE setInt32OffAddr# #-} +setInt32OffAddr# addr off n x = setWord32OffAddr# addr off n (int32ToWord32# x) #else -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word8" - setInt8OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int# -> IO () -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word16" - setInt16OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int# -> IO () -foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word32" - setInt32OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int# -> IO () +setInt8OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int# -> IO () +{-# INLINE setInt8OffAddr# #-} +setInt8OffAddr# addr off n x = setWord8OffAddr# addr off n (int2Word# x) + +setInt16OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int# -> IO () +{-# INLINE setInt16OffAddr# #-} +setInt16OffAddr# addr off n x = setWord16OffAddr# addr off n (int2Word# x) + +setInt32OffAddr# :: Addr# -> CPtrdiff -> CSize -> Int# -> IO () +{-# INLINE setInt32OffAddr# #-} +setInt32OffAddr# addr off n x = setWord32OffAddr# addr off n (int2Word# x) #endif foreign import ccall unsafe "primitive-memops.h hsprimitive_memset_Word64" diff --git a/cbits/primitive-memops.c b/cbits/primitive-memops.c index 0b55558..15c4af0 100644 --- a/cbits/primitive-memops.c +++ b/cbits/primitive-memops.c @@ -64,3 +64,14 @@ MEMSET(Ptr, HsPtr) MEMSET_FLOAT(Float, HsFloat) MEMSET_FLOAT(Double, HsDouble) MEMSET(Char, HsChar) + +#define MEMSET_COMPAT(TYPE) \ +void hsprimitive_memset_ ## TYPE ## _compat \ + (Hs ## TYPE *p, ptrdiff_t off, size_t n, HsWord x) \ +{ \ + hsprimitive_memset_ ## TYPE(p, off, n, (Hs ## TYPE)x); \ +} + +MEMSET_COMPAT(Word8) +MEMSET_COMPAT(Word16) +MEMSET_COMPAT(Word32) diff --git a/cbits/primitive-memops.h b/cbits/primitive-memops.h index 10c0931..046f86c 100644 --- a/cbits/primitive-memops.h +++ b/cbits/primitive-memops.h @@ -15,6 +15,10 @@ int hsprimitive_memcmp_offset(HsWord8 *s1, HsInt off1, HsWord8 *s2, HsInt off2, void hsprimitive_memset_Word8(HsWord8 *, ptrdiff_t, size_t, HsWord8); void hsprimitive_memset_Word16(HsWord16 *, ptrdiff_t, size_t, HsWord16); void hsprimitive_memset_Word32(HsWord32 *, ptrdiff_t, size_t, HsWord32); +/* GHC < 9.2 represents narrow integers as machine words. */ +void hsprimitive_memset_Word8_compat(HsWord8 *, ptrdiff_t, size_t, HsWord); +void hsprimitive_memset_Word16_compat(HsWord16 *, ptrdiff_t, size_t, HsWord); +void hsprimitive_memset_Word32_compat(HsWord32 *, ptrdiff_t, size_t, HsWord); void hsprimitive_memset_Word64(HsWord64 *, ptrdiff_t, size_t, HsWord64); void hsprimitive_memset_Word(HsWord *, ptrdiff_t, size_t, HsWord); void hsprimitive_memset_Ptr(HsPtr *, ptrdiff_t, size_t, HsPtr);