Branch data Line data Source code
1 : : // This file is a part of Julia. License is MIT: https://julialang.org/license
2 : :
3 : : // X86 specific processor detection and dispatch
4 : :
5 : : // CPUID
6 : :
7 : 3484 : extern "C" JL_DLLEXPORT void jl_cpuid(int32_t CPUInfo[4], int32_t InfoType)
8 : : {
9 : : asm volatile (
10 : : #if defined(__i386__) && defined(__PIC__)
11 : : "xchg %%ebx, %%esi;"
12 : : "cpuid;"
13 : : "xchg %%esi, %%ebx;" :
14 : : "=S" (CPUInfo[1]),
15 : : #else
16 : : "cpuid" :
17 : 3484 : "=b" (CPUInfo[1]),
18 : : #endif
19 : : "=a" (CPUInfo[0]),
20 : 3484 : "=c" (CPUInfo[2]),
21 : 3484 : "=d" (CPUInfo[3]) :
22 : : "a" (InfoType)
23 : 3484 : );
24 : 3484 : }
25 : :
26 : 2850 : extern "C" JL_DLLEXPORT void jl_cpuidex(int32_t CPUInfo[4], int32_t InfoType, int32_t subInfoType)
27 : : {
28 : : asm volatile (
29 : : #if defined(__i386__) && defined(__PIC__)
30 : : "xchg %%ebx, %%esi;"
31 : : "cpuid;"
32 : : "xchg %%esi, %%ebx;" :
33 : : "=S" (CPUInfo[1]),
34 : : #else
35 : : "cpuid" :
36 : 2850 : "=b" (CPUInfo[1]),
37 : : #endif
38 : : "=a" (CPUInfo[0]),
39 : 2850 : "=c" (CPUInfo[2]),
40 : 2850 : "=d" (CPUInfo[3]) :
41 : : "a" (InfoType),
42 : : "c" (subInfoType)
43 : 2850 : );
44 : 2850 : }
45 : :
46 : : namespace X86 {
47 : :
48 : : enum class CPU : uint32_t {
49 : : generic = 0,
50 : : intel_nocona,
51 : : intel_prescott,
52 : : intel_atom_bonnell,
53 : : intel_atom_silvermont,
54 : : intel_atom_goldmont,
55 : : intel_atom_goldmont_plus,
56 : : intel_atom_tremont,
57 : : intel_core2,
58 : : intel_core2_penryn,
59 : : intel_yonah,
60 : : intel_corei7_nehalem,
61 : : intel_corei7_westmere,
62 : : intel_corei7_sandybridge,
63 : : intel_corei7_ivybridge,
64 : : intel_corei7_haswell,
65 : : intel_corei7_broadwell,
66 : : intel_corei7_skylake,
67 : : intel_corei7_skylake_avx512,
68 : : intel_corei7_cascadelake,
69 : : intel_corei7_cooperlake,
70 : : intel_corei7_cannonlake,
71 : : intel_corei7_icelake_client,
72 : : intel_corei7_icelake_server,
73 : : intel_corei7_tigerlake,
74 : : intel_corei7_alderlake,
75 : : intel_corei7_sapphirerapids,
76 : : intel_knights_landing,
77 : : intel_knights_mill,
78 : :
79 : : amd_fam10h,
80 : : amd_athlon_fx,
81 : : amd_athlon_64,
82 : : amd_athlon_64_sse3,
83 : : amd_bdver1,
84 : : amd_bdver2,
85 : : amd_bdver3,
86 : : amd_bdver4,
87 : : amd_btver1,
88 : : amd_btver2,
89 : : amd_k8,
90 : : amd_k8_sse3,
91 : : amd_opteron,
92 : : amd_opteron_sse3,
93 : : amd_barcelona,
94 : : amd_znver1,
95 : : amd_znver2,
96 : : amd_znver3,
97 : : };
98 : :
99 : : static constexpr size_t feature_sz = 11;
100 : : static constexpr FeatureName feature_names[] = {
101 : : #define JL_FEATURE_DEF(name, bit, llvmver) {#name, bit, llvmver},
102 : : #define JL_FEATURE_DEF_NAME(name, bit, llvmver, str) {str, bit, llvmver},
103 : : #include "features_x86.h"
104 : : #undef JL_FEATURE_DEF
105 : : #undef JL_FEATURE_DEF_NAME
106 : : };
107 : : static constexpr uint32_t nfeature_names = sizeof(feature_names) / sizeof(FeatureName);
108 : :
109 : : template<typename... Args>
110 : : static inline constexpr FeatureList<feature_sz> get_feature_masks(Args... args)
111 : : {
112 : : return ::get_feature_masks<feature_sz>(args...);
113 : : }
114 : :
115 : : #define JL_FEATURE_DEF_NAME(name, bit, llvmver, str) JL_FEATURE_DEF(name, bit, llvmver)
116 : : static constexpr auto feature_masks = get_feature_masks(
117 : : #define JL_FEATURE_DEF(name, bit, llvmver) bit,
118 : : #include "features_x86.h"
119 : : #undef JL_FEATURE_DEF
120 : : -1);
121 : :
122 : : namespace Feature {
123 : : enum : uint32_t {
124 : : #define JL_FEATURE_DEF(name, bit, llvmver) name = bit,
125 : : #include "features_x86.h"
126 : : #undef JL_FEATURE_DEF
127 : : };
128 : : #undef JL_FEATURE_DEF_NAME
129 : : static constexpr FeatureDep deps[] = {
130 : : {ssse3, sse3},
131 : : {fma, avx},
132 : : {sse41, ssse3},
133 : : {sse42, sse41},
134 : : {avx, sse42},
135 : : {f16c, avx},
136 : : {avx2, avx},
137 : : {vaes, avx},
138 : : {vaes, aes},
139 : : {vpclmulqdq, avx},
140 : : {vpclmulqdq, pclmul},
141 : : {avxvnni, avx2},
142 : : {avx512f, avx2},
143 : : {avx512dq, avx512f},
144 : : {avx512ifma, avx512f},
145 : : {avx512pf, avx512f},
146 : : {avx512er, avx512f},
147 : : {avx512cd, avx512f},
148 : : {avx512bw, avx512f},
149 : : {avx512bf16, avx512bw},
150 : : {avx512bitalg, avx512bw},
151 : : {avx512vl, avx512f},
152 : : {avx512vbmi, avx512bw},
153 : : {avx512vbmi2, avx512bw},
154 : : {avx512vnni, avx512f},
155 : : {avx512vp2intersect, avx512f},
156 : : {avx512vpopcntdq, avx512f},
157 : : {amx_int8, amx_tile},
158 : : {amx_bf16, amx_tile},
159 : : {sse4a, sse3},
160 : : {xop, fma4},
161 : : {fma4, avx},
162 : : {fma4, sse4a},
163 : : {xsaveopt, xsave},
164 : : {xsavec, xsave},
165 : : {xsaves, xsave},
166 : : };
167 : :
168 : : // We require cx16 on 64bit by default. This can be overwritten with `-cx16`
169 : : // This isn't really compatible with 32bit but we mask it off there with required LLVM version
170 : : constexpr auto generic = get_feature_masks(cx16);
171 : : constexpr auto bonnell = get_feature_masks(sse3, ssse3, cx16, movbe, sahf);
172 : : constexpr auto silvermont = bonnell | get_feature_masks(sse41, sse42, popcnt,
173 : : pclmul, prfchw, rdrnd);
174 : : constexpr auto goldmont = silvermont | get_feature_masks(aes, sha, rdseed, xsave, xsaveopt,
175 : : xsavec, xsaves, clflushopt, fsgsbase);
176 : : constexpr auto goldmont_plus = goldmont | get_feature_masks(ptwrite, rdpid); // sgx
177 : : constexpr auto tremont = goldmont_plus | get_feature_masks(clwb, gfni);
178 : : constexpr auto knl = get_feature_masks(sse3, ssse3, sse41, sse42, cx16, sahf, popcnt,
179 : : aes, pclmul, avx, xsave, xsaveopt, rdrnd, f16c, fsgsbase,
180 : : avx2, bmi, bmi2, fma, lzcnt, movbe, adx, rdseed, prfchw,
181 : : avx512f, avx512er, avx512cd, avx512pf, prefetchwt1);
182 : : constexpr auto knm = knl | get_feature_masks(avx512vpopcntdq);
183 : : constexpr auto yonah = get_feature_masks(sse3);
184 : : constexpr auto prescott = yonah;
185 : : constexpr auto core2 = get_feature_masks(sse3, ssse3, cx16, sahf);
186 : : constexpr auto nocona = get_feature_masks(sse3, cx16);
187 : : constexpr auto penryn = nocona | get_feature_masks(ssse3, sse41, sahf);
188 : : constexpr auto nehalem = penryn | get_feature_masks(sse42, popcnt);
189 : : constexpr auto westmere = nehalem | get_feature_masks(pclmul);
190 : : constexpr auto sandybridge = westmere | get_feature_masks(avx, xsave, xsaveopt);
191 : : constexpr auto ivybridge = sandybridge | get_feature_masks(rdrnd, f16c, fsgsbase);
192 : : constexpr auto haswell = ivybridge | get_feature_masks(avx2, bmi, bmi2, fma, lzcnt, movbe);
193 : : constexpr auto broadwell = haswell | get_feature_masks(adx, rdseed, prfchw);
194 : : constexpr auto skylake = broadwell | get_feature_masks(aes, xsavec, xsaves, clflushopt); // sgx
195 : : constexpr auto skx = skylake | get_feature_masks(avx512f, avx512cd, avx512dq, avx512bw, avx512vl,
196 : : pku, clwb);
197 : : constexpr auto cascadelake = skx | get_feature_masks(avx512vnni);
198 : : constexpr auto cooperlake = cascadelake | get_feature_masks(avx512bf16);
199 : : constexpr auto cannonlake = skylake | get_feature_masks(avx512f, avx512cd, avx512dq, avx512bw,
200 : : avx512vl, pku, avx512vbmi, avx512ifma,
201 : : sha); // sgx
202 : : constexpr auto icelake = cannonlake | get_feature_masks(avx512bitalg, vaes, avx512vbmi2,
203 : : vpclmulqdq, avx512vpopcntdq,
204 : : gfni, clwb, rdpid);
205 : : constexpr auto icelake_server = icelake | get_feature_masks(pconfig, wbnoinvd);
206 : : constexpr auto tigerlake = icelake | get_feature_masks(avx512vp2intersect, movdiri,
207 : : movdir64b, shstk);
208 : : constexpr auto alderlake = skylake | get_feature_masks(clwb, sha, waitpkg, shstk, gfni, vaes, vpclmulqdq, pconfig,
209 : : rdpid, movdiri, pku, movdir64b, serialize, ptwrite, avxvnni);
210 : : constexpr auto sapphirerapids = icelake_server |
211 : : get_feature_masks(amx_tile, amx_int8, amx_bf16, avx512bf16, serialize, cldemote, waitpkg,
212 : : ptwrite, tsxldtrk, enqcmd, shstk, avx512vp2intersect, movdiri, movdir64b);
213 : :
214 : : constexpr auto k8_sse3 = get_feature_masks(sse3, cx16);
215 : : constexpr auto amdfam10 = k8_sse3 | get_feature_masks(sse4a, lzcnt, popcnt, sahf);
216 : :
217 : : constexpr auto btver1 = amdfam10 | get_feature_masks(ssse3, prfchw);
218 : : constexpr auto btver2 = btver1 | get_feature_masks(sse41, sse42, avx, aes, pclmul, bmi, f16c,
219 : : movbe, xsave, xsaveopt);
220 : :
221 : : constexpr auto bdver1 = amdfam10 | get_feature_masks(xop, fma4, avx, ssse3, sse41, sse42, aes,
222 : : prfchw, pclmul, xsave, lwp);
223 : : constexpr auto bdver2 = bdver1 | get_feature_masks(f16c, bmi, tbm, fma);
224 : : constexpr auto bdver3 = bdver2 | get_feature_masks(xsaveopt, fsgsbase);
225 : : constexpr auto bdver4 = bdver3 | get_feature_masks(avx2, bmi2, mwaitx, movbe, rdrnd);
226 : :
227 : : constexpr auto znver1 = haswell | get_feature_masks(adx, aes, clflushopt, clzero, mwaitx, prfchw,
228 : : rdseed, sha, sse4a, xsavec, xsaves);
229 : : constexpr auto znver2 = znver1 | get_feature_masks(clwb, rdpid, wbnoinvd);
230 : : constexpr auto znver3 = znver2 | get_feature_masks(shstk, pku, vaes, vpclmulqdq);
231 : :
232 : : }
233 : :
234 : : static constexpr CPUSpec<CPU, feature_sz> cpus[] = {
235 : : {"generic", CPU::generic, CPU::generic, 0, Feature::generic},
236 : : {"bonnell", CPU::intel_atom_bonnell, CPU::generic, 0, Feature::bonnell},
237 : : {"silvermont", CPU::intel_atom_silvermont, CPU::generic, 0, Feature::silvermont},
238 : : {"goldmont", CPU::intel_atom_goldmont, CPU::generic, 0, Feature::goldmont},
239 : : {"goldmont-plus", CPU::intel_atom_goldmont_plus, CPU::generic, 0, Feature::goldmont_plus},
240 : : {"tremont", CPU::intel_atom_tremont, CPU::generic, 0, Feature::tremont},
241 : : {"core2", CPU::intel_core2, CPU::generic, 0, Feature::core2},
242 : : {"yonah", CPU::intel_yonah, CPU::generic, 0, Feature::yonah},
243 : : {"prescott", CPU::intel_prescott, CPU::generic, 0, Feature::prescott},
244 : : {"nocona", CPU::intel_nocona, CPU::generic, 0, Feature::nocona},
245 : : {"penryn", CPU::intel_core2_penryn, CPU::generic, 0, Feature::penryn},
246 : : {"nehalem", CPU::intel_corei7_nehalem, CPU::generic, 0, Feature::nehalem},
247 : : {"westmere", CPU::intel_corei7_westmere, CPU::generic, 0, Feature::westmere},
248 : : {"sandybridge", CPU::intel_corei7_sandybridge, CPU::generic, 0, Feature::sandybridge},
249 : : {"ivybridge", CPU::intel_corei7_ivybridge, CPU::generic, 0, Feature::ivybridge},
250 : : {"haswell", CPU::intel_corei7_haswell, CPU::generic, 0, Feature::haswell},
251 : : {"broadwell", CPU::intel_corei7_broadwell, CPU::generic, 0, Feature::broadwell},
252 : : {"skylake", CPU::intel_corei7_skylake, CPU::generic, 0, Feature::skylake},
253 : : {"knl", CPU::intel_knights_landing, CPU::generic, 0, Feature::knl},
254 : : {"knm", CPU::intel_knights_mill, CPU::generic, 0, Feature::knm},
255 : : {"skylake-avx512", CPU::intel_corei7_skylake_avx512, CPU::generic, 0, Feature::skx},
256 : : {"cascadelake", CPU::intel_corei7_cascadelake, CPU::generic, 0, Feature::cascadelake},
257 : : {"cooperlake", CPU::intel_corei7_cooperlake, CPU::generic, 0, Feature::cooperlake},
258 : : {"cannonlake", CPU::intel_corei7_cannonlake, CPU::generic, 0, Feature::cannonlake},
259 : : {"icelake-client", CPU::intel_corei7_icelake_client, CPU::generic, 0, Feature::icelake},
260 : : {"icelake-server", CPU::intel_corei7_icelake_server, CPU::generic, 0,
261 : : Feature::icelake_server},
262 : : {"tigerlake", CPU::intel_corei7_tigerlake, CPU::intel_corei7_icelake_client, 100000,
263 : : Feature::tigerlake},
264 : : {"alderlake", CPU::intel_corei7_alderlake, CPU::intel_corei7_skylake, 120000,
265 : : Feature::alderlake},
266 : : {"sapphirerapids", CPU::intel_corei7_sapphirerapids, CPU::intel_corei7_icelake_server, 120000,
267 : : Feature::sapphirerapids},
268 : :
269 : : {"athlon64", CPU::amd_athlon_64, CPU::generic, 0, Feature::generic},
270 : : {"athlon-fx", CPU::amd_athlon_fx, CPU::generic, 0, Feature::generic},
271 : : {"k8", CPU::amd_k8, CPU::generic, 0, Feature::generic},
272 : : {"opteron", CPU::amd_opteron, CPU::generic, 0, Feature::generic},
273 : :
274 : : {"athlon64-sse3", CPU::amd_athlon_64_sse3, CPU::generic, 0, Feature::k8_sse3},
275 : : {"k8-sse3", CPU::amd_k8_sse3, CPU::generic, 0, Feature::k8_sse3},
276 : : {"opteron-sse3", CPU::amd_opteron_sse3, CPU::generic, 0, Feature::k8_sse3},
277 : :
278 : : {"amdfam10", CPU::amd_fam10h, CPU::generic, 0, Feature::amdfam10},
279 : : {"barcelona", CPU::amd_barcelona, CPU::generic, 0, Feature::amdfam10},
280 : :
281 : : {"btver1", CPU::amd_btver1, CPU::generic, 0, Feature::btver1},
282 : : {"btver2", CPU::amd_btver2, CPU::generic, 0, Feature::btver2},
283 : :
284 : : {"bdver1", CPU::amd_bdver1, CPU::generic, 0, Feature::bdver1},
285 : : {"bdver2", CPU::amd_bdver2, CPU::generic, 0, Feature::bdver2},
286 : : {"bdver3", CPU::amd_bdver3, CPU::generic, 0, Feature::bdver3},
287 : : {"bdver4", CPU::amd_bdver4, CPU::generic, 0, Feature::bdver4},
288 : :
289 : : {"znver1", CPU::amd_znver1, CPU::generic, 0, Feature::znver1},
290 : : {"znver2", CPU::amd_znver2, CPU::generic, 0, Feature::znver2},
291 : : {"znver3", CPU::amd_znver3, CPU::amd_znver2, 120000, Feature::znver3},
292 : : };
293 : : static constexpr size_t ncpu_names = sizeof(cpus) / sizeof(cpus[0]);
294 : :
295 : : // For CPU model and feature detection on X86
296 : :
297 : : const int SIG_INTEL = 0x756e6547; // Genu
298 : : const int SIG_AMD = 0x68747541; // Auth
299 : :
300 : 570 : static uint64_t get_xcr0(void)
301 : : {
302 : : uint32_t eax, edx;
303 : 570 : asm volatile ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (0));
304 : 570 : return (uint64_t(edx) << 32) | eax;
305 : : }
306 : :
307 : 570 : static CPU get_intel_processor_name(uint32_t family, uint32_t model, uint32_t brand_id,
308 : : const uint32_t *features)
309 : : {
310 [ - + ]: 570 : if (brand_id != 0)
311 : 0 : return CPU::generic;
312 [ - + - - ]: 570 : switch (family) {
313 : 0 : case 3:
314 : : case 4:
315 : : case 5:
316 : 0 : return CPU::generic;
317 : 570 : case 6:
318 [ - - - - : 570 : switch (model) {
- - - - -
- + - - -
- - - - -
- - - - -
- - ]
319 : 0 : case 0x01: // Pentium Pro processor
320 : : case 0x03: // Intel Pentium II OverDrive processor, Pentium II processor, model 03
321 : : case 0x05: // Pentium II processor, model 05, Pentium II Xeon processor,
322 : : // model 05, and Intel Celeron processor, model 05
323 : : case 0x06: // Celeron processor, model 06
324 : : case 0x07: // Pentium III processor, model 07, and Pentium III Xeon processor, model 07
325 : : case 0x08: // Pentium III processor, model 08, Pentium III Xeon processor,
326 : : // model 08, and Celeron processor, model 08
327 : : case 0x0a: // Pentium III Xeon processor, model 0Ah
328 : : case 0x0b: // Pentium III processor, model 0Bh
329 : : case 0x09: // Intel Pentium M processor, Intel Celeron M processor model 09.
330 : : case 0x0d: // Intel Pentium M processor, Intel Celeron M processor, model
331 : : // 0Dh. All processors are manufactured using the 90 nm process.
332 : : case 0x15: // Intel EP80579 Integrated Processor and Intel EP80579
333 : : // Integrated Processor with Intel QuickAssist Technology
334 : 0 : return CPU::generic;
335 : 0 : case 0x0e: // Intel Core Duo processor, Intel Core Solo processor, model
336 : : // 0Eh. All processors are manufactured using the 65 nm process.
337 : 0 : return CPU::intel_yonah;
338 : 0 : case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile
339 : : // processor, Intel Core 2 Quad processor, Intel Core 2 Quad
340 : : // mobile processor, Intel Core 2 Extreme processor, Intel
341 : : // Pentium Dual-Core processor, Intel Xeon processor, model
342 : : // 0Fh. All processors are manufactured using the 65 nm process.
343 : : case 0x16: // Intel Celeron processor model 16h. All processors are
344 : : // manufactured using the 65 nm process
345 : 0 : return CPU::intel_core2;
346 : 0 : case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model
347 : : // 17h. All processors are manufactured using the 45 nm process.
348 : : //
349 : : // 45nm: Penryn , Wolfdale, Yorkfield (XE)
350 : : case 0x1d: // Intel Xeon processor MP. All processors are manufactured using
351 : : // the 45 nm process.
352 : 0 : return CPU::intel_core2_penryn;
353 : 0 : case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All
354 : : // processors are manufactured using the 45 nm process.
355 : : case 0x1e: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz.
356 : : // As found in a Summer 2010 model iMac.
357 : : case 0x1f:
358 : : case 0x2e: // Nehalem EX
359 : 0 : return CPU::intel_corei7_nehalem;
360 : 0 : case 0x25: // Intel Core i7, laptop version.
361 : : case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All
362 : : // processors are manufactured using the 32 nm process.
363 : : case 0x2f: // Westmere EX
364 : 0 : return CPU::intel_corei7_westmere;
365 : 0 : case 0x2a: // Intel Core i7 processor. All processors are manufactured
366 : : // using the 32 nm process.
367 : : case 0x2d:
368 : 0 : return CPU::intel_corei7_sandybridge;
369 : 0 : case 0x3a:
370 : : case 0x3e: // Ivy Bridge EP
371 : 0 : return CPU::intel_corei7_ivybridge;
372 : :
373 : : // Haswell:
374 : 0 : case 0x3c:
375 : : case 0x3f:
376 : : case 0x45:
377 : : case 0x46:
378 : 0 : return CPU::intel_corei7_haswell;
379 : :
380 : : // Broadwell:
381 : 0 : case 0x3d:
382 : : case 0x47:
383 : : case 0x4f:
384 : : case 0x56:
385 : 0 : return CPU::intel_corei7_broadwell;
386 : :
387 : : // Skylake:
388 : 570 : case 0x4e: // Skylake mobile
389 : : case 0x5e: // Skylake desktop
390 : : case 0x8e: // Kaby Lake mobile
391 : : case 0x9e: // Kaby Lake desktop
392 : : case 0xa5: // Comet Lake-H/S
393 : : case 0xa6: // Comet Lake-U
394 : 570 : return CPU::intel_corei7_skylake;
395 : :
396 : : // Skylake Xeon:
397 : 0 : case 0x55:
398 [ # # ]: 0 : if (test_nbit(features, Feature::avx512bf16))
399 : 0 : return CPU::intel_corei7_cooperlake;
400 [ # # ]: 0 : if (test_nbit(features, Feature::avx512vnni))
401 : 0 : return CPU::intel_corei7_cascadelake;
402 : 0 : return CPU::intel_corei7_skylake_avx512;
403 : :
404 : : // Cannonlake:
405 : 0 : case 0x66:
406 : 0 : return CPU::intel_corei7_cannonlake;
407 : :
408 : : // Icelake:
409 : 0 : case 0x7d:
410 : : case 0x7e:
411 : : case 0x9d:
412 : 0 : return CPU::intel_corei7_icelake_client;
413 : :
414 : : // Icelake Xeon:
415 : 0 : case 0x6a:
416 : : case 0x6c:
417 : 0 : return CPU::intel_corei7_icelake_server;
418 : :
419 : : // Tiger Lake
420 : 0 : case 0x8c:
421 : : case 0x8d:
422 : 0 : return CPU::intel_corei7_tigerlake;
423 : : //Alder Lake
424 : 0 : case 0x97:
425 : : case 0x9a:
426 : 0 : return CPU::intel_corei7_alderlake;
427 : :
428 : : // Sapphire Rapids
429 : 0 : case 0x8f:
430 : 0 : return CPU::intel_corei7_sapphirerapids;
431 : :
432 : 0 : case 0x1c: // Most 45 nm Intel Atom processors
433 : : case 0x26: // 45 nm Atom Lincroft
434 : : case 0x27: // 32 nm Atom Medfield
435 : : case 0x35: // 32 nm Atom Midview
436 : : case 0x36: // 32 nm Atom Midview
437 : 0 : return CPU::intel_atom_bonnell;
438 : :
439 : : // Atom Silvermont codes from the Intel software optimization guide.
440 : 0 : case 0x37:
441 : : case 0x4a:
442 : : case 0x4d:
443 : : case 0x5d:
444 : : // Airmont
445 : : case 0x4c:
446 : : case 0x5a:
447 : : case 0x75:
448 : 0 : return CPU::intel_atom_silvermont;
449 : :
450 : : // Goldmont:
451 : 0 : case 0x5c:
452 : : case 0x5f:
453 : 0 : return CPU::intel_atom_goldmont;
454 : 0 : case 0x7a:
455 : 0 : return CPU::intel_atom_goldmont_plus;
456 : 0 : case 0x86:
457 : : case 0x96:
458 : : case 0x9c:
459 : 0 : return CPU::intel_atom_tremont;
460 : :
461 : 0 : case 0x57:
462 : 0 : return CPU::intel_knights_landing;
463 : :
464 : 0 : case 0x85:
465 : 0 : return CPU::intel_knights_mill;
466 : :
467 : 0 : default:
468 : 0 : return CPU::generic;
469 : : }
470 : : break;
471 : 0 : case 15: {
472 [ # # ]: 0 : switch (model) {
473 : 0 : case 0: // Pentium 4 processor, Intel Xeon processor. All processors are
474 : : // model 00h and manufactured using the 0.18 micron process.
475 : : case 1: // Pentium 4 processor, Intel Xeon processor, Intel Xeon
476 : : // processor MP, and Intel Celeron processor. All processors are
477 : : // model 01h and manufactured using the 0.18 micron process.
478 : : case 2: // Pentium 4 processor, Mobile Intel Pentium 4 processor - M,
479 : : // Intel Xeon processor, Intel Xeon processor MP, Intel Celeron
480 : : // processor, and Mobile Intel Celeron processor. All processors
481 : : // are model 02h and manufactured using the 0.13 micron process.
482 : : default:
483 : 0 : return CPU::generic;
484 : :
485 : 0 : case 3: // Pentium 4 processor, Intel Xeon processor, Intel Celeron D
486 : : // processor. All processors are model 03h and manufactured using
487 : : // the 90 nm process.
488 : : case 4: // Pentium 4 processor, Pentium 4 processor Extreme Edition,
489 : : // Pentium D processor, Intel Xeon processor, Intel Xeon
490 : : // processor MP, Intel Celeron D processor. All processors are
491 : : // model 04h and manufactured using the 90 nm process.
492 : : case 6: // Pentium 4 processor, Pentium D processor, Pentium processor
493 : : // Extreme Edition, Intel Xeon processor, Intel Xeon processor
494 : : // MP, Intel Celeron D processor. All processors are model 06h
495 : : // and manufactured using the 65 nm process.
496 : : #ifdef _CPU_X86_64_
497 : 0 : return CPU::intel_nocona;
498 : : #else
499 : : return CPU::intel_prescott;
500 : : #endif
501 : : }
502 : : }
503 : 0 : default:
504 : 0 : break; /*"generic"*/
505 : : }
506 : 0 : return CPU::generic;
507 : : }
508 : :
509 : 0 : static CPU get_amd_processor_name(uint32_t family, uint32_t model, const uint32_t *features)
510 : : {
511 [ # # # # : 0 : switch (family) {
# # # # ]
512 : 0 : case 4:
513 : : case 5:
514 : : case 6:
515 : : default:
516 : 0 : return CPU::generic;
517 : 0 : case 15:
518 [ # # ]: 0 : if (test_nbit(features, Feature::sse3))
519 : 0 : return CPU::amd_k8_sse3;
520 [ # # # ]: 0 : switch (model) {
521 : 0 : case 1:
522 : 0 : return CPU::amd_opteron;
523 : 0 : case 5:
524 : 0 : return CPU::amd_athlon_fx;
525 : 0 : default:
526 : 0 : return CPU::amd_athlon_64;
527 : : }
528 : 0 : case 16:
529 [ # # ]: 0 : switch (model) {
530 : 0 : case 2:
531 : 0 : return CPU::amd_barcelona;
532 : 0 : case 4:
533 : : case 8:
534 : : default:
535 : 0 : return CPU::amd_fam10h;
536 : : }
537 : 0 : case 20:
538 : 0 : return CPU::amd_btver1;
539 : 0 : case 21:
540 [ # # # # ]: 0 : if (model >= 0x50 && model <= 0x6f)
541 : 0 : return CPU::amd_bdver4;
542 [ # # # # ]: 0 : if (model >= 0x30 && model <= 0x3f)
543 : 0 : return CPU::amd_bdver3;
544 [ # # # # ]: 0 : if (model >= 0x10 && model <= 0x1f)
545 : 0 : return CPU::amd_bdver2;
546 [ # # ]: 0 : if (model <= 0x0f)
547 : 0 : return CPU::amd_bdver1;
548 : 0 : return CPU::amd_btver1; // fallback
549 : 0 : case 22:
550 : 0 : return CPU::amd_btver2;
551 : 0 : case 23:
552 : : // Known models:
553 : : // Zen: 1, 17
554 : : // Zen+: 8, 24
555 : : // Zen2: 96, 113
556 [ # # ]: 0 : if (model >= 0x30)
557 : 0 : return CPU::amd_znver2;
558 : 0 : return CPU::amd_znver1;
559 : 0 : case 0x19: // AMD Family 19h
560 [ # # # # ]: 0 : if (model <= 0x0f || model == 0x21)
561 : 0 : return CPU::amd_znver3; // 00h-0Fh, 21h: Zen3
562 : 0 : return CPU::amd_znver3; // fallback
563 : : }
564 : : }
565 : :
566 : : template<typename T>
567 : 570 : static inline void features_disable_avx512(T &features)
568 : : {
569 : : using namespace Feature;
570 : 570 : unset_bits(features, avx512f, avx512dq, avx512ifma, avx512pf, avx512er, avx512cd,
571 : : avx512bw, avx512vl, avx512vbmi, avx512vpopcntdq, avx512vbmi2, avx512vnni,
572 : : avx512bitalg, avx512vp2intersect, avx512bf16);
573 : 570 : }
574 : :
575 : : template<typename T>
576 : 0 : static inline void features_disable_avx(T &features)
577 : : {
578 : : using namespace Feature;
579 : 0 : unset_bits(features, avx, Feature::fma, f16c, xsave, avx2, xop, fma4,
580 : : xsaveopt, xsavec, xsaves, vaes, vpclmulqdq);
581 : 0 : }
582 : :
583 : : template<typename T>
584 : 570 : static inline void features_disable_amx(T &features)
585 : : {
586 : : using namespace Feature;
587 : 570 : unset_bits(features, amx_bf16, amx_tile, amx_int8);
588 : 570 : }
589 : :
590 : 570 : static NOINLINE std::pair<uint32_t,FeatureList<feature_sz>> _get_host_cpu(void)
591 : : {
592 : 570 : FeatureList<feature_sz> features = {};
593 : :
594 : : int32_t info0[4];
595 : 570 : jl_cpuid(info0, 0);
596 : 570 : uint32_t maxleaf = info0[0];
597 [ - + ]: 570 : if (maxleaf < 1)
598 : 0 : return std::make_pair(uint32_t(CPU::generic), features);
599 : : int32_t info1[4];
600 : 570 : jl_cpuid(info1, 1);
601 : :
602 : 570 : auto vendor = info0[1];
603 : 570 : auto brand_id = info1[1] & 0xff;
604 : :
605 : 570 : auto family = (info1[0] >> 8) & 0xf; // Bits 8 - 11
606 : 570 : auto model = (info1[0] >> 4) & 0xf; // Bits 4 - 7
607 [ - + - - ]: 570 : if (family == 6 || family == 0xf) {
608 [ - + ]: 570 : if (family == 0xf)
609 : : // Examine extended family ID if family ID is F.
610 : 0 : family += (info1[0] >> 20) & 0xff; // Bits 20 - 27
611 : : // Examine extended model ID if family ID is 6 or F.
612 : 570 : model += ((info1[0] >> 16) & 0xf) << 4; // Bits 16 - 19
613 : : }
614 : :
615 : : // Fill in the features
616 : 570 : features[0] = info1[2];
617 : 570 : features[1] = info1[3];
618 [ + - ]: 570 : if (maxleaf >= 7) {
619 : : int32_t info7[4];
620 : 570 : jl_cpuidex(info7, 7, 0);
621 : 570 : features[2] = info7[1];
622 : 570 : features[3] = info7[2];
623 : 570 : features[4] = info7[3];
624 : : }
625 : : int32_t infoex0[4];
626 : 570 : jl_cpuid(infoex0, 0x80000000);
627 : 570 : uint32_t maxexleaf = infoex0[0];
628 [ + - ]: 570 : if (maxexleaf >= 0x80000001) {
629 : : int32_t infoex1[4];
630 : 570 : jl_cpuid(infoex1, 0x80000001);
631 : 570 : features[5] = infoex1[2];
632 : 570 : features[6] = infoex1[3];
633 : : }
634 [ + - ]: 570 : if (maxleaf >= 0xd) {
635 : : int32_t infod[4];
636 : 570 : jl_cpuidex(infod, 0xd, 0x1);
637 : 570 : features[7] = infod[0];
638 : : }
639 [ + - ]: 570 : if (maxexleaf >= 0x80000008) {
640 : : int32_t infoex8[4];
641 : 570 : jl_cpuidex(infoex8, 0x80000008, 0);
642 : 570 : features[8] = infoex8[1];
643 : : }
644 [ + - ]: 570 : if (maxleaf >= 7) {
645 : : int32_t info7[4];
646 : 570 : jl_cpuidex(info7, 7, 1);
647 : 570 : features[9] = info7[0];
648 : : }
649 [ + - ]: 570 : if (maxleaf >= 0x14) {
650 : : int32_t info14[4];
651 : 570 : jl_cpuidex(info14, 0x14, 0);
652 : 570 : features[10] = info14[1];
653 : : }
654 : :
655 : : // Fix up AVX bits to account for OS support and match LLVM model
656 : 570 : uint64_t xcr0 = 0;
657 : 570 : bool hasxsave = test_all_bits(features[0], 1 << 27);
658 [ + - ]: 570 : if (hasxsave) {
659 : 570 : xcr0 = get_xcr0();
660 : 570 : hasxsave = test_all_bits(xcr0, 0x6);
661 : : }
662 [ + - + - ]: 570 : bool hasavx = hasxsave && test_all_bits(features[0], 1 << 28);
663 : 570 : unset_bits(features, 32 + 27);
664 [ - + ]: 570 : if (!hasavx)
665 : 0 : features_disable_avx(features);
666 : : #ifdef _OS_DARWIN_
667 : : // See https://github.com/llvm/llvm-project/commit/82921bf2baed96b700f90b090d5dc2530223d9c0
668 : : // and https://github.com/apple/darwin-xnu/blob/a449c6a3b8014d9406c2ddbdc81795da24aa7443/osfmk/i386/fpu.c#L174
669 : : // Darwin lazily saves the AVX512 context on first use
670 : : bool hasavx512save = hasavx;
671 : : #else
672 [ + - - + ]: 570 : bool hasavx512save = hasavx && test_all_bits(xcr0, 0xe0);
673 : : #endif
674 [ + - ]: 570 : if (!hasavx512save)
675 : 570 : features_disable_avx512(features);
676 : : // AMX requires additional context to be saved by the OS.
677 [ + - - + ]: 570 : bool hasamxsave = hasxsave && test_all_bits(xcr0, (1 << 17) | (1 << 18));
678 [ + - ]: 570 : if (!hasamxsave)
679 : 570 : features_disable_amx(features);
680 : : // Ignore feature bits that we are not interested in.
681 : 570 : mask_features(feature_masks, &features[0]);
682 : :
683 : : uint32_t cpu;
684 [ + - ]: 570 : if (vendor == SIG_INTEL) {
685 : 570 : cpu = uint32_t(get_intel_processor_name(family, model, brand_id, &features[0]));
686 : : }
687 [ # # ]: 0 : else if (vendor == SIG_AMD) {
688 : 0 : cpu = uint32_t(get_amd_processor_name(family, model, &features[0]));
689 : : }
690 : : else {
691 : 0 : cpu = uint32_t(CPU::generic);
692 : : }
693 : :
694 : 570 : return std::make_pair(cpu, features);
695 : : }
696 : :
697 : 8000 : static inline const std::pair<uint32_t,FeatureList<feature_sz>> &get_host_cpu()
698 : : {
699 [ + + + - ]: 8000 : static auto host_cpu = _get_host_cpu();
700 : 8000 : return host_cpu;
701 : : }
702 : :
703 : 0 : static inline const CPUSpec<CPU,feature_sz> *find_cpu(uint32_t cpu)
704 : : {
705 : 0 : return ::find_cpu(cpu, cpus, ncpu_names);
706 : : }
707 : :
708 : 571 : static inline const CPUSpec<CPU,feature_sz> *find_cpu(llvm::StringRef name)
709 : : {
710 : 571 : return ::find_cpu(name, cpus, ncpu_names);
711 : : }
712 : :
713 : 567 : static inline const char *find_cpu_name(uint32_t cpu)
714 : : {
715 : 567 : return ::find_cpu_name(cpu, cpus, ncpu_names);
716 : : }
717 : :
718 : 1130 : static inline const std::string &host_cpu_name()
719 : : {
720 : : static std::string name =
721 : 1134 : (CPU)get_host_cpu().first != CPU::generic ?
722 : 1134 : std::string(find_cpu_name(get_host_cpu().first)) :
723 [ + + + - : 1130 : jl_get_cpu_name_llvm();
+ - + - ]
724 : 1130 : return name;
725 : : }
726 : :
727 : 1692 : static inline const char *normalize_cpu_name(llvm::StringRef name)
728 : : {
729 [ - + ]: 1692 : if (name == "atom")
730 : 0 : return "bonnell";
731 [ - + ]: 1692 : if (name == "slm")
732 : 0 : return "silvermont";
733 [ - + ]: 1692 : if (name == "glm")
734 : 0 : return "goldmont";
735 [ - + ]: 1692 : if (name == "corei7")
736 : 0 : return "nehalem";
737 [ - + ]: 1692 : if (name == "corei7-avx")
738 : 0 : return "sandybridge";
739 [ - + ]: 1692 : if (name == "core-avx-i")
740 : 0 : return "ivybridge";
741 [ - + ]: 1692 : if (name == "core-avx2")
742 : 0 : return "haswell";
743 [ - + ]: 1692 : if (name == "skx")
744 : 0 : return "skylake-avx512";
745 : : #ifdef _CPU_X86_
746 : : // i686 isn't a supported target but it's a common default one so just make it mean pentium4.
747 : : if (name == "pentium4" || name == "i686")
748 : : return "generic";
749 : : #else
750 [ + - - + : 1692 : if (name == "x86-64" || name == "x86_64")
- + ]
751 : 0 : return "generic";
752 : : #endif
753 : 1692 : return nullptr;
754 : : }
755 : :
756 : : template<size_t n>
757 : 570 : static inline void enable_depends(FeatureList<n> &features)
758 : : {
759 : 570 : ::enable_depends(features, Feature::deps, sizeof(Feature::deps) / sizeof(FeatureDep));
760 : 570 : }
761 : :
762 : : template<size_t n>
763 : 571 : static inline void disable_depends(FeatureList<n> &features)
764 : : {
765 : 571 : ::disable_depends(features, Feature::deps, sizeof(Feature::deps) / sizeof(FeatureDep));
766 : 571 : }
767 : :
768 : 1129 : static const std::vector<TargetData<feature_sz>> &get_cmdline_targets(void)
769 : : {
770 : 0 : auto feature_cb = [] (const char *str, size_t len, FeatureList<feature_sz> &list) {
771 : 0 : auto fbit = find_feature_bit(feature_names, nfeature_names, str, len);
772 [ # # ]: 0 : if (fbit == (uint32_t)-1)
773 : 0 : return false;
774 : 0 : set_bit(list, fbit, true);
775 : 0 : return true;
776 : : };
777 : 1129 : auto &targets = ::get_cmdline_targets<feature_sz>(feature_cb);
778 [ + + ]: 2258 : for (auto &t: targets) {
779 [ - + ]: 1129 : if (auto nname = normalize_cpu_name(t.name)) {
780 : 0 : t.name = nname;
781 : : }
782 : : }
783 : 1129 : return targets;
784 : : }
785 : :
786 : : static std::vector<TargetData<feature_sz>> jit_targets;
787 : :
788 : 570 : static TargetData<feature_sz> arg_target_data(const TargetData<feature_sz> &arg, bool require_host)
789 : : {
790 : 570 : TargetData<feature_sz> res = arg;
791 : 570 : const FeatureList<feature_sz> *cpu_features = nullptr;
792 [ + + ]: 570 : if (res.name == "native") {
793 : 567 : res.name = host_cpu_name();
794 : 567 : cpu_features = &get_host_cpu().second;
795 : : }
796 [ - + ]: 3 : else if (auto spec = find_cpu(res.name)) {
797 : 0 : cpu_features = &spec->features;
798 : : }
799 : : else {
800 : 3 : res.en.flags |= JL_TARGET_UNKNOWN_NAME;
801 : : }
802 [ + + ]: 570 : if (cpu_features) {
803 [ + + ]: 6804 : for (size_t i = 0; i < feature_sz; i++) {
804 : 6237 : res.en.features[i] |= (*cpu_features)[i];
805 : : }
806 : : }
807 : 570 : enable_depends(res.en.features);
808 : : // Mask our rdrand/rdseed/rtm/xsaveopt features that LLVM doesn't use and rr disables
809 : 570 : unset_bits(res.en.features, Feature::rdrnd, Feature::rdseed, Feature::rtm, Feature::xsaveopt);
810 [ + + ]: 6840 : for (size_t i = 0; i < feature_sz; i++)
811 : 6270 : res.en.features[i] &= ~res.dis.features[i];
812 [ + - ]: 570 : if (require_host) {
813 [ + + ]: 6840 : for (size_t i = 0; i < feature_sz; i++) {
814 : 6270 : res.en.features[i] &= get_host_cpu().second[i];
815 : : }
816 : : }
817 : 570 : disable_depends(res.en.features);
818 [ + + ]: 570 : if (cpu_features) {
819 : : // If the base feature if known, fill in the disable features
820 [ + + ]: 6804 : for (size_t i = 0; i < feature_sz; i++) {
821 : 6237 : res.dis.features[i] = feature_masks[i] & ~res.en.features[i];
822 : : }
823 : : }
824 : 570 : return res;
825 : : }
826 : :
827 : 1120 : static int max_vector_size(const FeatureList<feature_sz> &features)
828 : : {
829 [ - + ]: 1120 : if (test_nbit(features, Feature::avx512f))
830 : 0 : return 64;
831 [ + - ]: 1120 : if (test_nbit(features, Feature::avx))
832 : 1120 : return 32;
833 : : // SSE is required
834 : 0 : return 16;
835 : : }
836 : :
837 : 563 : static uint32_t sysimg_init_cb(const void *id)
838 : : {
839 : : // First see what target is requested for the JIT.
840 : 563 : auto &cmdline = get_cmdline_targets();
841 : 1123 : TargetData<feature_sz> target = arg_target_data(cmdline[0], true);
842 : : // Then find the best match in the sysimg
843 : 563 : auto sysimg = deserialize_target_data<feature_sz>((const uint8_t*)id);
844 : : // We translate `generic` to `pentium4` or `x86-64` before sending it to LLVM
845 : : // (see `get_llvm_target_noext`) which will be serialized into the sysimg target data.
846 : : // Translate them back so we can actually match them.
847 : : // We also track to see if the sysimg allows -cx16, however if the user does
848 : : // something silly like add +cx16 on a 32bit target, we want to disable this
849 : : // check, hence the pointer size check.
850 : 563 : bool sysimg_allows_no_cx16 = sizeof(void *) == 4;;
851 [ + + ]: 1126 : for (auto &t: sysimg) {
852 [ - + ]: 563 : if (auto nname = normalize_cpu_name(t.name)) {
853 : 0 : t.name = nname;
854 : : }
855 : :
856 : : // Take note to see if the sysimg explicitly allows an architecture without cx16
857 : 563 : sysimg_allows_no_cx16 |= !test_nbit(t.en.features, Feature::cx16);
858 : : }
859 [ + - + + : 563 : if (!sysimg_allows_no_cx16 && !test_nbit(target.en.features, Feature::cx16)) {
+ + ]
860 : 3 : jl_error("Your CPU does not support the CX16 instruction, which is required "
861 : : "by this version of Julia! This is often due to running inside of a "
862 : : "virtualized environment. Please read "
863 : : "https://docs.julialang.org/en/v1/devdocs/sysimg/ for more.");
864 : : }
865 : 560 : auto match = match_sysimg_targets(sysimg, target, max_vector_size);
866 : : // Now we've decided on which sysimg version to use.
867 : : // Make sure the JIT target is compatible with it and save the JIT target.
868 [ - + - + ]: 560 : if (match.vreg_size != max_vector_size(target.en.features) &&
869 [ # # ]: 0 : (sysimg[match.best_idx].en.flags & JL_TARGET_VEC_CALL)) {
870 [ # # ]: 0 : if (match.vreg_size < 64) {
871 : 0 : features_disable_avx512(target.en.features);
872 : : }
873 [ # # ]: 0 : if (match.vreg_size < 32) {
874 : 0 : features_disable_avx(target.en.features);
875 : : }
876 : : }
877 : 560 : jit_targets.push_back(std::move(target));
878 : 560 : return match.best_idx;
879 : : }
880 : :
881 : 566 : static void ensure_jit_target(bool imaging)
882 : : {
883 : 566 : auto &cmdline = get_cmdline_targets();
884 : 566 : check_cmdline(cmdline, imaging);
885 [ + + ]: 566 : if (!jit_targets.empty())
886 : 559 : return;
887 [ + + ]: 14 : for (auto &arg: cmdline) {
888 : 14 : auto data = arg_target_data(arg, jit_targets.empty());
889 : 7 : jit_targets.push_back(std::move(data));
890 : : }
891 : 7 : auto ntargets = jit_targets.size();
892 : : // Now decide the clone condition.
893 [ - + ]: 7 : for (size_t i = 1; i < ntargets; i++) {
894 : 0 : auto &t = jit_targets[i];
895 [ # # ]: 0 : if (t.en.flags & JL_TARGET_CLONE_ALL)
896 : 0 : continue;
897 : : // Always clone when code checks CPU features
898 : 0 : t.en.flags |= JL_TARGET_CLONE_CPU;
899 : : // The most useful one in general...
900 : 0 : t.en.flags |= JL_TARGET_CLONE_LOOP;
901 : 0 : auto &features0 = jit_targets[t.base].en.features;
902 : : // Special case for KNL/KNM since they're so different
903 [ # # ]: 0 : if (!(t.dis.flags & JL_TARGET_CLONE_ALL)) {
904 [ # # # # ]: 0 : if ((t.name == "knl" || t.name == "knm") &&
905 [ # # # # : 0 : jit_targets[t.base].name != "knl" && jit_targets[t.base].name != "knm") {
# # ]
906 : 0 : t.en.flags |= JL_TARGET_CLONE_ALL;
907 : 0 : break;
908 : : }
909 : : }
910 : : static constexpr uint32_t clone_math[] = {Feature::fma, Feature::fma4};
911 : : static constexpr uint32_t clone_simd[] = {Feature::sse3, Feature::ssse3,
912 : : Feature::sse41, Feature::sse42,
913 : : Feature::avx, Feature::avx2,
914 : : Feature::vaes, Feature::vpclmulqdq,
915 : : Feature::sse4a, Feature::avx512f,
916 : : Feature::avx512dq, Feature::avx512ifma,
917 : : Feature::avx512pf, Feature::avx512er,
918 : : Feature::avx512cd, Feature::avx512bw,
919 : : Feature::avx512vl, Feature::avx512vbmi,
920 : : Feature::avx512vpopcntdq,
921 : : Feature::avx512vbmi2, Feature::avx512vnni,
922 : : Feature::avx512bitalg, Feature::avx512bf16,
923 : : Feature::avx512vp2intersect};
924 [ # # ]: 0 : for (auto fe: clone_math) {
925 [ # # # # : 0 : if (!test_nbit(features0, fe) && test_nbit(t.en.features, fe)) {
# # ]
926 : 0 : t.en.flags |= JL_TARGET_CLONE_MATH;
927 : 0 : break;
928 : : }
929 : : }
930 [ # # ]: 0 : for (auto fe: clone_simd) {
931 [ # # # # : 0 : if (!test_nbit(features0, fe) && test_nbit(t.en.features, fe)) {
# # ]
932 : 0 : t.en.flags |= JL_TARGET_CLONE_SIMD;
933 : 0 : break;
934 : : }
935 : : }
936 : : }
937 : : }
938 : :
939 : : static std::pair<std::string,std::vector<std::string>>
940 : 568 : get_llvm_target_noext(const TargetData<feature_sz> &data)
941 : : {
942 : 1136 : std::string name = data.name;
943 : 568 : auto *spec = find_cpu(name);
944 [ + - ]: 568 : while (spec) {
945 [ + - ]: 568 : if (spec->llvmver <= JL_LLVM_VERSION)
946 : 568 : break;
947 : 0 : spec = find_cpu((uint32_t)spec->fallback);
948 : 0 : name = spec->name;
949 : : }
950 [ + + ]: 568 : if (name == "generic") {
951 : : // Use translate `generic` into what we actually require
952 : : #ifdef _CPU_X86_
953 : : name = "pentium4";
954 : : #else
955 : 1 : name = "x86-64";
956 : : #endif
957 : : }
958 : 1136 : std::vector<std::string> features;
959 [ + + ]: 42032 : for (auto &fename: feature_names) {
960 [ - + ]: 41464 : if (fename.llvmver > JL_LLVM_VERSION)
961 : 0 : continue;
962 [ + + ]: 41464 : if (test_nbit(data.en.features, fename.bit)) {
963 : 13681 : features.insert(features.begin(), std::string("+") + fename.name);
964 : : }
965 [ + - ]: 27783 : else if (test_nbit(data.dis.features, fename.bit)) {
966 : 27783 : features.push_back(std::string("-") + fename.name);
967 : : }
968 : : }
969 : 568 : features.push_back("+sse2");
970 : 568 : features.push_back("+mmx");
971 : 568 : features.push_back("+fxsr");
972 : : #ifdef _CPU_X86_64_
973 : : // This is required to make LLVM happy if LLVM's feature based CPU arch guess
974 : : // returns a value that may not have 64bit support.
975 : : // This can happen with virtualization.
976 : 568 : features.push_back("+64bit");
977 : : #endif
978 : 568 : features.push_back("+cx8");
979 : 568 : return std::make_pair(std::move(name), std::move(features));
980 : : }
981 : :
982 : : static std::pair<std::string,std::vector<std::string>>
983 : 566 : get_llvm_target_vec(const TargetData<feature_sz> &data)
984 : : {
985 : 566 : auto res0 = get_llvm_target_noext(data);
986 : 566 : append_ext_features(res0.second, data.ext_features);
987 : 566 : return res0;
988 : : }
989 : :
990 : : static std::pair<std::string,std::string>
991 : 2 : get_llvm_target_str(const TargetData<feature_sz> &data)
992 : : {
993 : 4 : auto res0 = get_llvm_target_noext(data);
994 : 4 : auto features = join_feature_strs(res0.second);
995 : 2 : append_ext_features(features, data.ext_features);
996 : 2 : return std::make_pair(std::move(res0.first), std::move(features));
997 : : }
998 : :
999 : : }
1000 : :
1001 : : using namespace X86;
1002 : :
1003 : 0 : JL_DLLEXPORT void jl_dump_host_cpu(void)
1004 : : {
1005 : 0 : dump_cpu_spec(get_host_cpu().first, get_host_cpu().second, feature_names, nfeature_names,
1006 : : cpus, ncpu_names);
1007 : 0 : }
1008 : :
1009 : 563 : JL_DLLEXPORT jl_value_t *jl_get_cpu_name(void)
1010 : : {
1011 : 563 : return jl_cstr_to_string(host_cpu_name().c_str());
1012 : : }
1013 : :
1014 : 563 : jl_sysimg_fptrs_t jl_init_processor_sysimg(void *hdl)
1015 : : {
1016 [ - + ]: 563 : if (!jit_targets.empty())
1017 : 0 : jl_error("JIT targets already initialized");
1018 : 563 : return parse_sysimg(hdl, sysimg_init_cb);
1019 : : }
1020 : :
1021 : 566 : extern "C" JL_DLLEXPORT std::pair<std::string,std::vector<std::string>> jl_get_llvm_target(bool imaging, uint32_t &flags)
1022 : : {
1023 : 566 : ensure_jit_target(imaging);
1024 : 566 : flags = jit_targets[0].en.flags;
1025 : 566 : return get_llvm_target_vec(jit_targets[0]);
1026 : : }
1027 : :
1028 : 3 : extern "C" JL_DLLEXPORT const std::pair<std::string,std::string> &jl_get_llvm_disasm_target(void)
1029 : : {
1030 : 2 : static const auto res = get_llvm_target_str(TargetData<feature_sz>{"generic", "",
1031 [ + + + - ]: 4 : {feature_masks, 0}, {{}, 0}, 0});
1032 : 3 : return res;
1033 : : }
1034 : :
1035 : 1 : extern "C" JL_DLLEXPORT std::vector<jl_target_spec_t> jl_get_llvm_clone_targets(void)
1036 : : {
1037 [ - + ]: 1 : if (jit_targets.empty())
1038 : 0 : jl_error("JIT targets not initialized");
1039 : 1 : std::vector<jl_target_spec_t> res;
1040 [ + + ]: 2 : for (auto &target: jit_targets) {
1041 : 1 : auto features_en = target.en.features;
1042 : 1 : auto features_dis = target.dis.features;
1043 [ + + ]: 74 : for (auto &fename: feature_names) {
1044 [ - + ]: 73 : if (fename.llvmver > JL_LLVM_VERSION) {
1045 : 0 : unset_bits(features_en, fename.bit);
1046 : 0 : unset_bits(features_dis, fename.bit);
1047 : : }
1048 : : }
1049 : 1 : X86::disable_depends(features_en);
1050 : 2 : jl_target_spec_t ele;
1051 : 1 : std::tie(ele.cpu_name, ele.cpu_features) = get_llvm_target_str(target);
1052 : 2 : ele.data = serialize_target_data(target.name, features_en, features_dis,
1053 : 2 : target.ext_features);
1054 : 1 : ele.flags = target.en.flags;
1055 : 1 : ele.base = target.base;
1056 : 1 : res.push_back(ele);
1057 : : }
1058 : 1 : return res;
1059 : : }
1060 : :
1061 : 29 : extern "C" int jl_test_cpu_feature(jl_cpu_feature_t feature)
1062 : : {
1063 [ - + ]: 29 : if (feature >= 32 * feature_sz)
1064 : 0 : return 0;
1065 : 29 : return test_nbit(&get_host_cpu().second[0], feature);
1066 : : }
1067 : :
1068 : : // -- set/clear the FZ/DAZ flags on x86 & x86-64 --
1069 : :
1070 : : // Cache of information recovered from `cpuid` since executing `cpuid` it at runtime is slow.
1071 : 602 : static uint32_t subnormal_flags = [] {
1072 : : int32_t info[4];
1073 : 602 : jl_cpuid(info, 0);
1074 [ + - ]: 602 : if (info[0] >= 1) {
1075 : 602 : jl_cpuid(info, 1);
1076 [ + - ]: 602 : if (info[3] & (1 << 26)) {
1077 : : // SSE2 supports both FZ and DAZ
1078 : 602 : return 0x00008040;
1079 : : }
1080 [ # # ]: 0 : else if (info[3] & (1 << 25)) {
1081 : : // SSE supports only the FZ flag
1082 : 0 : return 0x00008000;
1083 : : }
1084 : : }
1085 : 0 : return 0;
1086 : : }();
1087 : :
1088 : : // Returns non-zero if subnormals go to 0; zero otherwise.
1089 : 2 : extern "C" JL_DLLEXPORT int32_t jl_get_zero_subnormals(void)
1090 : : {
1091 : 2 : return _mm_getcsr() & subnormal_flags;
1092 : : }
1093 : :
1094 : : // Return zero on success, non-zero on failure.
1095 : 575 : extern "C" JL_DLLEXPORT int32_t jl_set_zero_subnormals(int8_t isZero)
1096 : : {
1097 : 575 : uint32_t flags = subnormal_flags;
1098 [ + - ]: 575 : if (flags) {
1099 : 575 : uint32_t state = _mm_getcsr();
1100 [ + + ]: 575 : if (isZero)
1101 : 1 : state |= flags;
1102 : : else
1103 : 574 : state &= ~flags;
1104 : : _mm_setcsr(state);
1105 : 575 : return 0;
1106 : : }
1107 : : else {
1108 : : // Report a failure only if user is trying to enable FTZ/DAZ.
1109 : 0 : return isZero;
1110 : : }
1111 : : }
1112 : :
1113 : : // X86 does not support default NaNs
1114 : 0 : extern "C" JL_DLLEXPORT int32_t jl_get_default_nans(void)
1115 : : {
1116 : 0 : return 0;
1117 : : }
1118 : :
1119 : 573 : extern "C" JL_DLLEXPORT int32_t jl_set_default_nans(int8_t isDefault)
1120 : : {
1121 : 573 : return isDefault;
1122 : : }
|