1 /* 2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include <stdlib.h> 12 #include <string.h> 13 #include "arm.h" 14 15 #ifdef WINAPI_FAMILY 16 #include <winapifamily.h> 17 #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) 18 #define getenv(x) NULL 19 #endif 20 #endif 21 22 static int arm_cpu_env_flags(int *flags) { 23 char *env; 24 env = getenv("VPX_SIMD_CAPS"); 25 if (env && *env) { 26 *flags = (int)strtol(env, NULL, 0); 27 return 0; 28 } 29 *flags = 0; 30 return -1; 31 } 32 33 static int arm_cpu_env_mask(void) { 34 char *env; 35 env = getenv("VPX_SIMD_CAPS_MASK"); 36 return env && *env ? (int)strtol(env, NULL, 0) : ~0; 37 } 38 39 #if !CONFIG_RUNTIME_CPU_DETECT 40 41 int arm_cpu_caps(void) { 42 /* This function should actually be a no-op. There is no way to adjust any of 43 * these because the RTCD tables do not exist: the functions are called 44 * statically */ 45 int flags; 46 int mask; 47 if (!arm_cpu_env_flags(&flags)) { 48 return flags; 49 } 50 mask = arm_cpu_env_mask(); 51 #if HAVE_EDSP 52 flags |= HAS_EDSP; 53 #endif /* HAVE_EDSP */ 54 #if HAVE_MEDIA 55 flags |= HAS_MEDIA; 56 #endif /* HAVE_MEDIA */ 57 #if HAVE_NEON 58 flags |= HAS_NEON; 59 #endif /* HAVE_NEON */ 60 return flags & mask; 61 } 62 63 #elif defined(_MSC_VER) /* end !CONFIG_RUNTIME_CPU_DETECT */ 64 /*For GetExceptionCode() and EXCEPTION_ILLEGAL_INSTRUCTION.*/ 65 #define WIN32_LEAN_AND_MEAN 66 #define WIN32_EXTRA_LEAN 67 #include <windows.h> 68 69 int arm_cpu_caps(void) { 70 int flags; 71 int mask; 72 if (!arm_cpu_env_flags(&flags)) { 73 return flags; 74 } 75 mask = arm_cpu_env_mask(); 76 /* MSVC has no inline __asm support for ARM, but it does let you __emit 77 * instructions via their assembled hex code. 78 * All of these instructions should be essentially nops. 79 */ 80 #if HAVE_EDSP 81 if (mask & HAS_EDSP) { 82 __try { 83 /*PLD [r13]*/ 84 __emit(0xF5DDF000); 85 flags |= HAS_EDSP; 86 } __except (GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION) { 87 /*Ignore exception.*/ 88 } 89 } 90 #if HAVE_MEDIA 91 if (mask & HAS_MEDIA) 92 __try { 93 /*SHADD8 r3,r3,r3*/ 94 __emit(0xE6333F93); 95 flags |= HAS_MEDIA; 96 } __except (GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION) { 97 /*Ignore exception.*/ 98 } 99 } 100 #if HAVE_NEON 101 if (mask &HAS_NEON) { 102 __try { 103 /*VORR q0,q0,q0*/ 104 __emit(0xF2200150); 105 flags |= HAS_NEON; 106 } __except (GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION) { 107 /*Ignore exception.*/ 108 } 109 } 110 #endif /* HAVE_NEON */ 111 #endif /* HAVE_MEDIA */ 112 #endif /* HAVE_EDSP */ 113 return flags & mask; 114 } 115 116 #elif defined(__ANDROID__) /* end _MSC_VER */ 117 #include <cpu-features.h> 118 119 int arm_cpu_caps(void) { 120 int flags; 121 int mask; 122 uint64_t features; 123 if (!arm_cpu_env_flags(&flags)) { 124 return flags; 125 } 126 mask = arm_cpu_env_mask(); 127 features = android_getCpuFeatures(); 128 129 #if HAVE_EDSP 130 flags |= HAS_EDSP; 131 #endif /* HAVE_EDSP */ 132 #if HAVE_MEDIA 133 flags |= HAS_MEDIA; 134 #endif /* HAVE_MEDIA */ 135 #if HAVE_NEON 136 if (features & ANDROID_CPU_ARM_FEATURE_NEON) 137 flags |= HAS_NEON; 138 #endif /* HAVE_NEON */ 139 return flags & mask; 140 } 141 142 #elif defined(__linux__) /* end __ANDROID__ */ 143 144 #include <stdio.h> 145 146 int arm_cpu_caps(void) { 147 FILE *fin; 148 int flags; 149 int mask; 150 if (!arm_cpu_env_flags(&flags)) { 151 return flags; 152 } 153 mask = arm_cpu_env_mask(); 154 /* Reading /proc/self/auxv would be easier, but that doesn't work reliably 155 * on Android. 156 * This also means that detection will fail in Scratchbox. 157 */ 158 fin = fopen("/proc/cpuinfo", "r"); 159 if (fin != NULL) { 160 /* 512 should be enough for anybody (it's even enough for all the flags 161 * that x86 has accumulated... so far). 162 */ 163 char buf[512]; 164 while (fgets(buf, 511, fin) != NULL) { 165 #if HAVE_EDSP || HAVE_NEON 166 if (memcmp(buf, "Features", 8) == 0) { 167 char *p; 168 #if HAVE_EDSP 169 p = strstr(buf, " edsp"); 170 if (p != NULL && (p[5] == ' ' || p[5] == '\n')) { 171 flags |= HAS_EDSP; 172 } 173 #if HAVE_NEON 174 p = strstr(buf, " neon"); 175 if (p != NULL && (p[5] == ' ' || p[5] == '\n')) { 176 flags |= HAS_NEON; 177 } 178 #endif /* HAVE_NEON */ 179 #endif /* HAVE_EDSP */ 180 } 181 #endif /* HAVE_EDSP || HAVE_NEON */ 182 #if HAVE_MEDIA 183 if (memcmp(buf, "CPU architecture:", 17) == 0) { 184 int version; 185 version = atoi(buf + 17); 186 if (version >= 6) { 187 flags |= HAS_MEDIA; 188 } 189 } 190 #endif /* HAVE_MEDIA */ 191 } 192 fclose(fin); 193 } 194 return flags & mask; 195 } 196 #else /* end __linux__ */ 197 #error "--enable-runtime-cpu-detect selected, but no CPU detection method " \ 198 "available for your platform. Reconfigure with --disable-runtime-cpu-detect." 199 #endif 200