michael@0: /* michael@0: * Copyright (c) 2010 The WebM project authors. All Rights Reserved. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license michael@0: * that can be found in the LICENSE file in the root of the source michael@0: * tree. An additional intellectual property rights grant can be found michael@0: * in the file PATENTS. All contributing project authors may michael@0: * be found in the AUTHORS file in the root of the source tree. michael@0: */ michael@0: michael@0: #include michael@0: #include michael@0: #include "arm.h" michael@0: michael@0: static int arm_cpu_env_flags(int *flags) { michael@0: char *env; michael@0: env = getenv("VPX_SIMD_CAPS"); michael@0: if (env && *env) { michael@0: *flags = (int)strtol(env, NULL, 0); michael@0: return 0; michael@0: } michael@0: *flags = 0; michael@0: return -1; michael@0: } michael@0: michael@0: static int arm_cpu_env_mask(void) { michael@0: char *env; michael@0: env = getenv("VPX_SIMD_CAPS_MASK"); michael@0: return env && *env ? (int)strtol(env, NULL, 0) : ~0; michael@0: } michael@0: michael@0: #if !CONFIG_RUNTIME_CPU_DETECT michael@0: michael@0: int arm_cpu_caps(void) { michael@0: /* This function should actually be a no-op. There is no way to adjust any of michael@0: * these because the RTCD tables do not exist: the functions are called michael@0: * statically */ michael@0: int flags; michael@0: int mask; michael@0: if (!arm_cpu_env_flags(&flags)) { michael@0: return flags; michael@0: } michael@0: mask = arm_cpu_env_mask(); michael@0: #if HAVE_EDSP michael@0: flags |= HAS_EDSP; michael@0: #endif /* HAVE_EDSP */ michael@0: #if HAVE_MEDIA michael@0: flags |= HAS_MEDIA; michael@0: #endif /* HAVE_MEDIA */ michael@0: #if HAVE_NEON michael@0: flags |= HAS_NEON; michael@0: #endif /* HAVE_NEON */ michael@0: return flags & mask; michael@0: } michael@0: michael@0: #elif defined(_MSC_VER) /* end !CONFIG_RUNTIME_CPU_DETECT */ michael@0: /*For GetExceptionCode() and EXCEPTION_ILLEGAL_INSTRUCTION.*/ michael@0: #define WIN32_LEAN_AND_MEAN michael@0: #define WIN32_EXTRA_LEAN michael@0: #include michael@0: michael@0: int arm_cpu_caps(void) { michael@0: int flags; michael@0: int mask; michael@0: if (!arm_cpu_env_flags(&flags)) { michael@0: return flags; michael@0: } michael@0: mask = arm_cpu_env_mask(); michael@0: /* MSVC has no inline __asm support for ARM, but it does let you __emit michael@0: * instructions via their assembled hex code. michael@0: * All of these instructions should be essentially nops. michael@0: */ michael@0: #if HAVE_EDSP michael@0: if (mask & HAS_EDSP) { michael@0: __try { michael@0: /*PLD [r13]*/ michael@0: __emit(0xF5DDF000); michael@0: flags |= HAS_EDSP; michael@0: } __except (GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION) { michael@0: /*Ignore exception.*/ michael@0: } michael@0: } michael@0: #if HAVE_MEDIA michael@0: if (mask & HAS_MEDIA) michael@0: __try { michael@0: /*SHADD8 r3,r3,r3*/ michael@0: __emit(0xE6333F93); michael@0: flags |= HAS_MEDIA; michael@0: } __except (GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION) { michael@0: /*Ignore exception.*/ michael@0: } michael@0: } michael@0: #if HAVE_NEON michael@0: if (mask &HAS_NEON) { michael@0: __try { michael@0: /*VORR q0,q0,q0*/ michael@0: __emit(0xF2200150); michael@0: flags |= HAS_NEON; michael@0: } __except (GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION) { michael@0: /*Ignore exception.*/ michael@0: } michael@0: } michael@0: #endif /* HAVE_NEON */ michael@0: #endif /* HAVE_MEDIA */ michael@0: #endif /* HAVE_EDSP */ michael@0: return flags & mask; michael@0: } michael@0: michael@0: #elif defined(__ANDROID__) /* end _MSC_VER */ michael@0: #include michael@0: michael@0: int arm_cpu_caps(void) { michael@0: int flags; michael@0: int mask; michael@0: uint64_t features; michael@0: if (!arm_cpu_env_flags(&flags)) { michael@0: return flags; michael@0: } michael@0: mask = arm_cpu_env_mask(); michael@0: features = android_getCpuFeatures(); michael@0: michael@0: #if HAVE_EDSP michael@0: flags |= HAS_EDSP; michael@0: #endif /* HAVE_EDSP */ michael@0: #if HAVE_MEDIA michael@0: flags |= HAS_MEDIA; michael@0: #endif /* HAVE_MEDIA */ michael@0: #if HAVE_NEON michael@0: if (features & ANDROID_CPU_ARM_FEATURE_NEON) michael@0: flags |= HAS_NEON; michael@0: #endif /* HAVE_NEON */ michael@0: return flags & mask; michael@0: } michael@0: michael@0: #elif defined(__linux__) /* end __ANDROID__ */ michael@0: michael@0: #include michael@0: michael@0: int arm_cpu_caps(void) { michael@0: FILE *fin; michael@0: int flags; michael@0: int mask; michael@0: if (!arm_cpu_env_flags(&flags)) { michael@0: return flags; michael@0: } michael@0: mask = arm_cpu_env_mask(); michael@0: /* Reading /proc/self/auxv would be easier, but that doesn't work reliably michael@0: * on Android. michael@0: * This also means that detection will fail in Scratchbox. michael@0: */ michael@0: fin = fopen("/proc/cpuinfo", "r"); michael@0: if (fin != NULL) { michael@0: /* 512 should be enough for anybody (it's even enough for all the flags michael@0: * that x86 has accumulated... so far). michael@0: */ michael@0: char buf[512]; michael@0: while (fgets(buf, 511, fin) != NULL) { michael@0: #if HAVE_EDSP || HAVE_NEON michael@0: if (memcmp(buf, "Features", 8) == 0) { michael@0: char *p; michael@0: #if HAVE_EDSP michael@0: p = strstr(buf, " edsp"); michael@0: if (p != NULL && (p[5] == ' ' || p[5] == '\n')) { michael@0: flags |= HAS_EDSP; michael@0: } michael@0: #if HAVE_NEON michael@0: p = strstr(buf, " neon"); michael@0: if (p != NULL && (p[5] == ' ' || p[5] == '\n')) { michael@0: flags |= HAS_NEON; michael@0: } michael@0: #endif /* HAVE_NEON */ michael@0: #endif /* HAVE_EDSP */ michael@0: } michael@0: #endif /* HAVE_EDSP || HAVE_NEON */ michael@0: #if HAVE_MEDIA michael@0: if (memcmp(buf, "CPU architecture:", 17) == 0) { michael@0: int version; michael@0: version = atoi(buf + 17); michael@0: if (version >= 6) { michael@0: flags |= HAS_MEDIA; michael@0: } michael@0: } michael@0: #endif /* HAVE_MEDIA */ michael@0: } michael@0: fclose(fin); michael@0: } michael@0: return flags & mask; michael@0: } michael@0: #else /* end __linux__ */ michael@0: #error "--enable-runtime-cpu-detect selected, but no CPU detection method " \ michael@0: "available for your platform. Reconfigure with --disable-runtime-cpu-detect." michael@0: #endif