internal/cpu: detect cpu features in internal/cpu package
change hash/crc32 package to use cpu package instead of using
runtime internal variables to check crc32 instruction
Change-Id: I8f88d2351bde8ed4e256f9adf822a08b9a00f532
diff --git a/src/hash/crc32/crc32_arm64.go b/src/hash/crc32/crc32_arm64.go
index 1704486..1f8779d 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 26a86e4..53274c5 100644
--- a/src/hash/crc32/crc32_arm64.s
+++ b/src/hash/crc32/crc32_arm64.s
@@ -89,9 +89,3 @@
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 38fedc4..e81ae7e 100644
--- a/src/internal/cpu/cpu.go
+++ b/src/internal/cpu/cpu.go
@@ -57,3 +57,21 @@
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 d3c6cc8..2e2f733 100644
--- a/src/internal/cpu/cpu_arm64.go
+++ b/src/internal/cpu/cpu_arm64.go
@@ -2,6 +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
+
+// 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 the kernel.
+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 01285af..8de132d 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 986a341..96827e7 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 @@
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)
}
}