cmd/compile/internal/ssa: make oneBit function generic

Allows rewrite rules using oneBit to be made more compact.

Change-Id: I986715f77db5b548759d809fe668e1893048f25c
Reviewed-on: https://go-review.googlesource.com/c/go/+/699295
Reviewed-by: Youlin Feng <fengyoulin@live.com>
Commit-Queue: Keith Randall <khr@golang.org>
Auto-Submit: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Michael Munday 2025-08-26 22:12:29 +01:00 committed by Gopher Robot
parent fe42628dae
commit 84b070bfb1
3 changed files with 24 additions and 37 deletions

View file

@ -1896,22 +1896,10 @@
(Neq(8|16|32|64) s:(Sub(8|16|32|64) x y) (Const(8|16|32|64) [0])) && s.Uses == 1 => (Neq(8|16|32|64) x y) (Neq(8|16|32|64) s:(Sub(8|16|32|64) x y) (Const(8|16|32|64) [0])) && s.Uses == 1 => (Neq(8|16|32|64) x y)
// Optimize bitsets // Optimize bitsets
(Eq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [y])) && oneBit8(y) (Eq(8|16|32|64) (And(8|16|32|64) <t> x (Const(8|16|32|64) <t> [y])) (Const(8|16|32|64) <t> [y])) && oneBit(y)
=> (Neq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [0])) => (Neq(8|16|32|64) (And(8|16|32|64) <t> x (Const(8|16|32|64) <t> [y])) (Const(8|16|32|64) <t> [0]))
(Eq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [y])) && oneBit16(y) (Neq(8|16|32|64) (And(8|16|32|64) <t> x (Const(8|16|32|64) <t> [y])) (Const(8|16|32|64) <t> [y])) && oneBit(y)
=> (Neq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [0])) => (Eq(8|16|32|64) (And(8|16|32|64) <t> x (Const(8|16|32|64) <t> [y])) (Const(8|16|32|64) <t> [0]))
(Eq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [y])) && oneBit32(y)
=> (Neq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [0]))
(Eq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [y])) && oneBit64(y)
=> (Neq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [0]))
(Neq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [y])) && oneBit8(y)
=> (Eq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [0]))
(Neq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [y])) && oneBit16(y)
=> (Eq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [0]))
(Neq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [y])) && oneBit32(y)
=> (Eq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [0]))
(Neq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [y])) && oneBit64(y)
=> (Eq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [0]))
// Reassociate expressions involving // Reassociate expressions involving
// constants such that constants come first, // constants such that constants come first,

View file

