blob: 1fe15172dc456db548506f353a748fcfd0e3b431 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
/*
* The instruction set level. See simd.h. The level is picked once, before
* the first terminal exists, so every call in a process uses the same
* kernels.
*/
#include "term.h"
#include "simd.h"
#include <stdatomic.h>
#include <stdlib.h>
#include <string.h>
int term_isa_level;
static atomic_int isa_state;
static const char *const level_names[] = { "base", "avx2", "avx512" };
#if defined(TERM_ISA_RUNTIME)
/* The AVX-512 kernels also need VBMI and VBMI2. Every CPU with VBMI except
* Cannon Lake has VBMI2. */
static int cpu_level(void)
{
__builtin_cpu_init();
if (__builtin_cpu_supports("x86-64-v4") && __builtin_cpu_supports("avx512vbmi") &&
__builtin_cpu_supports("avx512vbmi2"))
return TERM_ISA_AVX512;
if (__builtin_cpu_supports("x86-64-v3"))
return TERM_ISA_AVX2;
return TERM_ISA_BASE;
}
#else
static int cpu_level(void)
{
return TERM_ISA_FLOOR;
}
#endif
static int pick_level(void)
{
int level = cpu_level();
/* TERM_HEADLESS_ISA can only lower the level, never below the floor the
* compiler flags fix. */
const char *want = getenv("TERM_HEADLESS_ISA");
for (int i = TERM_ISA_FLOOR; want && i < level; i++)
if (!strcmp(want, level_names[i]))
level = i;
return level;
}
/* The first caller picks the level. A second caller waits until it is set. */
void term_isa_init(void)
{
if (atomic_load_explicit(&isa_state, memory_order_acquire) == 2)
return;
int expected = 0;
if (atomic_compare_exchange_strong(&isa_state, &expected, 1)) {
term_isa_level = pick_level();
atomic_store_explicit(&isa_state, 2, memory_order_release);
return;
}
while (atomic_load_explicit(&isa_state, memory_order_acquire) != 2)
term_cpu_relax();
}
const char *term_isa(void)
{
term_isa_init();
#if defined(__aarch64__)
return "neon";
#else
int level = TERM_ISA_FLOOR;
if (term_use_avx2())
level = TERM_ISA_AVX2;
if (term_use_avx512())
level = TERM_ISA_AVX512;
return level_names[level];
#endif
}
|