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