@ -470,11 +470,10 @@ func ntz32(x int32) int { return bits.TrailingZeros32(uint32(x)) }
func ntz16(x int16) int { return bits.TrailingZeros16(uint16(x)) } func ntz16(x int16) int { return bits.TrailingZeros16(uint16(x)) }
func ntz8(x int8) int { return bits.TrailingZeros8(uint8(x)) } func ntz8(x int8) int { return bits.TrailingZeros8(uint8(x)) }
func oneBit(x int64) bool { return x&(x-1) == 0 && x != 0 } // oneBit reports whether x contains exactly one set bit.
func oneBit8(x int8) bool { return x&(x-1) == 0 && x != 0 } func oneBit[T int8 | int16 | int32 | int64](x T) bool {
func oneBit16(x int16) bool { return x&(x-1) == 0 && x != 0 } return x&(x-1) == 0 && x != 0
func oneBit32(x int32) bool { return x&(x-1) == 0 && x != 0 } }
func oneBit64(x int64) bool { return x&(x-1) == 0 && x != 0 }
// nto returns the number of trailing ones. // nto returns the number of trailing ones.
func nto(x int64) int64 { func nto(x int64) int64 {

View file

@ -8796,7 +8796,7 @@ func rewriteValuegeneric_OpEq16(v *Value) bool {
break break
} }
// match: (Eq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [y])) // match: (Eq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [y]))
// cond: oneBit16(y) // cond: oneBit(y)
// result: (Neq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [0])) // result: (Neq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [0]))
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 {
@ -8813,7 +8813,7 @@ func rewriteValuegeneric_OpEq16(v *Value) bool {
continue continue
} }
y := auxIntToInt16(v_0_1.AuxInt) y := auxIntToInt16(v_0_1.AuxInt)
if v_1.Op != OpConst16 || v_1.Type != t || auxIntToInt16(v_1.AuxInt) != y || !(oneBit16(y)) { if v_1.Op != OpConst16 || v_1.Type != t || auxIntToInt16(v_1.AuxInt) != y || !(oneBit(y)) {
continue continue
} }
v.reset(OpNeq16) v.reset(OpNeq16)
@ -9660,7 +9660,7 @@ func rewriteValuegeneric_OpEq32(v *Value) bool {
break break
} }
// match: (Eq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [y])) // match: (Eq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [y]))
// cond: oneBit32(y) // cond: oneBit(y)
// result: (Neq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [0])) // result: (Neq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [0]))
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 {
@ -9677,7 +9677,7 @@ func rewriteValuegeneric_OpEq32(v *Value) bool {
continue continue
} }
y := auxIntToInt32(v_0_1.AuxInt) y := auxIntToInt32(v_0_1.AuxInt)
if v_1.Op != OpConst32 || v_1.Type != t || auxIntToInt32(v_1.AuxInt) != y || !(oneBit32(y)) { if v_1.Op != OpConst32 || v_1.Type != t || auxIntToInt32(v_1.AuxInt) != y || !(oneBit(y)) {
continue continue
} }
v.reset(OpNeq32) v.reset(OpNeq32)
@ -10241,7 +10241,7 @@ func rewriteValuegeneric_OpEq64(v *Value) bool {
break break
} }
// match: (Eq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [y])) // match: (Eq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [y]))
// cond: oneBit64(y) // cond: oneBit(y)
// result: (Neq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [0])) // result: (Neq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [0]))
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 {
@ -10258,7 +10258,7 @@ func rewriteValuegeneric_OpEq64(v *Value) bool {
continue continue
} }
y := auxIntToInt64(v_0_1.AuxInt) y := auxIntToInt64(v_0_1.AuxInt)
if v_1.Op != OpConst64 || v_1.Type != t || auxIntToInt64(v_1.AuxInt) != y || !(oneBit64(y)) { if v_1.Op != OpConst64 || v_1.Type != t || auxIntToInt64(v_1.AuxInt) != y || !(oneBit(y)) {
continue continue
} }
v.reset(OpNeq64) v.reset(OpNeq64)
@ -10663,7 +10663,7 @@ func rewriteValuegeneric_OpEq8(v *Value) bool {
break break
} }
// match: (Eq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [y])) // match: (Eq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [y]))
// cond: oneBit8(y) // cond: oneBit(y)
// result: (Neq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [0])) // result: (Neq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [0]))
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 {
@ -10680,7 +10680,7 @@ func rewriteValuegeneric_OpEq8(v *Value) bool {
continue continue
} }
y := auxIntToInt8(v_0_1.AuxInt) y := auxIntToInt8(v_0_1.AuxInt)
if v_1.Op != OpConst8 || v_1.Type != t || auxIntToInt8(v_1.AuxInt) != y || !(oneBit8(y)) { if v_1.Op != OpConst8 || v_1.Type != t || auxIntToInt8(v_1.AuxInt) != y || !(oneBit(y)) {
continue continue
} }
v.reset(OpNeq8) v.reset(OpNeq8)
@ -20309,7 +20309,7 @@ func rewriteValuegeneric_OpNeq16(v *Value) bool {
break break
} }
// match: (Neq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [y])) // match: (Neq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [y]))
// cond: oneBit16(y) // cond: oneBit(y)
// result: (Eq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [0])) // result: (Eq16 (And16 <t> x (Const16 <t> [y])) (Const16 <t> [0]))
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 {
@ -20326,7 +20326,7 @@ func rewriteValuegeneric_OpNeq16(v *Value) bool {
continue continue
} }
y := auxIntToInt16(v_0_1.AuxInt) y := auxIntToInt16(v_0_1.AuxInt)
if v_1.Op != OpConst16 || v_1.Type != t || auxIntToInt16(v_1.AuxInt) != y || !(oneBit16(y)) { if v_1.Op != OpConst16 || v_1.Type != t || auxIntToInt16(v_1.AuxInt) != y || !(oneBit(y)) {
continue continue
} }
v.reset(OpEq16) v.reset(OpEq16)
@ -20496,7 +20496,7 @@ func rewriteValuegeneric_OpNeq32(v *Value) bool {
break break
} }
// match: (Neq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [y])) // match: (Neq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [y]))
// cond: oneBit32(y) // cond: oneBit(y)
// result: (Eq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [0])) // result: (Eq32 (And32 <t> x (Const32 <t> [y])) (Const32 <t> [0]))
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 {
@ -20513,7 +20513,7 @@ func rewriteValuegeneric_OpNeq32(v *Value) bool {
continue continue
} }
y := auxIntToInt32(v_0_1.AuxInt) y := auxIntToInt32(v_0_1.AuxInt)
if v_1.Op != OpConst32 || v_1.Type != t || auxIntToInt32(v_1.AuxInt) != y || !(oneBit32(y)) { if v_1.Op != OpConst32 || v_1.Type != t || auxIntToInt32(v_1.AuxInt) != y || !(oneBit(y)) {
continue continue
} }
v.reset(OpEq32) v.reset(OpEq32)
@ -20706,7 +20706,7 @@ func rewriteValuegeneric_OpNeq64(v *Value) bool {
break break
} }
// match: (Neq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [y])) // match: (Neq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [y]))
// cond: oneBit64(y) // cond: oneBit(y)
// result: (Eq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [0])) // result: (Eq64 (And64 <t> x (Const64 <t> [y])) (Const64 <t> [0]))
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 {
@ -20723,7 +20723,7 @@ func rewriteValuegeneric_OpNeq64(v *Value) bool {
continue continue
} }
y := auxIntToInt64(v_0_1.AuxInt) y := auxIntToInt64(v_0_1.AuxInt)
if v_1.Op != OpConst64 || v_1.Type != t || auxIntToInt64(v_1.AuxInt) != y || !(oneBit64(y)) { if v_1.Op != OpConst64 || v_1.Type != t || auxIntToInt64(v_1.AuxInt) != y || !(oneBit(y)) {
continue continue
} }
v.reset(OpEq64) v.reset(OpEq64)
@ -20916,7 +20916,7 @@ func rewriteValuegeneric_OpNeq8(v *Value) bool {
break break
} }
// match: (Neq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [y])) // match: (Neq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [y]))
// cond: oneBit8(y) // cond: oneBit(y)
// result: (Eq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [0])) // result: (Eq8 (And8 <t> x (Const8 <t> [y])) (Const8 <t> [0]))
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 {
@ -20933,7 +20933,7 @@ func rewriteValuegeneric_OpNeq8(v *Value) bool {
continue continue
} }
y := auxIntToInt8(v_0_1.AuxInt) y := auxIntToInt8(v_0_1.AuxInt)
if v_1.Op != OpConst8 || v_1.Type != t || auxIntToInt8(v_1.AuxInt) != y || !(oneBit8(y)) { if v_1.Op != OpConst8 || v_1.Type != t || auxIntToInt8(v_1.AuxInt) != y || !(oneBit(y)) {
continue continue
} }
v.reset(OpEq8) v.reset(OpEq8)