diff options
author | Ian Lance Taylor <iant@golang.org> | 2018-09-24 21:46:21 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2018-09-24 21:46:21 +0000 |
commit | dd931d9b48647e898dc80927c532ae93cc09e192 (patch) | |
tree | 71be2295cd79b8a182f6130611658db8628772d5 /libgo/go/internal/cpu | |
parent | 779d8a5ad09b01428726ea5a0e6c87bd9ac3c0e4 (diff) | |
download | gcc-dd931d9b48647e898dc80927c532ae93cc09e192.zip gcc-dd931d9b48647e898dc80927c532ae93cc09e192.tar.gz gcc-dd931d9b48647e898dc80927c532ae93cc09e192.tar.bz2 |
libgo: update to Go 1.11
Reviewed-on: https://go-review.googlesource.com/136435
gotools/:
* Makefile.am (mostlyclean-local): Run chmod on check-go-dir to
make sure it is writable.
(check-go-tools): Likewise.
(check-vet): Copy internal/objabi to check-vet-dir.
* Makefile.in: Rebuild.
From-SVN: r264546
Diffstat (limited to 'libgo/go/internal/cpu')
-rw-r--r-- | libgo/go/internal/cpu/cpu.go | 142 | ||||
-rw-r--r-- | libgo/go/internal/cpu/cpu_386.go | 7 | ||||
-rw-r--r-- | libgo/go/internal/cpu/cpu_amd64.go | 7 | ||||
-rw-r--r-- | libgo/go/internal/cpu/cpu_amd64p32.go | 7 | ||||
-rw-r--r-- | libgo/go/internal/cpu/cpu_arm64.go | 107 | ||||
-rw-r--r-- | libgo/go/internal/cpu/cpu_arm64_test.go | 26 | ||||
-rw-r--r-- | libgo/go/internal/cpu/cpu_gccgo.c | 66 | ||||
-rw-r--r-- | libgo/go/internal/cpu/cpu_no_init.go | 16 | ||||
-rw-r--r-- | libgo/go/internal/cpu/cpu_ppc64x.go | 46 | ||||
-rw-r--r-- | libgo/go/internal/cpu/cpu_ppc64x_test.go | 33 | ||||
-rw-r--r-- | libgo/go/internal/cpu/cpu_s390x.go | 146 | ||||
-rw-r--r-- | libgo/go/internal/cpu/cpu_s390x_test.go | 63 | ||||
-rw-r--r-- | libgo/go/internal/cpu/cpu_test.go | 68 | ||||
-rw-r--r-- | libgo/go/internal/cpu/cpu_wasm.go | 7 | ||||
-rw-r--r-- | libgo/go/internal/cpu/cpu_x86.go | 91 | ||||
-rw-r--r-- | libgo/go/internal/cpu/cpu_x86_test.go | 47 | ||||
-rw-r--r-- | libgo/go/internal/cpu/export_test.go | 9 |
17 files changed, 782 insertions, 106 deletions
diff --git a/libgo/go/internal/cpu/cpu.go b/libgo/go/internal/cpu/cpu.go index 22fc561..9567a4f 100644 --- a/libgo/go/internal/cpu/cpu.go +++ b/libgo/go/internal/cpu/cpu.go @@ -6,6 +6,11 @@ // used by the Go standard library. package cpu +// DebugOptions is set to true by the runtime if go was compiled with GOEXPERIMENT=debugcpu +// and GOOS is Linux or Darwin. +// This should not be changed after it is initialized. +var DebugOptions bool + var X86 x86 // The booleans in x86 contain the correspondingly named cpuid feature bit. @@ -37,9 +42,9 @@ 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 +// require kernel support to work (darn, scv), so there are feature 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 +// maintain some of the old feature checks for optional categories for // safety. // The struct is padded to avoid false sharing. type ppc64 struct { @@ -63,15 +68,126 @@ var ARM64 arm64 // The booleans in arm64 contain the correspondingly named cpu feature bit. // The struct is padded to avoid false sharing. type arm64 struct { - _ [CacheLineSize]byte - HasFP bool - HasASIMD bool - HasEVTSTRM bool - HasAES bool - HasPMULL bool - HasSHA1 bool - HasSHA2 bool - HasCRC32 bool - HasATOMICS bool - _ [CacheLineSize]byte + _ [CacheLineSize]byte + HasFP bool + HasASIMD bool + HasEVTSTRM bool + HasAES bool + HasPMULL bool + HasSHA1 bool + HasSHA2 bool + HasCRC32 bool + HasATOMICS bool + HasFPHP bool + HasASIMDHP bool + HasCPUID bool + HasASIMDRDM bool + HasJSCVT bool + HasFCMA bool + HasLRCPC bool + HasDCPOP bool + HasSHA3 bool + HasSM3 bool + HasSM4 bool + HasASIMDDP bool + HasSHA512 bool + HasSVE bool + HasASIMDFHM bool + _ [CacheLineSize]byte +} + +var S390X s390x + +type s390x struct { + _ [CacheLineSize]byte + HasZArch bool // z architecture mode is active [mandatory] + HasSTFLE bool // store facility list extended [mandatory] + HasLDisp bool // long (20-bit) displacements [mandatory] + HasEImm bool // 32-bit immediates [mandatory] + HasDFP bool // decimal floating point + HasETF3Enhanced bool // ETF-3 enhanced + HasMSA bool // message security assist (CPACF) + HasAES bool // KM-AES{128,192,256} functions + HasAESCBC bool // KMC-AES{128,192,256} functions + HasAESCTR bool // KMCTR-AES{128,192,256} functions + HasAESGCM bool // KMA-GCM-AES{128,192,256} functions + HasGHASH bool // KIMD-GHASH function + HasSHA1 bool // K{I,L}MD-SHA-1 functions + HasSHA256 bool // K{I,L}MD-SHA-256 functions + HasSHA512 bool // K{I,L}MD-SHA-512 functions + HasVX bool // vector facility. Note: the runtime sets this when it processes auxv records. + _ [CacheLineSize]byte +} + +// Initialize examines the processor and sets the relevant variables above. +// This is called by the runtime package early in program initialization, +// before normal init functions are run. env is set by runtime on Linux and Darwin +// if go was compiled with GOEXPERIMENT=debugcpu. +func Initialize(env string) { + doinit() + processOptions(env) +} + +// options contains the cpu debug options that can be used in GODEBUGCPU. +// Options are arch dependent and are added by the arch specific doinit functions. +// Features that are mandatory for the specific GOARCH should not be added to options +// (e.g. SSE2 on amd64). +var options []option + +// Option names should be lower case. e.g. avx instead of AVX. +type option struct { + Name string + Feature *bool +} + +// processOptions disables CPU feature values based on the parsed env string. +// The env string is expected to be of the form feature1=0,feature2=0... +// where feature names is one of the architecture specifc list stored in the +// cpu packages options variable. If env contains all=0 then all capabilities +// referenced through the options variable are disabled. Other feature +// names and values other than 0 are silently ignored. +func processOptions(env string) { +field: + for env != "" { + field := "" + i := indexByte(env, ',') + if i < 0 { + field, env = env, "" + } else { + field, env = env[:i], env[i+1:] + } + i = indexByte(field, '=') + if i < 0 { + continue + } + key, value := field[:i], field[i+1:] + + // Only allow turning off CPU features by specifying '0'. + if value == "0" { + if key == "all" { + for _, v := range options { + *v.Feature = false + } + return + } else { + for _, v := range options { + if v.Name == key { + *v.Feature = false + continue field + } + } + } + } + } +} + +// indexByte returns the index of the first instance of c in s, +// or -1 if c is not present in s. +func indexByte(s string, c byte) int { + for i := 0; i < len(s); i++ { + if s[i] == c { + return i + } + } + return -1 } diff --git a/libgo/go/internal/cpu/cpu_386.go b/libgo/go/internal/cpu/cpu_386.go new file mode 100644 index 0000000..561c81f --- /dev/null +++ b/libgo/go/internal/cpu/cpu_386.go @@ -0,0 +1,7 @@ +// Copyright 2018 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 GOARCH = "386" diff --git a/libgo/go/internal/cpu/cpu_amd64.go b/libgo/go/internal/cpu/cpu_amd64.go new file mode 100644 index 0000000..9b00153 --- /dev/null +++ b/libgo/go/internal/cpu/cpu_amd64.go @@ -0,0 +1,7 @@ +// Copyright 2018 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 GOARCH = "amd64" diff --git a/libgo/go/internal/cpu/cpu_amd64p32.go b/libgo/go/internal/cpu/cpu_amd64p32.go new file mode 100644 index 0000000..177b14e --- /dev/null +++ b/libgo/go/internal/cpu/cpu_amd64p32.go @@ -0,0 +1,7 @@ +// Copyright 2018 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 GOARCH = "amd64p32" diff --git a/libgo/go/internal/cpu/cpu_arm64.go b/libgo/go/internal/cpu/cpu_arm64.go index e1278a1..009f2a2 100644 --- a/libgo/go/internal/cpu/cpu_arm64.go +++ b/libgo/go/internal/cpu/cpu_arm64.go @@ -2,42 +2,99 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build arm64 - package cpu const CacheLineSize = 64 // arm64 doesn't have a 'cpuid' equivalent, so we rely on HWCAP/HWCAP2. -// These are linknamed in runtime/os_linux_arm64.go and are initialized by -// archauxv(). -var arm64_hwcap uint -var arm64_hwcap2 uint +// These are initialized by archauxv in runtime/os_linux_arm64.go. +// These should not be changed after they are initialized. +var HWCap uint +var HWCap2 uint // HWCAP/HWCAP2 bits. These are exposed by Linux. const ( - _ARM64_FEATURE_HAS_FP = (1 << 0) - _ARM64_FEATURE_HAS_ASIMD = (1 << 1) - _ARM64_FEATURE_HAS_EVTSTRM = (1 << 2) - _ARM64_FEATURE_HAS_AES = (1 << 3) - _ARM64_FEATURE_HAS_PMULL = (1 << 4) - _ARM64_FEATURE_HAS_SHA1 = (1 << 5) - _ARM64_FEATURE_HAS_SHA2 = (1 << 6) - _ARM64_FEATURE_HAS_CRC32 = (1 << 7) - _ARM64_FEATURE_HAS_ATOMICS = (1 << 8) + hwcap_FP = (1 << 0) + hwcap_ASIMD = (1 << 1) + hwcap_EVTSTRM = (1 << 2) + hwcap_AES = (1 << 3) + hwcap_PMULL = (1 << 4) + hwcap_SHA1 = (1 << 5) + hwcap_SHA2 = (1 << 6) + hwcap_CRC32 = (1 << 7) + hwcap_ATOMICS = (1 << 8) + hwcap_FPHP = (1 << 9) + hwcap_ASIMDHP = (1 << 10) + hwcap_CPUID = (1 << 11) + hwcap_ASIMDRDM = (1 << 12) + hwcap_JSCVT = (1 << 13) + hwcap_FCMA = (1 << 14) + hwcap_LRCPC = (1 << 15) + hwcap_DCPOP = (1 << 16) + hwcap_SHA3 = (1 << 17) + hwcap_SM3 = (1 << 18) + hwcap_SM4 = (1 << 19) + hwcap_ASIMDDP = (1 << 20) + hwcap_SHA512 = (1 << 21) + hwcap_SVE = (1 << 22) + hwcap_ASIMDFHM = (1 << 23) ) -func init() { +func doinit() { + options = []option{ + {"evtstrm", &ARM64.HasEVTSTRM}, + {"aes", &ARM64.HasAES}, + {"pmull", &ARM64.HasPMULL}, + {"sha1", &ARM64.HasSHA1}, + {"sha2", &ARM64.HasSHA2}, + {"crc32", &ARM64.HasCRC32}, + {"atomics", &ARM64.HasATOMICS}, + {"fphp", &ARM64.HasFPHP}, + {"asimdhp", &ARM64.HasASIMDHP}, + {"cpuid", &ARM64.HasCPUID}, + {"asimdrdm", &ARM64.HasASIMDRDM}, + {"jscvt", &ARM64.HasJSCVT}, + {"fcma", &ARM64.HasFCMA}, + {"lrcpc", &ARM64.HasLRCPC}, + {"dcpop", &ARM64.HasDCPOP}, + {"sha3", &ARM64.HasSHA3}, + {"sm3", &ARM64.HasSM3}, + {"sm4", &ARM64.HasSM4}, + {"asimddp", &ARM64.HasASIMDDP}, + {"sha512", &ARM64.HasSHA512}, + {"sve", &ARM64.HasSVE}, + {"asimdfhm", &ARM64.HasASIMDFHM}, + + // These capabilities should always be enabled on arm64: + // {"fp", &ARM64.HasFP}, + // {"asimd", &ARM64.HasASIMD}, + } + // HWCAP feature bits - ARM64.HasFP = isSet(arm64_hwcap, _ARM64_FEATURE_HAS_FP) - ARM64.HasASIMD = isSet(arm64_hwcap, _ARM64_FEATURE_HAS_ASIMD) - ARM64.HasEVTSTRM = isSet(arm64_hwcap, _ARM64_FEATURE_HAS_EVTSTRM) - ARM64.HasAES = isSet(arm64_hwcap, _ARM64_FEATURE_HAS_AES) - ARM64.HasPMULL = isSet(arm64_hwcap, _ARM64_FEATURE_HAS_PMULL) - ARM64.HasSHA1 = isSet(arm64_hwcap, _ARM64_FEATURE_HAS_SHA1) - ARM64.HasSHA2 = isSet(arm64_hwcap, _ARM64_FEATURE_HAS_SHA2) - ARM64.HasCRC32 = isSet(arm64_hwcap, _ARM64_FEATURE_HAS_CRC32) - ARM64.HasATOMICS = isSet(arm64_hwcap, _ARM64_FEATURE_HAS_ATOMICS) + ARM64.HasFP = isSet(HWCap, hwcap_FP) + ARM64.HasASIMD = isSet(HWCap, hwcap_ASIMD) + ARM64.HasEVTSTRM = isSet(HWCap, hwcap_EVTSTRM) + ARM64.HasAES = isSet(HWCap, hwcap_AES) + ARM64.HasPMULL = isSet(HWCap, hwcap_PMULL) + ARM64.HasSHA1 = isSet(HWCap, hwcap_SHA1) + ARM64.HasSHA2 = isSet(HWCap, hwcap_SHA2) + ARM64.HasCRC32 = isSet(HWCap, hwcap_CRC32) + ARM64.HasATOMICS = isSet(HWCap, hwcap_ATOMICS) + ARM64.HasFPHP = isSet(HWCap, hwcap_FPHP) + ARM64.HasASIMDHP = isSet(HWCap, hwcap_ASIMDHP) + ARM64.HasCPUID = isSet(HWCap, hwcap_CPUID) + ARM64.HasASIMDRDM = isSet(HWCap, hwcap_ASIMDRDM) + ARM64.HasJSCVT = isSet(HWCap, hwcap_JSCVT) + ARM64.HasFCMA = isSet(HWCap, hwcap_FCMA) + ARM64.HasLRCPC = isSet(HWCap, hwcap_LRCPC) + ARM64.HasDCPOP = isSet(HWCap, hwcap_DCPOP) + ARM64.HasSHA3 = isSet(HWCap, hwcap_SHA3) + ARM64.HasSM3 = isSet(HWCap, hwcap_SM3) + ARM64.HasSM4 = isSet(HWCap, hwcap_SM4) + ARM64.HasASIMDDP = isSet(HWCap, hwcap_ASIMDDP) + ARM64.HasSHA512 = isSet(HWCap, hwcap_SHA512) + ARM64.HasSVE = isSet(HWCap, hwcap_SVE) + ARM64.HasASIMDFHM = isSet(HWCap, hwcap_ASIMDFHM) } func isSet(hwc uint, value uint) bool { diff --git a/libgo/go/internal/cpu/cpu_arm64_test.go b/libgo/go/internal/cpu/cpu_arm64_test.go new file mode 100644 index 0000000..f4c419a --- /dev/null +++ b/libgo/go/internal/cpu/cpu_arm64_test.go @@ -0,0 +1,26 @@ +// Copyright 2018 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_test + +import ( + . "internal/cpu" + "runtime" + "testing" +) + +func TestARM64minimalFeatures(t *testing.T) { + switch runtime.GOOS { + case "linux", "android": + default: + t.Skipf("%s/arm64 is not supported", runtime.GOOS) + } + + if !ARM64.HasASIMD { + t.Fatalf("HasASIMD expected true, got false") + } + if !ARM64.HasFP { + t.Fatalf("HasFP expected true, got false") + } +} diff --git a/libgo/go/internal/cpu/cpu_gccgo.c b/libgo/go/internal/cpu/cpu_gccgo.c new file mode 100644 index 0000000..6625ddc --- /dev/null +++ b/libgo/go/internal/cpu/cpu_gccgo.c @@ -0,0 +1,66 @@ +// Copyright 2018 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. + +#include <stdint.h> + +#if defined(__i386__) || defined(__x86_64__) +#include <cpuid.h> +#include <x86intrin.h> +#endif + +#include "runtime.h" + +#if defined(__i386__) || defined(__x86_64__) + +struct cpuid_ret { + uint32_t eax; + uint32_t ebx; + uint32_t ecx; + uint32_t edx; +}; + +struct cpuid_ret cpuid(uint32_t, uint32_t) + __asm__(GOSYM_PREFIX "internal_cpu.cpuid") + __attribute__((no_split_stack)); + +struct cpuid_ret cpuid(uint32_t eaxArg, uint32_t ecxArg) { + unsigned int eax = 0; + unsigned int ebx = 0; + unsigned int ecx = 0; + unsigned int edx = 0; + struct cpuid_ret ret; + + __get_cpuid_count(eaxArg, ecxArg, &eax, &ebx, &ecx, &edx); + ret.eax = (uint32_t)(eax); + ret.ebx = (uint32_t)(ebx); + ret.ecx = (uint32_t)(ecx); + ret.edx = (uint32_t)(edx); + return ret; +} + +struct xgetbv_ret { + uint32_t eax; + uint32_t edx; +}; + +struct xgetbv_ret xgetbv(void) + __asm__(GOSYM_PREFIX "internal_cpu.xgetbv") + __attribute__((no_split_stack)); + +#pragma GCC push_options +#pragma GCC target("xsave") + +struct xgetbv_ret xgetbv(void) { + long long r; + struct xgetbv_ret ret; + + r = _xgetbv(0); + ret.eax = r & 0xffffffff; + ret.edx = r >> 32; + return ret; +} + +#pragma GCC pop_options + +#endif /* defined(__i386__) || defined(__x86_64__) */ diff --git a/libgo/go/internal/cpu/cpu_no_init.go b/libgo/go/internal/cpu/cpu_no_init.go new file mode 100644 index 0000000..1be4f29 --- /dev/null +++ b/libgo/go/internal/cpu/cpu_no_init.go @@ -0,0 +1,16 @@ +// Copyright 2018 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 +// +build !amd64 +// +build !amd64p32 +// +build !arm64 +// +build !ppc64 +// +build !ppc64le +// +build !s390x + +package cpu + +func doinit() { +} diff --git a/libgo/go/internal/cpu/cpu_ppc64x.go b/libgo/go/internal/cpu/cpu_ppc64x.go index 7f09372..d3f02ef 100644 --- a/libgo/go/internal/cpu/cpu_ppc64x.go +++ b/libgo/go/internal/cpu/cpu_ppc64x.go @@ -9,10 +9,10 @@ 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 +// These are initialized by archauxv in runtime/os_linux_ppc64x.go. +// These should not be changed after they are initialized. +var HWCap uint +var HWCap2 uint // HWCAP/HWCAP2 bits. These are exposed by the kernel. const ( @@ -32,21 +32,35 @@ const ( _PPC_FEATURE2_SCV = 0x00100000 ) -func init() { +func doinit() { + options = []option{ + {"htm", &PPC64.HasHTM}, + {"htmnosc", &PPC64.HasHTMNOSC}, + {"darn", &PPC64.HasDARN}, + {"scv", &PPC64.HasSCV}, + + // These capabilities should always be enabled on ppc64 and ppc64le: + // {"vmx", &PPC64.HasVMX}, + // {"dfp", &PPC64.HasDFP}, + // {"vsx", &PPC64.HasVSX}, + // {"isel", &PPC64.HasISEL}, + // {"vcrypto", &PPC64.HasVCRYPTO}, + } + // 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) + PPC64.HasVMX = isSet(HWCap, _PPC_FEATURE_HAS_ALTIVEC) + PPC64.HasDFP = isSet(HWCap, _PPC_FEATURE_HAS_DFP) + PPC64.HasVSX = isSet(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) + PPC64.IsPOWER8 = isSet(HWCap2, _PPC_FEATURE2_ARCH_2_07) + PPC64.HasHTM = isSet(HWCap2, _PPC_FEATURE2_HAS_HTM) + PPC64.HasISEL = isSet(HWCap2, _PPC_FEATURE2_HAS_ISEL) + PPC64.HasVCRYPTO = isSet(HWCap2, _PPC_FEATURE2_HAS_VEC_CRYPTO) + PPC64.HasHTMNOSC = isSet(HWCap2, _PPC_FEATURE2_HTM_NOSC) + PPC64.IsPOWER9 = isSet(HWCap2, _PPC_FEATURE2_ARCH_3_00) + PPC64.HasDARN = isSet(HWCap2, _PPC_FEATURE2_DARN) + PPC64.HasSCV = isSet(HWCap2, _PPC_FEATURE2_SCV) } func isSet(hwc uint, value uint) bool { diff --git a/libgo/go/internal/cpu/cpu_ppc64x_test.go b/libgo/go/internal/cpu/cpu_ppc64x_test.go new file mode 100644 index 0000000..9c43d1e --- /dev/null +++ b/libgo/go/internal/cpu/cpu_ppc64x_test.go @@ -0,0 +1,33 @@ +// Copyright 2018 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_test + +import ( + . "internal/cpu" + "testing" +) + +func TestPPC64minimalFeatures(t *testing.T) { + if !PPC64.IsPOWER8 { + t.Fatalf("IsPOWER8 expected true, got false") + } + if !PPC64.HasVMX { + t.Fatalf("HasVMX expected true, got false") + } + if !PPC64.HasDFP { + t.Fatalf("HasDFP expected true, got false") + } + if !PPC64.HasVSX { + t.Fatalf("HasVSX expected true, got false") + } + if !PPC64.HasISEL { + t.Fatalf("HasISEL expected true, got false") + } + if !PPC64.HasVCRYPTO { + t.Fatalf("HasVCRYPTO expected true, got false") + } +} diff --git a/libgo/go/internal/cpu/cpu_s390x.go b/libgo/go/internal/cpu/cpu_s390x.go index 4455809..9dedb4c 100644 --- a/libgo/go/internal/cpu/cpu_s390x.go +++ b/libgo/go/internal/cpu/cpu_s390x.go @@ -5,3 +5,149 @@ package cpu const CacheLineSize = 256 + +// bitIsSet reports whether the bit at index is set. The bit index +// is in big endian order, so bit index 0 is the leftmost bit. +func bitIsSet(bits []uint64, index uint) bool { + return bits[index/64]&((1<<63)>>(index%64)) != 0 +} + +// function is the function code for the named function. +type function uint8 + +const ( + // KM{,A,C,CTR} function codes + aes128 function = 18 // AES-128 + aes192 = 19 // AES-192 + aes256 = 20 // AES-256 + + // K{I,L}MD function codes + sha1 = 1 // SHA-1 + sha256 = 2 // SHA-256 + sha512 = 3 // SHA-512 + + // KLMD function codes + ghash = 65 // GHASH +) + +// queryResult contains the result of a Query function +// call. Bits are numbered in big endian order so the +// leftmost bit (the MSB) is at index 0. +type queryResult struct { + bits [2]uint64 +} + +// Has reports whether the given functions are present. +func (q *queryResult) Has(fns ...function) bool { + if len(fns) == 0 { + panic("no function codes provided") + } + for _, f := range fns { + if !bitIsSet(q.bits[:], uint(f)) { + return false + } + } + return true +} + +// facility is a bit index for the named facility. +type facility uint8 + +const ( + // mandatory facilities + zarch facility = 1 // z architecture mode is active + stflef = 7 // store-facility-list-extended + ldisp = 18 // long-displacement + eimm = 21 // extended-immediate + + // miscellaneous facilities + dfp = 42 // decimal-floating-point + etf3eh = 30 // extended-translation 3 enhancement + + // cryptography facilities + msa = 17 // message-security-assist + msa3 = 76 // message-security-assist extension 3 + msa4 = 77 // message-security-assist extension 4 + msa5 = 57 // message-security-assist extension 5 + msa8 = 146 // message-security-assist extension 8 + + // Note: vx and highgprs are excluded because they require + // kernel support and so must be fetched from HWCAP. +) + +// facilityList contains the result of an STFLE call. +// Bits are numbered in big endian order so the +// leftmost bit (the MSB) is at index 0. +type facilityList struct { + bits [4]uint64 +} + +// Has reports whether the given facilities are present. +func (s *facilityList) Has(fs ...facility) bool { + if len(fs) == 0 { + panic("no facility bits provided") + } + for _, f := range fs { + if !bitIsSet(s.bits[:], uint(f)) { + return false + } + } + return true +} + +// The following feature detection functions are defined in cpu_s390x.s. +// They are likely to be expensive to call so the results should be cached. +func stfle() facilityList { panic("not implemented for gccgo") } +func kmQuery() queryResult { panic("not implemented for gccgo") } +func kmcQuery() queryResult { panic("not implemented for gccgo") } +func kmctrQuery() queryResult { panic("not implemented for gccgo") } +func kmaQuery() queryResult { panic("not implemented for gccgo") } +func kimdQuery() queryResult { panic("not implemented for gccgo") } +func klmdQuery() queryResult { panic("not implemented for gccgo") } + +func doinit() { + options = []option{ + {"zarch", &S390X.HasZArch}, + {"stfle", &S390X.HasSTFLE}, + {"ldisp", &S390X.HasLDisp}, + {"msa", &S390X.HasMSA}, + {"eimm", &S390X.HasEImm}, + {"dfp", &S390X.HasDFP}, + {"etf3eh", &S390X.HasETF3Enhanced}, + {"vx", &S390X.HasVX}, + } + + aes := []function{aes128, aes192, aes256} + facilities := stfle() + + S390X.HasZArch = facilities.Has(zarch) + S390X.HasSTFLE = facilities.Has(stflef) + S390X.HasLDisp = facilities.Has(ldisp) + S390X.HasEImm = facilities.Has(eimm) + S390X.HasDFP = facilities.Has(dfp) + S390X.HasETF3Enhanced = facilities.Has(etf3eh) + S390X.HasMSA = facilities.Has(msa) + + if S390X.HasMSA { + // cipher message + km, kmc := kmQuery(), kmcQuery() + S390X.HasAES = km.Has(aes...) + S390X.HasAESCBC = kmc.Has(aes...) + if facilities.Has(msa4) { + kmctr := kmctrQuery() + S390X.HasAESCTR = kmctr.Has(aes...) + } + if facilities.Has(msa8) { + kma := kmaQuery() + S390X.HasAESGCM = kma.Has(aes...) + } + + // compute message digest + kimd := kimdQuery() // intermediate (no padding) + klmd := klmdQuery() // last (padding) + S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1) + S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256) + S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512) + S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist + } +} diff --git a/libgo/go/internal/cpu/cpu_s390x_test.go b/libgo/go/internal/cpu/cpu_s390x_test.go new file mode 100644 index 0000000..d910bbe --- /dev/null +++ b/libgo/go/internal/cpu/cpu_s390x_test.go @@ -0,0 +1,63 @@ +// Copyright 2018 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_test + +import ( + "errors" + . "internal/cpu" + "io/ioutil" + "regexp" + "testing" +) + +func getFeatureList() ([]string, error) { + cpuinfo, err := ioutil.ReadFile("/proc/cpuinfo") + if err != nil { + return nil, err + } + r := regexp.MustCompile("features\\s*:\\s*(.*)") + b := r.FindSubmatch(cpuinfo) + if len(b) < 2 { + return nil, errors.New("no feature list in /proc/cpuinfo") + } + return regexp.MustCompile("\\s+").Split(string(b[1]), -1), nil +} + +func TestS390XAgainstCPUInfo(t *testing.T) { + // mapping of linux feature strings to S390X fields + mapping := make(map[string]*bool) + for _, option := range Options { + mapping[option.Name] = option.Feature + } + + // these must be true on the machines Go supports + mandatory := make(map[string]bool) + mandatory["zarch"] = false + mandatory["eimm"] = false + mandatory["ldisp"] = false + mandatory["stfle"] = false + + features, err := getFeatureList() + if err != nil { + t.Error(err) + } + for _, feature := range features { + if _, ok := mandatory[feature]; ok { + mandatory[feature] = true + } + if flag, ok := mapping[feature]; ok { + if !*flag { + t.Errorf("feature '%v' not detected", feature) + } + } else { + t.Logf("no entry for '%v'", feature) + } + } + for k, v := range mandatory { + if !v { + t.Errorf("mandatory feature '%v' not detected", k) + } + } +} diff --git a/libgo/go/internal/cpu/cpu_test.go b/libgo/go/internal/cpu/cpu_test.go index 07b0243..d4115a1 100644 --- a/libgo/go/internal/cpu/cpu_test.go +++ b/libgo/go/internal/cpu/cpu_test.go @@ -5,46 +5,52 @@ package cpu_test import ( - "internal/cpu" - "runtime" + . "internal/cpu" + "internal/testenv" + "os" + "os/exec" + "strings" "testing" ) -func TestAMD64minimalFeatures(t *testing.T) { - if runtime.GOARCH == "amd64" { - if !cpu.X86.HasSSE2 { - t.Fatalf("HasSSE2 expected true, got false") - } +func MustHaveDebugOptionsEnabled(t *testing.T) { + if !DebugOptions { + t.Skipf("skipping test: cpu feature options not enabled") } } -func TestAVX2hasAVX(t *testing.T) { - if runtime.GOARCH == "amd64" { - if cpu.X86.HasAVX2 && !cpu.X86.HasAVX { - t.Fatalf("HasAVX expected true, got false") - } +func runDebugOptionsTest(t *testing.T, test string, options string) { + MustHaveDebugOptionsEnabled(t) + + testenv.MustHaveExec(t) + + env := "GODEBUGCPU=" + options + + cmd := exec.Command(os.Args[0], "-test.run="+test) + cmd.Env = append(cmd.Env, env) + + output, err := cmd.CombinedOutput() + got := strings.TrimSpace(string(output)) + want := "PASS" + if err != nil || got != want { + t.Fatalf("%s with %s: want %s, got %v", test, env, want, got) } } -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") +func TestDisableAllCapabilities(t *testing.T) { + runDebugOptionsTest(t, "TestAllCapabilitiesDisabled", "all=0") +} + +func TestAllCapabilitiesDisabled(t *testing.T) { + MustHaveDebugOptionsEnabled(t) + + if os.Getenv("GODEBUGCPU") != "all=0" { + t.Skipf("skipping test: GODEBUGCPU=all=0 not set") + } + + for _, o := range Options { + if got := *o.Feature; got != false { + t.Errorf("%v: expected false, got %v", o.Name, got) } } } diff --git a/libgo/go/internal/cpu/cpu_wasm.go b/libgo/go/internal/cpu/cpu_wasm.go new file mode 100644 index 0000000..1107a7a --- /dev/null +++ b/libgo/go/internal/cpu/cpu_wasm.go @@ -0,0 +1,7 @@ +// Copyright 2018 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 = 64 diff --git a/libgo/go/internal/cpu/cpu_x86.go b/libgo/go/internal/cpu/cpu_x86.go index 34c632f..7d9d3aa 100644 --- a/libgo/go/internal/cpu/cpu_x86.go +++ b/libgo/go/internal/cpu/cpu_x86.go @@ -14,7 +14,56 @@ 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) -func init() { +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{ + {"adx", &X86.HasADX}, + {"aes", &X86.HasAES}, + {"avx", &X86.HasAVX}, + {"avx2", &X86.HasAVX2}, + {"bmi1", &X86.HasBMI1}, + {"bmi2", &X86.HasBMI2}, + {"erms", &X86.HasERMS}, + {"fma", &X86.HasFMA}, + {"pclmulqdq", &X86.HasPCLMULQDQ}, + {"popcnt", &X86.HasPOPCNT}, + {"sse3", &X86.HasSSE3}, + {"sse41", &X86.HasSSE41}, + {"sse42", &X86.HasSSE42}, + {"ssse3", &X86.HasSSSE3}, + + // sse2 set as last element so it can easily be removed again. See code below. + {"sse2", &X86.HasSSE2}, + } + + // Remove sse2 from options on amd64(p32) because SSE2 is a mandatory feature for these GOARCHs. + if GOARCH == "amd64" || GOARCH == "amd64p32" { + options = options[:len(options)-1] + } + maxID, _, _, _ := cpuid(0, 0) if maxID < 1 { @@ -22,40 +71,40 @@ func init() { } _, _, ecx1, edx1 := cpuid(1, 0) - X86.HasSSE2 = isSet(26, edx1) - - X86.HasSSE3 = isSet(0, ecx1) - X86.HasPCLMULQDQ = isSet(1, ecx1) - X86.HasSSSE3 = isSet(9, ecx1) - X86.HasFMA = isSet(12, ecx1) - X86.HasSSE41 = isSet(19, ecx1) - X86.HasSSE42 = isSet(20, ecx1) - X86.HasPOPCNT = isSet(23, ecx1) - X86.HasAES = isSet(25, ecx1) - X86.HasOSXSAVE = isSet(27, ecx1) + 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(1, eax) && isSet(2, eax) + osSupportsAVX = isSet(eax, 1<<1) && isSet(eax, 1<<2) } - X86.HasAVX = isSet(28, ecx1) && osSupportsAVX + X86.HasAVX = isSet(ecx1, cpuid_AVX) && osSupportsAVX if maxID < 7 { return } _, ebx7, _, _ := cpuid(7, 0) - X86.HasBMI1 = isSet(3, ebx7) - X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX - X86.HasBMI2 = isSet(8, ebx7) - X86.HasERMS = isSet(9, ebx7) - X86.HasADX = isSet(19, ebx7) + 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(bitpos uint, value uint32) bool { - return value&(1<<bitpos) != 0 +func isSet(hwc uint32, value uint32) bool { + return hwc&value != 0 } diff --git a/libgo/go/internal/cpu/cpu_x86_test.go b/libgo/go/internal/cpu/cpu_x86_test.go new file mode 100644 index 0000000..d03306c --- /dev/null +++ b/libgo/go/internal/cpu/cpu_x86_test.go @@ -0,0 +1,47 @@ +// Copyright 2018 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 amd64p32 + +package cpu_test + +import ( + . "internal/cpu" + "os" + "runtime" + "testing" +) + +func TestAMD64minimalFeatures(t *testing.T) { + if runtime.GOARCH != "amd64" { + return + } + + if !X86.HasSSE2 { + t.Fatalf("HasSSE2 expected true, got false") + } +} + +func TestX86ifAVX2hasAVX(t *testing.T) { + if X86.HasAVX2 && !X86.HasAVX { + t.Fatalf("HasAVX expected true when HasAVX2 is true, got false") + } +} + +func TestDisableSSE2(t *testing.T) { + runDebugOptionsTest(t, "TestSSE2DebugOption", "sse2=0") +} + +func TestSSE2DebugOption(t *testing.T) { + MustHaveDebugOptionsEnabled(t) + + if os.Getenv("GODEBUGCPU") != "sse2=0" { + t.Skipf("skipping test: GODEBUGCPU=sse2=0 not set") + } + + want := runtime.GOARCH != "386" // SSE2 can only be disabled on 386. + if got := X86.HasSSE2; got != want { + t.Errorf("X86.HasSSE2 on %s expected %v, got %v", runtime.GOARCH, want, got) + } +} diff --git a/libgo/go/internal/cpu/export_test.go b/libgo/go/internal/cpu/export_test.go new file mode 100644 index 0000000..91bfc1b --- /dev/null +++ b/libgo/go/internal/cpu/export_test.go @@ -0,0 +1,9 @@ +// Copyright 2018 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 + +var ( + Options = options +) |