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 = 1;
91  bool sse_avail = ((mmx_abcd[3] & 0x02000000) == 0x02000000);
92  if (sse_avail)
93  {
94  level = 2;
95  bool sse2_avail = ((mmx_abcd[3] & 0x04000000) == 0x04000000);
96  if (sse2_avail)
97  {
98  level = 3;
99  bool sse3_avail = ((mmx_abcd[2] & 0x00000001) == 0x00000001);
100  if (sse3_avail)
101  {
102  level = 4;
103  bool ssse3_avail = ((mmx_abcd[2] & 0x00000200) == 0x00000200);
104  if (ssse3_avail)
105  {
106  level = 5;
107  bool sse41_avail = ((mmx_abcd[2] & 0x00080000) == 0x00080000);
108  bool sse42_avail = ((mmx_abcd[2] & 0x00100000) == 0x00100000);
109  if (sse41_avail && sse42_avail)
110  {
111  level = 6;
112 
113  uint64_t xcr_val = 0;
114  bool osxsave_avail, ymm_avail, avx_avail = false;
115  osxsave_avail = ((mmx_abcd[2] & 0x08000000) == 0x08000000);
116  if (osxsave_avail)
117  {
118  xcr_val = read_xcr(0);
119  ymm_avail = osxsave_avail && ((xcr_val & 0x6) == 0x6);
120  avx_avail = ymm_avail && (mmx_abcd[2] & 0x10000000);
121  }
122  if (avx_avail)
123  {
124  level = 7;
125 
126  uint32_t avx2_abcd[4];
127  run_cpuid(7, 0, avx2_abcd);
128  bool avx2_avail = (avx2_abcd[1] & 0x20) != 0;
129  if (avx2_avail)
130  {
131  level = 8;
132  bool avx2fma_avail =
133  avx2_avail && ((mmx_abcd[2] & 0x1000) == 0x1000);
134  if (avx2fma_avail)
135  {
136  level = 9;
137 
138  bool zmm_avail =
139  osxsave_avail && ((xcr_val & 0xE) == 0xE);
140  bool avx512vl_avail = (avx2_abcd[1] & 0x80000000) != 0;
141  bool avx512_avail = zmm_avail && avx512vl_avail;
142  if (avx512_avail)
143  level = 10;
144  }
145  }
146  }
147  }
148  }
149  }
150  }
151  }
152  }
153  return true;
154  }
155 
157  static int cpu_level;
159 
160 #else
161 
163  static int cpu_level = 0;
164  static bool cpu_level_initialized = true;
165 
166 #endif // !OJPH_DISABLE_INTEL_SIMD
167 
168 
171  {
172  assert(cpu_level_initialized);
173  return cpu_level;
174  }
175 
176 }
bool init_cpu_ext_level(int &level)
Definition: ojph_arch.cpp:81
uint64_t read_xcr(uint32_t index)
Definition: ojph_arch.cpp:69
int cpu_ext_level()
Definition: ojph_arch.cpp:170
static int cpu_level
Definition: ojph_arch.cpp:157
static bool cpu_level_initialized
Definition: ojph_arch.cpp:158
bool run_cpuid(uint32_t eax, uint32_t ecx, uint32_t *abcd)
Definition: ojph_arch.cpp:50