Home | History | Annotate | Download | only in vpx_ports
      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 {
     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 
     28 static 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 
     42 int 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 
    105 int 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 
    166 int 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