diff --git a/src/hash/crc32/crc32_arm64.go b/src/hash/crc32/crc32_arm64.go index 17044861c7f..1f8779d506f 100644 --- a/src/hash/crc32/crc32_arm64.go +++ b/src/hash/crc32/crc32_arm64.go @@ -8,11 +8,12 @@ package crc32 -func supportsCRC32() bool +import "internal/cpu" + func castagnoliUpdate(crc uint32, p []byte) uint32 func ieeeUpdate(crc uint32, p []byte) uint32 -var hasCRC32 = supportsCRC32() +var hasCRC32 = cpu.ARM64.HasCRC32 func archAvailableCastagnoli() bool { return hasCRC32 diff --git a/src/hash/crc32/crc32_arm64.s b/src/hash/crc32/crc32_arm64.s index 26a86e4efa6..53274c56235 100644 --- a/src/hash/crc32/crc32_arm64.s +++ b/src/hash/crc32/crc32_arm64.s @@ -89,9 +89,3 @@ less_than_2: done: MOVWU R9, ret+32(FP) RET - -// func supportsCRC32() bool -TEXT ·supportsCRC32(SB),NOSPLIT,$0-1 - MOVB runtime·supportCRC32(SB), R0 - MOVB R0, ret+0(FP) - RET diff --git a/src/internal/cpu/cpu.go b/src/internal/cpu/cpu.go index 38fedc4e2b4..22fc561002d 100644 --- a/src/internal/cpu/cpu.go +++ b/src/internal/cpu/cpu.go @@ -57,3 +57,21 @@ type ppc64 struct { IsPOWER9 bool // ISA v3.00 (POWER9) _ [CacheLineSize]byte } + +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 +} diff --git a/src/internal/cpu/cpu_arm64.go b/src/internal/cpu/cpu_arm64.go index 4d071b3a4e6..e1278a147a1 100644 --- a/src/internal/cpu/cpu_arm64.go +++ b/src/internal/cpu/cpu_arm64.go @@ -2,13 +2,44 @@ // 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 -// TODO: delete this once https://go-review.googlesource.com/c/go/+/76490 lands. -// These will just be false for now. -var ARM64 struct { - HasSHA1 bool - HasSHA2 bool +// 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 + +// 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) +) + +func init() { + // 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) +} + +func isSet(hwc uint, value uint) bool { + return hwc&value != 0 } diff --git a/src/runtime/os_darwin_arm64.go b/src/runtime/os_darwin_arm64.go index 01285afa190..8de132d8e2f 100644 --- a/src/runtime/os_darwin_arm64.go +++ b/src/runtime/os_darwin_arm64.go @@ -4,8 +4,6 @@ package runtime -var supportCRC32 = false - //go:nosplit func cputicks() int64 { // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand(). diff --git a/src/runtime/os_linux_arm64.go b/src/runtime/os_linux_arm64.go index 986a34135e4..96827e7c9f1 100644 --- a/src/runtime/os_linux_arm64.go +++ b/src/runtime/os_linux_arm64.go @@ -2,14 +2,22 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build arm64 + package runtime -const ( - _ARM64_FEATURE_HAS_CRC32 = 0x80 -) +// For go:linkname +import _ "unsafe" var randomNumber uint32 -var supportCRC32 bool + +// arm64 doesn't have a 'cpuid' instruction equivalent and relies on +// HWCAP/HWCAP2 bits for hardware capabilities. + +//go:linkname cpu_hwcap internal/cpu.arm64_hwcap +//go:linkname cpu_hwcap2 internal/cpu.arm64_hwcap2 +var cpu_hwcap uint +var cpu_hwcap2 uint func archauxv(tag, val uintptr) { switch tag { @@ -20,7 +28,9 @@ func archauxv(tag, val uintptr) { randomNumber = uint32(startupRandomData[4]) | uint32(startupRandomData[5])<<8 | uint32(startupRandomData[6])<<16 | uint32(startupRandomData[7])<<24 case _AT_HWCAP: - supportCRC32 = val&_ARM64_FEATURE_HAS_CRC32 != 0 + cpu_hwcap = uint(val) + case _AT_HWCAP2: + cpu_hwcap2 = uint(val) } }