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 
42 namespace 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  {
90  level = X86_CPU_EXT_LEVEL_MMX;
91  bool sse_avail = ((mmx_abcd[3] & 0x02000000) == 0x02000000);
92  if (sse_avail)
93  {
94  level = X86_CPU_EXT_LEVEL_SSE;
95  bool sse2_avail = ((mmx_abcd[3] & 0x04000000) == 0x04000000);
96  if (sse2_avail)
97  {
98  level = X86_CPU_EXT_LEVEL_SSE2;
99  bool sse3_avail = ((mmx_abcd[2] & 0x00000001) == 0x00000001);
100  if (sse3_avail)
101  {
102  level = X86_CPU_EXT_LEVEL_SSE3;
103  bool ssse3_avail = ((mmx_abcd[2] & 0x00000200) == 0x00000200);
104  if (ssse3_avail)
105  {
106  level = X86_CPU_EXT_LEVEL_SSSE3;
107  bool sse41_avail = ((mmx_abcd[2] & 0x00080000) == 0x00080000);
108  if (sse41_avail) {
109  level = X86_CPU_EXT_LEVEL_SSE41;
110  bool sse42_avail = ((mmx_abcd[2] & 0x00100000) == 0x00100000);
111  if (sse42_avail)
112  {
113  level = X86_CPU_EXT_LEVEL_SSE42;
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);
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  {
133  level = X86_CPU_EXT_LEVEL_AVX2;
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 & 0xE) == 0xE);
142  bool avx512vl_avail = (avx2_abcd[1] & 0x80000000) != 0;
143  bool avx512_avail = zmm_avail && avx512vl_avail;
144  if (avx512_avail)
145  level = X86_CPU_EXT_LEVEL_AVX512;
146  }
147  }
148  }
149  }
150  }
151  }
152  }
153  }
154  }
155  }
156  return true;
157  }
158 
159 #elif defined(OJPH_ENABLE_WASM_SIMD) && defined(OJPH_EMSCRIPTEN)
160 
162  bool init_cpu_ext_level(int& level) {
163  level = 1;
164  return true;
165  }
166 
167 #else
168 
170  bool init_cpu_ext_level(int& level) {
171  level = 0;
172  return true;
173  }
174 
175 #endif
176 
178  static int cpu_level;
180 
183  {
184  assert(cpu_level_initialized);
185  return cpu_level;
186  }
187 
188 }
bool init_cpu_ext_level(int &level)
Definition: ojph_arch.cpp:81
@ X86_CPU_EXT_LEVEL_AVX2
Definition: ojph_arch.h:83
@ X86_CPU_EXT_LEVEL_AVX
Definition: ojph_arch.h:82
@ X86_CPU_EXT_LEVEL_AVX512
Definition: ojph_arch.h:85
@ X86_CPU_EXT_LEVEL_SSE2
Definition: ojph_arch.h:77
@ X86_CPU_EXT_LEVEL_SSE41
Definition: ojph_arch.h:80
@ X86_CPU_EXT_LEVEL_SSE
Definition: ojph_arch.h:76
@ X86_CPU_EXT_LEVEL_MMX
Definition: ojph_arch.h:75
@ X86_CPU_EXT_LEVEL_SSE42
Definition: ojph_arch.h:81
@ X86_CPU_EXT_LEVEL_SSSE3
Definition: ojph_arch.h:79
@ X86_CPU_EXT_LEVEL_SSE3
Definition: ojph_arch.h:78
@ X86_CPU_EXT_LEVEL_AVX2FMA
Definition: ojph_arch.h:84
uint64_t read_xcr(uint32_t index)
Definition: ojph_arch.cpp:69
int get_cpu_ext_level()
Definition: ojph_arch.cpp:182
static int cpu_level
Definition: ojph_arch.cpp:178
static bool cpu_level_initialized
Definition: ojph_arch.cpp:179
bool run_cpuid(uint32_t eax, uint32_t ecx, uint32_t *abcd)
Definition: ojph_arch.cpp:50