mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
runtime: delete timediv
Now that the compiler handles constant 64-bit divisions without function calls on 32-bit systems, we no longer need to maintain and test a bad custom implementation of 64-bit division. Change-Id: If28807ad4f86507267ae69bc8f0b09ec18e98b66 Reviewed-on: https://go-review.googlesource.com/c/go/+/716463 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Russ Cox <rsc@golang.org> Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
cbbd385cb8
commit
d32b1f02c3
15 changed files with 27 additions and 132 deletions
|
|
@ -121,7 +121,8 @@ type timespec struct {
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func (ts *timespec) setNsec(ns int64) {
|
func (ts *timespec) setNsec(ns int64) {
|
||||||
ts.tv_sec = int64(timediv(ns, 1e9, &ts.tv_nsec))
|
ts.tv_sec = int64(ns / 1e9)
|
||||||
|
ts.tv_nsec = int32(ns % 1e9)
|
||||||
}
|
}
|
||||||
|
|
||||||
type timeval struct {
|
type timeval struct {
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,8 @@ type timespec struct {
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func (ts *timespec) setNsec(ns int64) {
|
func (ts *timespec) setNsec(ns int64) {
|
||||||
ts.tv_sec = int64(timediv(ns, 1e9, &ts.tv_nsec))
|
ts.tv_sec = int64(ns / 1e9)
|
||||||
|
ts.tv_nsec = int32(ns % 1e9)
|
||||||
}
|
}
|
||||||
|
|
||||||
type timeval struct {
|
type timeval struct {
|
||||||
|
|
|
||||||
|
|
@ -210,7 +210,8 @@ type timespec struct {
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func (ts *timespec) setNsec(ns int64) {
|
func (ts *timespec) setNsec(ns int64) {
|
||||||
ts.tv_sec = timediv(ns, 1e9, &ts.tv_nsec)
|
ts.tv_sec = int32(ns / 1e9)
|
||||||
|
ts.tv_nsec = int32(ns % 1e9)
|
||||||
}
|
}
|
||||||
|
|
||||||
type timeval struct {
|
type timeval struct {
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,8 @@ type timespec struct {
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func (ts *timespec) setNsec(ns int64) {
|
func (ts *timespec) setNsec(ns int64) {
|
||||||
ts.tv_sec = int64(timediv(ns, 1e9, &ts.tv_nsec))
|
ts.tv_sec = int64(ns / 1e9)
|
||||||
|
ts.tv_nsec = int32(ns % 1e9)
|
||||||
}
|
}
|
||||||
|
|
||||||
type timeval struct {
|
type timeval struct {
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,8 @@ type timespec32 struct {
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func (ts *timespec32) setNsec(ns int64) {
|
func (ts *timespec32) setNsec(ns int64) {
|
||||||
ts.tv_sec = timediv(ns, 1e9, &ts.tv_nsec)
|
ts.tv_sec = int32(ns / 1e9)
|
||||||
|
ts.tv_nsec = int32(ns % 1e9)
|
||||||
}
|
}
|
||||||
|
|
||||||
type timespec struct {
|
type timespec struct {
|
||||||
|
|
@ -156,9 +157,8 @@ type timespec struct {
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func (ts *timespec) setNsec(ns int64) {
|
func (ts *timespec) setNsec(ns int64) {
|
||||||
var newNS int32
|
ts.tv_sec = int64(ns / 1e9)
|
||||||
ts.tv_sec = int64(timediv(ns, 1e9, &newNS))
|
ts.tv_nsec = int64(ns % 1e9)
|
||||||
ts.tv_nsec = int64(newNS)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type timeval struct {
|
type timeval struct {
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,8 @@ type timespec32 struct {
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func (ts *timespec32) setNsec(ns int64) {
|
func (ts *timespec32) setNsec(ns int64) {
|
||||||
ts.tv_sec = timediv(ns, 1e9, &ts.tv_nsec)
|
ts.tv_sec = int32(ns / 1e9)
|
||||||
|
ts.tv_nsec = int32(ns % 1e9)
|
||||||
}
|
}
|
||||||
|
|
||||||
type timespec struct {
|
type timespec struct {
|
||||||
|
|
@ -115,9 +116,8 @@ type timespec struct {
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func (ts *timespec) setNsec(ns int64) {
|
func (ts *timespec) setNsec(ns int64) {
|
||||||
var newNS int32
|
ts.tv_sec = int64(ns / 1e9)
|
||||||
ts.tv_sec = int64(timediv(ns, 1e9, &newNS))
|
ts.tv_nsec = int64(ns % 1e9)
|
||||||
ts.tv_nsec = int64(newNS)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type stackt struct {
|
type stackt struct {
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,8 @@ type timespec32 struct {
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func (ts *timespec32) setNsec(ns int64) {
|
func (ts *timespec32) setNsec(ns int64) {
|
||||||
ts.tv_sec = timediv(ns, 1e9, &ts.tv_nsec)
|
ts.tv_sec = int32(ns / 1e9)
|
||||||
|
ts.tv_nsec = int32(ns % 1e9)
|
||||||
}
|
}
|
||||||
|
|
||||||
type timespec struct {
|
type timespec struct {
|
||||||
|
|
@ -113,9 +114,8 @@ type timespec struct {
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func (ts *timespec) setNsec(ns int64) {
|
func (ts *timespec) setNsec(ns int64) {
|
||||||
var newNS int32
|
ts.tv_sec = int64(ns / 1e9)
|
||||||
ts.tv_sec = int64(timediv(ns, 1e9, &newNS))
|
ts.tv_nsec = int64(ns % 1e9)
|
||||||
ts.tv_nsec = int64(newNS)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type timeval struct {
|
type timeval struct {
|
||||||
|
|
|
||||||
|
|
@ -147,7 +147,8 @@ type timespec struct {
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func (ts *timespec) setNsec(ns int64) {
|
func (ts *timespec) setNsec(ns int64) {
|
||||||
ts.tv_sec = int64(timediv(ns, 1e9, &ts.tv_nsec))
|
ts.tv_sec = int64(ns / 1e9)
|
||||||
|
ts.tv_nsec = int32(ns % 1e9)
|
||||||
}
|
}
|
||||||
|
|
||||||
type timeval struct {
|
type timeval struct {
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,8 @@ type timespec struct {
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
func (ts *timespec) setNsec(ns int64) {
|
func (ts *timespec) setNsec(ns int64) {
|
||||||
ts.tv_sec = int64(timediv(ns, 1e9, &ts.tv_nsec))
|
ts.tv_sec = int64(ns / 1e9)
|
||||||
|
ts.tv_nsec = int32(ns % 1e9)
|
||||||
}
|
}
|
||||||
|
|
||||||
type timeval struct {
|
type timeval struct {
|
||||||
|
|
|
||||||
|
|
@ -1472,8 +1472,6 @@ func Releasem() {
|
||||||
releasem(getg().m)
|
releasem(getg().m)
|
||||||
}
|
}
|
||||||
|
|
||||||
var Timediv = timediv
|
|
||||||
|
|
||||||
type PIController struct {
|
type PIController struct {
|
||||||
piController
|
piController
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,7 @@ func futexsleep1(addr *uint32, val uint32, ns int64) {
|
||||||
// The timeout is specified in microseconds - ensure that we
|
// The timeout is specified in microseconds - ensure that we
|
||||||
// do not end up dividing to zero, which would put us to sleep
|
// do not end up dividing to zero, which would put us to sleep
|
||||||
// indefinitely...
|
// indefinitely...
|
||||||
timeout = timediv(ns, 1000, nil)
|
timeout = int32(ns / 1000)
|
||||||
if timeout == 0 {
|
if timeout == 0 {
|
||||||
timeout = 1
|
timeout = 1
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -486,7 +486,7 @@ func semacreate(mp *m) {
|
||||||
func semasleep(ns int64) int {
|
func semasleep(ns int64) int {
|
||||||
gp := getg()
|
gp := getg()
|
||||||
if ns >= 0 {
|
if ns >= 0 {
|
||||||
ms := timediv(ns, 1000000, nil)
|
ms := int32(ns / 1000000)
|
||||||
if ms == 0 {
|
if ms == 0 {
|
||||||
ms = 1
|
ms = 1
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -664,7 +664,7 @@ func semasleep(ns int64) int32 {
|
||||||
start := nanotime()
|
start := nanotime()
|
||||||
elapsed := int64(0)
|
elapsed := int64(0)
|
||||||
for {
|
for {
|
||||||
ms := int64(timediv(ns-elapsed, 1000000, nil))
|
ms := (ns - elapsed) / 1000000
|
||||||
if ms == 0 {
|
if ms == 0 {
|
||||||
ms = 1
|
ms = 1
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -212,10 +212,6 @@ func check() {
|
||||||
throw("bad unsafe.Sizeof y1")
|
throw("bad unsafe.Sizeof y1")
|
||||||
}
|
}
|
||||||
|
|
||||||
if timediv(12345*1000000000+54321, 1000000000, &e) != 12345 || e != 54321 {
|
|
||||||
throw("bad timediv")
|
|
||||||
}
|
|
||||||
|
|
||||||
var z uint32
|
var z uint32
|
||||||
z = 1
|
z = 1
|
||||||
if !atomic.Cas(&z, 1, 2) {
|
if !atomic.Cas(&z, 1, 2) {
|
||||||
|
|
@ -593,35 +589,6 @@ func setTraceback(level string) {
|
||||||
atomic.Store(&traceback_cache, t)
|
atomic.Store(&traceback_cache, t)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Poor mans 64-bit division.
|
|
||||||
// This is a very special function, do not use it if you are not sure what you are doing.
|
|
||||||
// int64 division is lowered into _divv() call on 386, which does not fit into nosplit functions.
|
|
||||||
// Handles overflow in a time-specific manner.
|
|
||||||
// This keeps us within no-split stack limits on 32-bit processors.
|
|
||||||
//
|
|
||||||
//go:nosplit
|
|
||||||
func timediv(v int64, div int32, rem *int32) int32 {
|
|
||||||
res := int32(0)
|
|
||||||
for bit := 30; bit >= 0; bit-- {
|
|
||||||
if v >= int64(div)<<uint(bit) {
|
|
||||||
v = v - (int64(div) << uint(bit))
|
|
||||||
// Before this for loop, res was 0, thus all these
|
|
||||||
// power of 2 increments are now just bitsets.
|
|
||||||
res |= 1 << uint(bit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if v >= int64(div) {
|
|
||||||
if rem != nil {
|
|
||||||
*rem = 0
|
|
||||||
}
|
|
||||||
return 0x7fffffff
|
|
||||||
}
|
|
||||||
if rem != nil {
|
|
||||||
*rem = int32(v)
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helpers for Go. Must be NOSPLIT, must only call NOSPLIT functions, and must not block.
|
// Helpers for Go. Must be NOSPLIT, must only call NOSPLIT functions, and must not block.
|
||||||
|
|
||||||
//go:nosplit
|
//go:nosplit
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ package runtime_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
|
||||||
"internal/asan"
|
"internal/asan"
|
||||||
"internal/cpu"
|
"internal/cpu"
|
||||||
"internal/msan"
|
"internal/msan"
|
||||||
|
|
@ -498,81 +497,6 @@ func TestVersion(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTimediv(t *testing.T) {
|
|
||||||
for _, tc := range []struct {
|
|
||||||
num int64
|
|
||||||
div int32
|
|
||||||
ret int32
|
|
||||||
rem int32
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
num: 8,
|
|
||||||
div: 2,
|
|
||||||
ret: 4,
|
|
||||||
rem: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
num: 9,
|
|
||||||
div: 2,
|
|
||||||
ret: 4,
|
|
||||||
rem: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
// Used by runtime.check.
|
|
||||||
num: 12345*1000000000 + 54321,
|
|
||||||
div: 1000000000,
|
|
||||||
ret: 12345,
|
|
||||||
rem: 54321,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
num: 1<<32 - 1,
|
|
||||||
div: 2,
|
|
||||||
ret: 1<<31 - 1, // no overflow.
|
|
||||||
rem: 1,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
num: 1 << 32,
|
|
||||||
div: 2,
|
|
||||||
ret: 1<<31 - 1, // overflow.
|
|
||||||
rem: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
num: 1 << 40,
|
|
||||||
div: 2,
|
|
||||||
ret: 1<<31 - 1, // overflow.
|
|
||||||
rem: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
num: 1<<40 + 1,
|
|
||||||
div: 1 << 10,
|
|
||||||
ret: 1 << 30,
|
|
||||||
rem: 1,
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
name := fmt.Sprintf("%d div %d", tc.num, tc.div)
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
// Double check that the inputs make sense using
|
|
||||||
// standard 64-bit division.
|
|
||||||
ret64 := tc.num / int64(tc.div)
|
|
||||||
rem64 := tc.num % int64(tc.div)
|
|
||||||
if ret64 != int64(int32(ret64)) {
|
|
||||||
// Simulate timediv overflow value.
|
|
||||||
ret64 = 1<<31 - 1
|
|
||||||
rem64 = 0
|
|
||||||
}
|
|
||||||
if ret64 != int64(tc.ret) {
|
|
||||||
t.Errorf("%d / %d got ret %d rem %d want ret %d rem %d", tc.num, tc.div, ret64, rem64, tc.ret, tc.rem)
|
|
||||||
}
|
|
||||||
|
|
||||||
var rem int32
|
|
||||||
ret := Timediv(tc.num, tc.div, &rem)
|
|
||||||
if ret != tc.ret || rem != tc.rem {
|
|
||||||
t.Errorf("timediv %d / %d got ret %d rem %d want ret %d rem %d", tc.num, tc.div, ret, rem, tc.ret, tc.rem)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func BenchmarkProcYield(b *testing.B) {
|
func BenchmarkProcYield(b *testing.B) {
|
||||||
benchN := func(n uint32) func(*testing.B) {
|
benchN := func(n uint32) func(*testing.B) {
|
||||||
return func(b *testing.B) {
|
return func(b *testing.B) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue