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 #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