From d32b1f02c3e869b6ddf73d2113477b1fd77d42c8 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 29 Oct 2025 13:37:52 -0400 Subject: [PATCH] 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 Auto-Submit: Russ Cox Reviewed-by: Alan Donovan --- src/runtime/defs1_netbsd_386.go | 3 +- src/runtime/defs1_netbsd_arm.go | 3 +- src/runtime/defs_freebsd_386.go | 3 +- src/runtime/defs_freebsd_arm.go | 3 +- src/runtime/defs_linux_386.go | 8 ++-- src/runtime/defs_linux_arm.go | 8 ++-- src/runtime/defs_linux_mipsx.go | 8 ++-- src/runtime/defs_openbsd_386.go | 3 +- src/runtime/defs_openbsd_arm.go | 3 +- src/runtime/export_test.go | 2 - src/runtime/os_dragonfly.go | 2 +- src/runtime/os_plan9.go | 2 +- src/runtime/os_windows.go | 2 +- src/runtime/runtime1.go | 33 -------------- src/runtime/runtime_test.go | 76 --------------------------------- 15 files changed, 27 insertions(+), 132 deletions(-) diff --git a/src/runtime/defs1_netbsd_386.go b/src/runtime/defs1_netbsd_386.go index 16c55def92..cb4d6f1cf1 100644 --- a/src/runtime/defs1_netbsd_386.go +++ b/src/runtime/defs1_netbsd_386.go @@ -121,7 +121,8 @@ type timespec struct { //go:nosplit 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 { diff --git a/src/runtime/defs1_netbsd_arm.go b/src/runtime/defs1_netbsd_arm.go index 77a59d4a05..d31fcd471d 100644 --- a/src/runtime/defs1_netbsd_arm.go +++ b/src/runtime/defs1_netbsd_arm.go @@ -123,7 +123,8 @@ type timespec struct { //go:nosplit 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 { diff --git a/src/runtime/defs_freebsd_386.go b/src/runtime/defs_freebsd_386.go index 42a0faf74d..20ac643ad7 100644 --- a/src/runtime/defs_freebsd_386.go +++ b/src/runtime/defs_freebsd_386.go @@ -210,7 +210,8 @@ type timespec struct { //go:nosplit 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 { diff --git a/src/runtime/defs_freebsd_arm.go b/src/runtime/defs_freebsd_arm.go index dbb54da51b..cf61fcade5 100644 --- a/src/runtime/defs_freebsd_arm.go +++ b/src/runtime/defs_freebsd_arm.go @@ -182,7 +182,8 @@ type timespec struct { //go:nosplit 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 { diff --git a/src/runtime/defs_linux_386.go b/src/runtime/defs_linux_386.go index c6c7d7d6d8..d1875954f3 100644 --- a/src/runtime/defs_linux_386.go +++ b/src/runtime/defs_linux_386.go @@ -146,7 +146,8 @@ type timespec32 struct { //go:nosplit 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 { @@ -156,9 +157,8 @@ type timespec struct { //go:nosplit func (ts *timespec) setNsec(ns int64) { - var newNS int32 - ts.tv_sec = int64(timediv(ns, 1e9, &newNS)) - ts.tv_nsec = int64(newNS) + ts.tv_sec = int64(ns / 1e9) + ts.tv_nsec = int64(ns % 1e9) } type timeval struct { diff --git a/src/runtime/defs_linux_arm.go b/src/runtime/defs_linux_arm.go index ff879fad89..94577fc597 100644 --- a/src/runtime/defs_linux_arm.go +++ b/src/runtime/defs_linux_arm.go @@ -105,7 +105,8 @@ type timespec32 struct { //go:nosplit 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 { @@ -115,9 +116,8 @@ type timespec struct { //go:nosplit func (ts *timespec) setNsec(ns int64) { - var newNS int32 - ts.tv_sec = int64(timediv(ns, 1e9, &newNS)) - ts.tv_nsec = int64(newNS) + ts.tv_sec = int64(ns / 1e9) + ts.tv_nsec = int64(ns % 1e9) } type stackt struct { diff --git a/src/runtime/defs_linux_mipsx.go b/src/runtime/defs_linux_mipsx.go index 5b10b910db..5a446e0595 100644 --- a/src/runtime/defs_linux_mipsx.go +++ b/src/runtime/defs_linux_mipsx.go @@ -103,7 +103,8 @@ type timespec32 struct { //go:nosplit 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 { @@ -113,9 +114,8 @@ type timespec struct { //go:nosplit func (ts *timespec) setNsec(ns int64) { - var newNS int32 - ts.tv_sec = int64(timediv(ns, 1e9, &newNS)) - ts.tv_nsec = int64(newNS) + ts.tv_sec = int64(ns / 1e9) + ts.tv_nsec = int64(ns % 1e9) } type timeval struct { diff --git a/src/runtime/defs_openbsd_386.go b/src/runtime/defs_openbsd_386.go index 996745f6f8..c77b5e16cb 100644 --- a/src/runtime/defs_openbsd_386.go +++ b/src/runtime/defs_openbsd_386.go @@ -147,7 +147,8 @@ type timespec struct { //go:nosplit 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 { diff --git a/src/runtime/defs_openbsd_arm.go b/src/runtime/defs_openbsd_arm.go index cdda6b4ad1..5393ea4eeb 100644 --- a/src/runtime/defs_openbsd_arm.go +++ b/src/runtime/defs_openbsd_arm.go @@ -152,7 +152,8 @@ type timespec struct { //go:nosplit 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 { diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index 9f2fcacc30..d6fce72bf0 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -1472,8 +1472,6 @@ func Releasem() { releasem(getg().m) } -var Timediv = timediv - type PIController struct { piController } diff --git a/src/runtime/os_dragonfly.go b/src/runtime/os_dragonfly.go index fbbee64fd3..c34af7f072 100644 --- a/src/runtime/os_dragonfly.go +++ b/src/runtime/os_dragonfly.go @@ -113,7 +113,7 @@ func futexsleep1(addr *uint32, val uint32, ns int64) { // The timeout is specified in microseconds - ensure that we // do not end up dividing to zero, which would put us to sleep // indefinitely... - timeout = timediv(ns, 1000, nil) + timeout = int32(ns / 1000) if timeout == 0 { timeout = 1 } diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go index 72a8657985..80c101f1a1 100644 --- a/src/runtime/os_plan9.go +++ b/src/runtime/os_plan9.go @@ -486,7 +486,7 @@ func semacreate(mp *m) { func semasleep(ns int64) int { gp := getg() if ns >= 0 { - ms := timediv(ns, 1000000, nil) + ms := int32(ns / 1000000) if ms == 0 { ms = 1 } diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go index 7610802e0f..2ae625580d 100644 --- a/src/runtime/os_windows.go +++ b/src/runtime/os_windows.go @@ -664,7 +664,7 @@ func semasleep(ns int64) int32 { start := nanotime() elapsed := int64(0) for { - ms := int64(timediv(ns-elapsed, 1000000, nil)) + ms := (ns - elapsed) / 1000000 if ms == 0 { ms = 1 } diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go index 3ec5c44ebd..43e4c14236 100644 --- a/src/runtime/runtime1.go +++ b/src/runtime/runtime1.go @@ -212,10 +212,6 @@ func check() { throw("bad unsafe.Sizeof y1") } - if timediv(12345*1000000000+54321, 1000000000, &e) != 12345 || e != 54321 { - throw("bad timediv") - } - var z uint32 z = 1 if !atomic.Cas(&z, 1, 2) { @@ -593,35 +589,6 @@ func setTraceback(level string) { 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)<= 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. //go:nosplit diff --git a/src/runtime/runtime_test.go b/src/runtime/runtime_test.go index 6c628f8903..c1c63e3cea 100644 --- a/src/runtime/runtime_test.go +++ b/src/runtime/runtime_test.go @@ -6,7 +6,6 @@ package runtime_test import ( "flag" - "fmt" "internal/asan" "internal/cpu" "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) { benchN := func(n uint32) func(*testing.B) { return func(b *testing.B) { -- 2.52.0