|  | // Copyright 2017 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | // +build 386 amd64 | 
|  |  | 
|  | package cpu | 
|  |  | 
|  | const CacheLinePadSize = 64 | 
|  |  | 
|  | // cpuid is implemented in cpu_x86.s. | 
|  | func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) | 
|  |  | 
|  | // xgetbv with ecx = 0 is implemented in cpu_x86.s. | 
|  | func xgetbv() (eax, edx uint32) | 
|  |  | 
|  | const ( | 
|  | // edx bits | 
|  | cpuid_SSE2 = 1 << 26 | 
|  |  | 
|  | // ecx bits | 
|  | cpuid_SSE3      = 1 << 0 | 
|  | cpuid_PCLMULQDQ = 1 << 1 | 
|  | cpuid_SSSE3     = 1 << 9 | 
|  | cpuid_FMA       = 1 << 12 | 
|  | cpuid_SSE41     = 1 << 19 | 
|  | cpuid_SSE42     = 1 << 20 | 
|  | cpuid_POPCNT    = 1 << 23 | 
|  | cpuid_AES       = 1 << 25 | 
|  | cpuid_OSXSAVE   = 1 << 27 | 
|  | cpuid_AVX       = 1 << 28 | 
|  |  | 
|  | // ebx bits | 
|  | cpuid_BMI1 = 1 << 3 | 
|  | cpuid_AVX2 = 1 << 5 | 
|  | cpuid_BMI2 = 1 << 8 | 
|  | cpuid_ERMS = 1 << 9 | 
|  | cpuid_ADX  = 1 << 19 | 
|  | ) | 
|  |  | 
|  | func doinit() { | 
|  | options = []option{ | 
|  | {Name: "adx", Feature: &X86.HasADX}, | 
|  | {Name: "aes", Feature: &X86.HasAES}, | 
|  | {Name: "avx", Feature: &X86.HasAVX}, | 
|  | {Name: "avx2", Feature: &X86.HasAVX2}, | 
|  | {Name: "bmi1", Feature: &X86.HasBMI1}, | 
|  | {Name: "bmi2", Feature: &X86.HasBMI2}, | 
|  | {Name: "erms", Feature: &X86.HasERMS}, | 
|  | {Name: "fma", Feature: &X86.HasFMA}, | 
|  | {Name: "pclmulqdq", Feature: &X86.HasPCLMULQDQ}, | 
|  | {Name: "popcnt", Feature: &X86.HasPOPCNT}, | 
|  | {Name: "sse3", Feature: &X86.HasSSE3}, | 
|  | {Name: "sse41", Feature: &X86.HasSSE41}, | 
|  | {Name: "sse42", Feature: &X86.HasSSE42}, | 
|  | {Name: "ssse3", Feature: &X86.HasSSSE3}, | 
|  |  | 
|  | // These capabilities should always be enabled on amd64: | 
|  | {Name: "sse2", Feature: &X86.HasSSE2, Required: GOARCH == "amd64"}, | 
|  | } | 
|  |  | 
|  | maxID, _, _, _ := cpuid(0, 0) | 
|  |  | 
|  | if maxID < 1 { | 
|  | return | 
|  | } | 
|  |  | 
|  | _, _, ecx1, edx1 := cpuid(1, 0) | 
|  | X86.HasSSE2 = isSet(edx1, cpuid_SSE2) | 
|  |  | 
|  | X86.HasSSE3 = isSet(ecx1, cpuid_SSE3) | 
|  | X86.HasPCLMULQDQ = isSet(ecx1, cpuid_PCLMULQDQ) | 
|  | X86.HasSSSE3 = isSet(ecx1, cpuid_SSSE3) | 
|  | X86.HasFMA = isSet(ecx1, cpuid_FMA) | 
|  | X86.HasSSE41 = isSet(ecx1, cpuid_SSE41) | 
|  | X86.HasSSE42 = isSet(ecx1, cpuid_SSE42) | 
|  | X86.HasPOPCNT = isSet(ecx1, cpuid_POPCNT) | 
|  | X86.HasAES = isSet(ecx1, cpuid_AES) | 
|  | X86.HasOSXSAVE = isSet(ecx1, cpuid_OSXSAVE) | 
|  |  | 
|  | osSupportsAVX := false | 
|  | // For XGETBV, OSXSAVE bit is required and sufficient. | 
|  | if X86.HasOSXSAVE { | 
|  | eax, _ := xgetbv() | 
|  | // Check if XMM and YMM registers have OS support. | 
|  | osSupportsAVX = isSet(eax, 1<<1) && isSet(eax, 1<<2) | 
|  | } | 
|  |  | 
|  | X86.HasAVX = isSet(ecx1, cpuid_AVX) && osSupportsAVX | 
|  |  | 
|  | if maxID < 7 { | 
|  | return | 
|  | } | 
|  |  | 
|  | _, ebx7, _, _ := cpuid(7, 0) | 
|  | X86.HasBMI1 = isSet(ebx7, cpuid_BMI1) | 
|  | X86.HasAVX2 = isSet(ebx7, cpuid_AVX2) && osSupportsAVX | 
|  | X86.HasBMI2 = isSet(ebx7, cpuid_BMI2) | 
|  | X86.HasERMS = isSet(ebx7, cpuid_ERMS) | 
|  | X86.HasADX = isSet(ebx7, cpuid_ADX) | 
|  | } | 
|  |  | 
|  | func isSet(hwc uint32, value uint32) bool { | 
|  | return hwc&value != 0 | 
|  | } |