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 41 #define OPUS_CPU_ARM_V4 (1) 42 #define OPUS_CPU_ARM_EDSP (1<<1) 43 #define OPUS_CPU_ARM_MEDIA (1<<2) 44 #define OPUS_CPU_ARM_NEON (1<<3) 45 46 #if defined(_MSC_VER) 47 /*For GetExceptionCode() and EXCEPTION_ILLEGAL_INSTRUCTION.*/ 48 # define WIN32_LEAN_AND_MEAN 49 # define WIN32_EXTRA_LEAN 50 # include <windows.h> 51 52 static OPUS_INLINE opus_uint32 opus_cpu_capabilities(void){ 53 opus_uint32 flags; 54 flags=0; 55 /* MSVC has no OPUS_INLINE __asm support for ARM, but it does let you __emit 56 * instructions via their assembled hex code. 57 * All of these instructions should be essentially nops. */ 58 # if defined(OPUS_ARM_MAY_HAVE_EDSP) 59 __try{ 60 /*PLD [r13]*/ 61 __emit(0xF5DDF000); 62 flags|=OPUS_CPU_ARM_EDSP; 63 } 64 __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){ 65 /*Ignore exception.*/ 66 } 67 # if defined(OPUS_ARM_MAY_HAVE_MEDIA) 68 __try{ 69 /*SHADD8 r3,r3,r3*/ 70 __emit(0xE6333F93); 71 flags|=OPUS_CPU_ARM_MEDIA; 72 } 73 __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){ 74 /*Ignore exception.*/ 75 } 76 # if defined(OPUS_ARM_MAY_HAVE_NEON) 77 __try{ 78 /*VORR q0,q0,q0*/ 79 __emit(0xF2200150); 80 flags|=OPUS_CPU_ARM_NEON; 81 } 82 __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){ 83 /*Ignore exception.*/ 84 } 85 # endif 86 # endif 87 # endif 88 return flags; 89 } 90 91 #elif defined(__linux__) 92 /* Linux based */ 93 opus_uint32 opus_cpu_capabilities(void) 94 { 95 opus_uint32 flags = 0; 96 FILE *cpuinfo; 97 98 /* Reading /proc/self/auxv would be easier, but that doesn't work reliably on 99 * Android */ 100 cpuinfo = fopen("/proc/cpuinfo", "r"); 101 102 if(cpuinfo != NULL) 103 { 104 /* 512 should be enough for anybody (it's even enough for all the flags that 105 * x86 has accumulated... so far). */ 106 char buf[512]; 107 108 while(fgets(buf, 512, cpuinfo) != NULL) 109 { 110 # if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_NEON) 111 /* Search for edsp and neon flag */ 112 if(memcmp(buf, "Features", 8) == 0) 113 { 114 char *p; 115 # if defined(OPUS_ARM_MAY_HAVE_EDSP) 116 p = strstr(buf, " edsp"); 117 if(p != NULL && (p[5] == ' ' || p[5] == '\n')) 118 flags |= OPUS_CPU_ARM_EDSP; 119 # endif 120 121 # if defined(OPUS_ARM_MAY_HAVE_NEON) 122 p = strstr(buf, " neon"); 123 if(p != NULL && (p[5] == ' ' || p[5] == '\n')) 124 flags |= OPUS_CPU_ARM_NEON; 125 # endif 126 } 127 # endif 128 129 # if defined(OPUS_ARM_MAY_HAVE_MEDIA) 130 /* Search for media capabilities (>= ARMv6) */ 131 if(memcmp(buf, "CPU architecture:", 17) == 0) 132 { 133 int version; 134 version = atoi(buf+17); 135 136 if(version >= 6) 137 flags |= OPUS_CPU_ARM_MEDIA; 138 } 139 # endif 140 } 141 142 fclose(cpuinfo); 143 } 144 return flags; 145 } 146 #else 147 /* The feature registers which can tell us what the processor supports are 148 * accessible in priveleged modes only, so we can't have a general user-space 149 * detection method like on x86.*/ 150 # error "Configured to use ARM asm but no CPU detection method available for " \ 151 "your platform. Reconfigure with --disable-rtcd (or send patches)." 152 #endif 153 154 int opus_select_arch(void) 155 { 156 opus_uint32 flags = opus_cpu_capabilities(); 157 int arch = 0; 158 159 if(!(flags & OPUS_CPU_ARM_EDSP)) 160 return arch; 161 arch++; 162 163 if(!(flags & OPUS_CPU_ARM_MEDIA)) 164 return arch; 165 arch++; 166 167 if(!(flags & OPUS_CPU_ARM_NEON)) 168 return arch; 169 arch++; 170 171 return arch; 172 } 173 174 #endif 175