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