Commit 2e8c31b3 authored by Martin Möhrmann's avatar Martin Möhrmann

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: default avatarIan Lance Taylor <iant@golang.org>
Reviewed-by: default avatarKeith Randall <khr@golang.org>
parent 4363c98f
...@@ -66,6 +66,16 @@ type ppc64 struct { ...@@ -66,6 +66,16 @@ type ppc64 struct {
_ CacheLinePad _ 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 var ARM64 arm64
// The booleans in arm64 contain the correspondingly named cpu feature bit. // The booleans in arm64 contain the correspondingly named cpu feature bit.
......
...@@ -5,3 +5,28 @@ ...@@ -5,3 +5,28 @@
package cpu package cpu
const CacheLineSize = 32 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 @@ ...@@ -5,6 +5,7 @@
// +build !386 // +build !386
// +build !amd64 // +build !amd64
// +build !amd64p32 // +build !amd64p32
// +build !arm
// +build !arm64 // +build !arm64
// +build !ppc64 // +build !ppc64
// +build !ppc64le // +build !ppc64le
......
...@@ -14,4 +14,6 @@ const ( ...@@ -14,4 +14,6 @@ const (
offset_x86_HasAVX2 = unsafe.Offsetof(cpu.X86.HasAVX2) offset_x86_HasAVX2 = unsafe.Offsetof(cpu.X86.HasAVX2)
offset_x86_HasERMS = unsafe.Offsetof(cpu.X86.HasERMS) offset_x86_HasERMS = unsafe.Offsetof(cpu.X86.HasERMS)
offset_x86_HasSSE2 = unsafe.Offsetof(cpu.X86.HasSSE2) offset_x86_HasSSE2 = unsafe.Offsetof(cpu.X86.HasSSE2)
offset_arm_HasIDIVA = unsafe.Offsetof(cpu.ARM.HasIDIVA)
) )
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
package runtime package runtime
var hardDiv bool // TODO: set if a hardware divider is available
func checkgoarm() { func checkgoarm() {
// TODO(minux): FP checks like in os_linux_arm.go. // TODO(minux): FP checks like in os_linux_arm.go.
......
...@@ -389,6 +389,7 @@ const ( ...@@ -389,6 +389,7 @@ const (
_AT_PAGESZ = 6 // Page size in bytes _AT_PAGESZ = 6 // Page size in bytes
_AT_TIMEKEEP = 22 // Pointer to timehands. _AT_TIMEKEEP = 22 // Pointer to timehands.
_AT_HWCAP = 25 // CPU feature flags _AT_HWCAP = 25 // CPU feature flags
_AT_HWCAP2 = 26 // CPU feature flags 2
) )
func sysauxv(auxv []uintptr) { func sysauxv(auxv []uintptr) {
......
...@@ -4,22 +4,29 @@ ...@@ -4,22 +4,29 @@
package runtime package runtime
import "internal/cpu"
const ( const (
_HWCAP_VFP = 1 << 6 _HWCAP_VFP = 1 << 6
_HWCAP_VFPv3 = 1 << 13 _HWCAP_VFPv3 = 1 << 13
_HWCAP_IDIVA = 1 << 17
) )
var hwcap = ^uint32(0) // set by archauxv // AT_HWCAP is not available on FreeBSD-11.1-RELEASE or earlier.
var hardDiv bool // set if a hardware divider is available // 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() { 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("runtime: this CPU has no floating point hardware, so it cannot run\n")
print("this GOARM=", goarm, " binary. Recompile using GOARM=5.\n") print("this GOARM=", goarm, " binary. Recompile using GOARM=5.\n")
exit(1) 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("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") print("this GOARM=", goarm, " binary. Recompile using GOARM=5 or GOARM=6.\n")
exit(1) exit(1)
...@@ -35,9 +42,11 @@ func checkgoarm() { ...@@ -35,9 +42,11 @@ func checkgoarm() {
func archauxv(tag, val uintptr) { func archauxv(tag, val uintptr) {
switch tag { switch tag {
case _AT_HWCAP: // CPU capability bit flags case _AT_HWCAP:
hwcap = uint32(val) cpu.HWCap = uint(val)
hardDiv = (hwcap & _HWCAP_IDIVA) != 0 goarmHWCap = cpu.HWCap
case _AT_HWCAP2:
cpu.HWCap2 = uint(val)
} }
} }
......
...@@ -4,20 +4,20 @@ ...@@ -4,20 +4,20 @@
package runtime package runtime
import "unsafe" import (
"internal/cpu"
"unsafe"
)
const ( const (
_AT_PLATFORM = 15 // introduced in at least 2.6.11 _AT_PLATFORM = 15 // introduced in at least 2.6.11
_HWCAP_VFP = 1 << 6 // 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_VFPv3 = 1 << 13 // introduced in 2.6.30
_HWCAP_IDIVA = 1 << 17
) )
var randomNumber uint32 var randomNumber uint32
var armArch uint8 = 6 // we default to ARMv6 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() { func checkgoarm() {
// On Android, /proc/self/auxv might be unreadable and hwcap won't // On Android, /proc/self/auxv might be unreadable and hwcap won't
...@@ -26,12 +26,12 @@ func checkgoarm() { ...@@ -26,12 +26,12 @@ func checkgoarm() {
if GOOS == "android" { if GOOS == "android" {
return 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("runtime: this CPU has no floating point hardware, so it cannot run\n")
print("this GOARM=", goarm, " binary. Recompile using GOARM=5.\n") print("this GOARM=", goarm, " binary. Recompile using GOARM=5.\n")
exit(1) 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("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") print("this GOARM=", goarm, " binary. Recompile using GOARM=5 or GOARM=6.\n")
exit(1) exit(1)
...@@ -53,9 +53,10 @@ func archauxv(tag, val uintptr) { ...@@ -53,9 +53,10 @@ func archauxv(tag, val uintptr) {
armArch = t - '0' armArch = t - '0'
} }
case _AT_HWCAP: // CPU capability bit flags case _AT_HWCAP:
hwcap = uint32(val) cpu.HWCap = uint(val)
hardDiv = (hwcap & _HWCAP_IDIVA) != 0 case _AT_HWCAP2:
cpu.HWCap2 = uint(val)
} }
} }
......
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
package runtime package runtime
var hardDiv bool // TODO: set if a hardware divider is available
func checkgoarm() { func checkgoarm() {
// TODO(minux): FP checks like in os_linux_arm.go. // TODO(minux): FP checks like in os_linux_arm.go.
......
...@@ -6,8 +6,6 @@ package runtime ...@@ -6,8 +6,6 @@ package runtime
import "unsafe" 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) { func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintptr) {
// Machine dependent mcontext initialisation for LWP. // Machine dependent mcontext initialisation for LWP.
mc.__gregs[_REG_R15] = uint32(funcPC(lwp_tramp)) mc.__gregs[_REG_R15] = uint32(funcPC(lwp_tramp))
......
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
package runtime package runtime
var hardDiv bool // TODO: set if a hardware divider is available
func checkgoarm() { func checkgoarm() {
// TODO(minux): FP checks like in os_linux_arm.go. // TODO(minux): FP checks like in os_linux_arm.go.
......
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
package runtime package runtime
var hardDiv bool // TODO: set if a hardware divider is available
func checkgoarm() { func checkgoarm() {
return // TODO(minux) return // TODO(minux)
} }
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
// the RET instruction will clobber R12 on nacl, and the compiler's register // the RET instruction will clobber R12 on nacl, and the compiler's register
// allocator needs to know. // allocator needs to know.
TEXT runtime·udiv(SB),NOSPLIT|NOFRAME,$0 TEXT runtime·udiv(SB),NOSPLIT|NOFRAME,$0
MOVBU runtime·hardDiv(SB), Ra MOVBU internalcpu·ARM+const_offset_arm_HasIDIVA(SB), Ra
CMP $0, Ra CMP $0, Ra
BNE udiv_hardware BNE udiv_hardware
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment