/* * ORC - Oil Runtime Compiler * Copyright (c) 2003,2004 David A. Schleef * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include #if defined(__linux__) #include #endif /***** arm *****/ #ifdef __arm__ #if 0 static unsigned long orc_profile_stamp_xscale(void) { unsigned int ts; __asm__ __volatile__ ( " mrc p14, 0, %0, c1, c0, 0 \n" : "=r" (ts)); return ts; } #endif #if defined(__linux__) static unsigned long orc_check_neon_proc_auxv (void) { unsigned long flags = 0; unsigned long aux[2]; ssize_t count; int fd; fd = open("/proc/self/auxv", O_RDONLY); if (fd < 0) { ORC_LOG ("Failed to open /proc/self/auxv"); return 0; } while (1) { count = read(fd, aux, sizeof(aux)); if (count < sizeof(aux)) { break; } if (aux[0] == AT_HWCAP) { /* if (aux[1] & 64) flags |= ORC_TARGET_NEON_VFP; */ /* if (aux[1] & 512) flags |= ORC_TARGET_NEON_IWMMXT; */ if (aux[1] & 4096) flags |= ORC_TARGET_NEON_NEON; if (aux[1] & 128) flags |= ORC_TARGET_ARM_EDSP; ORC_INFO("arm hwcap %08x", aux[1]); } if (aux[0] == AT_PLATFORM) { ORC_INFO("arm platform %s", (char *)aux[1]); } else if (aux[0] == AT_NULL) { break; } } close(fd); return flags; } #endif #ifdef ANDROID static char * get_proc_cpuinfo (void) { char *cpuinfo; int fd; int n; cpuinfo = malloc(4096); if (cpuinfo == NULL) return NULL; fd = open("/proc/cpuinfo", O_RDONLY); if (fd < 0) { free (cpuinfo); return NULL; } n = read(fd, cpuinfo, 4095); if (n < 0) { free (cpuinfo); close (fd); return NULL; } cpuinfo[n] = 0; close (fd); return cpuinfo; } static char * get_cpuinfo_line (char *cpuinfo, const char *tag) { char *flags; char *end; char *colon; flags = strstr(cpuinfo,tag); if (flags == NULL) return NULL; end = strchr(flags, '\n'); if (end == NULL) return NULL; colon = strchr (flags, ':'); if (colon == NULL) return NULL; colon++; if(colon >= end) return NULL; return _strndup (colon, end-colon); } static unsigned long orc_cpu_arm_getflags_cpuinfo () { unsigned long ret = 0; char *cpuinfo; char *cpuinfo_line; char **flags; char **f; cpuinfo = get_proc_cpuinfo(); if (cpuinfo == NULL) { ORC_DEBUG ("Failed to read /proc/cpuinfo"); return 0; } cpuinfo_line = get_cpuinfo_line(cpuinfo, "CPU architecture"); if (cpuinfo_line) { int arm_arch = strtoul (cpuinfo_line, NULL, 0); if (arm_arch >= 8L) { /* Armv8 always supports these, but they won't be listed * in the CPU info optional features */ ret = ORC_TARGET_ARM_EDSP | ORC_TARGET_NEON_NEON; goto out; } free(cpuinfo_line); } cpuinfo_line = get_cpuinfo_line(cpuinfo, "Features"); if (cpuinfo_line == NULL) { free (cpuinfo); return 0; } flags = strsplit(cpuinfo_line, ' '); for (f = flags; *f; f++) { if (strcmp (*f, "edsp") == 0) ret |= ORC_TARGET_ARM_EDSP; else if (strcmp (*f, "neon") == 0) ret |= ORC_TARGET_NEON_NEON; free (*f); } free (flags); out: free (cpuinfo_line); free (cpuinfo); return ret; } #endif unsigned long orc_arm_get_cpu_flags (void) { unsigned long neon_flags = 0; #ifdef __linux__ neon_flags = orc_check_neon_proc_auxv (); #endif #ifdef ANDROID if (!neon_flags) { /* On ARM, /proc/self/auxv might not be accessible. * Fall back to /proc/cpuinfo */ neon_flags = orc_cpu_arm_getflags_cpuinfo (); } #endif if (orc_compiler_flag_check ("-neon")) { neon_flags &= ~ORC_TARGET_NEON_NEON; } return neon_flags; } #endif