mirror of https://github.com/golang/go.git
internal/cpu: consolidate arm64 feature detection
Move code to detect and mask arm64 CPU features from runtime to internal/cpu. Change-Id: Ib784e2ff056e8def125d68827b852f07a3eff0db Reviewed-on: https://go-review.googlesource.com/c/go/+/261878 Trust: Martin Möhrmann <moehrmann@google.com> Trust: Tobias Klauser <tobias.klauser@gmail.com> Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com> Reviewed-by: Benny Siegert <bsiegert@gmail.com>
This commit is contained in:
parent
55b2d479d7
commit
de932da453
|
|
@ -0,0 +1,7 @@
|
|||
// Copyright 2020 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 GOOS = "android"
|
||||
|
|
@ -6,13 +6,11 @@ package cpu
|
|||
|
||||
const CacheLinePadSize = 64
|
||||
|
||||
// arm64 doesn't have a 'cpuid' equivalent, so we rely on HWCAP/HWCAP2.
|
||||
// These are initialized by archauxv and should not be changed after they are
|
||||
// initialized.
|
||||
// HWCap may be initialized by archauxv and
|
||||
// should not be changed after it was initialized.
|
||||
var HWCap uint
|
||||
var HWCap2 uint
|
||||
|
||||
// HWCAP/HWCAP2 bits. These are exposed by Linux.
|
||||
// HWCAP bits. These are exposed by Linux.
|
||||
const (
|
||||
hwcap_AES = 1 << 3
|
||||
hwcap_PMULL = 1 << 4
|
||||
|
|
@ -32,15 +30,66 @@ func doinit() {
|
|||
{Name: "atomics", Feature: &ARM64.HasATOMICS},
|
||||
}
|
||||
|
||||
// HWCAP feature bits
|
||||
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)
|
||||
switch GOOS {
|
||||
case "linux", "android":
|
||||
// HWCap was populated by the runtime from the auxillary vector.
|
||||
// Use HWCap information since reading aarch64 system registers
|
||||
// is not supported in user space on older linux kernels.
|
||||
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)
|
||||
|
||||
// The Samsung S9+ kernel reports support for atomics, but not all cores
|
||||
// actually support them, resulting in SIGILL. See issue #28431.
|
||||
// TODO(elias.naur): Only disable the optimization on bad chipsets on android.
|
||||
ARM64.HasATOMICS = isSet(HWCap, hwcap_ATOMICS) && GOOS != "android"
|
||||
|
||||
case "freebsd":
|
||||
// Retrieve info from system register ID_AA64ISAR0_EL1.
|
||||
isar0 := getisar0()
|
||||
|
||||
// ID_AA64ISAR0_EL1
|
||||
switch extractBits(isar0, 4, 7) {
|
||||
case 1:
|
||||
ARM64.HasAES = true
|
||||
case 2:
|
||||
ARM64.HasAES = true
|
||||
ARM64.HasPMULL = true
|
||||
}
|
||||
|
||||
switch extractBits(isar0, 8, 11) {
|
||||
case 1:
|
||||
ARM64.HasSHA1 = true
|
||||
}
|
||||
|
||||
switch extractBits(isar0, 12, 15) {
|
||||
case 1, 2:
|
||||
ARM64.HasSHA2 = true
|
||||
}
|
||||
|
||||
switch extractBits(isar0, 16, 19) {
|
||||
case 1:
|
||||
ARM64.HasCRC32 = true
|
||||
}
|
||||
|
||||
switch extractBits(isar0, 20, 23) {
|
||||
case 2:
|
||||
ARM64.HasATOMICS = true
|
||||
}
|
||||
default:
|
||||
// Other operating systems do not support reading HWCap from auxillary vector
|
||||
// or reading privileged aarch64 system registers in user space.
|
||||
}
|
||||
}
|
||||
|
||||
func extractBits(data uint64, start, end uint) uint {
|
||||
return (uint)(data>>start) & ((1 << (end - start + 1)) - 1)
|
||||
}
|
||||
|
||||
func isSet(hwc uint, value uint) bool {
|
||||
return hwc&value != 0
|
||||
}
|
||||
|
||||
func getisar0() uint64
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright 2020 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 "textflag.h"
|
||||
|
||||
// func getisar0() uint64
|
||||
TEXT ·getisar0(SB),NOSPLIT,$0
|
||||
// get Instruction Set Attributes 0 into R0
|
||||
MRS ID_AA64ISAR0_EL1, R0
|
||||
MOVD R0, ret+0(FP)
|
||||
RET
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
// Copyright 2020 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 GOOS = "freebsd"
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright 2020 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 !android
|
||||
|
||||
package cpu
|
||||
|
||||
const GOOS = "linux"
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright 2020 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 !linux
|
||||
// +build !freebsd
|
||||
// +build !android
|
||||
|
||||
package cpu
|
||||
|
||||
const GOOS = "other"
|
||||
|
|
@ -7,7 +7,6 @@
|
|||
// +build !dragonfly
|
||||
// +build !freebsd
|
||||
// +build !netbsd
|
||||
// +build !openbsd !arm64
|
||||
// +build !solaris
|
||||
|
||||
package runtime
|
||||
|
|
|
|||
|
|
@ -4,149 +4,6 @@
|
|||
|
||||
package runtime
|
||||
|
||||
import "internal/cpu"
|
||||
|
||||
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 getisar0() uint64
|
||||
func getisar1() uint64
|
||||
func getpfr0() uint64
|
||||
|
||||
// no hwcap support on FreeBSD aarch64, we need to retrieve the info from
|
||||
// ID_AA64ISAR0_EL1, ID_AA64ISAR1_EL1 and ID_AA64PFR0_EL1
|
||||
func archauxv(tag, val uintptr) {
|
||||
var isar0, isar1, pfr0 uint64
|
||||
|
||||
isar0 = getisar0()
|
||||
isar1 = getisar1()
|
||||
pfr0 = getpfr0()
|
||||
|
||||
// ID_AA64ISAR0_EL1
|
||||
switch extractBits(isar0, 4, 7) {
|
||||
case 1:
|
||||
cpu.HWCap |= hwcap_AES
|
||||
case 2:
|
||||
cpu.HWCap |= hwcap_PMULL | hwcap_AES
|
||||
}
|
||||
|
||||
switch extractBits(isar0, 8, 11) {
|
||||
case 1:
|
||||
cpu.HWCap |= hwcap_SHA1
|
||||
}
|
||||
|
||||
switch extractBits(isar0, 12, 15) {
|
||||
case 1:
|
||||
cpu.HWCap |= hwcap_SHA2
|
||||
case 2:
|
||||
cpu.HWCap |= hwcap_SHA2 | hwcap_SHA512
|
||||
}
|
||||
|
||||
switch extractBits(isar0, 16, 19) {
|
||||
case 1:
|
||||
cpu.HWCap |= hwcap_CRC32
|
||||
}
|
||||
|
||||
switch extractBits(isar0, 20, 23) {
|
||||
case 2:
|
||||
cpu.HWCap |= hwcap_ATOMICS
|
||||
}
|
||||
|
||||
switch extractBits(isar0, 28, 31) {
|
||||
case 1:
|
||||
cpu.HWCap |= hwcap_ASIMDRDM
|
||||
}
|
||||
|
||||
switch extractBits(isar0, 32, 35) {
|
||||
case 1:
|
||||
cpu.HWCap |= hwcap_SHA3
|
||||
}
|
||||
|
||||
switch extractBits(isar0, 36, 39) {
|
||||
case 1:
|
||||
cpu.HWCap |= hwcap_SM3
|
||||
}
|
||||
|
||||
switch extractBits(isar0, 40, 43) {
|
||||
case 1:
|
||||
cpu.HWCap |= hwcap_SM4
|
||||
}
|
||||
|
||||
switch extractBits(isar0, 44, 47) {
|
||||
case 1:
|
||||
cpu.HWCap |= hwcap_ASIMDDP
|
||||
}
|
||||
|
||||
// ID_AA64ISAR1_EL1
|
||||
switch extractBits(isar1, 0, 3) {
|
||||
case 1:
|
||||
cpu.HWCap |= hwcap_DCPOP
|
||||
}
|
||||
|
||||
switch extractBits(isar1, 12, 15) {
|
||||
case 1:
|
||||
cpu.HWCap |= hwcap_JSCVT
|
||||
}
|
||||
|
||||
switch extractBits(isar1, 16, 19) {
|
||||
case 1:
|
||||
cpu.HWCap |= hwcap_FCMA
|
||||
}
|
||||
|
||||
switch extractBits(isar1, 20, 23) {
|
||||
case 1:
|
||||
cpu.HWCap |= hwcap_LRCPC
|
||||
}
|
||||
|
||||
// ID_AA64PFR0_EL1
|
||||
switch extractBits(pfr0, 16, 19) {
|
||||
case 0:
|
||||
cpu.HWCap |= hwcap_FP
|
||||
case 1:
|
||||
cpu.HWCap |= hwcap_FP | hwcap_FPHP
|
||||
}
|
||||
|
||||
switch extractBits(pfr0, 20, 23) {
|
||||
case 0:
|
||||
cpu.HWCap |= hwcap_ASIMD
|
||||
case 1:
|
||||
cpu.HWCap |= hwcap_ASIMD | hwcap_ASIMDHP
|
||||
}
|
||||
|
||||
switch extractBits(pfr0, 32, 35) {
|
||||
case 1:
|
||||
cpu.HWCap |= hwcap_SVE
|
||||
}
|
||||
}
|
||||
|
||||
func extractBits(data uint64, start, end uint) uint {
|
||||
return (uint)(data>>start) & ((1 << (end - start + 1)) - 1)
|
||||
}
|
||||
|
||||
//go:nosplit
|
||||
func cputicks() int64 {
|
||||
// Currently cputicks() is used in blocking profiler and to seed fastrand().
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build freebsd
|
||||
// +build !arm,!arm64
|
||||
// +build !arm
|
||||
|
||||
package runtime
|
||||
|
||||
|
|
|
|||
|
|
@ -11,19 +11,7 @@ import "internal/cpu"
|
|||
func archauxv(tag, val uintptr) {
|
||||
switch tag {
|
||||
case _AT_HWCAP:
|
||||
// arm64 doesn't have a 'cpuid' instruction equivalent and relies on
|
||||
// HWCAP/HWCAP2 bits for hardware capabilities.
|
||||
hwcap := uint(val)
|
||||
if GOOS == "android" {
|
||||
// The Samsung S9+ kernel reports support for atomics, but not all cores
|
||||
// actually support them, resulting in SIGILL. See issue #28431.
|
||||
// TODO(elias.naur): Only disable the optimization on bad chipsets.
|
||||
const hwcap_ATOMICS = 1 << 8
|
||||
hwcap &= ^uint(hwcap_ATOMICS)
|
||||
}
|
||||
cpu.HWCap = hwcap
|
||||
case _AT_HWCAP2:
|
||||
cpu.HWCap2 = uint(val)
|
||||
cpu.HWCap = uint(val)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -359,7 +359,6 @@ func sysargs(argc int32, argv **byte) {
|
|||
// now argv+n is auxv
|
||||
auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize))
|
||||
sysauxv(auxv[:])
|
||||
archauxv(auxv[:])
|
||||
}
|
||||
|
||||
const (
|
||||
|
|
|
|||
|
|
@ -14,6 +14,3 @@ func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintp
|
|||
mc.__gregs[_REG_EDX] = uint32(uintptr(unsafe.Pointer(gp)))
|
||||
mc.__gregs[_REG_ESI] = uint32(fn)
|
||||
}
|
||||
|
||||
func archauxv(auxv []uintptr) {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,3 @@ func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintp
|
|||
mc.__gregs[_REG_R9] = uint64(uintptr(unsafe.Pointer(gp)))
|
||||
mc.__gregs[_REG_R12] = uint64(fn)
|
||||
}
|
||||
|
||||
func archauxv(auxv []uintptr) {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,3 @@ func cputicks() int64 {
|
|||
// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
|
||||
return nanotime()
|
||||
}
|
||||
|
||||
func archauxv(auxv []uintptr) {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,7 @@
|
|||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"internal/cpu"
|
||||
"unsafe"
|
||||
)
|
||||
import "unsafe"
|
||||
|
||||
func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintptr) {
|
||||
// Machine dependent mcontext initialisation for LWP.
|
||||
|
|
@ -24,10 +21,3 @@ func cputicks() int64 {
|
|||
// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
|
||||
return nanotime()
|
||||
}
|
||||
|
||||
func archauxv(auxv []uintptr) {
|
||||
// NetBSD does not supply AT_HWCAP, however we still need to initialise cpu.HWCaps.
|
||||
// For now specify the bare minimum until we add some form of capabilities
|
||||
// detection. See issue https://golang.org/issue/30824#issuecomment-494901591
|
||||
cpu.HWCap = 1<<1 | 1<<0 // ASIMD, FP
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,20 +4,9 @@
|
|||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"internal/cpu"
|
||||
)
|
||||
|
||||
//go:nosplit
|
||||
func cputicks() int64 {
|
||||
// Currently cputicks() is used in blocking profiler and to seed runtime·fastrand().
|
||||
// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
|
||||
return nanotime()
|
||||
}
|
||||
|
||||
func sysargs(argc int32, argv **byte) {
|
||||
// OpenBSD does not have auxv, however we still need to initialise cpu.HWCaps.
|
||||
// For now specify the bare minimum until we add some form of capabilities
|
||||
// detection. See issue #31746.
|
||||
cpu.HWCap = 1<<1 | 1<<0 // ASIMD, FP
|
||||
}
|
||||
|
|
|
|||
|
|
@ -515,24 +515,3 @@ TEXT runtime·getCntxct(SB),NOSPLIT,$0
|
|||
|
||||
MOVW R0, ret+8(FP)
|
||||
RET
|
||||
|
||||
// func getisar0() uint64
|
||||
TEXT runtime·getisar0(SB),NOSPLIT,$0
|
||||
// get Instruction Set Attributes 0 into R0
|
||||
MRS ID_AA64ISAR0_EL1, R0
|
||||
MOVD R0, ret+0(FP)
|
||||
RET
|
||||
|
||||
// func getisar1() uint64
|
||||
TEXT runtime·getisar1(SB),NOSPLIT,$0
|
||||
// get Instruction Set Attributes 1 into R0
|
||||
MRS ID_AA64ISAR1_EL1, R0
|
||||
MOVD R0, ret+0(FP)
|
||||
RET
|
||||
|
||||
// func getpfr0() uint64
|
||||
TEXT runtime·getpfr0(SB),NOSPLIT,$0
|
||||
// get Processor Feature Register 0 into R0
|
||||
MRS ID_AA64PFR0_EL1, R0
|
||||
MOVD R0, ret+0(FP)
|
||||
RET
|
||||
|
|
|
|||
Loading…
Reference in New Issue