mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: use FCLASSD for subnormal checks on riscv64
Only implemented for 64 bit floating point operations for now.
goos: linux
goarch: riscv64
pkg: math
cpu: Spacemit(R) X60
│ sec/op │ sec/op vs base │
Acos 154.1n ± 0% 154.1n ± 0% ~ (p=0.303 n=10)
Acosh 215.8n ± 6% 226.7n ± 0% ~ (p=0.439 n=10)
Asin 149.2n ± 1% 149.2n ± 0% ~ (p=0.700 n=10)
Asinh 262.1n ± 0% 258.5n ± 0% -1.37% (p=0.000 n=10)
Atan 99.48n ± 0% 99.49n ± 0% ~ (p=0.836 n=10)
Atanh 244.9n ± 0% 243.8n ± 0% -0.43% (p=0.002 n=10)
Atan2 158.2n ± 1% 153.3n ± 0% -3.10% (p=0.000 n=10)
Cbrt 186.8n ± 0% 181.1n ± 0% -3.03% (p=0.000 n=10)
Ceil 36.71n ± 1% 36.71n ± 0% ~ (p=0.434 n=10)
Copysign 6.531n ± 1% 6.526n ± 0% ~ (p=0.268 n=10)
Cos 98.19n ± 0% 95.40n ± 0% -2.84% (p=0.000 n=10)
Cosh 233.1n ± 0% 222.6n ± 0% -4.50% (p=0.000 n=10)
Erf 122.5n ± 0% 114.2n ± 0% -6.78% (p=0.000 n=10)
Erfc 126.0n ± 1% 116.6n ± 0% -7.46% (p=0.000 n=10)
Erfinv 138.8n ± 0% 138.6n ± 0% ~ (p=0.082 n=10)
Erfcinv 140.0n ± 0% 139.7n ± 0% ~ (p=0.359 n=10)
Exp 193.3n ± 0% 184.2n ± 0% -4.68% (p=0.000 n=10)
ExpGo 204.8n ± 0% 194.5n ± 0% -5.03% (p=0.000 n=10)
Expm1 152.5n ± 1% 145.0n ± 0% -4.92% (p=0.000 n=10)
Exp2 174.5n ± 0% 164.2n ± 0% -5.85% (p=0.000 n=10)
Exp2Go 184.4n ± 1% 175.4n ± 0% -4.88% (p=0.000 n=10)
Abs 4.912n ± 0% 4.914n ± 0% ~ (p=0.283 n=10)
Dim 15.50n ± 1% 15.52n ± 1% ~ (p=0.331 n=10)
Floor 36.89n ± 1% 36.76n ± 1% ~ (p=0.325 n=10)
Max 31.05n ± 1% 31.17n ± 1% ~ (p=0.628 n=10)
Min 31.01n ± 0% 31.06n ± 0% ~ (p=0.767 n=10)
Mod 294.1n ± 0% 245.6n ± 0% -16.52% (p=0.000 n=10)
Frexp 44.86n ± 1% 35.20n ± 0% -21.53% (p=0.000 n=10)
Gamma 195.8n ± 0% 185.4n ± 1% -5.29% (p=0.000 n=10)
Hypot 84.91n ± 0% 84.54n ± 1% -0.43% (p=0.006 n=10)
HypotGo 96.70n ± 0% 95.42n ± 1% -1.32% (p=0.000 n=10)
Ilogb 45.03n ± 0% 35.07n ± 1% -22.10% (p=0.000 n=10)
J0 634.5n ± 0% 627.2n ± 0% -1.16% (p=0.000 n=10)
J1 644.5n ± 0% 636.9n ± 0% -1.18% (p=0.000 n=10)
Jn 1.357µ ± 0% 1.344µ ± 0% -0.92% (p=0.000 n=10)
Ldexp 49.89n ± 0% 39.96n ± 0% -19.90% (p=0.000 n=10)
Lgamma 186.6n ± 0% 184.3n ± 0% -1.21% (p=0.000 n=10)
Log 150.4n ± 0% 141.1n ± 0% -6.15% (p=0.000 n=10)
Logb 46.70n ± 0% 35.89n ± 0% -23.15% (p=0.000 n=10)
Log1p 164.1n ± 0% 163.9n ± 0% ~ (p=0.122 n=10)
Log10 153.1n ± 0% 143.5n ± 0% -6.24% (p=0.000 n=10)
Log2 58.83n ± 0% 49.75n ± 0% -15.43% (p=0.000 n=10)
Modf 40.82n ± 1% 40.78n ± 0% ~ (p=0.239 n=10)
Nextafter32 49.15n ± 0% 48.93n ± 0% -0.44% (p=0.011 n=10)
Nextafter64 43.33n ± 0% 43.23n ± 0% ~ (p=0.228 n=10)
PowInt 269.4n ± 0% 243.8n ± 0% -9.49% (p=0.000 n=10)
PowFrac 618.0n ± 0% 571.7n ± 0% -7.48% (p=0.000 n=10)
Pow10Pos 13.09n ± 0% 13.05n ± 0% -0.31% (p=0.003 n=10)
Pow10Neg 30.99n ± 1% 30.99n ± 0% ~ (p=0.173 n=10)
Round 23.73n ± 0% 23.65n ± 0% -0.36% (p=0.011 n=10)
RoundToEven 27.87n ± 0% 27.73n ± 0% -0.48% (p=0.003 n=10)
Remainder 282.1n ± 0% 249.6n ± 0% -11.52% (p=0.000 n=10)
Signbit 11.46n ± 0% 11.42n ± 0% -0.39% (p=0.003 n=10)
Sin 115.2n ± 0% 113.2n ± 0% -1.74% (p=0.000 n=10)
Sincos 140.6n ± 0% 138.6n ± 0% -1.39% (p=0.000 n=10)
Sinh 252.0n ± 0% 241.4n ± 0% -4.21% (p=0.000 n=10)
SqrtIndirect 4.909n ± 0% 4.893n ± 0% -0.34% (p=0.021 n=10)
SqrtLatency 19.57n ± 1% 19.57n ± 0% ~ (p=0.087 n=10)
SqrtIndirectLatency 19.64n ± 0% 19.57n ± 0% -0.36% (p=0.025 n=10)
SqrtGoLatency 198.1n ± 0% 197.4n ± 0% -0.35% (p=0.014 n=10)
SqrtPrime 5.733µ ± 0% 5.725µ ± 0% ~ (p=0.116 n=10)
Tan 149.1n ± 0% 146.8n ± 0% -1.54% (p=0.000 n=10)
Tanh 248.2n ± 1% 238.1n ± 0% -4.05% (p=0.000 n=10)
Trunc 36.86n ± 0% 36.70n ± 0% -0.43% (p=0.029 n=10)
Y0 638.2n ± 0% 633.6n ± 0% -0.71% (p=0.000 n=10)
Y1 641.8n ± 0% 636.1n ± 0% -0.87% (p=0.000 n=10)
Yn 1.358µ ± 0% 1.345µ ± 0% -0.92% (p=0.000 n=10)
Float64bits 5.721n ± 0% 5.709n ± 0% -0.22% (p=0.044 n=10)
Float64frombits 4.905n ± 0% 4.893n ± 0% ~ (p=0.266 n=10)
Float32bits 12.27n ± 0% 12.23n ± 0% ~ (p=0.122 n=10)
Float32frombits 4.909n ± 0% 4.893n ± 0% -0.32% (p=0.024 n=10)
FMA 6.556n ± 0% 6.526n ± 0% ~ (p=0.283 n=10)
geomean 86.82n 83.75n -3.54%
Change-Id: I522297a79646d76543d516accce291f5a3cea337
Reviewed-on: https://go-review.googlesource.com/c/go/+/717560
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
Auto-Submit: Keith Randall <khr@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
This commit is contained in:
parent
0c28789bd7
commit
34aef89366
4 changed files with 364 additions and 0 deletions
|
|
@ -834,6 +834,18 @@
|
||||||
(FEQD x (FMOVDconst [math.Inf(1)])) => (SNEZ (ANDI <typ.Int64> [0b00_1000_0000] (FCLASSD x)))
|
(FEQD x (FMOVDconst [math.Inf(1)])) => (SNEZ (ANDI <typ.Int64> [0b00_1000_0000] (FCLASSD x)))
|
||||||
(FNED x (FMOVDconst [math.Inf(1)])) => (SEQZ (ANDI <typ.Int64> [0b00_1000_0000] (FCLASSD x)))
|
(FNED x (FMOVDconst [math.Inf(1)])) => (SEQZ (ANDI <typ.Int64> [0b00_1000_0000] (FCLASSD x)))
|
||||||
|
|
||||||
|
// Test for subnormal numbers using 64 bit classify instruction.
|
||||||
|
(FLTD x (FMOVDconst [+0x1p-1022])) => (SNEZ (ANDI <typ.Int64> [0b00_0011_1111] (FCLASSD x)))
|
||||||
|
(FLED (FMOVDconst [+0x1p-1022]) x) => (SNEZ (ANDI <typ.Int64> [0b00_1100_0000] (FCLASSD x)))
|
||||||
|
(FLED x (FMOVDconst [-0x1p-1022])) => (SNEZ (ANDI <typ.Int64> [0b00_0000_0011] (FCLASSD x)))
|
||||||
|
(FLTD (FMOVDconst [-0x1p-1022]) x) => (SNEZ (ANDI <typ.Int64> [0b00_1111_1100] (FCLASSD x)))
|
||||||
|
|
||||||
|
// Absorb unary sign bit operations into 64 bit classify instruction.
|
||||||
|
(S(EQ|NE)Z (ANDI [c] (FCLASSD (FNEGD x)))) => (S(EQ|NE)Z (ANDI <typ.Int64> [(c&0b11_0000_0000)|int64(bits.Reverse8(uint8(c))&0b1111_1111)] (FCLASSD x)))
|
||||||
|
(S(EQ|NE)Z (ANDI [c] (FCLASSD (FABSD x)))) => (S(EQ|NE)Z (ANDI <typ.Int64> [(c&0b11_1111_0000)|int64(bits.Reverse8(uint8(c))&0b0000_1111)] (FCLASSD x)))
|
||||||
|
(B(EQ|NE)Z (ANDI [c] (FCLASSD (FNEGD x))) yes no) => (B(EQ|NE)Z (ANDI <typ.Int64> [(c&0b11_0000_0000)|int64(bits.Reverse8(uint8(c))&0b1111_1111)] (FCLASSD x)) yes no)
|
||||||
|
(B(EQ|NE)Z (ANDI [c] (FCLASSD (FABSD x))) yes no) => (B(EQ|NE)Z (ANDI <typ.Int64> [(c&0b11_1111_0000)|int64(bits.Reverse8(uint8(c))&0b0000_1111)] (FCLASSD x)) yes no)
|
||||||
|
|
||||||
//
|
//
|
||||||
// Optimisations for rva22u64 and above.
|
// Optimisations for rva22u64 and above.
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ package ssa
|
||||||
|
|
||||||
import "internal/buildcfg"
|
import "internal/buildcfg"
|
||||||
import "math"
|
import "math"
|
||||||
|
import "math/bits"
|
||||||
import "cmd/compile/internal/types"
|
import "cmd/compile/internal/types"
|
||||||
|
|
||||||
func rewriteValueRISCV64(v *Value) bool {
|
func rewriteValueRISCV64(v *Value) bool {
|
||||||
|
|
@ -3657,6 +3658,38 @@ func rewriteValueRISCV64_OpRISCV64FLED(v *Value) bool {
|
||||||
v.AddArg(v0)
|
v.AddArg(v0)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
// match: (FLED (FMOVDconst [+0x1p-1022]) x)
|
||||||
|
// result: (SNEZ (ANDI <typ.Int64> [0b00_1100_0000] (FCLASSD x)))
|
||||||
|
for {
|
||||||
|
if v_0.Op != OpRISCV64FMOVDconst || auxIntToFloat64(v_0.AuxInt) != +0x1p-1022 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
x := v_1
|
||||||
|
v.reset(OpRISCV64SNEZ)
|
||||||
|
v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Int64)
|
||||||
|
v0.AuxInt = int64ToAuxInt(0b00_1100_0000)
|
||||||
|
v1 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64)
|
||||||
|
v1.AddArg(x)
|
||||||
|
v0.AddArg(v1)
|
||||||
|
v.AddArg(v0)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// match: (FLED x (FMOVDconst [-0x1p-1022]))
|
||||||
|
// result: (SNEZ (ANDI <typ.Int64> [0b00_0000_0011] (FCLASSD x)))
|
||||||
|
for {
|
||||||
|
x := v_0
|
||||||
|
if v_1.Op != OpRISCV64FMOVDconst || auxIntToFloat64(v_1.AuxInt) != -0x1p-1022 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
v.reset(OpRISCV64SNEZ)
|
||||||
|
v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Int64)
|
||||||
|
v0.AuxInt = int64ToAuxInt(0b00_0000_0011)
|
||||||
|
v1 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64)
|
||||||
|
v1.AddArg(x)
|
||||||
|
v0.AddArg(v1)
|
||||||
|
v.AddArg(v0)
|
||||||
|
return true
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
func rewriteValueRISCV64_OpRISCV64FLTD(v *Value) bool {
|
func rewriteValueRISCV64_OpRISCV64FLTD(v *Value) bool {
|
||||||
|
|
@ -3694,6 +3727,38 @@ func rewriteValueRISCV64_OpRISCV64FLTD(v *Value) bool {
|
||||||
v.AddArg(v0)
|
v.AddArg(v0)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
// match: (FLTD x (FMOVDconst [+0x1p-1022]))
|
||||||
|
// result: (SNEZ (ANDI <typ.Int64> [0b00_0011_1111] (FCLASSD x)))
|
||||||
|
for {
|
||||||
|
x := v_0
|
||||||
|
if v_1.Op != OpRISCV64FMOVDconst || auxIntToFloat64(v_1.AuxInt) != +0x1p-1022 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
v.reset(OpRISCV64SNEZ)
|
||||||
|
v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Int64)
|
||||||
|
v0.AuxInt = int64ToAuxInt(0b00_0011_1111)
|
||||||
|
v1 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64)
|
||||||
|
v1.AddArg(x)
|
||||||
|
v0.AddArg(v1)
|
||||||
|
v.AddArg(v0)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// match: (FLTD (FMOVDconst [-0x1p-1022]) x)
|
||||||
|
// result: (SNEZ (ANDI <typ.Int64> [0b00_1111_1100] (FCLASSD x)))
|
||||||
|
for {
|
||||||
|
if v_0.Op != OpRISCV64FMOVDconst || auxIntToFloat64(v_0.AuxInt) != -0x1p-1022 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
x := v_1
|
||||||
|
v.reset(OpRISCV64SNEZ)
|
||||||
|
v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Int64)
|
||||||
|
v0.AuxInt = int64ToAuxInt(0b00_1111_1100)
|
||||||
|
v1 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64)
|
||||||
|
v1.AddArg(x)
|
||||||
|
v0.AddArg(v1)
|
||||||
|
v.AddArg(v0)
|
||||||
|
return true
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
func rewriteValueRISCV64_OpRISCV64FMADDD(v *Value) bool {
|
func rewriteValueRISCV64_OpRISCV64FMADDD(v *Value) bool {
|
||||||
|
|
@ -7056,6 +7121,8 @@ func rewriteValueRISCV64_OpRISCV64RORW(v *Value) bool {
|
||||||
}
|
}
|
||||||
func rewriteValueRISCV64_OpRISCV64SEQZ(v *Value) bool {
|
func rewriteValueRISCV64_OpRISCV64SEQZ(v *Value) bool {
|
||||||
v_0 := v.Args[0]
|
v_0 := v.Args[0]
|
||||||
|
b := v.Block
|
||||||
|
typ := &b.Func.Config.Types
|
||||||
// match: (SEQZ (NEG x))
|
// match: (SEQZ (NEG x))
|
||||||
// result: (SEQZ x)
|
// result: (SEQZ x)
|
||||||
for {
|
for {
|
||||||
|
|
@ -7089,6 +7156,56 @@ func rewriteValueRISCV64_OpRISCV64SEQZ(v *Value) bool {
|
||||||
v.AddArg(x)
|
v.AddArg(x)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
// match: (SEQZ (ANDI [c] (FCLASSD (FNEGD x))))
|
||||||
|
// result: (SEQZ (ANDI <typ.Int64> [(c&0b11_0000_0000)|int64(bits.Reverse8(uint8(c))&0b1111_1111)] (FCLASSD x)))
|
||||||
|
for {
|
||||||
|
if v_0.Op != OpRISCV64ANDI {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
c := auxIntToInt64(v_0.AuxInt)
|
||||||
|
v_0_0 := v_0.Args[0]
|
||||||
|
if v_0_0.Op != OpRISCV64FCLASSD {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
v_0_0_0 := v_0_0.Args[0]
|
||||||
|
if v_0_0_0.Op != OpRISCV64FNEGD {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
x := v_0_0_0.Args[0]
|
||||||
|
v.reset(OpRISCV64SEQZ)
|
||||||
|
v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Int64)
|
||||||
|
v0.AuxInt = int64ToAuxInt((c & 0b11_0000_0000) | int64(bits.Reverse8(uint8(c))&0b1111_1111))
|
||||||
|
v1 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64)
|
||||||
|
v1.AddArg(x)
|
||||||
|
v0.AddArg(v1)
|
||||||
|
v.AddArg(v0)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// match: (SEQZ (ANDI [c] (FCLASSD (FABSD x))))
|
||||||
|
// result: (SEQZ (ANDI <typ.Int64> [(c&0b11_1111_0000)|int64(bits.Reverse8(uint8(c))&0b0000_1111)] (FCLASSD x)))
|
||||||
|
for {
|
||||||
|
if v_0.Op != OpRISCV64ANDI {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
c := auxIntToInt64(v_0.AuxInt)
|
||||||
|
v_0_0 := v_0.Args[0]
|
||||||
|
if v_0_0.Op != OpRISCV64FCLASSD {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
v_0_0_0 := v_0_0.Args[0]
|
||||||
|
if v_0_0_0.Op != OpRISCV64FABSD {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
x := v_0_0_0.Args[0]
|
||||||
|
v.reset(OpRISCV64SEQZ)
|
||||||
|
v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Int64)
|
||||||
|
v0.AuxInt = int64ToAuxInt((c & 0b11_1111_0000) | int64(bits.Reverse8(uint8(c))&0b0000_1111))
|
||||||
|
v1 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64)
|
||||||
|
v1.AddArg(x)
|
||||||
|
v0.AddArg(v1)
|
||||||
|
v.AddArg(v0)
|
||||||
|
return true
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
func rewriteValueRISCV64_OpRISCV64SLL(v *Value) bool {
|
func rewriteValueRISCV64_OpRISCV64SLL(v *Value) bool {
|
||||||
|
|
@ -7347,6 +7464,8 @@ func rewriteValueRISCV64_OpRISCV64SLTU(v *Value) bool {
|
||||||
}
|
}
|
||||||
func rewriteValueRISCV64_OpRISCV64SNEZ(v *Value) bool {
|
func rewriteValueRISCV64_OpRISCV64SNEZ(v *Value) bool {
|
||||||
v_0 := v.Args[0]
|
v_0 := v.Args[0]
|
||||||
|
b := v.Block
|
||||||
|
typ := &b.Func.Config.Types
|
||||||
// match: (SNEZ (NEG x))
|
// match: (SNEZ (NEG x))
|
||||||
// result: (SNEZ x)
|
// result: (SNEZ x)
|
||||||
for {
|
for {
|
||||||
|
|
@ -7380,6 +7499,56 @@ func rewriteValueRISCV64_OpRISCV64SNEZ(v *Value) bool {
|
||||||
v.AddArg(x)
|
v.AddArg(x)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
// match: (SNEZ (ANDI [c] (FCLASSD (FNEGD x))))
|
||||||
|
// result: (SNEZ (ANDI <typ.Int64> [(c&0b11_0000_0000)|int64(bits.Reverse8(uint8(c))&0b1111_1111)] (FCLASSD x)))
|
||||||
|
for {
|
||||||
|
if v_0.Op != OpRISCV64ANDI {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
c := auxIntToInt64(v_0.AuxInt)
|
||||||
|
v_0_0 := v_0.Args[0]
|
||||||
|
if v_0_0.Op != OpRISCV64FCLASSD {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
v_0_0_0 := v_0_0.Args[0]
|
||||||
|
if v_0_0_0.Op != OpRISCV64FNEGD {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
x := v_0_0_0.Args[0]
|
||||||
|
v.reset(OpRISCV64SNEZ)
|
||||||
|
v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Int64)
|
||||||
|
v0.AuxInt = int64ToAuxInt((c & 0b11_0000_0000) | int64(bits.Reverse8(uint8(c))&0b1111_1111))
|
||||||
|
v1 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64)
|
||||||
|
v1.AddArg(x)
|
||||||
|
v0.AddArg(v1)
|
||||||
|
v.AddArg(v0)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// match: (SNEZ (ANDI [c] (FCLASSD (FABSD x))))
|
||||||
|
// result: (SNEZ (ANDI <typ.Int64> [(c&0b11_1111_0000)|int64(bits.Reverse8(uint8(c))&0b0000_1111)] (FCLASSD x)))
|
||||||
|
for {
|
||||||
|
if v_0.Op != OpRISCV64ANDI {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
c := auxIntToInt64(v_0.AuxInt)
|
||||||
|
v_0_0 := v_0.Args[0]
|
||||||
|
if v_0_0.Op != OpRISCV64FCLASSD {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
v_0_0_0 := v_0_0.Args[0]
|
||||||
|
if v_0_0_0.Op != OpRISCV64FABSD {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
x := v_0_0_0.Args[0]
|
||||||
|
v.reset(OpRISCV64SNEZ)
|
||||||
|
v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Int64)
|
||||||
|
v0.AuxInt = int64ToAuxInt((c & 0b11_1111_0000) | int64(bits.Reverse8(uint8(c))&0b0000_1111))
|
||||||
|
v1 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64)
|
||||||
|
v1.AddArg(x)
|
||||||
|
v0.AddArg(v1)
|
||||||
|
v.AddArg(v0)
|
||||||
|
return true
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
func rewriteValueRISCV64_OpRISCV64SRA(v *Value) bool {
|
func rewriteValueRISCV64_OpRISCV64SRA(v *Value) bool {
|
||||||
|
|
@ -9940,6 +10109,50 @@ func rewriteBlockRISCV64(b *Block) bool {
|
||||||
b.resetWithControl2(BlockRISCV64BGEU, y, v0)
|
b.resetWithControl2(BlockRISCV64BGEU, y, v0)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
// match: (BEQZ (ANDI [c] (FCLASSD (FNEGD x))) yes no)
|
||||||
|
// result: (BEQZ (ANDI <typ.Int64> [(c&0b11_0000_0000)|int64(bits.Reverse8(uint8(c))&0b1111_1111)] (FCLASSD x)) yes no)
|
||||||
|
for b.Controls[0].Op == OpRISCV64ANDI {
|
||||||
|
v_0 := b.Controls[0]
|
||||||
|
c := auxIntToInt64(v_0.AuxInt)
|
||||||
|
v_0_0 := v_0.Args[0]
|
||||||
|
if v_0_0.Op != OpRISCV64FCLASSD {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
v_0_0_0 := v_0_0.Args[0]
|
||||||
|
if v_0_0_0.Op != OpRISCV64FNEGD {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
x := v_0_0_0.Args[0]
|
||||||
|
v0 := b.NewValue0(v_0.Pos, OpRISCV64ANDI, typ.Int64)
|
||||||
|
v0.AuxInt = int64ToAuxInt((c & 0b11_0000_0000) | int64(bits.Reverse8(uint8(c))&0b1111_1111))
|
||||||
|
v1 := b.NewValue0(v_0.Pos, OpRISCV64FCLASSD, typ.Int64)
|
||||||
|
v1.AddArg(x)
|
||||||
|
v0.AddArg(v1)
|
||||||
|
b.resetWithControl(BlockRISCV64BEQZ, v0)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// match: (BEQZ (ANDI [c] (FCLASSD (FABSD x))) yes no)
|
||||||
|
// result: (BEQZ (ANDI <typ.Int64> [(c&0b11_1111_0000)|int64(bits.Reverse8(uint8(c))&0b0000_1111)] (FCLASSD x)) yes no)
|
||||||
|
for b.Controls[0].Op == OpRISCV64ANDI {
|
||||||
|
v_0 := b.Controls[0]
|
||||||
|
c := auxIntToInt64(v_0.AuxInt)
|
||||||
|
v_0_0 := v_0.Args[0]
|
||||||
|
if v_0_0.Op != OpRISCV64FCLASSD {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
v_0_0_0 := v_0_0.Args[0]
|
||||||
|
if v_0_0_0.Op != OpRISCV64FABSD {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
x := v_0_0_0.Args[0]
|
||||||
|
v0 := b.NewValue0(v_0.Pos, OpRISCV64ANDI, typ.Int64)
|
||||||
|
v0.AuxInt = int64ToAuxInt((c & 0b11_1111_0000) | int64(bits.Reverse8(uint8(c))&0b0000_1111))
|
||||||
|
v1 := b.NewValue0(v_0.Pos, OpRISCV64FCLASSD, typ.Int64)
|
||||||
|
v1.AddArg(x)
|
||||||
|
v0.AddArg(v1)
|
||||||
|
b.resetWithControl(BlockRISCV64BEQZ, v0)
|
||||||
|
return true
|
||||||
|
}
|
||||||
case BlockRISCV64BGE:
|
case BlockRISCV64BGE:
|
||||||
// match: (BGE (MOVDconst [0]) cond yes no)
|
// match: (BGE (MOVDconst [0]) cond yes no)
|
||||||
// result: (BLEZ cond yes no)
|
// result: (BLEZ cond yes no)
|
||||||
|
|
@ -10141,6 +10354,50 @@ func rewriteBlockRISCV64(b *Block) bool {
|
||||||
b.resetWithControl2(BlockRISCV64BLTU, y, v0)
|
b.resetWithControl2(BlockRISCV64BLTU, y, v0)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
// match: (BNEZ (ANDI [c] (FCLASSD (FNEGD x))) yes no)
|
||||||
|
// result: (BNEZ (ANDI <typ.Int64> [(c&0b11_0000_0000)|int64(bits.Reverse8(uint8(c))&0b1111_1111)] (FCLASSD x)) yes no)
|
||||||
|
for b.Controls[0].Op == OpRISCV64ANDI {
|
||||||
|
v_0 := b.Controls[0]
|
||||||
|
c := auxIntToInt64(v_0.AuxInt)
|
||||||
|
v_0_0 := v_0.Args[0]
|
||||||
|
if v_0_0.Op != OpRISCV64FCLASSD {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
v_0_0_0 := v_0_0.Args[0]
|
||||||
|
if v_0_0_0.Op != OpRISCV64FNEGD {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
x := v_0_0_0.Args[0]
|
||||||
|
v0 := b.NewValue0(v_0.Pos, OpRISCV64ANDI, typ.Int64)
|
||||||
|
v0.AuxInt = int64ToAuxInt((c & 0b11_0000_0000) | int64(bits.Reverse8(uint8(c))&0b1111_1111))
|
||||||
|
v1 := b.NewValue0(v_0.Pos, OpRISCV64FCLASSD, typ.Int64)
|
||||||
|
v1.AddArg(x)
|
||||||
|
v0.AddArg(v1)
|
||||||
|
b.resetWithControl(BlockRISCV64BNEZ, v0)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// match: (BNEZ (ANDI [c] (FCLASSD (FABSD x))) yes no)
|
||||||
|
// result: (BNEZ (ANDI <typ.Int64> [(c&0b11_1111_0000)|int64(bits.Reverse8(uint8(c))&0b0000_1111)] (FCLASSD x)) yes no)
|
||||||
|
for b.Controls[0].Op == OpRISCV64ANDI {
|
||||||
|
v_0 := b.Controls[0]
|
||||||
|
c := auxIntToInt64(v_0.AuxInt)
|
||||||
|
v_0_0 := v_0.Args[0]
|
||||||
|
if v_0_0.Op != OpRISCV64FCLASSD {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
v_0_0_0 := v_0_0.Args[0]
|
||||||
|
if v_0_0_0.Op != OpRISCV64FABSD {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
x := v_0_0_0.Args[0]
|
||||||
|
v0 := b.NewValue0(v_0.Pos, OpRISCV64ANDI, typ.Int64)
|
||||||
|
v0.AuxInt = int64ToAuxInt((c & 0b11_1111_0000) | int64(bits.Reverse8(uint8(c))&0b0000_1111))
|
||||||
|
v1 := b.NewValue0(v_0.Pos, OpRISCV64FCLASSD, typ.Int64)
|
||||||
|
v1.AddArg(x)
|
||||||
|
v0.AddArg(v1)
|
||||||
|
b.resetWithControl(BlockRISCV64BNEZ, v0)
|
||||||
|
return true
|
||||||
|
}
|
||||||
case BlockIf:
|
case BlockIf:
|
||||||
// match: (If cond yes no)
|
// match: (If cond yes no)
|
||||||
// result: (BNEZ (MOVBUreg <typ.UInt64> cond) yes no)
|
// result: (BNEZ (MOVBUreg <typ.UInt64> cond) yes no)
|
||||||
|
|
|
||||||
|
|
@ -727,6 +727,65 @@ func TestFusedNaNChecks32(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// minNormal64 is the smallest float64 value that is not subnormal.
|
||||||
|
const minNormal64 = 2.2250738585072014e-308
|
||||||
|
|
||||||
|
//go:noinline
|
||||||
|
func isAbsLessThanMinNormal64(x float64) bool {
|
||||||
|
return math.Abs(x) < minNormal64
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:noinline
|
||||||
|
func isLessThanMinNormal64(x float64) bool {
|
||||||
|
return x < minNormal64
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:noinline
|
||||||
|
func isGreaterThanNegMinNormal64(x float64) bool {
|
||||||
|
return x > -minNormal64
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:noinline
|
||||||
|
func isGreaterThanOrEqualToMinNormal64(x float64) bool {
|
||||||
|
return math.Abs(x) >= minNormal64
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSubnormalComparisons(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
value float64
|
||||||
|
isAbsLessThanMinNormal bool
|
||||||
|
isPositive bool
|
||||||
|
isNegative bool
|
||||||
|
isNaN bool
|
||||||
|
}{
|
||||||
|
{value: math.Inf(1), isPositive: true},
|
||||||
|
{value: math.MaxFloat64, isPositive: true},
|
||||||
|
{value: math.Inf(-1), isNegative: true},
|
||||||
|
{value: -math.MaxFloat64, isNegative: true},
|
||||||
|
{value: math.NaN(), isNaN: true},
|
||||||
|
{value: minNormal64, isPositive: true},
|
||||||
|
{value: minNormal64 / 2, isAbsLessThanMinNormal: true, isPositive: true},
|
||||||
|
{value: -minNormal64, isNegative: true},
|
||||||
|
{value: -minNormal64 / 2, isAbsLessThanMinNormal: true, isNegative: true},
|
||||||
|
{value: 0, isAbsLessThanMinNormal: true, isPositive: true},
|
||||||
|
{value: math.Copysign(0, -1), isAbsLessThanMinNormal: true, isNegative: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
check := func(name string, f func(x float64) bool, value float64, want bool) {
|
||||||
|
got := f(value)
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("%v(%g): want %v, got %v", name, value, want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
check("isAbsLessThanMinNormal64", isAbsLessThanMinNormal64, test.value, test.isAbsLessThanMinNormal)
|
||||||
|
check("isLessThanMinNormal64", isLessThanMinNormal64, test.value, test.isAbsLessThanMinNormal || test.isNegative)
|
||||||
|
check("isGreaterThanNegMinNormal64", isGreaterThanNegMinNormal64, test.value, test.isAbsLessThanMinNormal || test.isPositive)
|
||||||
|
check("isGreaterThanOrEqualToMinNormal64", isGreaterThanOrEqualToMinNormal64, test.value, !test.isAbsLessThanMinNormal && !test.isNaN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var sinkFloat float64
|
var sinkFloat float64
|
||||||
|
|
||||||
func BenchmarkMul2(b *testing.B) {
|
func BenchmarkMul2(b *testing.B) {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
package codegen
|
package codegen
|
||||||
|
|
||||||
|
import "math"
|
||||||
|
|
||||||
// This file contains codegen tests related to arithmetic
|
// This file contains codegen tests related to arithmetic
|
||||||
// simplifications and optimizations on float types.
|
// simplifications and optimizations on float types.
|
||||||
// For codegen tests on integer types, see arithmetic.go.
|
// For codegen tests on integer types, see arithmetic.go.
|
||||||
|
|
@ -277,3 +279,37 @@ func Float64ConstantStore(p *float64) {
|
||||||
// riscv64: "MOVD [$]f64.4015ba5e353f7cee"
|
// riscv64: "MOVD [$]f64.4015ba5e353f7cee"
|
||||||
*p = 5.432
|
*p = 5.432
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------ //
|
||||||
|
// Subnormal tests //
|
||||||
|
// ------------------------ //
|
||||||
|
|
||||||
|
func isSubnormal(x float64) bool {
|
||||||
|
// riscv64:"FCLASSD" -"FABSD"
|
||||||
|
return math.Abs(x) < 2.2250738585072014e-308
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNormal(x float64) bool {
|
||||||
|
// riscv64:"FCLASSD" -"FABSD"
|
||||||
|
return math.Abs(x) >= 0x1p-1022
|
||||||
|
}
|
||||||
|
|
||||||
|
func isPosSubnormal(x float64) bool {
|
||||||
|
// riscv64:"FCLASSD"
|
||||||
|
return x > 0 && x < 2.2250738585072014e-308
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNegSubnormal(x float64) bool {
|
||||||
|
// riscv64:"FCLASSD"
|
||||||
|
return x < 0 && x > -0x1p-1022
|
||||||
|
}
|
||||||
|
|
||||||
|
func isPosNormal(x float64) bool {
|
||||||
|
// riscv64:"FCLASSD"
|
||||||
|
return x >= 2.2250738585072014e-308
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNegNormal(x float64) bool {
|
||||||
|
// riscv64:"FCLASSD"
|
||||||
|
return x <= -2.2250738585072014e-308
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue