From 70b957f3b65e069b4930ea94e2721eefa0f8f695 Mon Sep 17 00:00:00 2001 From: Meng Zhuo Date: Sat, 1 Dec 2018 23:49:00 +0800 Subject: [PATCH] cpu: add linux/arm64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port from Go internal/cpu Updates golang/go#25185 Change-Id: I8390980e38b61f6c428fafa0665a03952e7b00bb Reviewed-on: https://go-review.googlesource.com/c/150718 Run-TryBot: Tobias Klauser TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick Reviewed-by: Martin Möhrmann Reviewed-by: Tobias Klauser --- cpu/cpu.go | 32 +++++++++++++++++++++++++ cpu/cpu_arm.go | 2 ++ cpu/cpu_arm64.go | 60 ++++++++++++++++++++++++++++++++++++++++++++++ cpu/cpu_linux.go | 55 ++++++++++++++++++++++++++++++++++++++++++ cpu/cpu_mips64x.go | 2 ++ cpu/cpu_mipsx.go | 2 ++ cpu/cpu_ppc64x.go | 2 ++ cpu/cpu_s390x.go | 2 ++ cpu/cpu_test.go | 12 ++++++++++ 9 files changed, 169 insertions(+) create mode 100644 cpu/cpu_linux.go diff --git a/cpu/cpu.go b/cpu/cpu.go index 3d88f866..11e8fb9c 100644 --- a/cpu/cpu.go +++ b/cpu/cpu.go @@ -36,3 +36,35 @@ var X86 struct { HasSSE42 bool // Streaming SIMD extension 4 and 4.2 _ CacheLinePad } + +// ARM64 contains the supported CPU features of the +// current ARMv8(aarch64) platform. If the current platform +// is not arm64 then all feature flags are false. +var ARM64 struct { + _ CacheLinePad + HasFP bool // Floating-point instruction set (always available) + HasASIMD bool // Advanced SIMD (always available) + HasEVTSTRM bool // Event stream support + HasAES bool // AES hardware implementation + HasPMULL bool // Polynomial multiplication instruction set + HasSHA1 bool // SHA1 hardware implementation + HasSHA2 bool // SHA2 hardware implementation + HasCRC32 bool // CRC32 hardware implementation + HasATOMICS bool // Atomic memory operation instruction set + HasFPHP bool // Half precision floating-point instruction set + HasASIMDHP bool // Advanced SIMD half precision instruction set + HasCPUID bool // CPUID identification scheme registers + HasASIMDRDM bool // Rounding double multiply add/subtract instruction set + HasJSCVT bool // Javascript conversion from floating-point to integer + HasFCMA bool // Floating-point multiplication and addition of complex numbers + HasLRCPC bool // Release Consistent processor consistent support + HasDCPOP bool // Persistent memory support + HasSHA3 bool // SHA3 hardware implementation + HasSM3 bool // SM3 hardware implementation + HasSM4 bool // SM4 hardware implementation + HasASIMDDP bool // Advanced SIMD double precision instruction set + HasSHA512 bool // SHA512 hardware implementation + HasSVE bool // Scalable Vector Extensions + HasASIMDFHM bool // Advanced SIMD multiplication FP16 to FP32 + _ CacheLinePad +} diff --git a/cpu/cpu_arm.go b/cpu/cpu_arm.go index d93036f7..7f2348b7 100644 --- a/cpu/cpu_arm.go +++ b/cpu/cpu_arm.go @@ -5,3 +5,5 @@ package cpu const cacheLineSize = 32 + +func doinit() {} diff --git a/cpu/cpu_arm64.go b/cpu/cpu_arm64.go index 1d2ab290..02ed58b3 100644 --- a/cpu/cpu_arm64.go +++ b/cpu/cpu_arm64.go @@ -5,3 +5,63 @@ package cpu const cacheLineSize = 64 + +// HWCAP/HWCAP2 bits. These are exposed by Linux. +const ( + 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 doinit() { + // HWCAP feature bits + 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 { + return hwc&value != 0 +} diff --git a/cpu/cpu_linux.go b/cpu/cpu_linux.go new file mode 100644 index 00000000..126bb684 --- /dev/null +++ b/cpu/cpu_linux.go @@ -0,0 +1,55 @@ +// 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 !amd64,!amd64p32,!386 + +package cpu + +import ( + "encoding/binary" + "io/ioutil" +) + +const ( + _AT_HWCAP = 16 + _AT_HWCAP2 = 26 + + procAuxv = "/proc/self/auxv" + + uintSize uint = 32 << (^uint(0) >> 63) +) + +// For those platforms don't have a 'cpuid' equivalent we use HWCAP/HWCAP2 +// These are initialized in cpu_$GOARCH.go +// and should not be changed after they are initialized. +var HWCap uint +var HWCap2 uint + +func init() { + buf, err := ioutil.ReadFile(procAuxv) + if err != nil { + panic("read proc auxv failed: " + err.Error()) + } + + pb := int(uintSize / 8) + + for i := 0; i < len(buf)-pb*2; i += pb * 2 { + var tag, val uint + switch uintSize { + case 32: + tag = uint(binary.LittleEndian.Uint32(buf[i:])) + val = uint(binary.LittleEndian.Uint32(buf[i+pb:])) + case 64: + tag = uint(binary.LittleEndian.Uint64(buf[i:])) + val = uint(binary.LittleEndian.Uint64(buf[i+pb:])) + } + switch tag { + case _AT_HWCAP: + HWCap = val + case _AT_HWCAP2: + HWCap2 = val + } + } + doinit() +} diff --git a/cpu/cpu_mips64x.go b/cpu/cpu_mips64x.go index 6165f121..f55e0c82 100644 --- a/cpu/cpu_mips64x.go +++ b/cpu/cpu_mips64x.go @@ -7,3 +7,5 @@ package cpu const cacheLineSize = 32 + +func doinit() {} diff --git a/cpu/cpu_mipsx.go b/cpu/cpu_mipsx.go index 1269eee8..cda87b1a 100644 --- a/cpu/cpu_mipsx.go +++ b/cpu/cpu_mipsx.go @@ -7,3 +7,5 @@ package cpu const cacheLineSize = 32 + +func doinit() {} diff --git a/cpu/cpu_ppc64x.go b/cpu/cpu_ppc64x.go index d10759a5..70c959bd 100644 --- a/cpu/cpu_ppc64x.go +++ b/cpu/cpu_ppc64x.go @@ -7,3 +7,5 @@ package cpu const cacheLineSize = 128 + +func doinit() {} diff --git a/cpu/cpu_s390x.go b/cpu/cpu_s390x.go index 684c4f00..ce8a2289 100644 --- a/cpu/cpu_s390x.go +++ b/cpu/cpu_s390x.go @@ -5,3 +5,5 @@ package cpu const cacheLineSize = 256 + +func doinit() {} diff --git a/cpu/cpu_test.go b/cpu/cpu_test.go index baf4b87b..0c8cc83b 100644 --- a/cpu/cpu_test.go +++ b/cpu/cpu_test.go @@ -26,3 +26,15 @@ func TestAVX2hasAVX(t *testing.T) { } } } + +func TestARM64minimalFeatures(t *testing.T) { + if runtime.GOARCH != "arm64" || runtime.GOOS != "linux" { + return + } + if !cpu.ARM64.HasASIMD { + t.Fatal("HasASIMD expected true, got false") + } + if !cpu.ARM64.HasFP { + t.Fatal("HasFP expected true, got false") + } +}