From: Carlos Eduardo Seo Date: Mon, 10 Jul 2017 18:28:27 +0000 (-0300) Subject: runtime, internal/cpu: CPU capabilities detection for ppc64x X-Git-Tag: go1.10beta1~1606 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=6661cf6dfd91dc3dd5d233e8bdb9f2d60829c68e;p=gostls13.git runtime, internal/cpu: CPU capabilities detection for ppc64x This change replaces the current runtime capabilities check for ppc64x with the new internal/cpu package. It also adds support for the new POWER9 ISA and capabilities. Updates #15403 Change-Id: I5b64a79e782f8da3603e5529600434f602986292 Reviewed-on: https://go-review.googlesource.com/53830 Reviewed-by: Martin Möhrmann --- diff --git a/src/internal/cpu/cpu.go b/src/internal/cpu/cpu.go index 2226b777e2..6a8e23d425 100644 --- a/src/internal/cpu/cpu.go +++ b/src/internal/cpu/cpu.go @@ -30,3 +30,28 @@ type x86 struct { HasSSE42 bool _ [CacheLineSize]byte } + +var PPC64 ppc64 + +// For ppc64x, it is safe to check only for ISA level starting on ISA v3.00, +// since there are no optional categories. There are some exceptions that also +// require kernel support to work (darn, scv), so there are capability bits for +// those as well. The minimum processor requirement is POWER8 (ISA 2.07), so we +// maintain some of the old capability checks for optional categories for +// safety. +// The struct is padded to avoid false sharing. +type ppc64 struct { + _ [CacheLineSize]byte + HasVMX bool // Vector unit (Altivec) + HasDFP bool // Decimal Floating Point unit + HasVSX bool // Vector-scalar unit + HasHTM bool // Hardware Transactional Memory + HasISEL bool // Integer select + HasVCRYPTO bool // Vector cryptography + HasHTMNOSC bool // HTM: kernel-aborted transaction in syscalls + HasDARN bool // Hardware random number generator (requires kernel enablement) + HasSCV bool // Syscall vectored (requires kernel enablement) + IsPOWER8 bool // ISA v2.07 (POWER8) + IsPOWER9 bool // ISA v3.00 (POWER9) + _ [CacheLineSize]byte +} diff --git a/src/internal/cpu/cpu_ppc64.go b/src/internal/cpu/cpu_ppc64.go deleted file mode 100644 index 5b15150847..0000000000 --- a/src/internal/cpu/cpu_ppc64.go +++ /dev/null @@ -1,7 +0,0 @@ -// 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. - -package cpu - -const CacheLineSize = 128 diff --git a/src/internal/cpu/cpu_ppc64le.go b/src/internal/cpu/cpu_ppc64le.go deleted file mode 100644 index 5b15150847..0000000000 --- a/src/internal/cpu/cpu_ppc64le.go +++ /dev/null @@ -1,7 +0,0 @@ -// 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. - -package cpu - -const CacheLineSize = 128 diff --git a/src/internal/cpu/cpu_ppc64x.go b/src/internal/cpu/cpu_ppc64x.go new file mode 100644 index 0000000000..7f093723b2 --- /dev/null +++ b/src/internal/cpu/cpu_ppc64x.go @@ -0,0 +1,54 @@ +// 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 ppc64 ppc64le + +package cpu + +const CacheLineSize = 128 + +// ppc64x doesn't have a 'cpuid' equivalent, so we rely on HWCAP/HWCAP2. +// These are linknamed in runtime/os_linux_ppc64x.go and are initialized by +// archauxv(). +var ppc64x_hwcap uint +var ppc64x_hwcap2 uint + +// HWCAP/HWCAP2 bits. These are exposed by the kernel. +const ( + // ISA Level + _PPC_FEATURE2_ARCH_2_07 = 0x80000000 + _PPC_FEATURE2_ARCH_3_00 = 0x00800000 + + // CPU features + _PPC_FEATURE_HAS_ALTIVEC = 0x10000000 + _PPC_FEATURE_HAS_DFP = 0x00000400 + _PPC_FEATURE_HAS_VSX = 0x00000080 + _PPC_FEATURE2_HAS_HTM = 0x40000000 + _PPC_FEATURE2_HAS_ISEL = 0x08000000 + _PPC_FEATURE2_HAS_VEC_CRYPTO = 0x02000000 + _PPC_FEATURE2_HTM_NOSC = 0x01000000 + _PPC_FEATURE2_DARN = 0x00200000 + _PPC_FEATURE2_SCV = 0x00100000 +) + +func init() { + // HWCAP feature bits + PPC64.HasVMX = isSet(ppc64x_hwcap, _PPC_FEATURE_HAS_ALTIVEC) + PPC64.HasDFP = isSet(ppc64x_hwcap, _PPC_FEATURE_HAS_DFP) + PPC64.HasVSX = isSet(ppc64x_hwcap, _PPC_FEATURE_HAS_VSX) + + // HWCAP2 feature bits + PPC64.IsPOWER8 = isSet(ppc64x_hwcap2, _PPC_FEATURE2_ARCH_2_07) + PPC64.HasHTM = isSet(ppc64x_hwcap2, _PPC_FEATURE2_HAS_HTM) + PPC64.HasISEL = isSet(ppc64x_hwcap2, _PPC_FEATURE2_HAS_ISEL) + PPC64.HasVCRYPTO = isSet(ppc64x_hwcap2, _PPC_FEATURE2_HAS_VEC_CRYPTO) + PPC64.HasHTMNOSC = isSet(ppc64x_hwcap2, _PPC_FEATURE2_HTM_NOSC) + PPC64.IsPOWER9 = isSet(ppc64x_hwcap2, _PPC_FEATURE2_ARCH_3_00) + PPC64.HasDARN = isSet(ppc64x_hwcap2, _PPC_FEATURE2_DARN) + PPC64.HasSCV = isSet(ppc64x_hwcap2, _PPC_FEATURE2_SCV) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 +} diff --git a/src/internal/cpu/cpu_test.go b/src/internal/cpu/cpu_test.go index ab9836ac2f..07b0243f30 100644 --- a/src/internal/cpu/cpu_test.go +++ b/src/internal/cpu/cpu_test.go @@ -25,3 +25,26 @@ func TestAVX2hasAVX(t *testing.T) { } } } + +func TestPPC64minimalFeatures(t *testing.T) { + if runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" { + if !cpu.PPC64.IsPOWER8 { + t.Fatalf("IsPOWER8 expected true, got false") + } + if !cpu.PPC64.HasVMX { + t.Fatalf("HasVMX expected true, got false") + } + if !cpu.PPC64.HasDFP { + t.Fatalf("HasDFP expected true, got false") + } + if !cpu.PPC64.HasVSX { + t.Fatalf("HasVSX expected true, got false") + } + if !cpu.PPC64.HasISEL { + t.Fatalf("HasISEL expected true, got false") + } + if !cpu.PPC64.HasVCRYPTO { + t.Fatalf("HasVCRYPTO expected true, got false") + } + } +} diff --git a/src/runtime/os_linux_ppc64x.go b/src/runtime/os_linux_ppc64x.go index b0da98b0bd..e37bfc453a 100644 --- a/src/runtime/os_linux_ppc64x.go +++ b/src/runtime/os_linux_ppc64x.go @@ -6,55 +6,22 @@ package runtime -import ( - "runtime/internal/sys" -) +// For go:linkname +import _ "unsafe" -const ( - // ISA level - // Go currently requires POWER5 as a minimum for ppc64, so we need - // to check for ISA 2.03 and beyond. - _PPC_FEATURE_POWER5_PLUS = 0x00020000 // ISA 2.03 (POWER5+) - _PPC_FEATURE_ARCH_2_05 = 0x00001000 // ISA 2.05 (POWER6) - _PPC_FEATURE_POWER6_EXT = 0x00000200 // mffgpr/mftgpr extension (POWER6x) - _PPC_FEATURE_ARCH_2_06 = 0x00000100 // ISA 2.06 (POWER7) - _PPC_FEATURE2_ARCH_2_07 = 0x80000000 // ISA 2.07 (POWER8) +// ppc64x doesn't have a 'cpuid' instruction equivalent and relies on +// HWCAP/HWCAP2 bits for hardware capabilities. - // Standalone capabilities - _PPC_FEATURE_HAS_ALTIVEC = 0x10000000 // SIMD/Vector unit - _PPC_FEATURE_HAS_VSX = 0x00000080 // Vector scalar unit -) - -type facilities struct { - _ [sys.CacheLineSize]byte - isPOWER5x bool // ISA 2.03 - isPOWER6 bool // ISA 2.05 - isPOWER6x bool // ISA 2.05 + mffgpr/mftgpr extension - isPOWER7 bool // ISA 2.06 - isPOWER8 bool // ISA 2.07 - hasVMX bool // Vector unit - hasVSX bool // Vector scalar unit - _ [sys.CacheLineSize]byte -} - -// cpu can be tested at runtime in go assembler code to check for -// a certain ISA level or hardware capability, for example: -// ·cpu+facilities_hasVSX(SB) for checking the availability of VSX -// or -// ·cpu+facilities_isPOWER7(SB) for checking if the processor implements -// ISA 2.06 instructions. -var cpu facilities +//go:linkname cpu_hwcap internal/cpu.ppc64x_hwcap +//go:linkname cpu_hwcap2 internal/cpu.ppc64x_hwcap2 +var cpu_hwcap uint +var cpu_hwcap2 uint func archauxv(tag, val uintptr) { switch tag { case _AT_HWCAP: - cpu.isPOWER5x = val&_PPC_FEATURE_POWER5_PLUS != 0 - cpu.isPOWER6 = val&_PPC_FEATURE_ARCH_2_05 != 0 - cpu.isPOWER6x = val&_PPC_FEATURE_POWER6_EXT != 0 - cpu.isPOWER7 = val&_PPC_FEATURE_ARCH_2_06 != 0 - cpu.hasVMX = val&_PPC_FEATURE_HAS_ALTIVEC != 0 - cpu.hasVSX = val&_PPC_FEATURE_HAS_VSX != 0 + cpu_hwcap = uint(val) case _AT_HWCAP2: - cpu.isPOWER8 = val&_PPC_FEATURE2_ARCH_2_07 != 0 + cpu_hwcap2 = uint(val) } }