diff options
Diffstat (limited to 'src/cmd')
| -rw-r--r-- | src/cmd/compile/internal/ssa/_gen/RISCV64.rules | 12 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/rewriteRISCV64.go | 257 | ||||
| -rw-r--r-- | src/cmd/compile/internal/test/float_test.go | 59 |
3 files changed, 328 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/ssa/_gen/RISCV64.rules b/src/cmd/compile/internal/ssa/_gen/RISCV64.rules index 31829a5eed..646948f2df 100644 --- a/src/cmd/compile/internal/ssa/_gen/RISCV64.rules +++ b/src/cmd/compile/internal/ssa/_gen/RISCV64.rules @@ -834,6 +834,18 @@ (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))) +// 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. // diff --git a/src/cmd/compile/internal/ssa/rewriteRISCV64.go b/src/cmd/compile/internal/ssa/rewriteRISCV64.go index 52870fe199..191c7b3d48 100644 --- a/src/cmd/compile/internal/ssa/rewriteRISCV64.go +++ b/src/cmd/compile/internal/ssa/rewriteRISCV64.go @@ -4,6 +4,7 @@ package ssa import "internal/buildcfg" import "math" +import "math/bits" import "cmd/compile/internal/types" func rewriteValueRISCV64(v *Value) bool { @@ -3657,6 +3658,38 @@ func rewriteValueRISCV64_OpRISCV64FLED(v *Value) bool { v.AddArg(v0) 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 } func rewriteValueRISCV64_OpRISCV64FLTD(v *Value) bool { @@ -3694,6 +3727,38 @@ func rewriteValueRISCV64_OpRISCV64FLTD(v *Value) bool { v.AddArg(v0) 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 } func rewriteValueRISCV64_OpRISCV64FMADDD(v *Value) bool { @@ -7056,6 +7121,8 @@ func rewriteValueRISCV64_OpRISCV64RORW(v *Value) bool { } func rewriteValueRISCV64_OpRISCV64SEQZ(v *Value) bool { v_0 := v.Args[0] + b := v.Block + typ := &b.Func.Config.Types // match: (SEQZ (NEG x)) // result: (SEQZ x) for { @@ -7089,6 +7156,56 @@ func rewriteValueRISCV64_OpRISCV64SEQZ(v *Value) bool { v.AddArg(x) 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 } func rewriteValueRISCV64_OpRISCV64SLL(v *Value) bool { @@ -7347,6 +7464,8 @@ func rewriteValueRISCV64_OpRISCV64SLTU(v *Value) bool { } func rewriteValueRISCV64_OpRISCV64SNEZ(v *Value) bool { v_0 := v.Args[0] + b := v.Block + typ := &b.Func.Config.Types // match: (SNEZ (NEG x)) // result: (SNEZ x) for { @@ -7380,6 +7499,56 @@ func rewriteValueRISCV64_OpRISCV64SNEZ(v *Value) bool { v.AddArg(x) 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 } func rewriteValueRISCV64_OpRISCV64SRA(v *Value) bool { @@ -9940,6 +10109,50 @@ func rewriteBlockRISCV64(b *Block) bool { b.resetWithControl2(BlockRISCV64BGEU, y, v0) 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: // match: (BGE (MOVDconst [0]) cond yes no) // result: (BLEZ cond yes no) @@ -10141,6 +10354,50 @@ func rewriteBlockRISCV64(b *Block) bool { b.resetWithControl2(BlockRISCV64BLTU, y, v0) 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: // match: (If cond yes no) // result: (BNEZ (MOVBUreg <typ.UInt64> cond) yes no) diff --git a/src/cmd/compile/internal/test/float_test.go b/src/cmd/compile/internal/test/float_test.go index 7a5e27870f..00735e3cb1 100644 --- a/src/cmd/compile/internal/test/float_test.go +++ b/src/cmd/compile/internal/test/float_test.go @@ -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 func BenchmarkMul2(b *testing.B) { |
