arm_cpudetect.c revision 1b362b15af34006e6a11974088a46d42b903418e
1538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber/*
2538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
3538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber *
4538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber *  Use of this source code is governed by a BSD-style license
5538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber *  that can be found in the LICENSE file in the root of the source
6538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber *  tree. An additional intellectual property rights grant can be found
7538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber *  in the file PATENTS.  All contributing project authors may
8538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber *  be found in the AUTHORS file in the root of the source tree.
9538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber */
10538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
11538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber#include <stdlib.h>
12538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber#include <string.h>
13538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber#include "arm.h"
14538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
15538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huberstatic int arm_cpu_env_flags(int *flags)
16538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber{
17538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    char *env;
18538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    env = getenv("VPX_SIMD_CAPS");
19538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    if (env && *env)
20538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    {
21538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        *flags = (int)strtol(env, NULL, 0);
22538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        return 0;
23538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    }
24538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    *flags = 0;
25538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    return -1;
26538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber}
27538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
28538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huberstatic int arm_cpu_env_mask(void)
29538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber{
30538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    char *env;
31538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    env = getenv("VPX_SIMD_CAPS_MASK");
32538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    return env && *env ? (int)strtol(env, NULL, 0) : ~0;
33538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber}
34538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
351b362b15af34006e6a11974088a46d42b903418eJohann#if !CONFIG_RUNTIME_CPU_DETECT
36538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
371b362b15af34006e6a11974088a46d42b903418eJohannint arm_cpu_caps(void)
381b362b15af34006e6a11974088a46d42b903418eJohann{
391b362b15af34006e6a11974088a46d42b903418eJohann  /* This function should actually be a no-op. There is no way to adjust any of
401b362b15af34006e6a11974088a46d42b903418eJohann   * these because the RTCD tables do not exist: the functions are called
411b362b15af34006e6a11974088a46d42b903418eJohann   * statically */
421b362b15af34006e6a11974088a46d42b903418eJohann    int flags;
431b362b15af34006e6a11974088a46d42b903418eJohann    int mask;
441b362b15af34006e6a11974088a46d42b903418eJohann    if (!arm_cpu_env_flags(&flags))
451b362b15af34006e6a11974088a46d42b903418eJohann    {
461b362b15af34006e6a11974088a46d42b903418eJohann        return flags;
471b362b15af34006e6a11974088a46d42b903418eJohann    }
481b362b15af34006e6a11974088a46d42b903418eJohann    mask = arm_cpu_env_mask();
491b362b15af34006e6a11974088a46d42b903418eJohann#if HAVE_EDSP
501b362b15af34006e6a11974088a46d42b903418eJohann    flags |= HAS_EDSP;
511b362b15af34006e6a11974088a46d42b903418eJohann#endif /* HAVE_EDSP */
521b362b15af34006e6a11974088a46d42b903418eJohann#if HAVE_MEDIA
531b362b15af34006e6a11974088a46d42b903418eJohann    flags |= HAS_MEDIA;
541b362b15af34006e6a11974088a46d42b903418eJohann#endif /* HAVE_MEDIA */
551b362b15af34006e6a11974088a46d42b903418eJohann#if HAVE_NEON
561b362b15af34006e6a11974088a46d42b903418eJohann    flags |= HAS_NEON;
571b362b15af34006e6a11974088a46d42b903418eJohann#endif /* HAVE_NEON */
581b362b15af34006e6a11974088a46d42b903418eJohann    return flags & mask;
591b362b15af34006e6a11974088a46d42b903418eJohann}
601b362b15af34006e6a11974088a46d42b903418eJohann
611b362b15af34006e6a11974088a46d42b903418eJohann#elif defined(_MSC_VER) /* end !CONFIG_RUNTIME_CPU_DETECT */
62538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber/*For GetExceptionCode() and EXCEPTION_ILLEGAL_INSTRUCTION.*/
63538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber#define WIN32_LEAN_AND_MEAN
64538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber#define WIN32_EXTRA_LEAN
65538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber#include <windows.h>
66538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
67538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huberint arm_cpu_caps(void)
68538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber{
69538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    int flags;
70538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    int mask;
71538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    if (!arm_cpu_env_flags(&flags))
72538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    {
73538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        return flags;
74538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    }
75538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    mask = arm_cpu_env_mask();
76538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    /* MSVC has no inline __asm support for ARM, but it does let you __emit
77538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber     *  instructions via their assembled hex code.
78538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber     * All of these instructions should be essentially nops.
79538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber     */
801b362b15af34006e6a11974088a46d42b903418eJohann#if HAVE_EDSP
81538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    if (mask & HAS_EDSP)
82538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    {
83538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        __try
84538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        {
85538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber            /*PLD [r13]*/
86538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber            __emit(0xF5DDF000);
87538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber            flags |= HAS_EDSP;
88538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        }
89538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        __except(GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION)
90538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        {
91538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber            /*Ignore exception.*/
92538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        }
93538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    }
941b362b15af34006e6a11974088a46d42b903418eJohann#if HAVE_MEDIA
95538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    if (mask & HAS_MEDIA)
96538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        __try
97538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        {
98538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber            /*SHADD8 r3,r3,r3*/
99538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber            __emit(0xE6333F93);
100538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber            flags |= HAS_MEDIA;
101538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        }
102538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        __except(GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION)
103538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        {
104538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber            /*Ignore exception.*/
105538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        }
106538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    }
1071b362b15af34006e6a11974088a46d42b903418eJohann#if HAVE_NEON
108538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    if (mask & HAS_NEON)
109538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    {
110538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        __try
111538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        {
112538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber            /*VORR q0,q0,q0*/
113538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber            __emit(0xF2200150);
114538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber            flags |= HAS_NEON;
115538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        }
116538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        __except(GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION)
117538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        {
118538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber            /*Ignore exception.*/
119538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        }
120538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    }
1211b362b15af34006e6a11974088a46d42b903418eJohann#endif /* HAVE_NEON */
1221b362b15af34006e6a11974088a46d42b903418eJohann#endif /* HAVE_MEDIA */
1231b362b15af34006e6a11974088a46d42b903418eJohann#endif /* HAVE_EDSP */
1241b362b15af34006e6a11974088a46d42b903418eJohann    return flags & mask;
1251b362b15af34006e6a11974088a46d42b903418eJohann}
1261b362b15af34006e6a11974088a46d42b903418eJohann
1271b362b15af34006e6a11974088a46d42b903418eJohann#elif defined(__ANDROID__) /* end _MSC_VER */
1281b362b15af34006e6a11974088a46d42b903418eJohann#include <cpu-features.h>
1291b362b15af34006e6a11974088a46d42b903418eJohann
1301b362b15af34006e6a11974088a46d42b903418eJohannint arm_cpu_caps(void)
1311b362b15af34006e6a11974088a46d42b903418eJohann{
1321b362b15af34006e6a11974088a46d42b903418eJohann    int flags;
1331b362b15af34006e6a11974088a46d42b903418eJohann    int mask;
1341b362b15af34006e6a11974088a46d42b903418eJohann    uint64_t features;
1351b362b15af34006e6a11974088a46d42b903418eJohann    if (!arm_cpu_env_flags(&flags))
1361b362b15af34006e6a11974088a46d42b903418eJohann    {
1371b362b15af34006e6a11974088a46d42b903418eJohann        return flags;
1381b362b15af34006e6a11974088a46d42b903418eJohann    }
1391b362b15af34006e6a11974088a46d42b903418eJohann    mask = arm_cpu_env_mask();
1401b362b15af34006e6a11974088a46d42b903418eJohann    features = android_getCpuFeatures();
1411b362b15af34006e6a11974088a46d42b903418eJohann
1421b362b15af34006e6a11974088a46d42b903418eJohann#if HAVE_EDSP
1431b362b15af34006e6a11974088a46d42b903418eJohann    flags |= HAS_EDSP;
1441b362b15af34006e6a11974088a46d42b903418eJohann#endif /* HAVE_EDSP */
1451b362b15af34006e6a11974088a46d42b903418eJohann#if HAVE_MEDIA
1461b362b15af34006e6a11974088a46d42b903418eJohann    flags |= HAS_MEDIA;
1471b362b15af34006e6a11974088a46d42b903418eJohann#endif /* HAVE_MEDIA */
1481b362b15af34006e6a11974088a46d42b903418eJohann#if HAVE_NEON
1491b362b15af34006e6a11974088a46d42b903418eJohann    if (features & ANDROID_CPU_ARM_FEATURE_NEON)
1501b362b15af34006e6a11974088a46d42b903418eJohann        flags |= HAS_NEON;
1511b362b15af34006e6a11974088a46d42b903418eJohann#endif /* HAVE_NEON */
152538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    return flags & mask;
153538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber}
154538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
1551b362b15af34006e6a11974088a46d42b903418eJohann#elif defined(__linux__) /* end __ANDROID__ */
156538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber#include <stdio.h>
157538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber
158538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huberint arm_cpu_caps(void)
159538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber{
160538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    FILE *fin;
161538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    int flags;
162538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    int mask;
163538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    if (!arm_cpu_env_flags(&flags))
164538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    {
165538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        return flags;
166538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    }
167538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    mask = arm_cpu_env_mask();
168538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    /* Reading /proc/self/auxv would be easier, but that doesn't work reliably
169538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber     *  on Android.
170538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber     * This also means that detection will fail in Scratchbox.
171538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber     */
172538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    fin = fopen("/proc/cpuinfo","r");
173538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    if(fin != NULL)
174538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    {
175538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        /* 512 should be enough for anybody (it's even enough for all the flags
176538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber         * that x86 has accumulated... so far).
177538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber         */
178538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        char buf[512];
179538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        while (fgets(buf, 511, fin) != NULL)
180538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        {
1811b362b15af34006e6a11974088a46d42b903418eJohann#if HAVE_EDSP || HAVE_NEON
182538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber            if (memcmp(buf, "Features", 8) == 0)
183538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber            {
184538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber                char *p;
1851b362b15af34006e6a11974088a46d42b903418eJohann#if HAVE_EDSP
186538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber                p=strstr(buf, " edsp");
187538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber                if (p != NULL && (p[5] == ' ' || p[5] == '\n'))
188538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber                {
189538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber                    flags |= HAS_EDSP;
190538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber                }
1911b362b15af34006e6a11974088a46d42b903418eJohann#if HAVE_NEON
192538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber                p = strstr(buf, " neon");
193538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber                if (p != NULL && (p[5] == ' ' || p[5] == '\n'))
194538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber                {
195538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber                    flags |= HAS_NEON;
196538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber                }
1971b362b15af34006e6a11974088a46d42b903418eJohann#endif /* HAVE_NEON */
1981b362b15af34006e6a11974088a46d42b903418eJohann#endif /* HAVE_EDSP */
199538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber            }
2001b362b15af34006e6a11974088a46d42b903418eJohann#endif /* HAVE_EDSP || HAVE_NEON */
2011b362b15af34006e6a11974088a46d42b903418eJohann#if HAVE_MEDIA
202538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber            if (memcmp(buf, "CPU architecture:",17) == 0){
203538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber                int version;
204538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber                version = atoi(buf+17);
205538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber                if (version >= 6)
206538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber                {
207538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber                    flags |= HAS_MEDIA;
208538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber                }
209538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber            }
2101b362b15af34006e6a11974088a46d42b903418eJohann#endif /* HAVE_MEDIA */
211538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        }
212538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber        fclose(fin);
213538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    }
214538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber    return flags & mask;
215538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber}
2161b362b15af34006e6a11974088a46d42b903418eJohann#else /* end __linux__ */
217538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber#error "--enable-runtime-cpu-detect selected, but no CPU detection method " \
2181b362b15af34006e6a11974088a46d42b903418eJohann "available for your platform. Reconfigure with --disable-runtime-cpu-detect."
219538f6170b788de7408b06efc6613dc98579aa6a6Andreas Huber#endif
220