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