1 module pfft.detect_avx;
2 
3 nothrow:
4 @nogc:
5 
6 private __gshared int avx_state;
7 
8 private void set_avx_state()
9 {
10     enum xcr0_avx_shift = 2;            // AVX enabled by OS
11     enum cpuid_avx = 1 << 28;           // processor supports AVX
12     enum cpuid_xsave = 1 << 26;         // processor supports xgetbv
13     enum mask = cpuid_avx | cpuid_xsave;
14 
15     int r = void;
16     version(GNU)
17         asm nothrow @nogc
18         {
19             "mov $1, %%eax
20             cpuid
21             mov $0, %%eax
22             and $0x14000000, %%ecx
23             cmp $0x14000000, %%ecx
24             jne exit_label%=
25             xor %%ecx, %%ecx
26             xgetbv
27             shr $2, %%eax
28             and $1, %%eax
29         exit_label%=: 
30             mov %%eax, %0"
31             : "=r" r
32             :
33             : "eax", "ebx", "ecx", "edx" ;
34         }
35     else
36         asm nothrow @nogc
37         {
38             mov EAX, 1;
39             cpuid;
40             mov EAX, 0;
41             and ECX, mask;
42             cmp ECX, mask;
43             jne exit_label;
44             xor ECX, ECX;
45             xgetbv;
46             shr EAX, xcr0_avx_shift;
47             and EAX, 1;
48         exit_label:
49             mov r, EAX;
50         }
51     
52     avx_state = r | 2;
53 }
54 
55 // TODO: use atomics there to protect avx_state
56 @property get()()
57 {
58     if(!avx_state)
59         set_avx_state();
60 
61     return avx_state & 1;
62 }
63