blob: cce3ae3a9db70c7e24b5873c200347d10bc7e5d9 [file] [log] [blame]
Aurélien Zanellicd4c8242013-05-31 15:07:00 +02001/* 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"
Jonathan Lennoxfdb3b3a2015-12-22 19:21:43 -050040#include "arch.h"
Aurélien Zanellicd4c8242013-05-31 15:07:00 +020041
Jonathan Lennoxfdb3b3a2015-12-22 19:21:43 -050042#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)
Aurélien Zanellicd4c8242013-05-31 15:07:00 +020046
47#if defined(_MSC_VER)
48/*For GetExceptionCode() and EXCEPTION_ILLEGAL_INSTRUCTION.*/
49# define WIN32_LEAN_AND_MEAN
50# define WIN32_EXTRA_LEAN
51# include <windows.h>
52
Gregory Maxwell7830cf12013-10-17 15:56:52 -070053static OPUS_INLINE opus_uint32 opus_cpu_capabilities(void){
Aurélien Zanellicd4c8242013-05-31 15:07:00 +020054 opus_uint32 flags;
55 flags=0;
Gregory Maxwell7830cf12013-10-17 15:56:52 -070056 /* MSVC has no OPUS_INLINE __asm support for ARM, but it does let you __emit
Aurélien Zanellicd4c8242013-05-31 15:07:00 +020057 * instructions via their assembled hex code.
58 * All of these instructions should be essentially nops. */
Jonathan Lennox1a94b2b2016-07-08 18:30:19 -040059# if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_MEDIA) \
60 || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
Aurélien Zanellicd4c8242013-05-31 15:07:00 +020061 __try{
62 /*PLD [r13]*/
63 __emit(0xF5DDF000);
Jonathan Lennoxfdb3b3a2015-12-22 19:21:43 -050064 flags|=OPUS_CPU_ARM_EDSP_FLAG;
Aurélien Zanellicd4c8242013-05-31 15:07:00 +020065 }
66 __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
67 /*Ignore exception.*/
68 }
Jonathan Lennox1a94b2b2016-07-08 18:30:19 -040069# if defined(OPUS_ARM_MAY_HAVE_MEDIA) \
70 || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
Aurélien Zanellicd4c8242013-05-31 15:07:00 +020071 __try{
72 /*SHADD8 r3,r3,r3*/
73 __emit(0xE6333F93);
Jonathan Lennoxfdb3b3a2015-12-22 19:21:43 -050074 flags|=OPUS_CPU_ARM_MEDIA_FLAG;
Aurélien Zanellicd4c8242013-05-31 15:07:00 +020075 }
76 __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
77 /*Ignore exception.*/
78 }
Jonathan Lennoxb4aa5dc2015-08-03 17:04:20 -040079# if defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
Aurélien Zanellicd4c8242013-05-31 15:07:00 +020080 __try{
81 /*VORR q0,q0,q0*/
82 __emit(0xF2200150);
Jonathan Lennoxfdb3b3a2015-12-22 19:21:43 -050083 flags|=OPUS_CPU_ARM_NEON_FLAG;
Aurélien Zanellicd4c8242013-05-31 15:07:00 +020084 }
85 __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
86 /*Ignore exception.*/
87 }
88# endif
89# endif
90# endif
91 return flags;
92}
93
94#elif defined(__linux__)
95/* Linux based */
Ralph Gilesb69bfb22020-06-14 00:53:30 -070096#include <stdio.h>
97
Aurélien Zanellicd4c8242013-05-31 15:07:00 +020098opus_uint32 opus_cpu_capabilities(void)
99{
100 opus_uint32 flags = 0;
101 FILE *cpuinfo;
102
103 /* Reading /proc/self/auxv would be easier, but that doesn't work reliably on
104 * Android */
105 cpuinfo = fopen("/proc/cpuinfo", "r");
106
107 if(cpuinfo != NULL)
108 {
109 /* 512 should be enough for anybody (it's even enough for all the flags that
110 * x86 has accumulated... so far). */
111 char buf[512];
112
113 while(fgets(buf, 512, cpuinfo) != NULL)
114 {
Jonathan Lennox1a94b2b2016-07-08 18:30:19 -0400115# if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_MEDIA) \
116 || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
Aurélien Zanellicd4c8242013-05-31 15:07:00 +0200117 /* Search for edsp and neon flag */
118 if(memcmp(buf, "Features", 8) == 0)
119 {
120 char *p;
121 p = strstr(buf, " edsp");
122 if(p != NULL && (p[5] == ' ' || p[5] == '\n'))
Jonathan Lennoxfdb3b3a2015-12-22 19:21:43 -0500123 flags |= OPUS_CPU_ARM_EDSP_FLAG;
Aurélien Zanellicd4c8242013-05-31 15:07:00 +0200124
Jonathan Lennoxb4aa5dc2015-08-03 17:04:20 -0400125# if defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
Aurélien Zanellicd4c8242013-05-31 15:07:00 +0200126 p = strstr(buf, " neon");
127 if(p != NULL && (p[5] == ' ' || p[5] == '\n'))
Jonathan Lennoxfdb3b3a2015-12-22 19:21:43 -0500128 flags |= OPUS_CPU_ARM_NEON_FLAG;
Timothy B. Terriberry39386e02013-11-18 13:30:13 -0500129# endif
Aurélien Zanellicd4c8242013-05-31 15:07:00 +0200130 }
Timothy B. Terriberry39386e02013-11-18 13:30:13 -0500131# endif
Aurélien Zanellicd4c8242013-05-31 15:07:00 +0200132
Jonathan Lennox1a94b2b2016-07-08 18:30:19 -0400133# if defined(OPUS_ARM_MAY_HAVE_MEDIA) \
134 || defined(OPUS_ARM_MAY_HAVE_NEON) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
Aurélien Zanellicd4c8242013-05-31 15:07:00 +0200135 /* Search for media capabilities (>= ARMv6) */
136 if(memcmp(buf, "CPU architecture:", 17) == 0)
137 {
138 int version;
139 version = atoi(buf+17);
140
141 if(version >= 6)
Jonathan Lennoxfdb3b3a2015-12-22 19:21:43 -0500142 flags |= OPUS_CPU_ARM_MEDIA_FLAG;
Aurélien Zanellicd4c8242013-05-31 15:07:00 +0200143 }
Timothy B. Terriberry39386e02013-11-18 13:30:13 -0500144# endif
Aurélien Zanellicd4c8242013-05-31 15:07:00 +0200145 }
146
147 fclose(cpuinfo);
148 }
149 return flags;
150}
151#else
152/* The feature registers which can tell us what the processor supports are
153 * accessible in priveleged modes only, so we can't have a general user-space
154 * detection method like on x86.*/
155# error "Configured to use ARM asm but no CPU detection method available for " \
156 "your platform. Reconfigure with --disable-rtcd (or send patches)."
157#endif
158
159int opus_select_arch(void)
160{
161 opus_uint32 flags = opus_cpu_capabilities();
162 int arch = 0;
163
Jonathan Lennoxfdb3b3a2015-12-22 19:21:43 -0500164 if(!(flags & OPUS_CPU_ARM_EDSP_FLAG)) {
165 /* Asserts ensure arch values are sequential */
166 celt_assert(arch == OPUS_ARCH_ARM_V4);
Aurélien Zanellicd4c8242013-05-31 15:07:00 +0200167 return arch;
Jonathan Lennoxfdb3b3a2015-12-22 19:21:43 -0500168 }
Aurélien Zanellicd4c8242013-05-31 15:07:00 +0200169 arch++;
170
Jonathan Lennoxfdb3b3a2015-12-22 19:21:43 -0500171 if(!(flags & OPUS_CPU_ARM_MEDIA_FLAG)) {
172 celt_assert(arch == OPUS_ARCH_ARM_EDSP);
Aurélien Zanellicd4c8242013-05-31 15:07:00 +0200173 return arch;
Jonathan Lennoxfdb3b3a2015-12-22 19:21:43 -0500174 }
Aurélien Zanellicd4c8242013-05-31 15:07:00 +0200175 arch++;
176
Jonathan Lennoxfdb3b3a2015-12-22 19:21:43 -0500177 if(!(flags & OPUS_CPU_ARM_NEON_FLAG)) {
178 celt_assert(arch == OPUS_ARCH_ARM_MEDIA);
Aurélien Zanellicd4c8242013-05-31 15:07:00 +0200179 return arch;
Jonathan Lennoxfdb3b3a2015-12-22 19:21:43 -0500180 }
Aurélien Zanellicd4c8242013-05-31 15:07:00 +0200181 arch++;
182
Jonathan Lennoxfdb3b3a2015-12-22 19:21:43 -0500183 celt_assert(arch == OPUS_ARCH_ARM_NEON);
Aurélien Zanellicd4c8242013-05-31 15:07:00 +0200184 return arch;
185}
186
187#endif