{-# LANGUAGE CPP #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnliftedFFITypes #-}
{- |
Description: Detect x86 features at runtime

This module provides the basic interface to detect CPU features.
The availability is indicated by a boolean variable (@b\<FEATRUE NAME\>@).
-}
module System.CPUFeatures.X86.Bool
  (bAESNI
  ,bAMX_BF16
  ,bAMX_FP16
  ,bAMX_INT8
  ,bAMX_TILE
  ,bAVX
  ,bAVX_VNNI
  ,bAVX10_1
  ,bAVX10_2
  ,bAVX2
  ,bAVX512_BF16
  ,bAVX512_BITALG
  ,bAVX512_FP16
  ,bAVX512_IFMA
  ,bAVX512_VBMI
  ,bAVX512_VBMI2
  ,bAVX512_VNNI
  ,bAVX512_VPOPCNTDQ
  ,bAVX512BW
  ,bAVX512CD
  ,bAVX512DQ
  ,bAVX512F
  ,bAVX512VL
  ,bBMI1
  ,bBMI2
  ,bF16C
  ,bFMA
  ,bGFNI
  ,bPCLMULQDQ
  ,bPOPCNT
  ,bRDRAND
  ,bSHA
  ,bSSE3
  ,bSSE4_1
  ,bSSE4_2
  ,bSSSE3
  ,bVAES
  ,bVPCLMULQDQ
  ,mAVX10
  ) where
#if defined(x86_64_HOST_ARCH) || defined(i386_HOST_ARCH)
import System.CPUFeatures.X86.Cpuid
import Data.Bits
-- import Data.Maybe (isJust)
#if defined(darwin_HOST_OS)
import GHC.Exts (Addr#)
#endif
#endif

bAESNI :: Bool
bAMX_BF16 :: Bool
bAMX_FP16 :: Bool
bAMX_INT8 :: Bool
bAMX_TILE :: Bool
bAVX :: Bool
bAVX_VNNI :: Bool
bAVX10_1 :: Bool
bAVX10_2 :: Bool
bAVX2 :: Bool
bAVX512_BF16 :: Bool
bAVX512_BITALG :: Bool
bAVX512_FP16 :: Bool
bAVX512_IFMA :: Bool
bAVX512_VBMI :: Bool
bAVX512_VBMI2 :: Bool
bAVX512_VNNI :: Bool
bAVX512_VPOPCNTDQ :: Bool
bAVX512BW :: Bool
bAVX512CD :: Bool
bAVX512DQ :: Bool
bAVX512F :: Bool
bAVX512VL :: Bool
bBMI1 :: Bool
bBMI2 :: Bool
bF16C :: Bool
bFMA :: Bool
bGFNI :: Bool
bPCLMULQDQ :: Bool
bPOPCNT :: Bool
bRDRAND :: Bool
bSHA :: Bool
bSSE3 :: Bool
bSSE4_1 :: Bool
bSSE4_2 :: Bool
bSSSE3 :: Bool
bVAES :: Bool
bVPCLMULQDQ :: Bool

mAVX10 :: Maybe Int

#if defined(x86_64_HOST_ARCH) || defined(i386_HOST_ARCH)

{-# NOINLINE cpuid_01 #-}
cpuid_01 :: CpuidResult
cpuid_01 :: CpuidResult
cpuid_01 = Word32 -> Word32 -> CpuidResult
X86Cpuid => Word32 -> Word32 -> CpuidResult
cpuid Word32
0x1 Word32
0

{-# NOINLINE cpuid_07_0 #-}
cpuid_07_0 :: CpuidResult
cpuid_07_0 :: CpuidResult
cpuid_07_0 = Word32 -> Word32 -> CpuidResult
X86Cpuid => Word32 -> Word32 -> CpuidResult
cpuid Word32
0x7 Word32
0

{-# NOINLINE cpuid_07_1 #-}
cpuid_07_1 :: CpuidResult
cpuid_07_1 :: CpuidResult
cpuid_07_1 = Word32 -> Word32 -> CpuidResult
X86Cpuid => Word32 -> Word32 -> CpuidResult
cpuid Word32
0x7 Word32
1

{-# NOINLINE cpuid_24_0 #-}
cpuid_24_0 :: CpuidResult
cpuid_24_0 :: CpuidResult
cpuid_24_0 = Word32 -> Word32 -> CpuidResult
X86Cpuid => Word32 -> Word32 -> CpuidResult
cpuid Word32
0x24 Word32
0

-- May be used by future AVX10
-- {-# NOINLINE cpuid_24_1 #-}
-- cpuid_24_1 :: CpuidResult
-- cpuid_24_1 = cpuid 0x24 1

#if defined(darwin_HOST_OS)
foreign import ccall unsafe hs_cpu_features_sysctl :: Addr# -> Bool
#endif

{-# NOINLINE mAVX10 #-}
mAVX10 :: Maybe Int
mAVX10 | Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
edx CpuidResult
cpuid_07_1) Int
19
       , Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ecx CpuidResult
cpuid_01) Int
27 -- OSXSAVE
       , (Word32 -> Word64
X86Cpuid => Word32 -> Word64
xgetbv Word32
0 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xe6) Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
0xe6 -- opmask, upper ZMM[0-15], ZMM[16-31], XMM, YMM
       , Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ebx CpuidResult
cpuid_24_0) Int
17 -- AVX10/256
       = let !version :: Int
version = Word32 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (CpuidResult -> Word32
ebx CpuidResult
cpuid_24_0 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. Word32
0xff)
         in Int -> Maybe Int
forall a. a -> Maybe a
Just Int
version
       | Bool
otherwise = Maybe Int
forall a. Maybe a
Nothing

bAESNI :: Bool
bAESNI = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ecx CpuidResult
cpuid_01) Int
25
bAMX_BF16 :: Bool
bAMX_BF16 = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
edx CpuidResult
cpuid_07_0) Int
22
bAMX_FP16 :: Bool
bAMX_FP16 = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
eax CpuidResult
cpuid_07_1) Int
21
bAMX_INT8 :: Bool
bAMX_INT8 = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
edx CpuidResult
cpuid_07_0) Int
25
bAMX_TILE :: Bool
bAMX_TILE = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
edx CpuidResult
cpuid_07_0) Int
24
{-# NOINLINE bAVX #-}
bAVX :: Bool
bAVX = (CpuidResult -> Word32
ecx CpuidResult
cpuid_01 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.&. (Int -> Word32
forall a. Bits a => Int -> a
bit Int
27 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Int -> Word32
forall a. Bits a => Int -> a
bit Int
28)) Word32 -> Word32 -> Bool
forall a. Eq a => a -> a -> Bool
== Int -> Word32
forall a. Bits a => Int -> a
bit Int
27 Word32 -> Word32 -> Word32
forall a. Bits a => a -> a -> a
.|. Int -> Word32
forall a. Bits a => Int -> a
bit Int
28 Bool -> Bool -> Bool
&& (Word32 -> Word64
X86Cpuid => Word32 -> Word64
xgetbv Word32
0 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
6) Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
6 -- bit 27: OSXSAVE, bit 28: AVX
bAVX_VNNI :: Bool
bAVX_VNNI = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
eax CpuidResult
cpuid_07_1) Int
4
bAVX10_1 :: Bool
bAVX10_1 = Maybe Int
mAVX10 Maybe Int -> Maybe Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int -> Maybe Int
forall a. a -> Maybe a
Just Int
1
bAVX10_2 :: Bool
bAVX10_2 = Maybe Int
mAVX10 Maybe Int -> Maybe Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int -> Maybe Int
forall a. a -> Maybe a
Just Int
2
-- bAVX10_VL256 = isJust mAVX10 -- mAVX10 checks for VL256
-- bAVX10_VL512 = isJust mAVX10 && testBit (ebx cpuid_24_0) 18
bAVX2 :: Bool
bAVX2 = Bool
bAVX Bool -> Bool -> Bool
&& Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ebx CpuidResult
cpuid_07_0) Int
5
bAVX512_BF16 :: Bool
bAVX512_BF16 = Bool
bAVX512F Bool -> Bool -> Bool
&& Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
eax CpuidResult
cpuid_07_1) Int
5
bAVX512_BITALG :: Bool
bAVX512_BITALG = Bool
bAVX512F Bool -> Bool -> Bool
&& Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ecx CpuidResult
cpuid_07_0) Int
12
bAVX512_FP16 :: Bool
bAVX512_FP16 = Bool
bAVX512F Bool -> Bool -> Bool
&& Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
edx CpuidResult
cpuid_07_0) Int
23
bAVX512_IFMA :: Bool
bAVX512_IFMA = Bool
bAVX512F Bool -> Bool -> Bool
&& Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ebx CpuidResult
cpuid_07_0) Int
21
bAVX512_VBMI :: Bool
bAVX512_VBMI = Bool
bAVX512F Bool -> Bool -> Bool
&& Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ecx CpuidResult
cpuid_07_0) Int
1
bAVX512_VBMI2 :: Bool
bAVX512_VBMI2 = Bool
bAVX512F Bool -> Bool -> Bool
&& Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ecx CpuidResult
cpuid_07_0) Int
6
bAVX512_VNNI :: Bool
bAVX512_VNNI = Bool
bAVX512F Bool -> Bool -> Bool
&& Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ecx CpuidResult
cpuid_07_0) Int
11
-- bAVX512_VP2INTERSECT = bAVX512F && testBit (edx cpuid_07_0) 8
bAVX512_VPOPCNTDQ :: Bool
bAVX512_VPOPCNTDQ = Bool
bAVX512F Bool -> Bool -> Bool
&& Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ecx CpuidResult
cpuid_07_0) Int
14
bAVX512BW :: Bool
bAVX512BW = Bool
bAVX512F Bool -> Bool -> Bool
&& Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ebx CpuidResult
cpuid_07_0) Int
30
bAVX512CD :: Bool
bAVX512CD = Bool
bAVX512F Bool -> Bool -> Bool
&& Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ebx CpuidResult
cpuid_07_0) Int
28
bAVX512DQ :: Bool
bAVX512DQ = Bool
bAVX512F Bool -> Bool -> Bool
&& Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ebx CpuidResult
cpuid_07_0) Int
17
{-# NOINLINE bAVX512F #-}
#if defined(darwin_HOST_OS)
bAVX512F = hs_cpu_features_sysctl "hw.optional.avx512f"# -- AVX-512 support on macOS is on-demand, that is, XCR0 is cleared by default.
#else
bAVX512F :: Bool
bAVX512F = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ecx CpuidResult
cpuid_01) Int
27 Bool -> Bool -> Bool
&& (Word32 -> Word64
X86Cpuid => Word32 -> Word64
xgetbv Word32
0 Word64 -> Word64 -> Word64
forall a. Bits a => a -> a -> a
.&. Word64
0xe6) Word64 -> Word64 -> Bool
forall a. Eq a => a -> a -> Bool
== Word64
0xe6 Bool -> Bool -> Bool
&& Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ebx CpuidResult
cpuid_07_0) Int
16 -- CPUID.1:ECX[bit 27]: OSXSAVE
#endif
bAVX512VL :: Bool
bAVX512VL = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ebx CpuidResult
cpuid_07_0) Int
31
bBMI1 :: Bool
bBMI1 = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ebx CpuidResult
cpuid_07_0) Int
3
bBMI2 :: Bool
bBMI2 = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ebx CpuidResult
cpuid_07_0) Int
8
bF16C :: Bool
bF16C = Bool
bAVX Bool -> Bool -> Bool
&& Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ecx CpuidResult
cpuid_01) Int
29
bFMA :: Bool
bFMA = Bool
bAVX Bool -> Bool -> Bool
&& Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ecx CpuidResult
cpuid_01) Int
12
bGFNI :: Bool
bGFNI = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ecx CpuidResult
cpuid_07_0) Int
8
bPCLMULQDQ :: Bool
bPCLMULQDQ = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ecx CpuidResult
cpuid_01) Int
1
bPOPCNT :: Bool
bPOPCNT = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ecx CpuidResult
cpuid_01) Int
23
bRDRAND :: Bool
bRDRAND = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ecx CpuidResult
cpuid_01) Int
30
bSHA :: Bool
bSHA = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ebx CpuidResult
cpuid_07_0) Int
29
bSSE3 :: Bool
bSSE3 = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ecx CpuidResult
cpuid_01) Int
0
bSSE4_1 :: Bool
bSSE4_1 = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ecx CpuidResult
cpuid_01) Int
19
bSSE4_2 :: Bool
bSSE4_2 = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ecx CpuidResult
cpuid_01) Int
20
bSSSE3 :: Bool
bSSSE3 = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ecx CpuidResult
cpuid_01) Int
9
bVAES :: Bool
bVAES = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ecx CpuidResult
cpuid_07_0) Int
9
bVPCLMULQDQ :: Bool
bVPCLMULQDQ = Word32 -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit (CpuidResult -> Word32
ecx CpuidResult
cpuid_07_0) Int
10

