1
2
3
4
5
6
7 package cpu
8
9 const CacheLinePadSize = 64
10
11
12 func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32)
13
14
15 func xgetbv() (eax, edx uint32)
16
17
18 func getGOAMD64level() int32
19
20 const (
21
22 cpuid_SSE3 = 1 << 0
23 cpuid_PCLMULQDQ = 1 << 1
24 cpuid_SSSE3 = 1 << 9
25 cpuid_FMA = 1 << 12
26 cpuid_SSE41 = 1 << 19
27 cpuid_SSE42 = 1 << 20
28 cpuid_POPCNT = 1 << 23
29 cpuid_AES = 1 << 25
30 cpuid_OSXSAVE = 1 << 27
31 cpuid_AVX = 1 << 28
32
33
34 cpuid_BMI1 = 1 << 3
35 cpuid_AVX2 = 1 << 5
36 cpuid_BMI2 = 1 << 8
37 cpuid_ERMS = 1 << 9
38 cpuid_AVX512F = 1 << 16
39 cpuid_AVX512DQ = 1 << 17
40 cpuid_ADX = 1 << 19
41 cpuid_AVX512CD = 1 << 28
42 cpuid_SHA = 1 << 29
43 cpuid_AVX512BW = 1 << 30
44 cpuid_AVX512VL = 1 << 31
45
46
47 cpuid_AVX512VPCLMULQDQ = 1 << 10
48
49
50 cpuid_FSRM = 1 << 4
51
52 cpuid_RDTSCP = 1 << 27
53 )
54
55 var maxExtendedFunctionInformation uint32
56
57 func doinit() {
58 options = []option{
59 {Name: "adx", Feature: &X86.HasADX},
60 {Name: "aes", Feature: &X86.HasAES},
61 {Name: "erms", Feature: &X86.HasERMS},
62 {Name: "fsrm", Feature: &X86.HasFSRM},
63 {Name: "pclmulqdq", Feature: &X86.HasPCLMULQDQ},
64 {Name: "rdtscp", Feature: &X86.HasRDTSCP},
65 {Name: "sha", Feature: &X86.HasSHA},
66 {Name: "vpclmulqdq", Feature: &X86.HasAVX512VPCLMULQDQ},
67 }
68 level := getGOAMD64level()
69 if level < 2 {
70
71
72 options = append(options,
73 option{Name: "popcnt", Feature: &X86.HasPOPCNT},
74 option{Name: "sse3", Feature: &X86.HasSSE3},
75 option{Name: "sse41", Feature: &X86.HasSSE41},
76 option{Name: "sse42", Feature: &X86.HasSSE42},
77 option{Name: "ssse3", Feature: &X86.HasSSSE3})
78 }
79 if level < 3 {
80
81
82 options = append(options,
83 option{Name: "avx", Feature: &X86.HasAVX},
84 option{Name: "avx2", Feature: &X86.HasAVX2},
85 option{Name: "bmi1", Feature: &X86.HasBMI1},
86 option{Name: "bmi2", Feature: &X86.HasBMI2},
87 option{Name: "fma", Feature: &X86.HasFMA})
88 }
89 if level < 4 {
90
91
92 options = append(options,
93 option{Name: "avx512f", Feature: &X86.HasAVX512F},
94 option{Name: "avx512cd", Feature: &X86.HasAVX512CD},
95 option{Name: "avx512bw", Feature: &X86.HasAVX512BW},
96 option{Name: "avx512dq", Feature: &X86.HasAVX512DQ},
97 option{Name: "avx512vl", Feature: &X86.HasAVX512VL},
98 )
99 }
100
101 maxID, _, _, _ := cpuid(0, 0)
102
103 if maxID < 1 {
104 return
105 }
106
107 maxExtendedFunctionInformation, _, _, _ = cpuid(0x80000000, 0)
108
109 _, _, ecx1, _ := cpuid(1, 0)
110
111 X86.HasSSE3 = isSet(ecx1, cpuid_SSE3)
112 X86.HasPCLMULQDQ = isSet(ecx1, cpuid_PCLMULQDQ)
113 X86.HasSSSE3 = isSet(ecx1, cpuid_SSSE3)
114 X86.HasSSE41 = isSet(ecx1, cpuid_SSE41)
115 X86.HasSSE42 = isSet(ecx1, cpuid_SSE42)
116 X86.HasPOPCNT = isSet(ecx1, cpuid_POPCNT)
117 X86.HasAES = isSet(ecx1, cpuid_AES)
118
119
120
121
122 X86.HasOSXSAVE = isSet(ecx1, cpuid_OSXSAVE)
123
124
125
126
127
128 X86.HasFMA = isSet(ecx1, cpuid_FMA) && X86.HasOSXSAVE
129
130 osSupportsAVX := false
131 osSupportsAVX512 := false
132
133 if X86.HasOSXSAVE {
134 eax, _ := xgetbv()
135
136 osSupportsAVX = isSet(eax, 1<<1) && isSet(eax, 1<<2)
137
138
139
140
141
142 osSupportsAVX512 = osSupportsAVX && isSet(eax, 1<<5) && isSet(eax, 1<<6) && isSet(eax, 1<<7)
143 }
144
145 X86.HasAVX = isSet(ecx1, cpuid_AVX) && osSupportsAVX
146
147 if maxID < 7 {
148 return
149 }
150
151 _, ebx7, ecx7, edx7 := cpuid(7, 0)
152 X86.HasBMI1 = isSet(ebx7, cpuid_BMI1)
153 X86.HasAVX2 = isSet(ebx7, cpuid_AVX2) && osSupportsAVX
154 X86.HasBMI2 = isSet(ebx7, cpuid_BMI2)
155 X86.HasERMS = isSet(ebx7, cpuid_ERMS)
156 X86.HasADX = isSet(ebx7, cpuid_ADX)
157 X86.HasSHA = isSet(ebx7, cpuid_SHA)
158
159 X86.HasAVX512F = isSet(ebx7, cpuid_AVX512F) && osSupportsAVX512
160 if X86.HasAVX512F {
161 X86.HasAVX512CD = isSet(ebx7, cpuid_AVX512CD)
162 X86.HasAVX512BW = isSet(ebx7, cpuid_AVX512BW)
163 X86.HasAVX512DQ = isSet(ebx7, cpuid_AVX512DQ)
164 X86.HasAVX512VL = isSet(ebx7, cpuid_AVX512VL)
165 X86.HasAVX512VPCLMULQDQ = isSet(ecx7, cpuid_AVX512VPCLMULQDQ)
166 }
167
168 X86.HasFSRM = isSet(edx7, cpuid_FSRM)
169
170 var maxExtendedInformation uint32
171 maxExtendedInformation, _, _, _ = cpuid(0x80000000, 0)
172
173 if maxExtendedInformation < 0x80000001 {
174 return
175 }
176
177 _, _, _, edxExt1 := cpuid(0x80000001, 0)
178 X86.HasRDTSCP = isSet(edxExt1, cpuid_RDTSCP)
179
180 doDerived = func() {
181
182
183
184
185
186
187
188 X86.HasAVX512 = X86.HasAVX512F && X86.HasAVX512CD && X86.HasAVX512BW && X86.HasAVX512DQ && X86.HasAVX512VL
189 }
190 }
191
192 func isSet(hwc uint32, value uint32) bool {
193 return hwc&value != 0
194 }
195
196
197
198
199 func Name() string {
200 if maxExtendedFunctionInformation < 0x80000004 {
201 return ""
202 }
203
204 data := make([]byte, 0, 3*4*4)
205
206 var eax, ebx, ecx, edx uint32
207 eax, ebx, ecx, edx = cpuid(0x80000002, 0)
208 data = appendBytes(data, eax, ebx, ecx, edx)
209 eax, ebx, ecx, edx = cpuid(0x80000003, 0)
210 data = appendBytes(data, eax, ebx, ecx, edx)
211 eax, ebx, ecx, edx = cpuid(0x80000004, 0)
212 data = appendBytes(data, eax, ebx, ecx, edx)
213
214
215 for len(data) > 0 && data[0] == ' ' {
216 data = data[1:]
217 }
218
219
220 for i, c := range data {
221 if c == '\x00' {
222 data = data[:i]
223 break
224 }
225 }
226
227 return string(data)
228 }
229
230 func appendBytes(b []byte, args ...uint32) []byte {
231 for _, arg := range args {
232 b = append(b,
233 byte((arg >> 0)),
234 byte((arg >> 8)),
235 byte((arg >> 16)),
236 byte((arg >> 24)))
237 }
238 return b
239 }
240
View as plain text