OpenJPH
Open-source implementation of JPEG2000 Part-15
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
42namespace 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 {
93 bool sse_avail = ((mmx_abcd[3] & 0x02000000) == 0x02000000);
94 if (sse_avail)
95 {
97 bool sse2_avail = ((mmx_abcd[3] & 0x04000000) == 0x04000000);
98 if (sse2_avail)
99 {
101 bool sse3_avail = ((mmx_abcd[2] & 0x00000001) == 0x00000001);
102 if (sse3_avail)
103 {
105 bool ssse3_avail = ((mmx_abcd[2] & 0x00000200) == 0x00000200);
106 if (ssse3_avail)
107 {
109 bool sse41_avail = ((mmx_abcd[2] & 0x00080000) == 0x00080000);
110 if (sse41_avail) {
112 bool sse42_avail = ((mmx_abcd[2] & 0x00100000) == 0x00100000);
113 if (sse42_avail)
114 {
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 {
136 bool avx2fma_avail =
137 avx2_avail && ((mmx_abcd[2] & 0x1000) == 0x1000);
138 if (avx2fma_avail)
139 {
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)
150 }
151 }
152 }
153 }
154 }
155 }
156 }
157 }
158 }
159 }
160 return true;
161 }
162 #elif defined(OJPH_ARCH_ARM)
163
164 #ifndef OJPH_OS_LINUX //Windows/Apple/Android
165
166 bool init_cpu_ext_level(int& level) {
168 return true;
169 }
170
171 #else // Linux
172
173 #if defined(__aarch64__) || defined(_M_ARM64) // 64-bit ARM
174
175 #include <sys/auxv.h>
176 #include <asm/hwcap.h>
177
178 bool init_cpu_ext_level(int& level) {
179 unsigned long hwcaps = getauxval(AT_HWCAP);
180 unsigned long hwcaps2 = getauxval(AT_HWCAP2);
181
183 if (hwcaps & HWCAP_ASIMD) {
185 if (hwcaps & HWCAP_SVE) {
186 level = ARM_CPU_EXT_LEVEL_SVE;
187 if (hwcaps2 & HWCAP2_SVE2)
189 }
190 }
191 return true;
192 }
193
194 #else // 32-bit ARM
195
196 #include <sys/auxv.h>
197 #include <asm/hwcap.h>
198
199 bool init_cpu_ext_level(int& level) {
200 unsigned long hwcaps = getauxval(AT_HWCAP);
202 if (hwcaps & HWCAP_NEON)
204 return true;
205 }
206
207 #endif // end of 64-bit ARM
208
209 #endif
210
211 #else // architectures other than Intel/AMD and ARM
212
214 bool init_cpu_ext_level(int& level) {
215 level = 0;
216 return true;
217 }
218
219 #endif // !OJPH_DISABLE_SIMD
220
221#elif defined(OJPH_ENABLE_WASM_SIMD) && defined(OJPH_EMSCRIPTEN)
222
224 bool init_cpu_ext_level(int& level) {
225 level = 1;
226 return true;
227 }
228
229#else
230
232 bool init_cpu_ext_level(int& level) {
233 level = 0;
234 return true;
235 }
236
237#endif
238
240 static int cpu_level;
242
245 {
246 assert(cpu_level_initialized);
247 return cpu_level;
248 }
249
250}
bool init_cpu_ext_level(int &level)
Definition: ojph_arch.cpp:214
@ X86_CPU_EXT_LEVEL_AVX2
Definition: ojph_arch.h:138
@ X86_CPU_EXT_LEVEL_AVX
Definition: ojph_arch.h:137
@ X86_CPU_EXT_LEVEL_AVX512
Definition: ojph_arch.h:140
@ X86_CPU_EXT_LEVEL_SSE2
Definition: ojph_arch.h:132
@ X86_CPU_EXT_LEVEL_SSE41
Definition: ojph_arch.h:135
@ X86_CPU_EXT_LEVEL_SSE
Definition: ojph_arch.h:131
@ X86_CPU_EXT_LEVEL_MMX
Definition: ojph_arch.h:130
@ X86_CPU_EXT_LEVEL_SSE42
Definition: ojph_arch.h:136
@ X86_CPU_EXT_LEVEL_SSSE3
Definition: ojph_arch.h:134
@ X86_CPU_EXT_LEVEL_SSE3
Definition: ojph_arch.h:133
@ X86_CPU_EXT_LEVEL_AVX2FMA
Definition: ojph_arch.h:139
OJPH_EXPORT int get_cpu_ext_level()
Definition: ojph_arch.cpp:244
static int cpu_level
Definition: ojph_arch.cpp:240
@ ARM_CPU_EXT_LEVEL_SVE
Definition: ojph_arch.h:147
@ ARM_CPU_EXT_LEVEL_SVE2
Definition: ojph_arch.h:148
@ ARM_CPU_EXT_LEVEL_NEON
Definition: ojph_arch.h:145
@ ARM_CPU_EXT_LEVEL_GENERIC
Definition: ojph_arch.h:144
@ ARM_CPU_EXT_LEVEL_ASIMD
Definition: ojph_arch.h:146
static bool cpu_level_initialized
Definition: ojph_arch.cpp:241