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