simdjson  3.1.8
Ridiculously Fast JSON
isadetection.h
1 /* From
2 https://github.com/endorno/pytorch/blob/master/torch/lib/TH/generic/simd/simd.h
3 Highly modified.
4 
5 Copyright (c) 2016- Facebook, Inc (Adam Paszke)
6 Copyright (c) 2014- Facebook, Inc (Soumith Chintala)
7 Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert)
8 Copyright (c) 2012-2014 Deepmind Technologies (Koray Kavukcuoglu)
9 Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu)
10 Copyright (c) 2011-2013 NYU (Clement Farabet)
11 Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, Leon Bottou,
12 Iain Melvin, Jason Weston) Copyright (c) 2006 Idiap Research Institute
13 (Samy Bengio) Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert,
14 Samy Bengio, Johnny Mariethoz)
15 
16 All rights reserved.
17 
18 Redistribution and use in source and binary forms, with or without
19 modification, are permitted provided that the following conditions are met:
20 
21 1. Redistributions of source code must retain the above copyright
22  notice, this list of conditions and the following disclaimer.
23 
24 2. Redistributions in binary form must reproduce the above copyright
25  notice, this list of conditions and the following disclaimer in the
26  documentation and/or other materials provided with the distribution.
27 
28 3. Neither the names of Facebook, Deepmind Technologies, NYU, NEC Laboratories
29 America and IDIAP Research Institute nor the names of its contributors may be
30  used to endorse or promote products derived from this software without
31  specific prior written permission.
32 
33 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
34 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
37 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
38 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
39 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
40 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
41 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
43 POSSIBILITY OF SUCH DAMAGE.
44 */
45 
46 #ifndef SIMDJSON_INTERNAL_ISADETECTION_H
47 #define SIMDJSON_INTERNAL_ISADETECTION_H
48 
49 #include <cstdint>
50 #include <cstdlib>
51 #if defined(_MSC_VER)
52 #include <intrin.h>
53 #elif defined(HAVE_GCC_GET_CPUID) && defined(USE_GCC_GET_CPUID)
54 #include <cpuid.h>
55 #endif
56 
57 namespace simdjson {
58 namespace internal {
59 
60 enum instruction_set {
61  DEFAULT = 0x0,
62  NEON = 0x1,
63  AVX2 = 0x4,
64  SSE42 = 0x8,
65  PCLMULQDQ = 0x10,
66  BMI1 = 0x20,
67  BMI2 = 0x40,
68  ALTIVEC = 0x80,
69  AVX512F = 0x100,
70  AVX512DQ = 0x200,
71  AVX512IFMA = 0x400,
72  AVX512PF = 0x800,
73  AVX512ER = 0x1000,
74  AVX512CD = 0x2000,
75  AVX512BW = 0x4000,
76  AVX512VL = 0x8000,
77  AVX512VBMI2 = 0x10000
78 };
79 
80 #if defined(__PPC64__)
81 
82 static inline uint32_t detect_supported_architectures() {
83  return instruction_set::ALTIVEC;
84 }
85 
86 #elif defined(__aarch64__) || defined(_M_ARM64)
87 
88 static inline uint32_t detect_supported_architectures() {
89  return instruction_set::NEON;
90 }
91 
92 #elif defined(__x86_64__) || defined(_M_AMD64) // x64
93 
94 
95 namespace {
96 // Can be found on Intel ISA Reference for CPUID
97 constexpr uint32_t cpuid_avx2_bit = 1 << 5;
98 constexpr uint32_t cpuid_bmi1_bit = 1 << 3;
99 constexpr uint32_t cpuid_bmi2_bit = 1 << 8;
100 constexpr uint32_t cpuid_avx512f_bit = 1 << 16;
101 constexpr uint32_t cpuid_avx512dq_bit = 1 << 17;
102 constexpr uint32_t cpuid_avx512ifma_bit = 1 << 21;
103 constexpr uint32_t cpuid_avx512pf_bit = 1 << 26;
104 constexpr uint32_t cpuid_avx512er_bit = 1 << 27;
105 constexpr uint32_t cpuid_avx512cd_bit = 1 << 28;
106 constexpr uint32_t cpuid_avx512bw_bit = 1 << 30;
107 constexpr uint32_t cpuid_avx512vl_bit = 1U << 31;
108 constexpr uint32_t cpuid_avx512vbmi2_bit = 1 << 6;
109 constexpr uint64_t cpuid_avx256_saved = uint64_t(1) << 2;
110 constexpr uint64_t cpuid_avx512_saved = uint64_t(7) << 5;
111 constexpr uint32_t cpuid_sse42_bit = 1 << 20;
112 constexpr uint32_t cpuid_osxsave = (uint32_t(1) << 26) | (uint32_t(1) << 27);
113 constexpr uint32_t cpuid_pclmulqdq_bit = 1 << 1;
114 }
115 
116 
117 
118 static inline void cpuid(uint32_t *eax, uint32_t *ebx, uint32_t *ecx,
119  uint32_t *edx) {
120 #if defined(_MSC_VER)
121  int cpu_info[4];
122  __cpuidex(cpu_info, *eax, *ecx);
123  *eax = cpu_info[0];
124  *ebx = cpu_info[1];
125  *ecx = cpu_info[2];
126  *edx = cpu_info[3];
127 #elif defined(HAVE_GCC_GET_CPUID) && defined(USE_GCC_GET_CPUID)
128  uint32_t level = *eax;
129  __get_cpuid(level, eax, ebx, ecx, edx);
130 #else
131  uint32_t a = *eax, b, c = *ecx, d;
132  asm volatile("cpuid\n\t" : "+a"(a), "=b"(b), "+c"(c), "=d"(d));
133  *eax = a;
134  *ebx = b;
135  *ecx = c;
136  *edx = d;
137 #endif
138 }
139 
140 
141 static inline uint64_t xgetbv() {
142 #if defined(_MSC_VER)
143  return _xgetbv(0);
144 #else
145  uint32_t xcr0_lo, xcr0_hi;
146  asm volatile("xgetbv\n\t" : "=a" (xcr0_lo), "=d" (xcr0_hi) : "c" (0));
147  return xcr0_lo | (uint64_t(xcr0_hi) << 32);
148 #endif
149 }
150 
151 static inline uint32_t detect_supported_architectures() {
152  uint32_t eax, ebx, ecx, edx;
153  uint32_t host_isa = 0x0;
154 
155  // EBX for EAX=0x1
156  eax = 0x1;
157  ecx = 0x0;
158  cpuid(&eax, &ebx, &ecx, &edx);
159 
160  if (ecx & cpuid_sse42_bit) {
161  host_isa |= instruction_set::SSE42;
162  } else {
163  return host_isa; // everything after is redundant
164  }
165 
166  if (ecx & cpuid_pclmulqdq_bit) {
167  host_isa |= instruction_set::PCLMULQDQ;
168  }
169 
170 
171  if ((ecx & cpuid_osxsave) != cpuid_osxsave) {
172  return host_isa;
173  }
174 
175  // xgetbv for checking if the OS saves registers
176  uint64_t xcr0 = xgetbv();
177 
178  if ((xcr0 & cpuid_avx256_saved) == 0) {
179  return host_isa;
180  }
181 
182  // ECX for EAX=0x7
183  eax = 0x7;
184  ecx = 0x0;
185  cpuid(&eax, &ebx, &ecx, &edx);
186  if (ebx & cpuid_avx2_bit) {
187  host_isa |= instruction_set::AVX2;
188  }
189  if (ebx & cpuid_bmi1_bit) {
190  host_isa |= instruction_set::BMI1;
191  }
192 
193  if (ebx & cpuid_bmi2_bit) {
194  host_isa |= instruction_set::BMI2;
195  }
196 
197  if (!((xcr0 & cpuid_avx512_saved) == cpuid_avx512_saved)) {
198  return host_isa;
199  }
200 
201  if (ebx & cpuid_avx512f_bit) {
202  host_isa |= instruction_set::AVX512F;
203  }
204 
205  if (ebx & cpuid_avx512dq_bit) {
206  host_isa |= instruction_set::AVX512DQ;
207  }
208 
209  if (ebx & cpuid_avx512ifma_bit) {
210  host_isa |= instruction_set::AVX512IFMA;
211  }
212 
213  if (ebx & cpuid_avx512pf_bit) {
214  host_isa |= instruction_set::AVX512PF;
215  }
216 
217  if (ebx & cpuid_avx512er_bit) {
218  host_isa |= instruction_set::AVX512ER;
219  }
220 
221  if (ebx & cpuid_avx512cd_bit) {
222  host_isa |= instruction_set::AVX512CD;
223  }
224 
225  if (ebx & cpuid_avx512bw_bit) {
226  host_isa |= instruction_set::AVX512BW;
227  }
228 
229  if (ebx & cpuid_avx512vl_bit) {
230  host_isa |= instruction_set::AVX512VL;
231  }
232 
233  if (ecx & cpuid_avx512vbmi2_bit) {
234  host_isa |= instruction_set::AVX512VBMI2;
235  }
236 
237  return host_isa;
238 }
239 #else // fallback
240 
241 
242 static inline uint32_t detect_supported_architectures() {
243  return instruction_set::DEFAULT;
244 }
245 
246 
247 #endif // end SIMD extension detection code
248 
249 } // namespace internal
250 } // namespace simdjson
251 
252 #endif // SIMDJSON_INTERNAL_ISADETECTION_H
We want to support argument-dependent lookup (ADL).