util: detect NEON at runtime on FreeBSD
[mesa.git] / src / util / u_cpu_detect.c
index 52b9ae547d46d68aa87f8a2f5125aaed76c674cd..19b21b0aa44a98dbbe24ad489395cf0c9da06a38 100644 (file)
 #if defined(PIPE_OS_FREEBSD) || defined(PIPE_OS_DRAGONFLY)
 #include <sys/types.h>
 #include <sys/sysctl.h>
+#if __has_include(<sys/auxv.h>)
+#include <sys/auxv.h>
+#define HAVE_ELF_AUX_INFO
+#endif
 #endif
 
 #if defined(PIPE_OS_LINUX)
@@ -92,7 +96,7 @@ static int has_cpuid(void);
 #endif
 
 
-#if defined(PIPE_ARCH_PPC) && !defined(PIPE_OS_APPLE)
+#if defined(PIPE_ARCH_PPC) && !defined(PIPE_OS_APPLE) && !defined(PIPE_OS_LINUX)
 static jmp_buf  __lv_powerpc_jmpbuf;
 static volatile sig_atomic_t __lv_powerpc_canjump = 0;
 
@@ -126,8 +130,29 @@ check_os_altivec_support(void)
          util_cpu_caps.has_altivec = 1;
       }
    }
-#else /* !PIPE_OS_APPLE */
-   /* not on Apple/Darwin, do it the brute-force way */
+#elif defined(PIPE_OS_LINUX) /* !PIPE_OS_APPLE */
+#if defined(PIPE_ARCH_PPC_64)
+    Elf64_auxv_t aux;
+#else
+    Elf32_auxv_t aux;
+#endif
+    int fd = open("/proc/self/auxv", O_RDONLY | O_CLOEXEC);
+    if (fd >= 0) {
+       while (read(fd, &aux, sizeof(aux)) == sizeof(aux)) {
+          if (aux.a_type == AT_HWCAP) {
+             char *env_vsx = getenv("GALLIVM_VSX");
+             uint64_t hwcap = aux.a_un.a_val;
+             util_cpu_caps.has_altivec = (hwcap >> 28) & 1;
+             if (!env_vsx || env_vsx[0] != '0') {
+                util_cpu_caps.has_vsx  = (hwcap >>  7) & 1;
+             }
+             break;
+          }
+       }
+       close(fd);
+    }
+#else /* !PIPE_OS_APPLE && !PIPE_OS_LINUX */
+   /* not on Apple/Darwin or Linux, do it the brute-force way */
    /* this is borrowed from the libmpeg2 library */
    signal(SIGILL, sigill_handler);
    if (setjmp(__lv_powerpc_jmpbuf)) {
@@ -171,7 +196,7 @@ check_os_altivec_support(void)
          util_cpu_caps.has_altivec = 0;
       }
    }
-#endif /* !PIPE_OS_APPLE */
+#endif /* !PIPE_OS_APPLE && !PIPE_OS_LINUX */
 }
 #endif /* PIPE_ARCH_PPC */
 
@@ -339,7 +364,14 @@ check_os_arm_support(void)
     * used. Because of this we cannot use PIPE_OS_ANDROID here, but rather
     * have a separate macro that only gets enabled from respective Android.mk.
     */
-#if defined(HAS_ANDROID_CPUFEATURES)
+#if defined(__ARM_NEON) || defined(__ARM_NEON__)
+   util_cpu_caps.has_neon = 1;
+#elif defined(PIPE_OS_FREEBSD) && defined(HAVE_ELF_AUX_INFO)
+   unsigned long hwcap = 0;
+   elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap));
+   if (hwcap & HWCAP_NEON)
+      util_cpu_caps.has_neon = 1;
+#elif defined(HAS_ANDROID_CPUFEATURES)
    AndroidCpuFamily cpu_family = android_getCpuFamily();
    uint64_t cpu_features = android_getCpuFeatures();
 
@@ -365,7 +397,14 @@ check_os_arm_support(void)
     }
 #endif /* PIPE_OS_LINUX */
 }
-#endif /* PIPE_ARCH_ARM */
+
+#elif defined(PIPE_ARCH_AARCH64)
+static void
+check_os_arm_support(void)
+{
+    util_cpu_caps.has_neon = true;
+}
+#endif /* PIPE_ARCH_ARM || PIPE_ARCH_AARCH64 */
 
 static void
 get_cpu_topology(void)
@@ -534,7 +573,7 @@ util_cpu_detect_once(void)
    }
 #endif /* PIPE_ARCH_X86 || PIPE_ARCH_X86_64 */
 
-#if defined(PIPE_ARCH_ARM)
+#if defined(PIPE_ARCH_ARM) || defined(PIPE_ARCH_AARCH64)
    check_os_arm_support();
 #endif