github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/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 // +build 386 amd64 7 8 package cpu 9 10 const CacheLinePadSize = 64 11 12 // cpuid is implemented in cpu_x86.s. 13 func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) 14 15 // xgetbv with ecx = 0 is implemented in cpu_x86.s. 16 func xgetbv() (eax, edx uint32) 17 18 const ( 19 // edx bits 20 cpuid_SSE2 = 1 << 26 21 22 // ecx bits 23 cpuid_SSE3 = 1 << 0 24 cpuid_PCLMULQDQ = 1 << 1 25 cpuid_SSSE3 = 1 << 9 26 cpuid_FMA = 1 << 12 27 cpuid_SSE41 = 1 << 19 28 cpuid_SSE42 = 1 << 20 29 cpuid_POPCNT = 1 << 23 30 cpuid_AES = 1 << 25 31 cpuid_OSXSAVE = 1 << 27 32 cpuid_AVX = 1 << 28 33 34 // ebx bits 35 cpuid_BMI1 = 1 << 3 36 cpuid_AVX2 = 1 << 5 37 cpuid_BMI2 = 1 << 8 38 cpuid_ERMS = 1 << 9 39 cpuid_ADX = 1 << 19 40 ) 41 42 var maxExtendedFunctionInformation uint32 43 44 func doinit() { 45 options = []option{ 46 {Name: "adx", Feature: &X86.HasADX}, 47 {Name: "aes", Feature: &X86.HasAES}, 48 {Name: "avx", Feature: &X86.HasAVX}, 49 {Name: "avx2", Feature: &X86.HasAVX2}, 50 {Name: "bmi1", Feature: &X86.HasBMI1}, 51 {Name: "bmi2", Feature: &X86.HasBMI2}, 52 {Name: "erms", Feature: &X86.HasERMS}, 53 {Name: "fma", Feature: &X86.HasFMA}, 54 {Name: "pclmulqdq", Feature: &X86.HasPCLMULQDQ}, 55 {Name: "popcnt", Feature: &X86.HasPOPCNT}, 56 {Name: "sse3", Feature: &X86.HasSSE3}, 57 {Name: "sse41", Feature: &X86.HasSSE41}, 58 {Name: "sse42", Feature: &X86.HasSSE42}, 59 {Name: "ssse3", Feature: &X86.HasSSSE3}, 60 61 // These capabilities should always be enabled on amd64: 62 {Name: "sse2", Feature: &X86.HasSSE2, Required: GOARCH == "amd64"}, 63 } 64 65 maxID, _, _, _ := cpuid(0, 0) 66 67 if maxID < 1 { 68 return 69 } 70 71 maxExtendedFunctionInformation, _, _, _ = cpuid(0x80000000, 0) 72 73 _, _, ecx1, edx1 := cpuid(1, 0) 74 X86.HasSSE2 = isSet(edx1, cpuid_SSE2) 75 76 X86.HasSSE3 = isSet(ecx1, cpuid_SSE3) 77 X86.HasPCLMULQDQ = isSet(ecx1, cpuid_PCLMULQDQ) 78 X86.HasSSSE3 = isSet(ecx1, cpuid_SSSE3) 79 X86.HasSSE41 = isSet(ecx1, cpuid_SSE41) 80 X86.HasSSE42 = isSet(ecx1, cpuid_SSE42) 81 X86.HasPOPCNT = isSet(ecx1, cpuid_POPCNT) 82 X86.HasAES = isSet(ecx1, cpuid_AES) 83 84 // OSXSAVE can be false when using older Operating Systems 85 // or when explicitly disabled on newer Operating Systems by 86 // e.g. setting the xsavedisable boot option on Windows 10. 87 X86.HasOSXSAVE = isSet(ecx1, cpuid_OSXSAVE) 88 89 // The FMA instruction set extension only has VEX prefixed instructions. 90 // VEX prefixed instructions require OSXSAVE to be enabled. 91 // See Intel 64 and IA-32 Architecture Software Developer’s Manual Volume 2 92 // Section 2.4 "AVX and SSE Instruction Exception Specification" 93 X86.HasFMA = isSet(ecx1, cpuid_FMA) && X86.HasOSXSAVE 94 95 osSupportsAVX := false 96 // For XGETBV, OSXSAVE bit is required and sufficient. 97 if X86.HasOSXSAVE { 98 eax, _ := xgetbv() 99 // Check if XMM and YMM registers have OS support. 100 osSupportsAVX = isSet(eax, 1<<1) && isSet(eax, 1<<2) 101 } 102 103 X86.HasAVX = isSet(ecx1, cpuid_AVX) && osSupportsAVX 104 105 if maxID < 7 { 106 return 107 } 108 109 _, ebx7, _, _ := cpuid(7, 0) 110 X86.HasBMI1 = isSet(ebx7, cpuid_BMI1) 111 X86.HasAVX2 = isSet(ebx7, cpuid_AVX2) && osSupportsAVX 112 X86.HasBMI2 = isSet(ebx7, cpuid_BMI2) 113 X86.HasERMS = isSet(ebx7, cpuid_ERMS) 114 X86.HasADX = isSet(ebx7, cpuid_ADX) 115 } 116 117 func isSet(hwc uint32, value uint32) bool { 118 return hwc&value != 0 119 } 120 121 // Name returns the CPU name given by the vendor. 122 // If the CPU name can not be determined an 123 // empty string is returned. 124 func Name() string { 125 if maxExtendedFunctionInformation < 0x80000004 { 126 return "" 127 } 128 129 data := make([]byte, 0, 3*4*4) 130 131 var eax, ebx, ecx, edx uint32 132 eax, ebx, ecx, edx = cpuid(0x80000002, 0) 133 data = appendBytes(data, eax, ebx, ecx, edx) 134 eax, ebx, ecx, edx = cpuid(0x80000003, 0) 135 data = appendBytes(data, eax, ebx, ecx, edx) 136 eax, ebx, ecx, edx = cpuid(0x80000004, 0) 137 data = appendBytes(data, eax, ebx, ecx, edx) 138 139 // Trim leading spaces. 140 for len(data) > 0 && data[0] == ' ' { 141 data = data[1:] 142 } 143 144 // Trim tail after and including the first null byte. 145 for i, c := range data { 146 if c == '\x00' { 147 data = data[:i] 148 break 149 } 150 } 151 152 return string(data) 153 } 154 155 func appendBytes(b []byte, args ...uint32) []byte { 156 for _, arg := range args { 157 b = append(b, 158 byte((arg >> 0)), 159 byte((arg >> 8)), 160 byte((arg >> 16)), 161 byte((arg >> 24))) 162 } 163 return b 164 }