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_INTEL_SIMD
45
47 // This snippet is borrowed from Intel; see for example
48 // https://software.intel.com/en-us/articles/
49 // how-to-detect-knl-instruction-support
50 bool run_cpuid(uint32_t eax, uint32_t ecx, uint32_t* abcd)
51 {
52 #ifdef OJPH_COMPILER_MSVC
53 __cpuidex((int *)abcd, eax, ecx);
54 #else
55 uint32_t ebx = 0, edx = 0;
56 #if defined( __i386__ ) && defined ( __PIC__ )
57 /* in case of PIC under 32-bit EBX cannot be clobbered */
58 __asm__ ( "movl %%ebx, %%edi \n\t cpuid \n\t xchgl %%ebx, %%edi"
59 : "=D" (ebx), "+a" (eax), "+c" (ecx), "=d" (edx) );
60 #else
61 __asm__ ( "cpuid" : "+b" (ebx), "+a" (eax), "+c" (ecx), "=d" (edx) );
62 #endif
63 abcd[0] = eax; abcd[1] = ebx; abcd[2] = ecx; abcd[3] = edx;
64 #endif
65 return true;
66 }
67
69 uint64_t read_xcr(uint32_t index)
70 {
71 #ifdef OJPH_COMPILER_MSVC
72 return _xgetbv(index);
73 #else
74 uint32_t eax = 0, edx = 0;
75 __asm__ ( "xgetbv" : "=a" (eax), "=d" (edx) : "c" (index) );
76 return ((uint64_t)edx << 32) | eax;
77 #endif
78 }
79
81 bool init_cpu_ext_level(int& level)
82 {
83 uint32_t mmx_abcd[4];
84 run_cpuid(1, 0, mmx_abcd);
85 bool mmx_avail = ((mmx_abcd[3] & 0x00800000) == 0x00800000);
86
87 level = 0;
88 if (mmx_avail)
89 {
91 bool sse_avail = ((mmx_abcd[3] & 0x02000000) == 0x02000000);
92 if (sse_avail)
93 {
95 bool sse2_avail = ((mmx_abcd[3] & 0x04000000) == 0x04000000);
96 if (sse2_avail)
97 {
99 bool sse3_avail = ((mmx_abcd[2] & 0x00000001) == 0x00000001);
100 if (sse3_avail)
101 {
103 bool ssse3_avail = ((mmx_abcd[2] & 0x00000200) == 0x00000200);
104 if (ssse3_avail)
105 {
107 bool sse41_avail = ((mmx_abcd[2] & 0x00080000) == 0x00080000);
108 if (sse41_avail) {
110 bool sse42_avail = ((mmx_abcd[2] & 0x00100000) == 0x00100000);
111 if (sse42_avail)
112 {
114
115 uint64_t xcr_val = 0;
116 bool osxsave_avail, ymm_avail, avx_avail = false;
117 osxsave_avail = ((mmx_abcd[2] & 0x08000000) == 0x08000000);
118 if (osxsave_avail)
119 {
120 xcr_val = read_xcr(0); // _XCR_XFEATURE_ENABLED_MASK = 0
121 ymm_avail = osxsave_avail && ((xcr_val & 0x6) == 0x6);
122 avx_avail = ymm_avail && (mmx_abcd[2] & 0x10000000);
123 }
124 if (avx_avail)
125 {
126 level = X86_CPU_EXT_LEVEL_AVX;
127
128 uint32_t avx2_abcd[4];
129 run_cpuid(7, 0, avx2_abcd);
130 bool avx2_avail = (avx2_abcd[1] & 0x20) != 0;
131 if (avx2_avail)
132 {
134 bool avx2fma_avail =
135 avx2_avail && ((mmx_abcd[2] & 0x1000) == 0x1000);
136 if (avx2fma_avail)
137 {
139
140 bool zmm_avail =
141 osxsave_avail && ((xcr_val & 0xE0) == 0xE0);
142 bool avx512f_avail = (avx2_abcd[1] & 0x10000) != 0;
143 bool avx512cd_avail = (avx2_abcd[1] & 0x10000000) != 0;
144 bool avx512_avail =
145 zmm_avail && avx512f_avail && avx512cd_avail;
146 if (avx512_avail)
148 }
149 }
150 }
151 }
152 }
153 }
154 }
155 }
156 }
157 }
158 return true;
159 }
160
161#elif defined(OJPH_ENABLE_WASM_SIMD) && defined(OJPH_EMSCRIPTEN)
162
164 bool init_cpu_ext_level(int& level) {
165 level = 1;
166 return true;
167 }
168
169#else
170
172 bool init_cpu_ext_level(int& level) {
173 level = 0;
174 return true;
175 }
176
177#endif
178
180 static int cpu_level;
182
185 {
186 assert(cpu_level_initialized);
187 return cpu_level;
188 }
189
190}
bool init_cpu_ext_level(int &level)
Definition: ojph_arch.cpp:81
@ X86_CPU_EXT_LEVEL_AVX2
Definition: ojph_arch.h:104
@ X86_CPU_EXT_LEVEL_AVX
Definition: ojph_arch.h:103
@ X86_CPU_EXT_LEVEL_AVX512
Definition: ojph_arch.h:106
@ X86_CPU_EXT_LEVEL_SSE2
Definition: ojph_arch.h:98
@ X86_CPU_EXT_LEVEL_SSE41
Definition: ojph_arch.h:101
@ X86_CPU_EXT_LEVEL_SSE
Definition: ojph_arch.h:97
@ X86_CPU_EXT_LEVEL_MMX
Definition: ojph_arch.h:96
@ X86_CPU_EXT_LEVEL_SSE42
Definition: ojph_arch.h:102
@ X86_CPU_EXT_LEVEL_SSSE3
Definition: ojph_arch.h:100
@ X86_CPU_EXT_LEVEL_SSE3
Definition: ojph_arch.h:99
@ X86_CPU_EXT_LEVEL_AVX2FMA
Definition: ojph_arch.h:105
uint64_t read_xcr(uint32_t index)
Definition: ojph_arch.cpp:69
OJPH_EXPORT int get_cpu_ext_level()
Definition: ojph_arch.cpp:184
static int cpu_level
Definition: ojph_arch.cpp:180
static bool cpu_level_initialized
Definition: ojph_arch.cpp:181
bool run_cpuid(uint32_t eax, uint32_t ecx, uint32_t *abcd)
Definition: ojph_arch.cpp:50