github.com/bir3/gocompiler@v0.9.2202/src/internal/cpu/cpu_x86.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build 386 || amd64 6 7 package cpu 8 9 const CacheLinePadSize = 64 10 11 // cpuid is implemented in cpu_x86.s. 12 func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) 13 14 // xgetbv with ecx = 0 is implemented in cpu_x86.s. 15 func xgetbv() (eax, edx uint32) 16 17 // getGOAMD64level is implemented in cpu_x86.s. Returns number in [1,4]. 18 func getGOAMD64level() int32 19 20 const ( 21 // edx bits 22 cpuid_SSE2 = 1 << 26 23 24 // ecx bits 25 cpuid_SSE3 = 1 << 0 26 cpuid_PCLMULQDQ = 1 << 1 27 cpuid_SSSE3 = 1 << 9 28 cpuid_FMA = 1 << 12 29 cpuid_SSE41 = 1 << 19 30 cpuid_SSE42 = 1 << 20 31 cpuid_POPCNT = 1 << 23 32 cpuid_AES = 1 << 25 33 cpuid_OSXSAVE = 1 << 27 34 cpuid_AVX = 1 << 28 35 36 // ebx bits 37 cpuid_BMI1 = 1 << 3 38 cpuid_AVX2 = 1 << 5 39 cpuid_BMI2 = 1 << 8 40 cpuid_ERMS = 1 << 9 41 cpuid_AVX512F = 1 << 16 42 cpuid_ADX = 1 << 19 43 cpuid_SHA = 1 << 29 44 cpuid_AVX512BW = 1 << 30 45 cpuid_AVX512VL = 1 << 31 46 47 // edx bits for CPUID 0x80000001 48 cpuid_RDTSCP = 1 << 27 49 ) 50 51 var maxExtendedFunctionInformation uint32 52 53 func doinit() { 54 options = []option{ 55 {Name: "adx", Feature: &X86.HasADX}, 56 {Name: "aes", Feature: &X86.HasAES}, 57 {Name: "erms", Feature: &X86.HasERMS}, 58 {Name: "pclmulqdq", Feature: &X86.HasPCLMULQDQ}, 59 {Name: "rdtscp", Feature: &X86.HasRDTSCP}, 60 {Name: "sha", Feature: &X86.HasSHA}, 61 } 62 level := getGOAMD64level() 63 if level < 2 { 64 // These options are required at level 2. At lower levels 65 // they can be turned off. 66 options = append(options, 67 option{Name: "popcnt", Feature: &X86.HasPOPCNT}, 68 option{Name: "sse3", Feature: &X86.HasSSE3}, 69 option{Name: "sse41", Feature: &X86.HasSSE41}, 70 option{Name: "sse42", Feature: &X86.HasSSE42}, 71 option{Name: "ssse3", Feature: &X86.HasSSSE3}) 72 } 73 if level < 3 { 74 // These options are required at level 3. At lower levels 75 // they can be turned off. 76 options = append(options, 77 option{Name: "avx", Feature: &X86.HasAVX}, 78 option{Name: "avx2", Feature: &X86.HasAVX2}, 79 option{Name: "bmi1", Feature: &X86.HasBMI1}, 80 option{Name: "bmi2", Feature: &X86.HasBMI2}, 81 option{Name: "fma", Feature: &X86.HasFMA}) 82 } 83 if level < 4 { 84 // These options are required at level 4. At lower levels 85 // they can be turned off. 86 options = append(options, 87 option{Name: "avx512f", Feature: &X86.HasAVX512F}, 88 option{Name: "avx512bw", Feature: &X86.HasAVX512BW}, 89 option{Name: "avx512vl", Feature: &X86.HasAVX512VL}, 90 ) 91 } 92 93 maxID, _, _, _ := cpuid(0, 0) 94 95 if maxID < 1 { 96 return 97 } 98 99 maxExtendedFunctionInformation, _, _, _ = cpuid(0x80000000, 0) 100 101 _, _, ecx1, _ := cpuid(1, 0) 102 103 X86.HasSSE3 = isSet(ecx1, cpuid_SSE3) 104 X86.HasPCLMULQDQ = isSet(ecx1, cpuid_PCLMULQDQ) 105 X86.HasSSSE3 = isSet(ecx1, cpuid_SSSE3) 106 X86.HasSSE41 = isSet(ecx1, cpuid_SSE41) 107 X86.HasSSE42 = isSet(ecx1, cpuid_SSE42) 108 X86.HasPOPCNT = isSet(ecx1, cpuid_POPCNT) 109 X86.HasAES = isSet(ecx1, cpuid_AES) 110 111 // OSXSAVE can be false when using older Operating Systems 112 // or when explicitly disabled on newer Operating Systems by 113 // e.g. setting the xsavedisable boot option on Windows 10. 114 X86.HasOSXSAVE = isSet(ecx1, cpuid_OSXSAVE) 115 116 // The FMA instruction set extension only has VEX prefixed instructions. 117 // VEX prefixed instructions require OSXSAVE to be enabled. 118 // See Intel 64 and IA-32 Architecture Software Developer’s Manual Volume 2 119 // Section 2.4 "AVX and SSE Instruction Exception Specification" 120 X86.HasFMA = isSet(ecx1, cpuid_FMA) && X86.HasOSXSAVE 121 122 osSupportsAVX := false 123 osSupportsAVX512 := false 124 // For XGETBV, OSXSAVE bit is required and sufficient. 125 if X86.HasOSXSAVE { 126 eax, _ := xgetbv() 127 // Check if XMM and YMM registers have OS support. 128 osSupportsAVX = isSet(eax, 1<<1) && isSet(eax, 1<<2) 129 130 // AVX512 detection does not work on Darwin, 131 // see https://github.com/golang/go/issues/49233 132 // 133 // Check if opmask, ZMMhi256 and Hi16_ZMM have OS support. 134 osSupportsAVX512 = osSupportsAVX && isSet(eax, 1<<5) && isSet(eax, 1<<6) && isSet(eax, 1<<7) 135 } 136 137 X86.HasAVX = isSet(ecx1, cpuid_AVX) && osSupportsAVX 138 139 if maxID < 7 { 140 return 141 } 142 143 _, ebx7, _, _ := cpuid(7, 0) 144 X86.HasBMI1 = isSet(ebx7, cpuid_BMI1) 145 X86.HasAVX2 = isSet(ebx7, cpuid_AVX2) && osSupportsAVX 146 X86.HasBMI2 = isSet(ebx7, cpuid_BMI2) 147 X86.HasERMS = isSet(ebx7, cpuid_ERMS) 148 X86.HasADX = isSet(ebx7, cpuid_ADX) 149 X86.HasSHA = isSet(ebx7, cpuid_SHA) 150 151 X86.HasAVX512F = isSet(ebx7, cpuid_AVX512F) && osSupportsAVX512 152 if X86.HasAVX512F { 153 X86.HasAVX512BW = isSet(ebx7, cpuid_AVX512BW) 154 X86.HasAVX512VL = isSet(ebx7, cpuid_AVX512VL) 155 } 156 157 var maxExtendedInformation uint32 158 maxExtendedInformation, _, _, _ = cpuid(0x80000000, 0) 159 160 if maxExtendedInformation < 0x80000001 { 161 return 162 } 163 164 _, _, _, edxExt1 := cpuid(0x80000001, 0) 165 X86.HasRDTSCP = isSet(edxExt1, cpuid_RDTSCP) 166 } 167 168 func isSet(hwc uint32, value uint32) bool { 169 return hwc&value != 0 170 } 171 172 // Name returns the CPU name given by the vendor. 173 // If the CPU name can not be determined an 174 // empty string is returned. 175 func Name() string { 176 if maxExtendedFunctionInformation < 0x80000004 { 177 return "" 178 } 179 180 data := make([]byte, 0, 3*4*4) 181 182 var eax, ebx, ecx, edx uint32 183 eax, ebx, ecx, edx = cpuid(0x80000002, 0) 184 data = appendBytes(data, eax, ebx, ecx, edx) 185 eax, ebx, ecx, edx = cpuid(0x80000003, 0) 186 data = appendBytes(data, eax, ebx, ecx, edx) 187 eax, ebx, ecx, edx = cpuid(0x80000004, 0) 188 data = appendBytes(data, eax, ebx, ecx, edx) 189 190 // Trim leading spaces. 191 for len(data) > 0 && data[0] == ' ' { 192 data = data[1:] 193 } 194 195 // Trim tail after and including the first null byte. 196 for i, c := range data { 197 if c == '\x00' { 198 data = data[:i] 199 break 200 } 201 } 202 203 return string(data) 204 } 205 206 func appendBytes(b []byte, args ...uint32) []byte { 207 for _, arg := range args { 208 b = append(b, 209 byte((arg >> 0)), 210 byte((arg >> 8)), 211 byte((arg >> 16)), 212 byte((arg >> 24))) 213 } 214 return b 215 }