aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/internal/cpu
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2018-09-24 21:46:21 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2018-09-24 21:46:21 +0000
commitdd931d9b48647e898dc80927c532ae93cc09e192 (patch)
tree71be2295cd79b8a182f6130611658db8628772d5 /libgo/go/internal/cpu
parent779d8a5ad09b01428726ea5a0e6c87bd9ac3c0e4 (diff)
downloadgcc-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.go142
-rw-r--r--libgo/go/internal/cpu/cpu_386.go7
-rw-r--r--libgo/go/internal/cpu/cpu_amd64.go7
-rw-r--r--libgo/go/internal/cpu/cpu_amd64p32.go7
-rw-r--r--libgo/go/internal/cpu/cpu_arm64.go107
-rw-r--r--libgo/go/internal/cpu/cpu_arm64_test.go26
-rw-r--r--libgo/go/internal/cpu/cpu_gccgo.c66
-rw-r--r--libgo/go/internal/cpu/cpu_no_init.go16
-rw-r--r--libgo/go/internal/cpu/cpu_ppc64x.go46
-rw-r--r--libgo/go/internal/cpu/cpu_ppc64x_test.go33
-rw-r--r--libgo/go/internal/cpu/cpu_s390x.go146
-rw-r--r--libgo/go/internal/cpu/cpu_s390x_test.go63
-rw-r--r--libgo/go/internal/cpu/cpu_test.go68
-rw-r--r--libgo/go/internal/cpu/cpu_wasm.go7
-rw-r--r--libgo/go/internal/cpu/cpu_x86.go91
-rw-r--r--libgo/go/internal/cpu/cpu_x86_test.go47
-rw-r--r--libgo/go/internal/cpu/export_test.go9
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
+)