winpr/sysinfo: added IsProcessorFeaturePresent and IsProcessorFeaturePresentEx
authorBernhard Miklautz <bmiklautz@thinstuff.at>
Wed, 27 Feb 2013 09:17:24 +0000 (10:17 +0100)
committerBernhard Miklautz <bmiklautz@thinstuff.at>
Fri, 1 Mar 2013 08:02:14 +0000 (09:02 +0100)
These functions can be used to check if an processor feature is supported.
IsProcessorFeaturePresentEx is a extended version which is not available
in the windows API and allows to query additional features.
Currently it works on the following platforms:
- i386/amd64 when compiling with gcc
- ARM on linux

libfreerdp/primitives/primitives.c
winpr/include/winpr/sysinfo.h
winpr/libwinpr/sysinfo/sysinfo.c
winpr/libwinpr/sysinfo/test/CMakeLists.txt
winpr/libwinpr/sysinfo/test/TestCPUFeatures.c [new file with mode: 0644]

index 99c71e3..245a6ce 100644 (file)
@@ -247,7 +247,7 @@ static const flagpair_t x86_flags[] =
 {
        { PRIM_X86_MMX_AVAILABLE,                               "MMX" },
        { PRIM_X86_3DNOW_AVAILABLE,                             "3DNow" },
-       { PRIM_X86_3DNOW_PREFETCH_AVAILABLE,                    "3DNow-PF" },
+       { PRIM_X86_3DNOW_PREFETCH_AVAILABLE,    "3DNow-PF" },
        { PRIM_X86_SSE_AVAILABLE,                               "SSE" },
        { PRIM_X86_SSE2_AVAILABLE,                              "SSE2" },
        { PRIM_X86_SSE3_AVAILABLE,                              "SSE3" },
@@ -256,7 +256,7 @@ static const flagpair_t x86_flags[] =
        { PRIM_X86_SSE42_AVAILABLE,                             "SSE4.2" },
        { PRIM_X86_AVX_AVAILABLE,                               "AVX" },
        { PRIM_X86_FMA_AVAILABLE,                               "FMA" },
-       { PRIM_X86_AVX_AES_AVAILABLE,                           "AVX-AES" },
+       { PRIM_X86_AVX_AES_AVAILABLE,                   "AVX-AES" },
        { PRIM_X86_AVX2_AVAILABLE,                              "AVX2" },
 };
 
@@ -268,7 +268,7 @@ static const flagpair_t arm_flags[] =
        { PRIM_ARM_VFP4_AVAILABLE,                              "VFP4" },
        { PRIM_ARM_FPA_AVAILABLE,                               "FPA" },
        { PRIM_ARM_FPE_AVAILABLE,                               "FPE" },
-       { PRIM_ARM_IWMMXT_AVAILABLE,                            "IWMMXT" },
+       { PRIM_ARM_IWMMXT_AVAILABLE,                    "IWMMXT" },
        { PRIM_ARM_NEON_AVAILABLE,                              "NEON" },
 };
 
index 2b37ab8..001232a 100644 (file)
 #define PF_FLOATING_POINT_PRECISION_ERRATA             0
 #define PF_FLOATING_POINT_EMULATED                     1
 #define PF_COMPARE_EXCHANGE_DOUBLE                     2
-#define PF_MMX_INSTRUCTIONS_AVAILABLE                  3
+#define PF_MMX_INSTRUCTIONS_AVAILABLE   3
 #define PF_PPC_MOVEMEM_64BIT_OK                                4
-#define PF_ALPHA_BYTE_INSTRUCTIONS                     5
-#define PF_XMMI_INSTRUCTIONS_AVAILABLE                 6
+#define PF_XMMI_INSTRUCTIONS_AVAILABLE                 6 //sse
 #define PF_3DNOW_INSTRUCTIONS_AVAILABLE                        7
 #define PF_RDTSC_INSTRUCTION_AVAILABLE                 8
 #define PF_PAE_ENABLED                                 9
-#define PF_XMMI64_INSTRUCTIONS_AVAILABLE               10
+#define PF_XMMI64_INSTRUCTIONS_AVAILABLE               10 //sse2
 #define PF_SSE_DAZ_MODE_AVAILABLE                      11
 #define PF_NX_ENABLED                                  12
 #define PF_SSE3_INSTRUCTIONS_AVAILABLE                 13
 #define PF_ARM_EXTERNAL_CACHE_AVAILABLE                        26
 #define PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE             27
 
