From: Russ Cox Date: Thu, 30 Jul 2015 14:54:53 +0000 (-0400) Subject: runtime: replace divide with multiply in runtime.usleep on arm X-Git-Tag: go1.5rc1~86 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=c9d2c7f0d26a9619069a3cb2291333174b6db63f;p=gostls13.git runtime: replace divide with multiply in runtime.usleep on arm We want to adjust the DIV calling convention to use m, and usleep can be called without an m, so switch to a multiplication by the reciprocal (and test). Step toward a fix for #6699 and #10486. Change-Id: Iccf76a18432d835e48ec64a2fa34a0e4d6d4b955 Reviewed-on: https://go-review.googlesource.com/12898 Reviewed-by: Ian Lance Taylor --- diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s index 661538c024..280a682a7c 100644 --- a/src/runtime/asm_arm.s +++ b/src/runtime/asm_arm.s @@ -1029,3 +1029,24 @@ TEXT runtime·prefetcht2(SB),NOSPLIT,$0-4 TEXT runtime·prefetchnta(SB),NOSPLIT,$0-4 RET + +// x -> x/1000000, x%1000000, called from Go with args, results on stack. +TEXT runtime·usplit(SB),NOSPLIT,$0-12 + MOVW x+0(FP), R0 + CALL runtime·usplitR0(SB) + MOVW R0, q+4(FP) + MOVW R1, r+8(FP) + RET + +// R0, R1 = R0/1000000, R0%1000000 +TEXT runtime·usplitR0(SB),NOSPLIT,$0 + // magic multiply to avoid software divide without available m. + // see output of go tool compile -S for x/1000000. + MOVW R0, R3 + MOVW $1125899907, R1 + MULLU R1, R0, (R0, R1) + MOVW R0>>18, R0 + MOVW $1000000, R1 + MULU R0, R1 + SUB R1, R3, R1 + RET diff --git a/src/runtime/export_arm_test.go b/src/runtime/export_arm_test.go new file mode 100644 index 0000000000..446d26465c --- /dev/null +++ b/src/runtime/export_arm_test.go @@ -0,0 +1,9 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Export guts for testing. + +package runtime + +var Usplit = usplit diff --git a/src/runtime/sys_arm.go b/src/runtime/sys_arm.go index 6e50d21098..d2e69146af 100644 --- a/src/runtime/sys_arm.go +++ b/src/runtime/sys_arm.go @@ -33,3 +33,6 @@ func rewindmorestack(buf *gobuf) { print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n") throw("runtime: misuse of rewindmorestack") } + +// for testing +func usplit(x uint32) (q, r uint32) diff --git a/src/runtime/sys_darwin_arm.s b/src/runtime/sys_darwin_arm.s index be35d37bc8..087dec551e 100644 --- a/src/runtime/sys_darwin_arm.s +++ b/src/runtime/sys_darwin_arm.s @@ -283,10 +283,7 @@ TEXT runtime·sigaction(SB),NOSPLIT,$0 TEXT runtime·usleep(SB),NOSPLIT,$12 MOVW usec+0(FP), R0 - MOVW R0, R1 - MOVW $1000000, R2 - DIV R2, R0 - MOD R2, R1 + CALL runtime·usplitR0(SB) MOVW R0, a-12(SP) MOVW R1, b-8(SP) diff --git a/src/runtime/sys_freebsd_arm.s b/src/runtime/sys_freebsd_arm.s index 0441d81b25..bd6ff96f31 100644 --- a/src/runtime/sys_freebsd_arm.s +++ b/src/runtime/sys_freebsd_arm.s @@ -302,15 +302,12 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$-8 TEXT runtime·usleep(SB),NOSPLIT,$16 MOVW usec+0(FP), R0 - MOVW R0, R2 - MOVW $1000000, R1 - DIV R1, R0 + CALL runtime·usplitR0(SB) // 0(R13) is the saved LR, don't use it MOVW R0, 4(R13) // tv_sec.low MOVW $0, R0 MOVW R0, 8(R13) // tv_sec.high - MOD R1, R2 - MOVW $1000, R1 + MOVW $1000, R2 MUL R1, R2 MOVW R2, 12(R13) // tv_nsec diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s index abdeb93e59..29eb8eb077 100644 --- a/src/runtime/sys_linux_arm.s +++ b/src/runtime/sys_linux_arm.s @@ -378,10 +378,7 @@ TEXT runtime·rt_sigaction(SB),NOSPLIT,$0 TEXT runtime·usleep(SB),NOSPLIT,$12 MOVW usec+0(FP), R0 - MOVW R0, R1 - MOVW $1000000, R2 - DIV R2, R0 - MOD R2, R1 + CALL runtime·usplitR0(SB) MOVW R0, 4(R13) MOVW R1, 8(R13) MOVW $0, R0 diff --git a/src/runtime/sys_netbsd_arm.s b/src/runtime/sys_netbsd_arm.s index 24c32a6158..ae669ce76b 100644 --- a/src/runtime/sys_netbsd_arm.s +++ b/src/runtime/sys_netbsd_arm.s @@ -104,15 +104,12 @@ TEXT runtime·lwp_tramp(SB),NOSPLIT,$0 TEXT runtime·usleep(SB),NOSPLIT,$16 MOVW usec+0(FP), R0 - MOVW R0, R2 - MOVW $1000000, R1 - DIV R1, R0 + CALL runtime·usplitR0(SB) // 0(R13) is the saved LR, don't use it MOVW R0, 4(R13) // tv_sec.low MOVW $0, R0 MOVW R0, 8(R13) // tv_sec.high - MOD R1, R2 - MOVW $1000, R1 + MOVW $1000, R2 MUL R1, R2 MOVW R2, 12(R13) // tv_nsec diff --git a/src/runtime/sys_openbsd_arm.s b/src/runtime/sys_openbsd_arm.s index ab7f2ae01f..60deb8f38a 100644 --- a/src/runtime/sys_openbsd_arm.s +++ b/src/runtime/sys_openbsd_arm.s @@ -70,14 +70,11 @@ TEXT runtime·write(SB),NOSPLIT,$-4 TEXT runtime·usleep(SB),NOSPLIT,$16 MOVW usec+0(FP), R0 - MOVW R0, R2 - MOVW $1000000, R1 - DIV R1, R0 + CALL runtime·usplitR0(SB) MOVW R0, 4(R13) // tv_sec - l32 MOVW $0, R0 MOVW R0, 8(R13) // tv_sec - h32 - MOD R1, R2 - MOVW $1000, R1 + MOVW $1000, R2 MUL R1, R2 MOVW R2, 12(R13) // tv_nsec diff --git a/src/runtime/vlop_arm_test.go b/src/runtime/vlop_arm_test.go index cd28419adf..1a211196f2 100644 --- a/src/runtime/vlop_arm_test.go +++ b/src/runtime/vlop_arm_test.go @@ -4,7 +4,10 @@ package runtime_test -import "testing" +import ( + "runtime" + "testing" +) // arm soft division benchmarks adapted from // http://ridiculousfish.com/files/division_benchmarks.tar.gz @@ -68,3 +71,14 @@ func BenchmarkUint32Mod13307(b *testing.B) { bmUint32Mod(13307, b) } func BenchmarkUint32Mod52513(b *testing.B) { bmUint32Mod(52513, b) } func BenchmarkUint32Mod60978747(b *testing.B) { bmUint32Mod(60978747, b) } func BenchmarkUint32Mod106956295(b *testing.B) { bmUint32Mod(106956295, b) } + +func TestUsplit(t *testing.T) { + var den uint32 = 1000000 + for _, x := range []uint32{0, 1, 999999, 1000000, 1010101, 0xFFFFFFFF} { + q1, r1 := runtime.Usplit(x) + q2, r2 := x/den, x%den + if q1 != q2 || r1 != r2 { + t.Errorf("%d/1e6, %d%%1e6 = %d, %d, want %d, %d", x, x, q1, r1, q2, r2) + } + } +}