import "internal/buildcfg"
import "math"
+import "math/bits"
import "cmd/compile/internal/types"
func rewriteValueRISCV64(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 {
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 {
}
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 {
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 {
}
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 {
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 {
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)
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)
}
}
+// 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) {