From 92fe95f02e86315e653ec06a5bdc590c544144c0 Mon Sep 17 00:00:00 2001 From: HowJMay Date: Sat, 7 Aug 2021 19:46:10 +0800 Subject: [PATCH] math: Add ARM64 implementation of frexp The implementation of Frexp on ARM64 has been implemented in this PR. The following benchmark was run on Apple Silicon M1 chips. BenchmarkArchFrexp-8 1.581 ns/op 0 B/op 0 allocs/op BenchmarkFrexpGO-8 2.079 ns/op 0 B/op 0 allocs/op The time spent on each iteration drop 23.95%. --- src/math/all_test.go | 12 ++++++++- src/math/arith_s390x.go | 6 ----- src/math/export_test.go | 1 + src/math/frexp_arm64.s | 57 +++++++++++++++++++++++++++++++++++++++++ src/math/frexp_asm.go | 12 +++++++++ src/math/frexp_noasm.go | 14 ++++++++++ src/math/stubs.go | 6 ----- 7 files changed, 95 insertions(+), 13 deletions(-) create mode 100644 src/math/frexp_arm64.s create mode 100644 src/math/frexp_asm.go create mode 100644 src/math/frexp_noasm.go diff --git a/src/math/all_test.go b/src/math/all_test.go index 55c805e199e..7b9f677dae7 100644 --- a/src/math/all_test.go +++ b/src/math/all_test.go @@ -2541,7 +2541,7 @@ func TestFrexp(t *testing.T) { } } for i := 0; i < len(vffrexpBC); i++ { - if f, j := Frexp(vffrexpBC[i]); !alike(frexpBC[i].f, f) || frexpBC[i].i != j { + if f, j := Frexp(vffrexpBC[i]); !veryclose(frexpBC[i].f, f) || frexpBC[i].i != j { t.Errorf("Frexp(%g) = %g, %d, want %g, %d", vffrexpBC[i], f, j, frexpBC[i].f, frexpBC[i].i) } } @@ -3467,6 +3467,16 @@ func BenchmarkFrexp(b *testing.B) { GlobalI = y } +func BenchmarkFrexpGO(b *testing.B) { + x := 0.0 + y := 0 + for i := 0; i < b.N; i++ { + x, y = FrexpGO(8) + } + GlobalF = x + GlobalI = y +} + func BenchmarkGamma(b *testing.B) { x := 0.0 for i := 0; i < b.N; i++ { diff --git a/src/math/arith_s390x.go b/src/math/arith_s390x.go index 129156a9f6d..cbbe672b395 100644 --- a/src/math/arith_s390x.go +++ b/src/math/arith_s390x.go @@ -135,12 +135,6 @@ func archPow(x, y float64) float64 func powTrampolineSetup(x, y float64) float64 func powAsm(x, y float64) float64 -const haveArchFrexp = false - -func archFrexp(x float64) (float64, int) { - panic("not implemented") -} - const haveArchLdexp = false func archLdexp(frac float64, exp int) float64 { diff --git a/src/math/export_test.go b/src/math/export_test.go index 53d9205b9d1..41a1eb8707a 100644 --- a/src/math/export_test.go +++ b/src/math/export_test.go @@ -8,6 +8,7 @@ package math var ExpGo = exp var Exp2Go = exp2 var HypotGo = hypot +var FrexpGo = frexp var SqrtGo = sqrt var TrigReduce = trigReduce diff --git a/src/math/frexp_arm64.s b/src/math/frexp_arm64.s new file mode 100644 index 00000000000..0618a92c977 --- /dev/null +++ b/src/math/frexp_arm64.s @@ -0,0 +1,57 @@ +// Copyright 2021 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. + +#include "textflag.h" + +#define PosInf 0x7FF0000000000000 +#define Float64SmallestNormal 2.2250738585072014e-308 + +// func archFrexp(x float64) (frac float64, exp int) +TEXT ·archFrexp(SB),NOSPLIT,$0-24 + FMOVD x+0(FP), F0 + MOVD ZR, R1 // R1 is the ret exp + FABSD F0, F3 // F3 is the absolute of 'x' + FCMPD $(0.0), F3 // avoid the input floating number is -0.0 + BEQ isInfOrNaNOrZero + + MOVD $PosInf, R3 + FMOVD R3, F30 // F30 is PosInf + FCMPD F30, F3 + BGE isInfOrNaNOrZero // isInf + FCMPED F0, F0 + BNE isInfOrNaNOrZero // isNaN + + FMOVD F3, R0 + UBFX $52, R0, $11, R0 + + FMOVD $Float64SmallestNormal, F29 + FCMPD F29, F3 + BGE pass + + // if abs(x) < SmallestNormal ,then run the following special case + FMOVD $(4503599627370496.0), F2 // 4503599627370496.0 is (1<<52) + FMULD F2, F0, F0 + SUB $(52), R1, R1 // set R1 to -52 + FMOVD F0, R0 + // tmp = int((x>>shift)&mask) + UBFX $52, R0, $11, R0 + +pass: + // tmp = tmp - bias + 1 + SUB $0x3FE, R0, R3 + // exp = exp + tmp + ADD R3, R1, R1 + + FMOVD F0, R0 + AND $0x800FFFFFFFFFFFFF, R0, R0 + ORR $0x3FE0000000000000, R0, R0 + FMOVD R0, F0 + FMOVD F0, frac+8(FP) + MOVD R1, exp+16(FP) + RET + +isInfOrNaNOrZero: + FMOVD F0, frac+8(FP) + MOVD R1, exp+16(FP) + RET diff --git a/src/math/frexp_asm.go b/src/math/frexp_asm.go new file mode 100644 index 00000000000..ab9d84f0cff --- /dev/null +++ b/src/math/frexp_asm.go @@ -0,0 +1,12 @@ +// Copyright 2021 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. + +//go:build arm64 +// +build arm64 + +package math + +const haveArchFrexp = true + +func archFrexp(x float64) (frac float64, exp int) diff --git a/src/math/frexp_noasm.go b/src/math/frexp_noasm.go new file mode 100644 index 00000000000..568c05c40d2 --- /dev/null +++ b/src/math/frexp_noasm.go @@ -0,0 +1,14 @@ +// Copyright 2021 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. + +//go:build !arm64 +// +build !arm64 + +package math + +const haveArchFrexp = false + +func archFrexp(x float64) (frac float64, exp int) + panic("not implemented") +} diff --git a/src/math/stubs.go b/src/math/stubs.go index e1345eb841d..18512ab7829 100644 --- a/src/math/stubs.go +++ b/src/math/stubs.go @@ -88,12 +88,6 @@ func archExpm1(x float64) float64 { panic("not implemented") } -const haveArchFrexp = false - -func archFrexp(x float64) (float64, int) { - panic("not implemented") -} - const haveArchLdexp = false func archLdexp(frac float64, exp int) float64 {