cmd/compile/internal/ssa: simplify riscv64 FCLASSD rewrite rules

We don't need to check that the bit patterns of the constants
match, it is sufficient to just check the constant is equal to the
given value.

While we're here also change the FCLASSD rules to use a bit pattern
for the mask. I think this improves readability, particularly as
more uses of FCLASSD get added (e.g. CL 717560).

These changes should not affect codegen.

Change-Id: I92a6338dc71e6a71e04306f67d7d86016c6e9c47
Reviewed-on: https://go-review.googlesource.com/c/go/+/717580
Reviewed-by: Michael Pratt <mpratt@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
Michael Munday 2025-11-03 23:05:25 +00:00 committed by Gopher Robot
parent 856238615d
commit a7d174ccaa
3 changed files with 40 additions and 84 deletions

View file

@ -823,16 +823,16 @@
(F(MADD|NMADD|MSUB|NMSUB)D x y neg:(FNEGD z)) && neg.Uses == 1 => (F(MSUB|NMSUB|MADD|NMADD)D x y z) (F(MADD|NMADD|MSUB|NMSUB)D x y neg:(FNEGD z)) && neg.Uses == 1 => (F(MSUB|NMSUB|MADD|NMADD)D x y z)
// Test for -∞ (bit 0) using 64 bit classify instruction. // Test for -∞ (bit 0) using 64 bit classify instruction.
(FLTD x (FMOVDconst [c])) && float64ExactBits(c, -math.MaxFloat64) => (ANDI [1] (FCLASSD x)) (FLTD x (FMOVDconst [-math.MaxFloat64])) => (ANDI [0b00_0000_0001] (FCLASSD x))
(FLED (FMOVDconst [c]) x) && float64ExactBits(c, -math.MaxFloat64) => (SNEZ (ANDI <typ.Int64> [0xff &^ 1] (FCLASSD x))) (FLED (FMOVDconst [-math.MaxFloat64]) x) => (SNEZ (ANDI <typ.Int64> [0b00_1111_1110] (FCLASSD x)))
(FEQD x (FMOVDconst [c])) && float64ExactBits(c, math.Inf(-1)) => (ANDI [1] (FCLASSD x)) (FEQD x (FMOVDconst [math.Inf(-1)])) => (ANDI [0b00_0000_0001] (FCLASSD x))
(FNED x (FMOVDconst [c])) && float64ExactBits(c, math.Inf(-1)) => (SEQZ (ANDI <typ.Int64> [1] (FCLASSD x))) (FNED x (FMOVDconst [math.Inf(-1)])) => (SEQZ (ANDI <typ.Int64> [0b00_0000_0001] (FCLASSD x)))
// Test for +∞ (bit 7) using 64 bit classify instruction. // Test for +∞ (bit 7) using 64 bit classify instruction.
(FLTD (FMOVDconst [c]) x) && float64ExactBits(c, math.MaxFloat64) => (SNEZ (ANDI <typ.Int64> [1<<7] (FCLASSD x))) (FLTD (FMOVDconst [math.MaxFloat64]) x) => (SNEZ (ANDI <typ.Int64> [0b00_1000_0000] (FCLASSD x)))
(FLED x (FMOVDconst [c])) && float64ExactBits(c, math.MaxFloat64) => (SNEZ (ANDI <typ.Int64> [0xff &^ (1<<7)] (FCLASSD x))) (FLED x (FMOVDconst [math.MaxFloat64])) => (SNEZ (ANDI <typ.Int64> [0b00_0111_1111] (FCLASSD x)))
(FEQD x (FMOVDconst [c])) && float64ExactBits(c, math.Inf(1)) => (SNEZ (ANDI <typ.Int64> [1<<7] (FCLASSD x))) (FEQD x (FMOVDconst [math.Inf(1)])) => (SNEZ (ANDI <typ.Int64> [0b00_1000_0000] (FCLASSD x)))
(FNED x (FMOVDconst [c])) && float64ExactBits(c, math.Inf(1)) => (SEQZ (ANDI <typ.Int64> [1<<7] (FCLASSD x))) (FNED x (FMOVDconst [math.Inf(1)])) => (SEQZ (ANDI <typ.Int64> [0b00_1000_0000] (FCLASSD x)))
// //
// Optimisations for rva22u64 and above. // Optimisations for rva22u64 and above.

View file

@ -765,10 +765,6 @@ func arm64ConditionalParamsToAuxInt(v arm64ConditionalParams) int64 {
return i return i
} }
func float64ExactBits(f float64, c float64) bool {
return math.Float64bits(f) == math.Float64bits(c)
}
func flagConstantToAuxInt(x flagConstant) int64 { func flagConstantToAuxInt(x flagConstant) int64 {
return int64(x) return int64(x)
} }

View file

@ -3582,21 +3582,16 @@ func rewriteValueRISCV64_OpRISCV64FEQD(v *Value) bool {
v_0 := v.Args[0] v_0 := v.Args[0]
b := v.Block b := v.Block
typ := &b.Func.Config.Types typ := &b.Func.Config.Types
// match: (FEQD x (FMOVDconst [c])) // match: (FEQD x (FMOVDconst [math.Inf(-1)]))
// cond: float64ExactBits(c, math.Inf(-1)) // result: (ANDI [0b00_0000_0001] (FCLASSD x))
// result: (ANDI [1] (FCLASSD x))
for { for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
x := v_0 x := v_0
if v_1.Op != OpRISCV64FMOVDconst { if v_1.Op != OpRISCV64FMOVDconst || auxIntToFloat64(v_1.AuxInt) != math.Inf(-1) {
continue
}
c := auxIntToFloat64(v_1.AuxInt)
if !(float64ExactBits(c, math.Inf(-1))) {
continue continue
} }
v.reset(OpRISCV64ANDI) v.reset(OpRISCV64ANDI)
v.AuxInt = int64ToAuxInt(1) v.AuxInt = int64ToAuxInt(0b00_0000_0001)
v0 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64) v0 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64)
v0.AddArg(x) v0.AddArg(x)
v.AddArg(v0) v.AddArg(v0)
@ -3604,22 +3599,17 @@ func rewriteValueRISCV64_OpRISCV64FEQD(v *Value) bool {
} }
break break
} }
// match: (FEQD x (FMOVDconst [c])) // match: (FEQD x (FMOVDconst [math.Inf(1)]))
// cond: float64ExactBits(c, math.Inf(1)) // result: (SNEZ (ANDI <typ.Int64> [0b00_1000_0000] (FCLASSD x)))
// result: (SNEZ (ANDI <typ.Int64> [1<<7] (FCLASSD x)))
for { for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
x := v_0 x := v_0
if v_1.Op != OpRISCV64FMOVDconst { if v_1.Op != OpRISCV64FMOVDconst || auxIntToFloat64(v_1.AuxInt) != math.Inf(1) {
continue
}
c := auxIntToFloat64(v_1.AuxInt)
if !(float64ExactBits(c, math.Inf(1))) {
continue continue
} }
v.reset(OpRISCV64SNEZ) v.reset(OpRISCV64SNEZ)
v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Int64) v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Int64)
v0.AuxInt = int64ToAuxInt(1 << 7) v0.AuxInt = int64ToAuxInt(0b00_1000_0000)
v1 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64) v1 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64)
v1.AddArg(x) v1.AddArg(x)
v0.AddArg(v1) v0.AddArg(v1)
@ -3635,42 +3625,32 @@ func rewriteValueRISCV64_OpRISCV64FLED(v *Value) bool {
v_0 := v.Args[0] v_0 := v.Args[0]
b := v.Block b := v.Block
typ := &b.Func.Config.Types typ := &b.Func.Config.Types
// match: (FLED (FMOVDconst [c]) x) // match: (FLED (FMOVDconst [-math.MaxFloat64]) x)
// cond: float64ExactBits(c, -math.MaxFloat64) // result: (SNEZ (ANDI <typ.Int64> [0b00_1111_1110] (FCLASSD x)))
// result: (SNEZ (ANDI <typ.Int64> [0xff &^ 1] (FCLASSD x)))
for { for {
if v_0.Op != OpRISCV64FMOVDconst { if v_0.Op != OpRISCV64FMOVDconst || auxIntToFloat64(v_0.AuxInt) != -math.MaxFloat64 {
break break
} }
c := auxIntToFloat64(v_0.AuxInt)
x := v_1 x := v_1
if !(float64ExactBits(c, -math.MaxFloat64)) {
break
}
v.reset(OpRISCV64SNEZ) v.reset(OpRISCV64SNEZ)
v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Int64) v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Int64)
v0.AuxInt = int64ToAuxInt(0xff &^ 1) v0.AuxInt = int64ToAuxInt(0b00_1111_1110)
v1 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64) v1 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64)
v1.AddArg(x) v1.AddArg(x)
v0.AddArg(v1) v0.AddArg(v1)
v.AddArg(v0) v.AddArg(v0)
return true return true
} }
// match: (FLED x (FMOVDconst [c])) // match: (FLED x (FMOVDconst [math.MaxFloat64]))
// cond: float64ExactBits(c, math.MaxFloat64) // result: (SNEZ (ANDI <typ.Int64> [0b00_0111_1111] (FCLASSD x)))
// result: (SNEZ (ANDI <typ.Int64> [0xff &^ (1<<7)] (FCLASSD x)))
for { for {
x := v_0 x := v_0
if v_1.Op != OpRISCV64FMOVDconst { if v_1.Op != OpRISCV64FMOVDconst || auxIntToFloat64(v_1.AuxInt) != math.MaxFloat64 {
break
}
c := auxIntToFloat64(v_1.AuxInt)
if !(float64ExactBits(c, math.MaxFloat64)) {
break break
} }
v.reset(OpRISCV64SNEZ) v.reset(OpRISCV64SNEZ)
v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Int64) v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Int64)
v0.AuxInt = int64ToAuxInt(0xff &^ (1 << 7)) v0.AuxInt = int64ToAuxInt(0b00_0111_1111)
v1 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64) v1 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64)
v1.AddArg(x) v1.AddArg(x)
v0.AddArg(v1) v0.AddArg(v1)
@ -3684,40 +3664,30 @@ func rewriteValueRISCV64_OpRISCV64FLTD(v *Value) bool {
v_0 := v.Args[0] v_0 := v.Args[0]
b := v.Block b := v.Block
typ := &b.Func.Config.Types typ := &b.Func.Config.Types
// match: (FLTD x (FMOVDconst [c])) // match: (FLTD x (FMOVDconst [-math.MaxFloat64]))
// cond: float64ExactBits(c, -math.MaxFloat64) // result: (ANDI [0b00_0000_0001] (FCLASSD x))
// result: (ANDI [1] (FCLASSD x))
for { for {
x := v_0 x := v_0
if v_1.Op != OpRISCV64FMOVDconst { if v_1.Op != OpRISCV64FMOVDconst || auxIntToFloat64(v_1.AuxInt) != -math.MaxFloat64 {
break
}
c := auxIntToFloat64(v_1.AuxInt)
if !(float64ExactBits(c, -math.MaxFloat64)) {
break break
} }
v.reset(OpRISCV64ANDI) v.reset(OpRISCV64ANDI)
v.AuxInt = int64ToAuxInt(1) v.AuxInt = int64ToAuxInt(0b00_0000_0001)
v0 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64) v0 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64)
v0.AddArg(x) v0.AddArg(x)
v.AddArg(v0) v.AddArg(v0)
return true return true
} }
// match: (FLTD (FMOVDconst [c]) x) // match: (FLTD (FMOVDconst [math.MaxFloat64]) x)
// cond: float64ExactBits(c, math.MaxFloat64) // result: (SNEZ (ANDI <typ.Int64> [0b00_1000_0000] (FCLASSD x)))
// result: (SNEZ (ANDI <typ.Int64> [1<<7] (FCLASSD x)))
for { for {
if v_0.Op != OpRISCV64FMOVDconst { if v_0.Op != OpRISCV64FMOVDconst || auxIntToFloat64(v_0.AuxInt) != math.MaxFloat64 {
break break
} }
c := auxIntToFloat64(v_0.AuxInt)
x := v_1 x := v_1
if !(float64ExactBits(c, math.MaxFloat64)) {
break
}
v.reset(OpRISCV64SNEZ) v.reset(OpRISCV64SNEZ)
v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Int64) v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Int64)
v0.AuxInt = int64ToAuxInt(1 << 7) v0.AuxInt = int64ToAuxInt(0b00_1000_0000)
v1 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64) v1 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64)
v1.AddArg(x) v1.AddArg(x)
v0.AddArg(v1) v0.AddArg(v1)
@ -4155,22 +4125,17 @@ func rewriteValueRISCV64_OpRISCV64FNED(v *Value) bool {
v_0 := v.Args[0] v_0 := v.Args[0]
b := v.Block b := v.Block
typ := &b.Func.Config.Types typ := &b.Func.Config.Types
// match: (FNED x (FMOVDconst [c])) // match: (FNED x (FMOVDconst [math.Inf(-1)]))
// cond: float64ExactBits(c, math.Inf(-1)) // result: (SEQZ (ANDI <typ.Int64> [0b00_0000_0001] (FCLASSD x)))
// result: (SEQZ (ANDI <typ.Int64> [1] (FCLASSD x)))
for { for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
x := v_0 x := v_0
if v_1.Op != OpRISCV64FMOVDconst { if v_1.Op != OpRISCV64FMOVDconst || auxIntToFloat64(v_1.AuxInt) != math.Inf(-1) {
continue
}
c := auxIntToFloat64(v_1.AuxInt)
if !(float64ExactBits(c, math.Inf(-1))) {
continue continue
} }
v.reset(OpRISCV64SEQZ) v.reset(OpRISCV64SEQZ)
v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Int64) v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Int64)
v0.AuxInt = int64ToAuxInt(1) v0.AuxInt = int64ToAuxInt(0b00_0000_0001)
v1 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64) v1 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64)
v1.AddArg(x) v1.AddArg(x)
v0.AddArg(v1) v0.AddArg(v1)
@ -4179,22 +4144,17 @@ func rewriteValueRISCV64_OpRISCV64FNED(v *Value) bool {
} }
break break
} }
// match: (FNED x (FMOVDconst [c])) // match: (FNED x (FMOVDconst [math.Inf(1)]))
// cond: float64ExactBits(c, math.Inf(1)) // result: (SEQZ (ANDI <typ.Int64> [0b00_1000_0000] (FCLASSD x)))
// result: (SEQZ (ANDI <typ.Int64> [1<<7] (FCLASSD x)))
for { for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 { for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
x := v_0 x := v_0
if v_1.Op != OpRISCV64FMOVDconst { if v_1.Op != OpRISCV64FMOVDconst || auxIntToFloat64(v_1.AuxInt) != math.Inf(1) {
continue
}
c := auxIntToFloat64(v_1.AuxInt)
if !(float64ExactBits(c, math.Inf(1))) {
continue continue
} }
v.reset(OpRISCV64SEQZ) v.reset(OpRISCV64SEQZ)
v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Int64) v0 := b.NewValue0(v.Pos, OpRISCV64ANDI, typ.Int64)
v0.AuxInt = int64ToAuxInt(1 << 7) v0.AuxInt = int64ToAuxInt(0b00_1000_0000)
v1 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64) v1 := b.NewValue0(v.Pos, OpRISCV64FCLASSD, typ.Int64)
v1.AddArg(x) v1.AddArg(x)
v0.AddArg(v1) v0.AddArg(v1)