cannam@154: /* Copyright (c) 2010 Xiph.Org Foundation cannam@154: * Copyright (c) 2013 Parrot */ cannam@154: /* cannam@154: Redistribution and use in source and binary forms, with or without cannam@154: modification, are permitted provided that the following conditions cannam@154: are met: cannam@154: cannam@154: - Redistributions of source code must retain the above copyright cannam@154: notice, this list of conditions and the following disclaimer. cannam@154: cannam@154: - Redistributions in binary form must reproduce the above copyright cannam@154: notice, this list of conditions and the following disclaimer in the cannam@154: documentation and/or other materials provided with the distribution. cannam@154: cannam@154: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS cannam@154: ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT cannam@154: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR cannam@154: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER cannam@154: OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, cannam@154: EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, cannam@154: PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR cannam@154: PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF cannam@154: LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING cannam@154: NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS cannam@154: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. cannam@154: */ cannam@154: cannam@154: /* Original code from libtheora modified to suit to Opus */ cannam@154: cannam@154: #ifdef HAVE_CONFIG_H cannam@154: #include "config.h" cannam@154: #endif cannam@154: cannam@154: #ifdef OPUS_HAVE_RTCD cannam@154: cannam@154: #include "armcpu.h" cannam@154: #include "cpu_support.h" cannam@154: #include "os_support.h" cannam@154: #include "opus_types.h" cannam@154: #include "arch.h" cannam@154: cannam@154: #define OPUS_CPU_ARM_V4_FLAG (1< cannam@154: cannam@154: static OPUS_INLINE opus_uint32 opus_cpu_capabilities(void){ cannam@154: opus_uint32 flags; cannam@154: flags=0; cannam@154: /* MSVC has no OPUS_INLINE __asm support for ARM, but it does let you __emit cannam@154: * instructions via their assembled hex code. cannam@154: * All of these instructions should be essentially nops. */ cannam@154: # if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_MEDIA) \ cannam@154: || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) cannam@154: __try{ cannam@154: /*PLD [r13]*/ cannam@154: __emit(0xF5DDF000); cannam@154: flags|=OPUS_CPU_ARM_EDSP_FLAG; cannam@154: } cannam@154: __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){ cannam@154: /*Ignore exception.*/ cannam@154: } cannam@154: # if defined(OPUS_ARM_MAY_HAVE_MEDIA) \ cannam@154: || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) cannam@154: __try{ cannam@154: /*SHADD8 r3,r3,r3*/ cannam@154: __emit(0xE6333F93); cannam@154: flags|=OPUS_CPU_ARM_MEDIA_FLAG; cannam@154: } cannam@154: __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){ cannam@154: /*Ignore exception.*/ cannam@154: } cannam@154: # if defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) cannam@154: __try{ cannam@154: /*VORR q0,q0,q0*/ cannam@154: __emit(0xF2200150); cannam@154: flags|=OPUS_CPU_ARM_NEON_FLAG; cannam@154: } cannam@154: __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){ cannam@154: /*Ignore exception.*/ cannam@154: } cannam@154: # endif cannam@154: # endif cannam@154: # endif cannam@154: return flags; cannam@154: } cannam@154: cannam@154: #elif defined(__linux__) cannam@154: /* Linux based */ cannam@154: opus_uint32 opus_cpu_capabilities(void) cannam@154: { cannam@154: opus_uint32 flags = 0; cannam@154: FILE *cpuinfo; cannam@154: cannam@154: /* Reading /proc/self/auxv would be easier, but that doesn't work reliably on cannam@154: * Android */ cannam@154: cpuinfo = fopen("/proc/cpuinfo", "r"); cannam@154: cannam@154: if(cpuinfo != NULL) cannam@154: { cannam@154: /* 512 should be enough for anybody (it's even enough for all the flags that cannam@154: * x86 has accumulated... so far). */ cannam@154: char buf[512]; cannam@154: cannam@154: while(fgets(buf, 512, cpuinfo) != NULL) cannam@154: { cannam@154: # if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_MEDIA) \ cannam@154: || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) cannam@154: /* Search for edsp and neon flag */ cannam@154: if(memcmp(buf, "Features", 8) == 0) cannam@154: { cannam@154: char *p; cannam@154: p = strstr(buf, " edsp"); cannam@154: if(p != NULL && (p[5] == ' ' || p[5] == '\n')) cannam@154: flags |= OPUS_CPU_ARM_EDSP_FLAG; cannam@154: cannam@154: # if defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) cannam@154: p = strstr(buf, " neon"); cannam@154: if(p != NULL && (p[5] == ' ' || p[5] == '\n')) cannam@154: flags |= OPUS_CPU_ARM_NEON_FLAG; cannam@154: # endif cannam@154: } cannam@154: # endif cannam@154: cannam@154: # if defined(OPUS_ARM_MAY_HAVE_MEDIA) \ cannam@154: || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR) cannam@154: /* Search for media capabilities (>= ARMv6) */ cannam@154: if(memcmp(buf, "CPU architecture:", 17) == 0) cannam@154: { cannam@154: int version; cannam@154: version = atoi(buf+17); cannam@154: cannam@154: if(version >= 6) cannam@154: flags |= OPUS_CPU_ARM_MEDIA_FLAG; cannam@154: } cannam@154: # endif cannam@154: } cannam@154: cannam@154: fclose(cpuinfo); cannam@154: } cannam@154: return flags; cannam@154: } cannam@154: #else cannam@154: /* The feature registers which can tell us what the processor supports are cannam@154: * accessible in priveleged modes only, so we can't have a general user-space cannam@154: * detection method like on x86.*/ cannam@154: # error "Configured to use ARM asm but no CPU detection method available for " \ cannam@154: "your platform. Reconfigure with --disable-rtcd (or send patches)." cannam@154: #endif cannam@154: cannam@154: int opus_select_arch(void) cannam@154: { cannam@154: opus_uint32 flags = opus_cpu_capabilities(); cannam@154: int arch = 0; cannam@154: cannam@154: if(!(flags & OPUS_CPU_ARM_EDSP_FLAG)) { cannam@154: /* Asserts ensure arch values are sequential */ cannam@154: celt_assert(arch == OPUS_ARCH_ARM_V4); cannam@154: return arch; cannam@154: } cannam@154: arch++; cannam@154: cannam@154: if(!(flags & OPUS_CPU_ARM_MEDIA_FLAG)) { cannam@154: celt_assert(arch == OPUS_ARCH_ARM_EDSP); cannam@154: return arch; cannam@154: } cannam@154: arch++; cannam@154: cannam@154: if(!(flags & OPUS_CPU_ARM_NEON_FLAG)) { cannam@154: celt_assert(arch == OPUS_ARCH_ARM_MEDIA); cannam@154: return arch; cannam@154: } cannam@154: arch++; cannam@154: cannam@154: celt_assert(arch == OPUS_ARCH_ARM_NEON); cannam@154: return arch; cannam@154: } cannam@154: cannam@154: #endif