#else

{-# INLINE bAESNI #-}
bAESNI = False

{-# INLINE bAMX_BF16 #-}
bAMX_BF16 = False

{-# INLINE bAMX_FP16 #-}
bAMX_FP16 = False

{-# INLINE bAMX_INT8 #-}
bAMX_INT8 = False

{-# INLINE bAMX_TILE #-}
bAMX_TILE = False

{-# INLINE bAVX #-}
bAVX = False

{-# INLINE bAVX_VNNI #-}
bAVX_VNNI = False

{-# INLINE bAVX10_1 #-}
bAVX10_1 = False

{-# INLINE bAVX10_2 #-}
bAVX10_2 = False

{-# INLINE bAVX2 #-}
bAVX2 = False

{-# INLINE bAVX512_BF16 #-}
bAVX512_BF16 = False

{-# INLINE bAVX512_BITALG #-}
bAVX512_BITALG = False

{-# INLINE bAVX512_FP16 #-}
bAVX512_FP16 = False

{-# INLINE bAVX512_IFMA #-}
bAVX512_IFMA = False

{-# INLINE bAVX512_VBMI #-}
bAVX512_VBMI = False

{-# INLINE bAVX512_VBMI2 #-}
bAVX512_VBMI2 = False

{-# INLINE bAVX512_VNNI #-}
bAVX512_VNNI = False

{-# INLINE bAVX512_VPOPCNTDQ #-}
bAVX512_VPOPCNTDQ = False

{-# INLINE bAVX512BW #-}
bAVX512BW = False

{-# INLINE bAVX512CD #-}
bAVX512CD = False

{-# INLINE bAVX512DQ #-}
bAVX512DQ = False

{-# INLINE bAVX512F #-}
bAVX512F = False

{-# INLINE bAVX512VL #-}
bAVX512VL = False

{-# INLINE bBMI1 #-}
bBMI1 = False

{-# INLINE bBMI2 #-}
bBMI2 = False

{-# INLINE bF16C #-}
bF16C = False

{-# INLINE bFMA #-}
bFMA = False

{-# INLINE bGFNI #-}
bGFNI = False

{-# INLINE bPCLMULQDQ #-}
bPCLMULQDQ = False

{-# INLINE bPOPCNT #-}
bPOPCNT = False

{-# INLINE bRDRAND #-}
bRDRAND = False

{-# INLINE bSHA #-}
bSHA = False

{-# INLINE bSSE3 #-}
bSSE3 = False

{-# INLINE bSSE4_1 #-}
bSSE4_1 = False

{-# INLINE bSSE4_2 #-}
bSSE4_2 = False

{-# INLINE bSSSE3 #-}
bSSSE3 = False

{-# INLINE bVAES #-}
bVAES = False

{-# INLINE bVPCLMULQDQ #-}
bVPCLMULQDQ = False

{-# INLINE mAVX10 #-}
mAVX10 = Nothing

#endif