mirror of https://github.com/golang/go.git
runtime: move arm hardware division support detection to internal/cpu
Assumes mandatory VFP and VFPv3 support to be present by default but not IDIVA if AT_HWCAP is not available. Adds GODEBUGCPU options to disable the use of code paths in the runtime that use hardware support for division. Change-Id: Ida02311bd9b9701de3fc120697e69445bf6c0853 Reviewed-on: https://go-review.googlesource.com/114826 Run-TryBot: Martin Möhrmann <moehrmann@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
4363c98f62
commit
2e8c31b3d2
|
|
@ -66,6 +66,16 @@ type ppc64 struct {
|
|||
_ CacheLinePad
|
||||
}
|
||||
|
||||
var ARM arm
|
||||
|
||||
// The booleans in arm contain the correspondingly named cpu feature bit.
|
||||
// The struct is padded to avoid false sharing.
|
||||
type arm struct {
|
||||
_ CacheLinePad
|
||||
HasIDIVA bool
|
||||
_ CacheLinePad
|
||||
}
|
||||
|
||||
var ARM64 arm64
|
||||
|
||||
// The booleans in arm64 contain the correspondingly named cpu feature bit.
|
||||
|
|
|
|||
|
|
@ -5,3 +5,28 @@
|
|||
package cpu
|
||||
|
||||
const CacheLineSize = 32
|
||||
|
||||
// arm doesn't have a 'cpuid' equivalent, so we rely on HWCAP/HWCAP2.
|
||||
// These are linknamed in runtime/os_(linux|freebsd)_arm.go and are
|
||||
// initialized by archauxv().
|
||||
// These should not be changed after they are initialized.
|
||||
var HWCap uint
|
||||
var HWCap2 uint
|
||||
|
||||
// HWCAP/HWCAP2 bits. These are exposed by Linux and FreeBSD.
|
||||
const (
|
||||
hwcap_IDIVA = 1 << 17
|
||||
)
|
||||
|
||||
func doinit() {
|
||||
options = []option{
|
||||
{"idiva", &ARM.HasIDIVA},
|
||||
}
|
||||
|
||||
// HWCAP feature bits
|
||||
ARM.HasIDIVA = isSet(HWCap, hwcap_IDIVA)
|
||||
}
|
||||
|
||||
func isSet(hwc uint, value uint) bool {
|
||||
return hwc&value != 0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
// +build !386
|
||||
// +build !amd64
|
||||
// +build !amd64p32
|
||||
// +build !arm
|
||||
// +build !arm64
|
||||
// +build !ppc64
|
||||
// +build !ppc64le
|
||||
|
|
|
|||
|
|
@ -14,4 +14,6 @@ const (
|
|||
offset_x86_HasAVX2 = unsafe.Offsetof(cpu.X86.HasAVX2)
|
||||
offset_x86_HasERMS = unsafe.Offsetof(cpu.X86.HasERMS)
|
||||
offset_x86_HasSSE2 = unsafe.Offsetof(cpu.X86.HasSSE2)
|
||||
|
||||
offset_arm_HasIDIVA = unsafe.Offsetof(cpu.ARM.HasIDIVA)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
package runtime
|
||||
|
||||
var hardDiv bool // TODO: set if a hardware divider is available
|
||||
|
||||
func checkgoarm() {
|
||||
// TODO(minux): FP checks like in os_linux_arm.go.
|
||||
|
||||
|
|
|
|||
|
|
@ -389,6 +389,7 @@ const (
|
|||
_AT_PAGESZ = 6 // Page size in bytes
|
||||
_AT_TIMEKEEP = 22 // Pointer to timehands.
|
||||
_AT_HWCAP = 25 // CPU feature flags
|
||||
_AT_HWCAP2 = 26 // CPU feature flags 2
|
||||
)
|
||||
|
||||
func sysauxv(auxv []uintptr) {
|
||||
|
|
|
|||
|
|
@ -4,22 +4,29 @@
|
|||
|
||||
package runtime
|
||||
|
||||
import "internal/cpu"
|
||||
|
||||
const (
|
||||
_HWCAP_VFP = 1 << 6
|
||||
_HWCAP_VFPv3 = 1 << 13
|
||||
_HWCAP_IDIVA = 1 << 17
|
||||
)
|
||||
|
||||
var hwcap = ^uint32(0) // set by archauxv
|
||||
var hardDiv bool // set if a hardware divider is available
|
||||
// AT_HWCAP is not available on FreeBSD-11.1-RELEASE or earlier.
|
||||
// Default to mandatory VFP hardware support for arm being available.
|
||||
// If AT_HWCAP is available goarmHWCap will be updated in archauxv.
|
||||
// TODO(moehrmann) remove once all go supported FreeBSD versions support _AT_HWCAP.
|
||||
var goarmHWCap uint = (_HWCAP_VFP | _HWCAP_VFPv3)
|
||||
|
||||
func checkgoarm() {
|
||||
if goarm > 5 && hwcap&_HWCAP_VFP == 0 {
|
||||
// Update cpu.HWCap to match goarmHWCap in case they were not updated in archauxv.
|
||||
cpu.HWCap = goarmHWCap
|
||||
|
||||
if goarm > 5 && cpu.HWCap&_HWCAP_VFP == 0 {
|
||||
print("runtime: this CPU has no floating point hardware, so it cannot run\n")
|
||||
print("this GOARM=", goarm, " binary. Recompile using GOARM=5.\n")
|
||||
exit(1)
|
||||
}
|
||||
if goarm > 6 && hwcap&_HWCAP_VFPv3 == 0 {
|
||||
if goarm > 6 && cpu.HWCap&_HWCAP_VFPv3 == 0 {
|
||||
print("runtime: this CPU has no VFPv3 floating point hardware, so it cannot run\n")
|
||||
print("this GOARM=", goarm, " binary. Recompile using GOARM=5 or GOARM=6.\n")
|
||||
exit(1)
|
||||
|
|
@ -35,9 +42,11 @@ func checkgoarm() {
|
|||
|
||||
func archauxv(tag, val uintptr) {
|
||||
switch tag {
|
||||
case _AT_HWCAP: // CPU capability bit flags
|
||||
hwcap = uint32(val)
|
||||
hardDiv = (hwcap & _HWCAP_IDIVA) != 0
|
||||
case _AT_HWCAP:
|
||||
cpu.HWCap = uint(val)
|
||||
goarmHWCap = cpu.HWCap
|
||||
case _AT_HWCAP2:
|
||||
cpu.HWCap2 = uint(val)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,20 +4,20 @@
|
|||
|
||||
package runtime
|
||||
|
||||
import "unsafe"
|
||||
import (
|
||||
"internal/cpu"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
_AT_PLATFORM = 15 // introduced in at least 2.6.11
|
||||
|
||||
_HWCAP_VFP = 1 << 6 // introduced in at least 2.6.11
|
||||
_HWCAP_VFPv3 = 1 << 13 // introduced in 2.6.30
|
||||
_HWCAP_IDIVA = 1 << 17
|
||||
)
|
||||
|
||||
var randomNumber uint32
|
||||
var armArch uint8 = 6 // we default to ARMv6
|
||||
var hwcap uint32 // set by archauxv
|
||||
var hardDiv bool // set if a hardware divider is available
|
||||
|
||||
func checkgoarm() {
|
||||
// On Android, /proc/self/auxv might be unreadable and hwcap won't
|
||||
|
|
@ -26,12 +26,12 @@ func checkgoarm() {
|
|||
if GOOS == "android" {
|
||||
return
|
||||
}
|
||||
if goarm > 5 && hwcap&_HWCAP_VFP == 0 {
|
||||
if goarm > 5 && cpu.HWCap&_HWCAP_VFP == 0 {
|
||||
print("runtime: this CPU has no floating point hardware, so it cannot run\n")
|
||||
print("this GOARM=", goarm, " binary. Recompile using GOARM=5.\n")
|
||||
exit(1)
|
||||
}
|
||||
if goarm > 6 && hwcap&_HWCAP_VFPv3 == 0 {
|
||||
if goarm > 6 && cpu.HWCap&_HWCAP_VFPv3 == 0 {
|
||||
print("runtime: this CPU has no VFPv3 floating point hardware, so it cannot run\n")
|
||||
print("this GOARM=", goarm, " binary. Recompile using GOARM=5 or GOARM=6.\n")
|
||||
exit(1)
|
||||
|
|
@ -53,9 +53,10 @@ func archauxv(tag, val uintptr) {
|
|||
armArch = t - '0'
|
||||
}
|
||||
|
||||
case _AT_HWCAP: // CPU capability bit flags
|
||||
hwcap = uint32(val)
|
||||
hardDiv = (hwcap & _HWCAP_IDIVA) != 0
|
||||
case _AT_HWCAP:
|
||||
cpu.HWCap = uint(val)
|
||||
case _AT_HWCAP2:
|
||||
cpu.HWCap2 = uint(val)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
package runtime
|
||||
|
||||
var hardDiv bool // TODO: set if a hardware divider is available
|
||||
|
||||
func checkgoarm() {
|
||||
// TODO(minux): FP checks like in os_linux_arm.go.
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@ package runtime
|
|||
|
||||
import "unsafe"
|
||||
|
||||
var hardDiv bool // TODO: set if a hardware divider is available
|
||||
|
||||
func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintptr) {
|
||||
// Machine dependent mcontext initialisation for LWP.
|
||||
mc.__gregs[_REG_R15] = uint32(funcPC(lwp_tramp))
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
package runtime
|
||||
|
||||
var hardDiv bool // TODO: set if a hardware divider is available
|
||||
|
||||
func checkgoarm() {
|
||||
// TODO(minux): FP checks like in os_linux_arm.go.
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
package runtime
|
||||
|
||||
var hardDiv bool // TODO: set if a hardware divider is available
|
||||
|
||||
func checkgoarm() {
|
||||
return // TODO(minux)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
// the RET instruction will clobber R12 on nacl, and the compiler's register
|
||||
// allocator needs to know.
|
||||
TEXT runtime·udiv(SB),NOSPLIT|NOFRAME,$0
|
||||
MOVBU runtime·hardDiv(SB), Ra
|
||||
MOVBU internal∕cpu·ARM+const_offset_arm_HasIDIVA(SB), Ra
|
||||
CMP $0, Ra
|
||||
BNE udiv_hardware
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue