diff --git a/pixman/pixman-cpu.c b/pixman/pixman-cpu.c index e4fb1e4..8e0dd15 100644 --- a/pixman/pixman-cpu.c +++ b/pixman/pixman-cpu.c @@ -246,60 +246,55 @@ pixman_have_arm_neon (void) #else /* linux ELF */ -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include -static pixman_bool_t arm_has_v7 = FALSE; static pixman_bool_t arm_has_v6 = FALSE; -static pixman_bool_t arm_has_vfp = FALSE; static pixman_bool_t arm_has_neon = FALSE; -static pixman_bool_t arm_has_iwmmxt = FALSE; static pixman_bool_t arm_tests_initialized = FALSE; +static sigjmp_buf cpu_jmpbuf; + static void -pixman_arm_read_auxv () +pixman_catch_sigill(int sig) { - int fd; - Elf32_auxv_t aux; + siglongjmp(cpu_jmpbuf, 1); +} + +static void +pixman_arm_check_neon (void) +{ + struct sigaction sa, old_sa; - fd = open ("/proc/self/auxv", O_RDONLY); - if (fd >= 0) + /* setup the sigaction */ + sa.sa_handler = pixman_catch_sigill; + sa.sa_flags = SA_RESTART; + sigemptyset(&sa.sa_mask); + sigaction(SIGILL, &sa, &old_sa); + +#if defined(USE_ARM_NEON) + if (!sigsetjmp(cpu_jmpbuf, 1)) { - while (read (fd, &aux, sizeof(Elf32_auxv_t)) == sizeof(Elf32_auxv_t)) - { - if (aux.a_type == AT_HWCAP) - { - uint32_t hwcap = aux.a_un.a_val; - /* hardcode these values to avoid depending on specific - * versions of the hwcap header, e.g. HWCAP_NEON - */ - arm_has_vfp = (hwcap & 64) != 0; - arm_has_iwmmxt = (hwcap & 512) != 0; - /* this flag is only present on kernel 2.6.29 */ - arm_has_neon = (hwcap & 4096) != 0; - } - else if (aux.a_type == AT_PLATFORM) - { - const char *plat = (const char*) aux.a_un.a_val; - if (strncmp (plat, "v7l", 3) == 0) - { - arm_has_v7 = TRUE; - arm_has_v6 = TRUE; - } - else if (strncmp (plat, "v6l", 3) == 0) - { - arm_has_v6 = TRUE; - } - } - } - close (fd); + asm volatile ( + ".fpu neon\n" + "\tvqadd.u8 d0, d1, d0\n" + ); + arm_has_neon = TRUE; } +#endif + +#if defined(USE_ARM_SIMD) + if (!sigsetjmp(cpu_jmpbuf, 1)) + { + asm volatile ( + ".arch armv6\n" + "\tuqadd8 r1, r1, r2\n" + : : :"r1", "r2"); + arm_has_v6 = TRUE; + } +#endif + + sigaction(SIGILL, &old_sa, NULL); arm_tests_initialized = TRUE; } @@ -309,7 +304,7 @@ pixman_bool_t pixman_have_arm_simd (void) { if (!arm_tests_initialized) - pixman_arm_read_auxv (); + pixman_arm_check_neon (); return arm_has_v6; } @@ -321,7 +316,7 @@ pixman_bool_t pixman_have_arm_neon (void) { if (!arm_tests_initialized) - pixman_arm_read_auxv (); + pixman_arm_check_neon (); return arm_has_neon; }