github.com/JimmyHuang454/JLS-go@v0.0.0-20230831150107-90d536585ba0/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_ADX = 1 << 19 42 cpuid_SHA = 1 << 29 43 44 // edx bits for CPUID 0x80000001 45 cpuid_RDTSCP = 1 << 27 46 ) 47 48 var maxExtendedFunctionInformation uint32 49 50 func doinit() { 51 options = []option{ 52 {Name: "adx", Feature: &X86.HasADX}, 53 {Name: "aes", Feature: &X86.HasAES}, 54 {Name: "erms", Feature: &X86.HasERMS}, 55 {Name: "pclmulqdq", Feature: &X86.HasPCLMULQDQ}, 56 {Name: "rdtscp", Feature: &X86.HasRDTSCP}, 57 {Name: "sha", Feature: &X86.HasSHA}, 58 } 59 level := getGOAMD64level() 60 if level < 2 { 61 // These options are required at level 2. At lower levels 62 // they can be turned off. 63 options = append(options, 64 option{Name: "popcnt", Feature: &X86.HasPOPCNT}, 65 option{Name: "sse3", Feature: &X86.HasSSE3}, 66 option{Name: "sse41", Feature: &X86.HasSSE41}, 67 option{Name: "sse42", Feature: &X86.HasSSE42}, 68 option{Name: "ssse3", Feature: &X86.HasSSSE3}) 69 } 70 if level < 3 { 71 // These options are required at level 3. At lower levels 72 // they can be turned off. 73 options = append(options, 74 option{Name: "avx", Feature: &X86.HasAVX}, 75 option{Name: "avx2", Feature: &X86.HasAVX2}, 76 option{Name: "bmi1", Feature: &X86.HasBMI1}, 77 option{Name: "bmi2", Feature: &X86.HasBMI2}, 78 option{Name: "fma", Feature: &X86.HasFMA}) 79 } 80 81 maxID, _, _, _ := cpuid(0, 0) 82 83 if maxID < 1 { 84 return 85 } 86 87 maxExtendedFunctionInformation, _, _, _ = cpuid(0x80000000, 0) 88 89 _, _, ecx1, _ := cpuid(1, 0) 90 91 X86.HasSSE3 = isSet(ecx1, cpuid_SSE3) 92 X86.HasPCLMULQDQ = isSet(ecx1, cpuid_PCLMULQDQ) 93 X86.HasSSSE3 = isSet(ecx1, cpuid_SSSE3) 94 X86.HasSSE41 = isSet(ecx1, cpuid_SSE41) 95 X86.HasSSE42 = isSet(ecx1, cpuid_SSE42) 96 X86.HasPOPCNT = isSet(ecx1, cpuid_POPCNT) 97 X86.HasAES = isSet(ecx1, cpuid_AES) 98 99 // OSXSAVE can be false when using older Operating Systems 100 // or when explicitly disabled on newer Operating Systems by 101 // e.g. setting the xsavedisable boot option on Windows 10. 102 X86.HasOSXSAVE = isSet(ecx1, cpuid_OSXSAVE) 103 104 // The FMA instruction set extension only has VEX prefixed instructions. 105 // VEX prefixed instructions require OSXSAVE to be enabled. 106 // See Intel 64 and IA-32 Architecture Software Developer’s Manual Volume 2 107 // Section 2.4 "AVX and SSE Instruction Exception Specification" 108 X86.HasFMA = isSet(ecx1, cpuid_FMA) && X86.HasOSXSAVE 109 110 osSupportsAVX := false 111 // For XGETBV, OSXSAVE bit is required and sufficient. 112 if X86.HasOSXSAVE { 113 eax, _ := xgetbv() 114 // Check if XMM and YMM registers have OS support. 115 osSupportsAVX = isSet(eax, 1<<1) && isSet(eax, 1<<2) 116 } 117 118 X86.HasAVX = isSet(ecx1, cpuid_AVX) && osSupportsAVX 119 120 if maxID < 7 { 121 return 122 } 123 124 _, ebx7, _, _ := cpuid(7, 0) 125 X86.HasBMI1 = isSet(ebx7, cpuid_BMI1) 126 X86.HasAVX2 = isSet(ebx7, cpuid_AVX2) && osSupportsAVX 127 X86.HasBMI2 = isSet(ebx7, cpuid_BMI2) 128 X86.HasERMS = isSet(ebx7, cpuid_ERMS) 129 X86.HasADX = isSet(ebx7, cpuid_ADX) 130 X86.HasSHA = isSet(ebx7, cpuid_SHA) 131 132 var maxExtendedInformation uint32 133 maxExtendedInformation, _, _, _ = cpuid(0x80000000, 0) 134 135 if maxExtendedInformation < 0x80000001 { 136 return 137 } 138 139 _, _, _, edxExt1 := cpuid(0x80000001, 0) 140 X86.HasRDTSCP = isSet(edxExt1, cpuid_RDTSCP) 141 } 142 143 func isSet(hwc uint32, value uint32) bool { 144 return hwc&value != 0 145 } 146 147 // Name returns the CPU name given by the vendor. 148 // If the CPU name can not be determined an 149 // empty string is returned. 150 func Name() string { 151 if maxExtendedFunctionInformation < 0x80000004 { 152 return "" 153 } 154 155 data := make([]byte, 0, 3*4*4) 156 157 var eax, ebx, ecx, edx uint32 158 eax, ebx, ecx, edx = cpuid(0x80000002, 0) 159 data = appendBytes(data, eax, ebx, ecx, edx) 160 eax, ebx, ecx, edx = cpuid(0x80000003, 0) 161 data = appendBytes(data, eax, ebx, ecx, edx) 162 eax, ebx, ecx, edx = cpuid(0x80000004, 0) 163 data = appendBytes(data, eax, ebx, ecx, edx) 164 165 // Trim leading spaces. 166 for len(data) > 0 && data[0] == ' ' { 167 data = data[1:] 168 } 169 170 // Trim tail after and including the first null byte. 171 for i, c := range data { 172 if c == '\x00' { 173 data = data[:i] 174 break 175 } 176 } 177 178 return string(data) 179 } 180 181 func appendBytes(b []byte, args ...uint32) []byte { 182 for _, arg := range args { 183 b = append(b, 184 byte((arg >> 0)), 185 byte((arg >> 8)), 186 byte((arg >> 16)), 187 byte((arg >> 24))) 188 } 189 return b 190 }