+#define PF_ARM_V4                       0x80000001
+#define PF_ARM_V5                       0x80000002
+#define PF_ARM_V6                       0x80000003
+#define PF_ARM_V7                       0x80000004
+#define PF_ARM_THUMB                    0x80000005
+#define PF_ARM_JAZELLE                  0x80000006
+#define PF_ARM_DSP                      0x80000007
+#define PF_ARM_MOVE_CP                  0x80000008
+#define PF_ARM_VFP10                    0x80000009
+#define PF_ARM_MPU                      0x8000000A
+#define PF_ARM_WRITE_BUFFER             0x8000000B
+#define PF_ARM_MBX                      0x8000000C
+#define PF_ARM_L2CACHE                  0x8000000D
+#define PF_ARM_PHYSICALLY_TAGGED_CACHE  0x8000000E
+#define PF_ARM_VFP_SINGLE_PRECISION     0x8000000F
+#define PF_ARM_VFP_DOUBLE_PRECISION     0x80000010
+#define PF_ARM_ITCM                     0x80000011
+#define PF_ARM_DTCM                     0x80000012
+#define PF_ARM_UNIFIED_CACHE            0x80000013
+#define PF_ARM_WRITE_BACK_CACHE         0x80000014
+#define PF_ARM_CACHE_CAN_BE_LOCKED_DOWN 0x80000015
+#define PF_ARM_L2CACHE_MEMORY_MAPPED    0x80000016
+#define PF_ARM_L2CACHE_COPROC           0x80000017
+#define PF_ARM_THUMB2                   0x80000018
+#define PF_ARM_T2EE                     0x80000019
+#define PF_ARM_VFP3                     0x8000001A
+#define PF_ARM_NEON                     0x8000001B
+#define PF_ARM_UNALIGNED_ACCESS         0x8000001C
+
+#define PF_ARM_INTEL_XSCALE             0x80010001
+#define PF_ARM_INTEL_PMU                0x80010002
+#define PF_ARM_INTEL_WMMX               0x80010003
+
+// extended flags
+#define PF_EX_3DNOW_PREFETCH            1
+#define PF_EX_SSSE3                     2
+#define PF_EX_SSE41                     3
+#define PF_EX_SSE42                     4
+#define PF_EX_AVX                              5
+#define PF_EX_FMA                       6
+#define PF_EX_AVX_AES                          7
+#define PF_EX_AVX2                             8
+#define PF_EX_ARM_VFP1                               9
+#define PF_EX_ARM_VFP3D16               10
+#define PF_EX_ARM_VFP4                               11
+#define PF_EX_ARM_IDIVA                 12
+#define PF_EX_ARM_IDIVT                 13
+
 typedef struct _SYSTEM_INFO
 {
        union
@@ -243,7 +290,10 @@ WINPR_API VOID GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime);
 
 WINPR_API DWORD GetTickCount(void);
 
+WINPR_API BOOL IsProcessorFeaturePresent(DWORD ProcessorFeature);
 #endif
 
+WINPR_API BOOL IsProcessorFeaturePresentEx(DWORD ProcessorFeature);
+
 #endif /* WINPR_SYSINFO_H */
 
index 6f574fe..0dddf6a 100644 (file)
@@ -3,6 +3,7 @@
  * System Information
  *
  * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
+ * Copyright 2013 Bernhard Miklautz <bmiklautz@thinstuff.at>
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 #endif
 
 #include <winpr/sysinfo.h>
+#include <winpr/platform.h>
+
+#if defined(__linux__) && defined(__GNUC__)
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#endif
 
 /**
  * api-ms-win-core-sysinfo-l1-1-1.dll:
@@ -109,7 +117,7 @@ DWORD GetNumberOfProcessors()
 {
        DWORD numCPUs = 1;
 
-       /* TODO: Android and iOS */
+       /* TODO: iOS */
 
 #if defined(__linux__) || defined(__sun) || defined(_AIX)
        numCPUs = (DWORD) sysconf(_SC_NPROCESSORS_ONLN);
