mirror of
https://github.com/golang/go.git
synced 2026-06-27 03:11:23 +00:00
cmd/compile: add first boolean and Eq support to known bits
When known bits analyze an Eq if it finds any bit that is known in both sides but different, it also knows the eq will always be false. Uniqued by LOC this adds 119 known bits hits when building the std. Updates #78633 Change-Id: I8299f0ad94383b21aec0cd3794d2f851c1260cef Reviewed-on: https://go-review.googlesource.com/c/go/+/765780 Reviewed-by: Keith Randall <khr@golang.org> Auto-Submit: Jorropo <jorropo.pgm@gmail.com> Reviewed-by: Keith Randall <khr@google.com> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Carlos Amedee <carlos@golang.org>
This commit is contained in:
parent
7a8dcab743
commit
b9e1876c11
2 changed files with 54 additions and 8 deletions
|
|
@ -9,7 +9,13 @@ func (kb *knownBitsState) fold(v *Value) (value, known int64) {
|
|||
return kb.entries[v.ID].value, kb.entries[v.ID].known
|
||||
}
|
||||
defer func() {
|
||||
// maintain the two invariants:
|
||||
// maintain the invariants:
|
||||
// 3. booleans are stored as 1 byte values who are either 0 or 1.
|
||||
if v.Type.IsBoolean() {
|
||||
value &= 1
|
||||
known |= ^1
|
||||
}
|
||||
|
||||
// 2. all values are sign-extended to int64 (inspired by RISC-V's xlen=64)
|
||||
switch v.Type.Size() {
|
||||
case 1:
|
||||
|
|
@ -39,16 +45,16 @@ func (kb *knownBitsState) fold(v *Value) (value, known int64) {
|
|||
|
||||
switch v.Op {
|
||||
// TODO: Shifts, rotates, extensions, ...
|
||||
case OpConst64, OpConst32, OpConst16, OpConst8:
|
||||
case OpConst64, OpConst32, OpConst16, OpConst8, OpConstBool:
|
||||
return v.AuxInt, -1
|
||||
case OpAnd64, OpAnd32, OpAnd16, OpAnd8:
|
||||
case OpAnd64, OpAnd32, OpAnd16, OpAnd8, OpAndB:
|
||||
x, xk := kb.fold(v.Args[0])
|
||||
y, yk := kb.fold(v.Args[1])
|
||||
onesInBoth := x & y
|
||||
zerosInX := ^x & xk
|
||||
zerosInY := ^y & yk
|
||||
return x & y, onesInBoth | zerosInX | zerosInY
|
||||
case OpOr64, OpOr32, OpOr16, OpOr8:
|
||||
case OpOr64, OpOr32, OpOr16, OpOr8, OpOrB:
|
||||
x, xk := kb.fold(v.Args[0])
|
||||
y, yk := kb.fold(v.Args[1])
|
||||
zerosInBoth := ^x & ^y & (xk & yk)
|
||||
|
|
@ -59,7 +65,7 @@ func (kb *knownBitsState) fold(v *Value) (value, known int64) {
|
|||
x, xk := kb.fold(v.Args[0])
|
||||
y, yk := kb.fold(v.Args[1])
|
||||
return x ^ y, xk & yk
|
||||
case OpCom64, OpCom32, OpCom16, OpCom8:
|
||||
case OpCom64, OpCom32, OpCom16, OpCom8, OpNot:
|
||||
x, xk := kb.fold(v.Args[0])
|
||||
return ^x, xk
|
||||
case OpPhi:
|
||||
|
|
@ -83,6 +89,17 @@ func (kb *knownBitsState) fold(v *Value) (value, known int64) {
|
|||
return value, known
|
||||
case OpCopy:
|
||||
return kb.fold(v.Args[0])
|
||||
case OpEq64, OpEq32, OpEq16, OpEq8, OpEqB:
|
||||
x, xk := kb.fold(v.Args[0])
|
||||
y, yk := kb.fold(v.Args[1])
|
||||
differentBits := x ^ y
|
||||
if differentBits&xk&yk != 0 {
|
||||
return 0, -1
|
||||
}
|
||||
if xk == -1 && yk == -1 {
|
||||
return boolToAuxInt(x == y), -1
|
||||
}
|
||||
return 0, -1 << 1
|
||||
default:
|
||||
return 0, 0
|
||||
}
|
||||
|
|
@ -109,11 +126,11 @@ func knownBits(f *Func) {
|
|||
|
||||
for _, b := range blocks {
|
||||
for _, v := range b.Values {
|
||||
if v.Uses == 0 || !v.Type.IsInteger() {
|
||||
if v.Uses == 0 || !(v.Type.IsInteger() || v.Type.IsBoolean()) {
|
||||
continue
|
||||
}
|
||||
switch v.Op {
|
||||
case OpConst64, OpConst32, OpConst16, OpConst8:
|
||||
case OpConst64, OpConst32, OpConst16, OpConst8, OpConstBool:
|
||||
continue
|
||||
}
|
||||
val, k := kb.fold(v)
|
||||
|
|
@ -121,11 +138,19 @@ func knownBits(f *Func) {
|
|||
continue
|
||||
}
|
||||
if f.pass.debug > 0 {
|
||||
f.Warnl(v.Pos, "known value of %v (%v): %d", v, v.Op, val)
|
||||
var pval any = val
|
||||
if v.Type.IsBoolean() {
|
||||
pval = val != 0
|
||||
}
|
||||
f.Warnl(v.Pos, "known value of %v (%v): %v", v, v.Op, pval)
|
||||
}
|
||||
var c *Value
|
||||
switch v.Type.Size() {
|
||||
case 1:
|
||||
if v.Type.IsBoolean() {
|
||||
c = f.ConstBool(v.Type, val != 0)
|
||||
break
|
||||
}
|
||||
c = f.ConstInt8(v.Type, int8(val))
|
||||
case 2:
|
||||
c = f.ConstInt16(v.Type, int16(val))
|
||||
|
|
@ -154,6 +179,7 @@ type knownBitsEntry struct {
|
|||
// This means let's say you know an 8 bits value is 0b10??????,
|
||||
// known = int64(int8(0b11000000))
|
||||
// value = int64(int8(0b10000000))
|
||||
// 3. booleans are stored as 1 byte values who are either 0 or 1.
|
||||
known, value int64
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -147,3 +147,23 @@ func unknownBitsPhiComAnd(cond bool) int {
|
|||
}
|
||||
return ^x & 1
|
||||
}
|
||||
|
||||
func knownBitsEqFalse(x, y uint64) bool {
|
||||
x |= 1
|
||||
y &^= 1
|
||||
return x == y // ERROR "known value of v[0-9]+ \(Eq64\): false$"
|
||||
}
|
||||
|
||||
func knownBitsEqTrue(x uint64, cond bool) bool {
|
||||
x |= (1<<32 - 1) << 32
|
||||
if cond {
|
||||
x |= 42
|
||||
}
|
||||
x |= 1<<32 - 1 // ERROR "known value of v[0-9]+ \(Or64\): -1$"
|
||||
return x == 1<<64-1 // ERROR "known value of v[0-9]+ \(Eq64\): true$"
|
||||
}
|
||||
|
||||
func unknownBitsEq(x, y uint64) bool {
|
||||
x |= 1
|
||||
return x == y
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue