tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

armcpu.c (9535B)


      1 /* Copyright (c) 2010 Xiph.Org Foundation
      2 * Copyright (c) 2013 Parrot */
      3 /*
      4   Redistribution and use in source and binary forms, with or without
      5   modification, are permitted provided that the following conditions
      6   are met:
      7 
      8   - Redistributions of source code must retain the above copyright
      9   notice, this list of conditions and the following disclaimer.
     10 
     11   - Redistributions in binary form must reproduce the above copyright
     12   notice, this list of conditions and the following disclaimer in the
     13   documentation and/or other materials provided with the distribution.
     14 
     15   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     16   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     17   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     18   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
     19   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     20   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     22   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     23   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     24   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     25   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26 */
     27 
     28 /* Original code from libtheora modified to suit to Opus */
     29 
     30 #ifdef HAVE_CONFIG_H
     31 #include "config.h"
     32 #endif
     33 
     34 #ifdef OPUS_HAVE_RTCD
     35 
     36 #include "armcpu.h"
     37 #include "cpu_support.h"
     38 #include "os_support.h"
     39 #include "opus_types.h"
     40 #include "arch.h"
     41 
     42 #define OPUS_CPU_ARM_V4_FLAG    (1<<OPUS_ARCH_ARM_V4)
     43 #define OPUS_CPU_ARM_EDSP_FLAG  (1<<OPUS_ARCH_ARM_EDSP)
     44 #define OPUS_CPU_ARM_MEDIA_FLAG (1<<OPUS_ARCH_ARM_MEDIA)
     45 #define OPUS_CPU_ARM_NEON_FLAG  (1<<OPUS_ARCH_ARM_NEON)
     46 #define OPUS_CPU_ARM_DOTPROD_FLAG  (1<<OPUS_ARCH_ARM_DOTPROD)
     47 
     48 #if defined(_MSC_VER)
     49 /*For GetExceptionCode() and EXCEPTION_ILLEGAL_INSTRUCTION.*/
     50 # define WIN32_LEAN_AND_MEAN
     51 # define WIN32_EXTRA_LEAN
     52 # include <windows.h>
     53 
     54 static OPUS_INLINE opus_uint32 opus_cpu_capabilities(void){
     55  opus_uint32 flags;
     56  flags=0;
     57  /* MSVC has no OPUS_INLINE __asm support for ARM, but it does let you __emit
     58   * instructions via their assembled hex code.
     59   * All of these instructions should be essentially nops. */
     60 # if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_MEDIA) \
     61 || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
     62  __try{
     63    /*PLD [r13]*/
     64    __emit(0xF5DDF000);
     65    flags|=OPUS_CPU_ARM_EDSP_FLAG;
     66  }
     67  __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
     68    /*Ignore exception.*/
     69  }
     70 #  if defined(OPUS_ARM_MAY_HAVE_MEDIA) \
     71 || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
     72  __try{
     73    /*SHADD8 r3,r3,r3*/
     74    __emit(0xE6333F93);
     75    flags|=OPUS_CPU_ARM_MEDIA_FLAG;
     76  }
     77  __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
     78    /*Ignore exception.*/
     79  }
     80 #   if defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
     81  __try{
     82    /*VORR q0,q0,q0*/
     83    __emit(0xF2200150);
     84    flags|=OPUS_CPU_ARM_NEON_FLAG;
     85  }
     86  __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
     87    /*Ignore exception.*/
     88  }
     89 #   endif
     90 #  endif
     91 # endif
     92  return flags;
     93 }
     94 
     95 #elif defined(__linux__)
     96 /* Linux based */
     97 #include <stdio.h>
     98 
     99 static opus_uint32 opus_cpu_capabilities(void)
    100 {
    101  opus_uint32 flags = 0;
    102  FILE *cpuinfo;
    103 
    104  /* Reading /proc/self/auxv would be easier, but that doesn't work reliably on
    105   * Android */
    106  cpuinfo = fopen("/proc/cpuinfo", "r");
    107 
    108  if(cpuinfo != NULL)
    109  {
    110    /* 512 should be enough for anybody (it's even enough for all the flags that
    111     * x86 has accumulated... so far). */
    112    char buf[512];
    113 
    114    while(fgets(buf, 512, cpuinfo) != NULL)
    115    {
    116 # if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_MEDIA) \
    117 || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
    118      /* Search for edsp and neon flag */
    119      if(memcmp(buf, "Features", 8) == 0)
    120      {
    121        char *p;
    122        p = strstr(buf, " edsp");
    123        if(p != NULL && (p[5] == ' ' || p[5] == '\n'))
    124          flags |= OPUS_CPU_ARM_EDSP_FLAG;
    125 
    126 #  if defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
    127        p = strstr(buf, " neon");
    128        if(p != NULL && (p[5] == ' ' || p[5] == '\n'))
    129          flags |= OPUS_CPU_ARM_NEON_FLAG;
    130        p = strstr(buf, " asimd");
    131        if(p != NULL && (p[6] == ' ' || p[6] == '\n'))
    132          flags |= OPUS_CPU_ARM_NEON_FLAG | OPUS_CPU_ARM_MEDIA_FLAG | OPUS_CPU_ARM_EDSP_FLAG;
    133 #  endif
    134 #  if defined(OPUS_ARM_MAY_HAVE_DOTPROD)
    135        p = strstr(buf, " asimddp");
    136        if(p != NULL && (p[8] == ' ' || p[8] == '\n'))
    137          flags |= OPUS_CPU_ARM_DOTPROD_FLAG;
    138 #  endif
    139      }
    140 # endif
    141 
    142 # if defined(OPUS_ARM_MAY_HAVE_MEDIA) \
    143 || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
    144      /* Search for media capabilities (>= ARMv6) */
    145      if(memcmp(buf, "CPU architecture:", 17) == 0)
    146      {
    147        int version;
    148        version = atoi(buf+17);
    149 
    150        if(version >= 6)
    151          flags |= OPUS_CPU_ARM_MEDIA_FLAG;
    152      }
    153 # endif
    154    }
    155 
    156 #if defined(OPUS_ARM_PRESUME_AARCH64_NEON_INTR)
    157    flags |= OPUS_CPU_ARM_EDSP_FLAG | OPUS_CPU_ARM_MEDIA_FLAG | OPUS_CPU_ARM_NEON_FLAG;
    158 # if defined(OPUS_ARM_PRESUME_DOTPROD)
    159    flags |= OPUS_CPU_ARM_DOTPROD_FLAG;
    160 # endif
    161 #endif
    162 
    163    fclose(cpuinfo);
    164  }
    165  return flags;
    166 }
    167 
    168 #elif defined(__APPLE__)
    169 #include <sys/types.h>
    170 #include <sys/sysctl.h>
    171 
    172 static opus_uint32 opus_cpu_capabilities(void)
    173 {
    174  opus_uint32 flags = 0;
    175 
    176 #if defined(OPUS_ARM_MAY_HAVE_DOTPROD)
    177  size_t size = sizeof(uint32_t);
    178  uint32_t value = 0;
    179  if (!sysctlbyname("hw.optional.arm.FEAT_DotProd", &value, &size, NULL, 0) && value)
    180  {
    181    flags |= OPUS_CPU_ARM_DOTPROD_FLAG;
    182  }
    183 #endif
    184 
    185 #if defined(OPUS_ARM_PRESUME_AARCH64_NEON_INTR)
    186  flags |= OPUS_CPU_ARM_EDSP_FLAG | OPUS_CPU_ARM_MEDIA_FLAG | OPUS_CPU_ARM_NEON_FLAG;
    187 # if defined(OPUS_ARM_PRESUME_DOTPROD)
    188  flags |= OPUS_CPU_ARM_DOTPROD_FLAG;
    189 # endif
    190 #endif
    191  return flags;
    192 }
    193 
    194 #elif defined(HAVE_ELF_AUX_INFO)
    195 #include <sys/auxv.h>
    196 
    197 static opus_uint32 opus_cpu_capabilities(void)
    198 {
    199  long hwcap = 0;
    200  opus_uint32 flags = 0;
    201 
    202 # if defined(OPUS_ARM_MAY_HAVE_MEDIA) \
    203 || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
    204  /* FreeBSD requires armv6+, which always supports media instructions */
    205  flags |= OPUS_CPU_ARM_MEDIA_FLAG;
    206 # endif
    207 
    208  elf_aux_info(AT_HWCAP, &hwcap, sizeof hwcap);
    209 
    210 # if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_MEDIA) \
    211 || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
    212 #  ifdef HWCAP_EDSP
    213  if (hwcap & HWCAP_EDSP)
    214    flags |= OPUS_CPU_ARM_EDSP_FLAG;
    215 #  endif
    216 
    217 #  if defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
    218 #   ifdef HWCAP_NEON
    219  if (hwcap & HWCAP_NEON)
    220    flags |= OPUS_CPU_ARM_NEON_FLAG;
    221 #   elif defined(HWCAP_ASIMD)
    222  if (hwcap & HWCAP_ASIMD)
    223    flags |= OPUS_CPU_ARM_NEON_FLAG | OPUS_CPU_ARM_MEDIA_FLAG | OPUS_CPU_ARM_EDSP_FLAG;
    224 #   endif
    225 #  endif
    226 #  if defined(OPUS_ARM_MAY_HAVE_DOTPROD) && defined(HWCAP_ASIMDDP)
    227  if (hwcap & HWCAP_ASIMDDP)
    228    flags |= OPUS_CPU_ARM_DOTPROD_FLAG;
    229 #  endif
    230 # endif
    231 
    232 #if defined(OPUS_ARM_PRESUME_AARCH64_NEON_INTR)
    233    flags |= OPUS_CPU_ARM_EDSP_FLAG | OPUS_CPU_ARM_MEDIA_FLAG | OPUS_CPU_ARM_NEON_FLAG;
    234 # if defined(OPUS_ARM_PRESUME_DOTPROD)
    235    flags |= OPUS_CPU_ARM_DOTPROD_FLAG;
    236 # endif
    237 #endif
    238 
    239  return (flags);
    240 }
    241 
    242 #elif defined(__OpenBSD__)
    243 #include <sys/types.h>
    244 #include <sys/sysctl.h>
    245 #include <machine/armreg.h>
    246 #include <machine/cpu.h>
    247 
    248 static opus_uint32 opus_cpu_capabilities(void)
    249 {
    250  opus_uint32 flags = 0;
    251 
    252 #if defined(OPUS_ARM_MAY_HAVE_DOTPROD) && defined(CPU_ID_AA64ISAR0)
    253  const int isar0_mib[] = { CTL_MACHDEP, CPU_ID_AA64ISAR0 };
    254  uint64_t isar0;
    255  size_t len = sizeof(isar0);
    256 
    257  if (sysctl(isar0_mib, 2, &isar0, &len, NULL, 0) != -1)
    258  {
    259    if (ID_AA64ISAR0_DP(isar0) >= ID_AA64ISAR0_DP_IMPL)
    260      flags |= OPUS_CPU_ARM_DOTPROD_FLAG;
    261  }
    262 #endif
    263 
    264 #if defined(OPUS_ARM_PRESUME_NEON_INTR) \
    265 || defined(OPUS_ARM_PRESUME_AARCH64_NEON_INTR)
    266  flags |= OPUS_CPU_ARM_EDSP_FLAG | OPUS_CPU_ARM_MEDIA_FLAG | OPUS_CPU_ARM_NEON_FLAG;
    267 # if defined(OPUS_ARM_PRESUME_DOTPROD)
    268  flags |= OPUS_CPU_ARM_DOTPROD_FLAG;
    269 # endif
    270 #endif
    271  return flags;
    272 }
    273 
    274 #else
    275 /* The feature registers which can tell us what the processor supports are
    276 * accessible in privileged modes only, so we can't have a general user-space
    277 * detection method like on x86.*/
    278 # error "Configured to use ARM asm but no CPU detection method available for " \
    279   "your platform.  Reconfigure with --disable-rtcd (or send patches)."
    280 #endif
    281 
    282 static int opus_select_arch_impl(void)
    283 {
    284  opus_uint32 flags = opus_cpu_capabilities();
    285  int arch = 0;
    286 
    287  if(!(flags & OPUS_CPU_ARM_EDSP_FLAG)) {
    288    /* Asserts ensure arch values are sequential */
    289    celt_assert(arch == OPUS_ARCH_ARM_V4);
    290    return arch;
    291  }
    292  arch++;
    293 
    294  if(!(flags & OPUS_CPU_ARM_MEDIA_FLAG)) {
    295    celt_assert(arch == OPUS_ARCH_ARM_EDSP);
    296    return arch;
    297  }
    298  arch++;
    299 
    300  if(!(flags & OPUS_CPU_ARM_NEON_FLAG)) {
    301    celt_assert(arch == OPUS_ARCH_ARM_MEDIA);
    302    return arch;
    303  }
    304  arch++;
    305 
    306  if(!(flags & OPUS_CPU_ARM_DOTPROD_FLAG)) {
    307    celt_assert(arch == OPUS_ARCH_ARM_NEON);
    308    return arch;
    309  }
    310  arch++;
    311 
    312  celt_assert(arch == OPUS_ARCH_ARM_DOTPROD);
    313  return arch;
    314 }
    315 
    316 int opus_select_arch(void) {
    317  int arch = opus_select_arch_impl();
    318 #ifdef FUZZING
    319  arch = rand()%(arch+1);
    320 #endif
    321  return arch;
    322 }
    323 #endif