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: 's avatarIan Lance Taylor <iant@golang.org>
Reviewed-by: 's avatarKeith Randall <khr@golang.org>
parent 4363c98f
......@@ -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
......
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