Skip to content

Commit 942780b

Browse files
egonelbregopherbot
authored andcommitted
cpu: darwin/arm64 feature detection
The ARM64 flags were not being correctly set for Mac M series laptops. Fixes golang/go#43046 Change-Id: I1d884dccd3f3a0a010ad7babbab26b73731ab583 Reviewed-on: https://go-review.googlesource.com/c/sys/+/737260 Auto-Submit: Keith Randall <khr@golang.org> Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Keith Randall <khr@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: David Chase <drchase@google.com>
1 parent acef388 commit 942780b

File tree

5 files changed

+155
-19
lines changed

5 files changed

+155
-19
lines changed

cpu/asm_darwin_arm64_gc.s

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2024 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build darwin && arm64 && gc
6+
7+
#include "textflag.h"
8+
9+
TEXT libc_sysctlbyname_trampoline<>(SB),NOSPLIT,$0-0
10+
JMP libc_sysctlbyname(SB)
11+
GLOBL ·libc_sysctlbyname_trampoline_addr(SB), RODATA, $8
12+
DATA ·libc_sysctlbyname_trampoline_addr(SB)/8, $libc_sysctlbyname_trampoline<>(SB)

cpu/cpu_darwin_arm64.go

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,66 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
package cpu
5+
//go:build darwin && arm64 && gc
66

7-
import "runtime"
7+
package cpu
88

99
func doinit() {
10-
ARM64.HasASIMD = true
11-
ARM64.HasFP = true
12-
13-
if runtime.GOOS != "ios" {
14-
// M-series SoCs are at least armv8.4-a
15-
ARM64.HasCRC32 = true // armv8.1
16-
ARM64.HasATOMICS = true // armv8.2
17-
ARM64.HasJSCVT = true // armv8.3, if HasFP
18-
19-
// Go already assumes these to be available
20-
// because they were on the M1.
21-
ARM64.HasAES = true
22-
ARM64.HasPMULL = true
23-
ARM64.HasSHA1 = true
24-
ARM64.HasSHA2 = true
25-
}
10+
setMinimalFeatures()
11+
12+
// The feature flags are explained in [Instruction Set Detection].
13+
// There are some differences between MacOS versions:
14+
//
15+
// MacOS 11 and 12 do not have "hw.optional" sysctl values for some of the features.
16+
//
17+
// MacOS 13 changed some of the naming conventions to align with ARM Architecture Reference Manual.
18+
// For example "hw.optional.armv8_2_sha512" became "hw.optional.arm.FEAT_SHA512".
19+
// It currently checks both to stay compatible with MacOS 11 and 12.
20+
// The old names also work with MacOS 13, however it's not clear whether
21+
// they will continue working with future OS releases.
22+
//
23+
// Once MacOS 12 is no longer supported the old names can be removed.
24+
//
25+
// [Instruction Set Detection]: https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics
26+
27+
// Encryption, hashing and checksum capabilities
28+
29+
// For the following flags there are no MacOS 11 sysctl flags.
30+
ARM64.HasAES = true || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_AES\x00"))
31+
ARM64.HasPMULL = true || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_PMULL\x00"))
32+
ARM64.HasSHA1 = true || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SHA1\x00"))
33+
ARM64.HasSHA2 = true || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SHA256\x00"))
34+
35+
ARM64.HasSHA3 = darwinSysctlEnabled([]byte("hw.optional.armv8_2_sha3\x00")) || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SHA3\x00"))
36+
ARM64.HasSHA512 = darwinSysctlEnabled([]byte("hw.optional.armv8_2_sha512\x00")) || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SHA512\x00"))
37+
38+
ARM64.HasCRC32 = darwinSysctlEnabled([]byte("hw.optional.armv8_crc32\x00"))
39+
40+
// Atomic and memory ordering
41+
ARM64.HasATOMICS = darwinSysctlEnabled([]byte("hw.optional.armv8_1_atomics\x00")) || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_LSE\x00"))
42+
ARM64.HasLRCPC = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_LRCPC\x00"))
43+
44+
// SIMD and floating point capabilities
45+
ARM64.HasFPHP = darwinSysctlEnabled([]byte("hw.optional.neon_fp16\x00")) || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_FP16\x00"))
46+
ARM64.HasASIMDHP = darwinSysctlEnabled([]byte("hw.optional.neon_hpfp\x00")) || darwinSysctlEnabled([]byte("hw.optional.AdvSIMD_HPFPCvt\x00"))
47+
ARM64.HasASIMDRDM = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_RDM\x00"))
48+
ARM64.HasASIMDDP = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_DotProd\x00"))
49+
ARM64.HasASIMDFHM = darwinSysctlEnabled([]byte("hw.optional.armv8_2_fhm\x00")) || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_FHM\x00"))
50+
ARM64.HasI8MM = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_I8MM\x00"))
51+
52+
ARM64.HasJSCVT = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_JSCVT\x00"))
53+
ARM64.HasFCMA = darwinSysctlEnabled([]byte("hw.optional.armv8_3_compnum\x00")) || darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_FCMA\x00"))
54+
55+
// Miscellaneous
56+
ARM64.HasDCPOP = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_DPB\x00"))
57+
ARM64.HasEVTSTRM = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_ECV\x00"))
58+
ARM64.HasDIT = darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_DIT\x00"))
59+
60+
// Not supported, but added for completeness
61+
ARM64.HasCPUID = false
62+
63+
ARM64.HasSM3 = false // darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SM3\x00"))
64+
ARM64.HasSM4 = false // darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SM4\x00"))
65+
ARM64.HasSVE = false // darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SVE\x00"))
66+
ARM64.HasSVE2 = false // darwinSysctlEnabled([]byte("hw.optional.arm.FEAT_SVE2\x00"))
2667
}

cpu/cpu_darwin_arm64_other.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2026 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
//go:build darwin && arm64 && !gc
6+
7+
package cpu
8+
9+
func doinit() {
10+
setMinimalFeatures()
11+
12+
ARM64.HasASIMD = true
13+
ARM64.HasFP = true
14+
15+
// Go already assumes these to be available because they were on the M1
16+
// and these are supported on all Apple arm64 chips.
17+
ARM64.HasAES = true
18+
ARM64.HasPMULL = true
19+
ARM64.HasSHA1 = true
20+
ARM64.HasSHA2 = true
21+
22+
if runtime.GOOS != "ios" {
23+
// Apple A7 processors do not support these, however
24+
// M-series SoCs are at least armv8.4-a
25+
ARM64.HasCRC32 = true // armv8.1
26+
ARM64.HasATOMICS = true // armv8.2
27+
ARM64.HasJSCVT = true // armv8.3, if HasFP
28+
}
29+
}

cpu/cpu_other_arm64.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
//go:build !linux && !netbsd && !openbsd && !windows && !darwin && arm64
5+
//go:build !darwin && !linux && !netbsd && !openbsd && !windows && arm64
66

77
package cpu
88

cpu/syscall_darwin_arm64_gc.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2024 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Minimal copy from internal/cpu and runtime to make sysctl calls.
6+
7+
//go:build darwin && arm64 && gc
8+
9+
package cpu
10+
11+
import (
12+
"syscall"
13+
"unsafe"
14+
)
15+
16+
type Errno = syscall.Errno
17+
18+
// adapted from internal/cpu/cpu_arm64_darwin.go
19+
func darwinSysctlEnabled(name []byte) bool {
20+
out := int32(0)
21+
nout := unsafe.Sizeof(out)
22+
if ret := sysctlbyname(&name[0], (*byte)(unsafe.Pointer(&out)), &nout, nil, 0); ret != nil {
23+
return false
24+
}
25+
return out > 0
26+
}
27+
28+
//go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib"
29+
30+
var libc_sysctlbyname_trampoline_addr uintptr
31+
32+
// adapted from runtime/sys_darwin.go in the pattern of sysctl() above, as defined in x/sys/unix
33+
func sysctlbyname(name *byte, old *byte, oldlen *uintptr, new *byte, newlen uintptr) error {
34+
if _, _, err := syscall_syscall6(
35+
libc_sysctlbyname_trampoline_addr,
36+
uintptr(unsafe.Pointer(name)),
37+
uintptr(unsafe.Pointer(old)),
38+
uintptr(unsafe.Pointer(oldlen)),
39+
uintptr(unsafe.Pointer(new)),
40+
uintptr(newlen),
41+
0,
42+
); err != 0 {
43+
return err
44+
}
45+
46+
return nil
47+
}
48+
49+
//go:cgo_import_dynamic libc_sysctlbyname sysctlbyname "/usr/lib/libSystem.B.dylib"
50+
51+
// Implemented in the runtime package (runtime/sys_darwin.go)
52+
func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
53+
54+
//go:linkname syscall_syscall6 syscall.syscall6

0 commit comments

Comments
 (0)