@@ -331,4 +339,305 @@ DWORD GetTickCount(void)
        return ticks;
 }
 
+/* If x86 and gcc*/
+#ifdef _M_IX86_AMD64
+#ifdef __GNUC__
+
+#ifdef __AVX__
+#define xgetbv(_func_, _lo_, _hi_) \
+    __asm__ __volatile__ ("xgetbv" : "=a" (_lo_), "=d" (_hi_) : "c" (_func_))
+#endif
+
+#define D_BIT_MMX       (1<<23)
+#define D_BIT_SSE       (1<<25)
+#define D_BIT_SSE2      (1<<26)
+#define D_BIT_3DN       (1<<30)
+#define C_BIT_SSE3      (1<<0)
+#define C_BIT_3DNP      (1<<8)
+#define C_BIT_SSSE3     (1<<9)
+#define C_BIT_SSE41     (1<<19)
+#define C_BIT_SSE42     (1<<20)
+#define C_BIT_XGETBV        (1<<27)
+#define C_BIT_AVX       (1<<28)
+#define C_BITS_AVX      (C_BIT_XGETBV|C_BIT_AVX)
+#define E_BIT_XMM       (1<<1)
+#define E_BIT_YMM       (1<<2)
+#define E_BITS_AVX      (E_BIT_XMM|E_BIT_YMM)
+#define C_BIT_FMA       (1<<11)
+#define C_BIT_AVX_AES       (1<<24)
+
+static void cpuid(
+    unsigned info,
+    unsigned *eax,
+    unsigned *ebx,
+    unsigned *ecx,
+    unsigned *edx)
+{
+    *eax = *ebx = *ecx = *edx = 0;
+
+    __asm volatile
+    (
+        /* The EBX (or RBX register on x86_64) is used for the PIC base address
+         * and must not be corrupted by our inline assembly.
+         */
+#ifdef _M_IX86
+        "mov %%ebx, %%esi;"
+        "cpuid;"
+        "xchg %%ebx, %%esi;"
+#else
+        "mov %%rbx, %%rsi;"
+        "cpuid;"
+        "xchg %%rbx, %%rsi;"
+#endif
+        : "=a" (*eax), "=S" (*ebx), "=c" (*ecx), "=d" (*edx)
+        : "0" (info)
+    );
+}
+#endif // __GNUC__
+#elif defined(_M_ARM)
+#if defined(__linux__)
+// HWCAP flags from linux kernel - uapi/asm/hwcap.h
+#define HWCAP_SWP (1 << 0)
+#define HWCAP_HALF  (1 << 1)
+#define HWCAP_THUMB (1 << 2)
+#define HWCAP_26BIT (1 << 3)  /* Play it safe */
+#define HWCAP_FAST_MULT (1 << 4)
+#define HWCAP_FPA (1 << 5)
+#define HWCAP_VFP (1 << 6)
+#define HWCAP_EDSP  (1 << 7)
+#define HWCAP_JAVA  (1 << 8)
+#define HWCAP_IWMMXT  (1 << 9)
+#define HWCAP_CRUNCH  (1 << 10)
+#define HWCAP_THUMBEE (1 << 11)
+#define HWCAP_NEON  (1 << 12)
+#define HWCAP_VFPv3 (1 << 13)
+#define HWCAP_VFPv3D16  (1 << 14) /* also set for VFPv4-D16 */
+#define HWCAP_TLS (1 << 15)
+#define HWCAP_VFPv4 (1 << 16)
+#define HWCAP_IDIVA (1 << 17)
+#define HWCAP_IDIVT (1 << 18)
+#define HWCAP_VFPD32  (1 << 19) /* set if VFP has 32 regs (not 16) */
+#define HWCAP_IDIV  (HWCAP_IDIVA | HWCAP_IDIVT)
+
+// From linux kernel uapi/linux/auxvec.h
+#define AT_HWCAP 16
+
+static unsigned GetARMCPUCaps(void){
+       unsigned caps = 0;
+
+       int fd = open ("/proc/self/auxv", O_RDONLY);
+
+       if (fd == -1)
+               return 0;
+
+       static struct
+       {
+               unsigned a_type;    /* Entry type */
+               unsigned  a_val;   /* Integer value */
+       } auxvec;
+
+       while (1){
+               int num;
+               num = read(fd, (char *)&auxvec, sizeof(auxvec));
+               if (num < 1 || (auxvec.a_type == 0 && auxvec.a_val == 0))
+                               break;
+               if (auxvec.a_type == AT_HWCAP) 
+               {
+                       caps = auxvec.a_val;    
+               }
+       }
+       close(fd);
+       return caps;
+}
+
+#endif // defined(__linux__)
+#endif // _M_IX86_AMD64
+
+BOOL IsProcessorFeaturePresent(DWORD ProcessorFeature)
+{
+       BOOL ret = FALSE;
+#ifdef _M_ARM
+#ifdef __linux__
+       unsigned caps;
+       caps = GetARMCPUCaps();
+
+       switch (ProcessorFeature)
+       {
+               case PF_ARM_NEON_INSTRUCTIONS_AVAILABLE:
+               case PF_ARM_NEON:
+                       if (caps & HWCAP_NEON)
+                               ret = TRUE;
+                       break;
+               case PF_ARM_THUMB:
+                       if (caps & HWCAP_THUMB)
+                               ret = TRUE;
+               case PF_ARM_VFP_32_REGISTERS_AVAILABLE:
+                       if (caps & HWCAP_VFPD32)
+                               ret = TRUE;
+               case PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE:
+                       if ((caps & HWCAP_IDIVA) || (caps & HWCAP_IDIVT))
+                               ret = TRUE;
+               case PF_ARM_VFP3:
+                       if (caps & HWCAP_VFPv3)
+                               ret = TRUE;
+                       break;
+               case PF_ARM_JAZELLE:
+                       if (caps & HWCAP_JAVA)
+                               ret = TRUE;
+                       break;
+               case PF_ARM_DSP:
+                       if (caps & HWCAP_EDSP)
+                               ret = TRUE;
+                       break;
+               case PF_ARM_MPU:
+                       if (caps & HWCAP_EDSP)
+                               ret = TRUE;
+                       break;
+               case PF_ARM_THUMB2:
+                       if ((caps & HWCAP_IDIVT) || (caps & HWCAP_VFPv4))
+                               ret = TRUE;
+                       break;
+               case PF_ARM_T2EE:
+                       if (caps & HWCAP_THUMBEE)
+                               ret = TRUE;
+                       break;
+               case PF_ARM_INTEL_WMMX:
+                       if (caps & HWCAP_IWMMXT)
+                               ret = TRUE;
+                       break;
+               default:
+                       break;
+       }
+#endif
+#elif defined(_M_IX86_AMD64)
+#ifdef __GNUC__
+       unsigned a, b, c, d;
+
+       cpuid(1, &a, &b, &c, &d);
+
+       switch (ProcessorFeature)
+       {
+               case PF_MMX_INSTRUCTIONS_AVAILABLE: 
+                       if (d & D_BIT_MMX)
+                               ret = TRUE;
+                       break;
+               case PF_XMMI_INSTRUCTIONS_AVAILABLE: 
+                       if (d & D_BIT_SSE)
+                               ret = TRUE;
+                       break;
+               case PF_XMMI64_INSTRUCTIONS_AVAILABLE: 
+                       if (d & D_BIT_SSE2)
+                               ret = TRUE;
+                       break;
+               case PF_3DNOW_INSTRUCTIONS_AVAILABLE:
+                       if (d & D_BIT_3DN)
+                               ret = TRUE;
+                       break;
+               case PF_SSE3_INSTRUCTIONS_AVAILABLE: 
+                       if (c & C_BIT_SSE3)
+                               ret = TRUE;
+                       break;
+               default:
+                       break;
+       }
+
+#endif // __GNUC__
+#endif
+       return ret;
+}
+#endif _WIN32
+
+BOOL IsProcessorFeaturePresentEx(DWORD ProcessorFeature)
+{
+       BOOL ret = FALSE;
+#ifdef _M_ARM
+#ifdef __linux__
+       unsigned caps;
+       caps = GetARMCPUCaps();
+
+       switch (ProcessorFeature)
+       {
+               case PF_EX_ARM_VFP1:
+                       if (caps & HWCAP_VFP)
+                               ret = TRUE;
+                       break;
+               case PF_EX_ARM_VFP3D16:
+                       if (caps & HWCAP_VFPv3D16)
+                               ret = TRUE;
+                       break;
+               case PF_EX_ARM_VFP4:
+                       if (caps & HWCAP_VFPv4)
+                               ret = TRUE;
+                       break;
+               case PF_EX_ARM_IDIVA:
+                       if (caps & HWCAP_IDIVA)
+                               ret = TRUE;
+                       break;
+               case PF_EX_ARM_IDIVT:
+                       if (caps & HWCAP_IDIVT)
+                               ret = TRUE;
+                       break;
+       }
+#endif // __linux__
+#elif defined(_M_IX86_AMD64)
+       unsigned a, b, c, d;
+       cpuid(1, &a, &b, &c, &d);
+
+       switch (ProcessorFeature)
+       {
+               case PF_EX_3DNOW_PREFETCH:
+                       if (c & C_BIT_3DNP)
+                               ret = TRUE;
+                       break;
+               case PF_EX_SSSE3:
+                       if (c & C_BIT_SSSE3)
+                               ret = TRUE;
+                       break;
+               case PF_EX_SSE41:
+                       if (c & C_BIT_SSE41)
+                               ret = TRUE;
+                       break;
+               case PF_EX_SSE42:
+                       if (c & C_BIT_SSE42)
+                               ret = TRUE;
+                       break;
+#ifdef __AVX__
+               case PF_EX_AVX:
+               case PF_EX_FMA:
+               case PF_EX_AVX_AES:
+                       {
+                               if ((c & C_BITS_AVX) != C_BITS_AVX)
+                                       ret = FALSE;
+
+                                       int e, f;
+                                       xgetbv(0, e, f);
+
+                                       if ((e & E_BITS_AVX) == E_BITS_AVX)
+                                       {
+                                               switch (ProcessorFeature)
+                                               {
+                                                       case: PF_EX_AVX:
+                                                               ret = TRUE;
+                                                               break;
+                                                       case: PF_EX_FMA:
+                                                               if (c & C_BIT_FMA)
+                                                                       ret = TRUE;
+                                                               break;
+                                                       case: PF_EX_AVX_AES:
+                                                               if (c & C_BIT_AVX_AES)
+                                                                       ret = TRUE;
+                                                               break;
+                                               {
+                                                       ret = TRUE;
+                                                       break;
+                                               }
+        }
+                       }
+                       break;
+#endif //__AVX__
+               default:
+                       break;
+       }
 #endif
+       return ret;
+}
index 79ba944..3eb8101 100644 (file)
@@ -5,7 +5,9 @@ set(MODULE_PREFIX "TEST_SYSINFO")
 set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
 
 set(${MODULE_PREFIX}_TESTS
-       TestGetNativeSystemInfo.c)
+       TestGetNativeSystemInfo.c
+       TestCPUFeatures.c
+       )
 
 create_test_sourcelist(${MODULE_PREFIX}_SRCS
        ${${MODULE_PREFIX}_DRIVER}
diff --git a/winpr/libwinpr/sysinfo/test/TestCPUFeatures.c b/winpr/libwinpr/sysinfo/test/TestCPUFeatures.c
new file mode 100644 (file)
index 0000000..e7c7e83
--- /dev/null
@@ -0,0 +1,45 @@
+
+#include <winpr/crt.h>
+#include <winpr/sysinfo.h>
+#include <winpr/platform.h>
+
+int TestCPUFeatures(int argc, char* argv[])
+{
+       printf("Base CPU Flags:\n");
+#ifdef _M_IX86_AMD64
+       printf("\tPF_MMX_INSTRUCTIONS_AVAILABLE:  %s\n", IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE) ? "yes" : "no");
+       printf("\tPF_XMMI_INSTRUCTIONS_AVAILABLE:  %s\n", IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE) ? "yes" : "no");
+       printf("\tPF_XMMI64_INSTRUCTIONS_AVAILABLE:  %s\n", IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE) ? "yes" : "no");
+       printf("\tPF_3DNOW_INSTRUCTIONS_AVAILABLE:  %s\n", IsProcessorFeaturePresent(PF_3DNOW_INSTRUCTIONS_AVAILABLE) ? "yes" : "no");
+       printf("\tPF_SSE3_INSTRUCTIONS_AVAILABLE:  %s\n", IsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE) ? "yes" : "no");
+       printf("\n");
+       printf("Extended CPU Flags (not found in windows API):\n");
+       printf("\tPF_EX_3DNOW_PREFETCH:  %s\n", IsProcessorFeaturePresentEx(PF_EX_3DNOW_PREFETCH) ? "yes" : "no");
+       printf("\tPF_EX_SSSE3:  %s\n", IsProcessorFeaturePresentEx(PF_EX_SSSE3) ? "yes" : "no");
+       printf("\tPF_EX_SSE41:  %s\n", IsProcessorFeaturePresentEx(PF_EX_SSE41) ? "yes" : "no");
+       printf("\tPF_EX_SSE42:  %s\n", IsProcessorFeaturePresentEx(PF_EX_SSE42) ? "yes" : "no");
+       printf("\tPF_EX_AVX:  %s\n", IsProcessorFeaturePresentEx(PF_EX_AVX) ? "yes" : "no");
+       printf("\tPF_EX_FMA:  %s\n", IsProcessorFeaturePresentEx(PF_EX_FMA) ? "yes" : "no");
+       printf("\tPF_EX_AVX_AES:  %s\n", IsProcessorFeaturePresentEx(PF_EX_AVX_AES) ? "yes" : "no");
+#elif defined(_M_ARM)
+       printf("\tPF_ARM_NEON_INSTRUCTIONS_AVAILABLE:  %s\n", IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) ? "yes" : "no");
+       printf("\tPF_ARM_THUMB:  %s\n", IsProcessorFeaturePresent(PF_ARM_THUMB) ? "yes" : "no");
+       printf("\tPF_ARM_VFP_32_REGISTERS_AVAILABLE:  %s\n", IsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE) ? "yes" : "no");
+       printf("\tPF_ARM_DIVIDE_INSTRUCTION_AVAILABLE:  %s\n", IsProcessorFeaturePresent(PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE) ? "yes" : "no");
+       printf("\tPF_ARM_VFP3:  %s\n", IsProcessorFeaturePresent(PF_ARM_VFP3) ? "yes" : "no");
+       printf("\tPF_ARM_THUMB:  %s\n", IsProcessorFeaturePresent(PF_ARM_THUMB) ? "yes" : "no");
+       printf("\tPF_ARM_JAZELLE:  %s\n", IsProcessorFeaturePresent(PF_ARM_JAZELLE) ? "yes" : "no");
+       printf("\tPF_ARM_DSP:  %s\n", IsProcessorFeaturePresent(PF_ARM_DSP) ? "yes" : "no");
+       printf("\tPF_ARM_THUMB2:  %s\n", IsProcessorFeaturePresent(PF_ARM_THUMB2) ? "yes" : "no");
+       printf("\tPF_ARM_T2EE:  %s\n", IsProcessorFeaturePresent(PF_ARM_T2EE) ? "yes" : "no");
+       printf("\tPF_ARM_INTEL_WMMX:  %s\n", IsProcessorFeaturePresent(PF_ARM_INTEL_WMMX) ? "yes" : "no");
+       printf("Extended CPU Flags (not found in windows API):\n");
+       printf("\tPF_EX_ARM_VFP1:  %s\n", IsProcessorFeaturePresentEx(PF_EX_ARM_VFP1) ? "yes" : "no");
+       printf("\tPF_EX_ARM_VFP3D16:  %s\n", IsProcessorFeaturePresentEx(PF_EX_ARM_VFP3D16) ? "yes" : "no");
+       printf("\tPF_EX_ARM_VFP4:  %s\n", IsProcessorFeaturePresentEx(PF_EX_ARM_VFP4) ? "yes" : "no");
+       printf("\tPF_EX_ARM_IDIVA:  %s\n", IsProcessorFeaturePresentEx(PF_EX_ARM_IDIVA) ? "yes" : "no");
+       printf("\tPF_EX_ARM_IDIVT:  %s\n", IsProcessorFeaturePresentEx(PF_EX_ARM_IDIVT) ? "yes" : "no");
+#endif
+       printf("\n");
+       return 0;
+}