OpenJPH Open-source implementation of JPEG2000 Part-15

Loading...
Searching...
No Matches
ojph_arch.cpp
Go to the documentation of this file.
1//***************************************************************************/
2// This software is released under the 2-Clause BSD license, included
3// below.
4//
5// Copyright (c) 2019, Aous Naman
6// Copyright (c) 2019, Kakadu Software Pty Ltd, Australia
7// Copyright (c) 2019, The University of New South Wales, Australia
8//
9// Redistribution and use in source and binary forms, with or without
10// modification, are permitted provided that the following conditions are
11// met:
12//
13// 1. Redistributions of source code must retain the above copyright
14// notice, this list of conditions and the following disclaimer.
15//
16// 2. Redistributions in binary form must reproduce the above copyright
17// notice, this list of conditions and the following disclaimer in the
18// documentation and/or other materials provided with the distribution.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
26// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31//***************************************************************************/
32// This file is part of the OpenJPH software implementation.
33// File: ojph_arch.cpp
34// Author: Aous Naman
35// Date: 28 August 2019
36//***************************************************************************/
37
38#include <cassert>
39
40#include "ojph_arch.h"
41
42 namespace ojph {
43
44#ifndef OJPH_DISABLE_SIMD
45
46 #if (defined(OJPH_ARCH_X86_64) || defined(OJPH_ARCH_I386))
47
49 // This snippet is borrowed from Intel; see for example
50 // https://software.intel.com/en-us/articles/
51 // how-to-detect-knl-instruction-support
52 bool run_cpuid(uint32_t eax, uint32_t ecx, uint32_t* abcd)
53 {
54 #ifdef OJPH_COMPILER_MSVC
55 __cpuidex((int *)abcd, eax, ecx);
56 #else
57 uint32_t ebx = 0, edx = 0;
58 #if defined( __i386__ ) && defined ( __PIC__ )
59 /* in case of PIC under 32-bit EBX cannot be clobbered */
60 __asm__ ( "movl %%ebx, %%edi \n\t cpuid \n\t xchgl %%ebx, %%edi"
61 : "=D" (ebx), "+a" (eax), "+c" (ecx), "=d" (edx) );
62 #else
63 __asm__ ( "cpuid" : "+b" (ebx), "+a" (eax), "+c" (ecx), "=d" (edx) );
64 #endif
65 abcd[0] = eax; abcd[1] = ebx; abcd[2] = ecx; abcd[3] = edx;
66 #endif
67 return true;
68 }
69
71 uint64_t read_xcr(uint32_t index)
72 {
73 #ifdef OJPH_COMPILER_MSVC
74 return _xgetbv(index);
75 #else
76 uint32_t eax = 0, edx = 0;
77 __asm__ ( "xgetbv" : "=a" (eax), "=d" (edx) : "c" (index) );
78 return ((uint64_t)edx << 32) | eax;
79 #endif
80 }
81
83 bool init_cpu_ext_level(int& level)
84 {
85 uint32_t mmx_abcd[4];
86 run_cpuid(1, 0, mmx_abcd);
87 bool mmx_avail = ((mmx_abcd[3] & 0x00800000) == 0x00800000);
88
89 level = 0;
90 if (mmx_avail)
91 {
92 level = X86_CPU_EXT_LEVEL_MMX;
93 bool sse_avail = ((mmx_abcd[3] & 0x02000000) == 0x02000000);
94 if (sse_avail)
95 {
96 level = X86_CPU_EXT_LEVEL_SSE;
97 bool sse2_avail = ((mmx_abcd[3] & 0x04000000) == 0x04000000);
98 if (sse2_avail)
99 {
100 level = X86_CPU_EXT_LEVEL_SSE2;
101 bool sse3_avail = ((mmx_abcd[2] & 0x00000001) == 0x00000001);
102 if (sse3_avail)
103 {
104 level = X86_CPU_EXT_LEVEL_SSE3;
105 bool ssse3_avail = ((mmx_abcd[2] & 0x00000200) == 0x00000200);
106 if (ssse3_avail)
107 {
108 level = X86_CPU_EXT_LEVEL_SSSE3;
109 bool sse41_avail = ((mmx_abcd[2] & 0x00080000) == 0x00080000);
110 if (sse41_avail) {
111 level = X86_CPU_EXT_LEVEL_SSE41;
112 bool sse42_avail = ((mmx_abcd[2] & 0x00100000) == 0x00100000);
113 if (sse42_avail)
114 {
115 level = X86_CPU_EXT_LEVEL_SSE42;
116
117 uint64_t xcr_val = 0;
118 bool osxsave_avail, ymm_avail, avx_avail = false;
119 osxsave_avail = ((mmx_abcd[2] & 0x08000000) == 0x08000000);
120 if (osxsave_avail)
121 {
122 xcr_val = read_xcr(0); // _XCR_XFEATURE_ENABLED_MASK = 0
123 ymm_avail = osxsave_avail && ((xcr_val & 0x6) == 0x6);
124 avx_avail = ymm_avail && (mmx_abcd[2] & 0x10000000);
125 }
126 if (avx_avail)
127 {
128 level = X86_CPU_EXT_LEVEL_AVX;
129
130 uint32_t avx2_abcd[4];
131 run_cpuid(7, 0, avx2_abcd);
132 bool avx2_avail = (avx2_abcd[1] & 0x20) != 0;
133 if (avx2_avail)
134 {
135 level = X86_CPU_EXT_LEVEL_AVX2;
136 bool avx2fma_avail =
137 avx2_avail && ((mmx_abcd[2] & 0x1000) == 0x1000);
138 if (avx2fma_avail)
139 {
140 level = X86_CPU_EXT_LEVEL_AVX2FMA;
141
142 bool zmm_avail =
143 osxsave_avail && ((xcr_val & 0xE0) == 0xE0);
144 bool avx512f_avail = (avx2_abcd[1] & 0x10000) != 0;
145 bool avx512cd_avail = (avx2_abcd[1] & 0x10000000) != 0;
146 bool avx512_avail =
147 zmm_avail && avx512f_avail && avx512cd_avail;
148 if (avx512_avail)
149 level = X86_CPU_EXT_LEVEL_AVX512;
150 }
151 }
152 }
153 }
154 }
155 }
156 }
157 }
158 }
159 }
160 return true;
161 }
162 #elif defined(OJPH_ARCH_ARM)
163
164 #if !defined(OJPH_OS_LINUX) && !defined(OJPH_OS_FREEBSD) && !defined(OJPH_OS_OPENBSD) // Windows/Apple/Android
165
166 bool init_cpu_ext_level(int& level) {
167 level = ARM_CPU_EXT_LEVEL_ASIMD;
168 return true;
169 }
170
171 #else // Linux/FreeBSD/OpenBSD
172
173 #if defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) // 64-bit ARM
174
175 #include <sys/auxv.h>
176 #ifdef OJPH_OS_LINUX
177 #include <asm/hwcap.h>
178 #endif
179
180 bool init_cpu_ext_level(int& level) {
181 #ifdef OJPH_OS_LINUX
182 unsigned long hwcaps = getauxval(AT_HWCAP);
183 unsigned long hwcaps2 = getauxval(AT_HWCAP2);
184 #else
185 unsigned long hwcaps = 0;
186 unsigned long hwcaps2 = 0;
187 elf_aux_info(AT_HWCAP, &hwcaps, sizeof(hwcaps));
188 elf_aux_info(AT_HWCAP2, &hwcaps2, sizeof(hwcaps2));
189 #endif
190
191 level = ARM_CPU_EXT_LEVEL_GENERIC;
192 if (hwcaps & HWCAP_ASIMD) {
193 level = ARM_CPU_EXT_LEVEL_ASIMD;
194 if (hwcaps & HWCAP_SVE) {
195 level = ARM_CPU_EXT_LEVEL_SVE;
196 if (hwcaps2 & HWCAP2_SVE2)
197 level = ARM_CPU_EXT_LEVEL_SVE2;
198 }
199 }
200 return true;
201 }
202
203 #else // 32-bit ARM
204
205 #include <sys/auxv.h>
206 #ifdef OJPH_OS_LINUX
207 #include <asm/hwcap.h>
208 #endif
209
210 bool init_cpu_ext_level(int& level) {
211 #ifdef OJPH_OS_LINUX
212 unsigned long hwcaps = getauxval(AT_HWCAP);
213 #else
214 unsigned long hwcaps = 0;
215 elf_aux_info(AT_HWCAP, &hwcaps, sizeof(hwcaps));
216 #endif
217 level = ARM_CPU_EXT_LEVEL_GENERIC;
218 if (hwcaps & HWCAP_NEON)
219 level = ARM_CPU_EXT_LEVEL_NEON;
220 return true;
221 }
222
223 #endif // end of 64-bit ARM
224
225 #endif
226
227 #else // architectures other than Intel/AMD and ARM
228
230 bool init_cpu_ext_level(int& level) {
231 level = 0;
232 return true;
233 }
234
235 #endif // !OJPH_DISABLE_SIMD
236
237#elif defined(OJPH_ENABLE_WASM_SIMD) && defined(OJPH_EMSCRIPTEN)
238
240 bool init_cpu_ext_level(int& level) {
241 level = 1;
242 return true;
243 }
244
245#else
246
248 bool init_cpu_ext_level(int& level) {
249 level = 0;
250 return true;
251 }
252
253#endif
254
256 static int cpu_level;
257 static bool cpu_level_initialized = init_cpu_ext_level(cpu_level);
258
260 int get_cpu_ext_level()
261 {
262 assert(cpu_level_initialized);
263 return cpu_level;
264 }
265
266}
ojph
Definition ojph_img_io.h:52
ojph::init_cpu_ext_level
bool init_cpu_ext_level(int &level)
Definition ojph_arch.cpp:230
ojph::ARM_CPU_EXT_LEVEL_SVE
@ ARM_CPU_EXT_LEVEL_SVE
Definition ojph_arch.h:151
ojph::ARM_CPU_EXT_LEVEL_SVE2
@ ARM_CPU_EXT_LEVEL_SVE2
Definition ojph_arch.h:152
ojph::ARM_CPU_EXT_LEVEL_NEON
@ ARM_CPU_EXT_LEVEL_NEON
Definition ojph_arch.h:149
ojph::ARM_CPU_EXT_LEVEL_GENERIC
@ ARM_CPU_EXT_LEVEL_GENERIC
Definition ojph_arch.h:148
ojph::ARM_CPU_EXT_LEVEL_ASIMD
@ ARM_CPU_EXT_LEVEL_ASIMD
Definition ojph_arch.h:150
ojph::get_cpu_ext_level
OJPH_EXPORT int get_cpu_ext_level()
Definition ojph_arch.cpp:260
ojph::cpu_level
static int cpu_level
Definition ojph_arch.cpp:256
ojph::cpu_level_initialized
static bool cpu_level_initialized
Definition ojph_arch.cpp:257
ojph::X86_CPU_EXT_LEVEL_AVX2
@ X86_CPU_EXT_LEVEL_AVX2
Definition ojph_arch.h:142
ojph::X86_CPU_EXT_LEVEL_AVX
@ X86_CPU_EXT_LEVEL_AVX
Definition ojph_arch.h:141
ojph::X86_CPU_EXT_LEVEL_AVX512
@ X86_CPU_EXT_LEVEL_AVX512
Definition ojph_arch.h:144
ojph::X86_CPU_EXT_LEVEL_SSE2
@ X86_CPU_EXT_LEVEL_SSE2
Definition ojph_arch.h:136
ojph::X86_CPU_EXT_LEVEL_SSE41
@ X86_CPU_EXT_LEVEL_SSE41
Definition ojph_arch.h:139
ojph::X86_CPU_EXT_LEVEL_SSE
@ X86_CPU_EXT_LEVEL_SSE
Definition ojph_arch.h:135
ojph::X86_CPU_EXT_LEVEL_MMX
@ X86_CPU_EXT_LEVEL_MMX
Definition ojph_arch.h:134
ojph::X86_CPU_EXT_LEVEL_SSE42
@ X86_CPU_EXT_LEVEL_SSE42
Definition ojph_arch.h:140
ojph::X86_CPU_EXT_LEVEL_SSSE3
@ X86_CPU_EXT_LEVEL_SSSE3
Definition ojph_arch.h:138
ojph::X86_CPU_EXT_LEVEL_SSE3
@ X86_CPU_EXT_LEVEL_SSE3
Definition ojph_arch.h:137
ojph::X86_CPU_EXT_LEVEL_AVX2FMA
@ X86_CPU_EXT_LEVEL_AVX2FMA
Definition ojph_arch.h:143
ojph_arch.h