cmd/compile: add RshU support to known bits

I havn't searched a real world usecase for this but it seems
fine for completeness.

This doesn't have any hits in the std.

Updates #78633

Change-Id: Id69a3c9ccf945f0d91dac6618afe7dfaf1af8da8
Reviewed-on: https://go-review.googlesource.com/c/go/+/766080
Reviewed-by: Mark Freeman <markfreeman@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Jorropo <jorropo.pgm@gmail.com>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Carlos Amedee <carlos@golang.org>
This commit is contained in:
Jorropo 2026-04-12 20:51:01 +02:00 committed by Gopher Robot
parent 977041b065
commit 767140eff2
2 changed files with 89 additions and 0 deletions

View file

@ -122,6 +122,11 @@ func (kb *knownBitsState) fold(v *Value) (value, known int64) {
OpLsh8x32, OpLsh16x32, OpLsh32x32, OpLsh64x32,
OpLsh8x64, OpLsh16x64, OpLsh32x64, OpLsh64x64:
return kb.computeKnownBitsForLsh(v)
case OpRsh8Ux8, OpRsh16Ux8, OpRsh32Ux8, OpRsh64Ux8,
OpRsh8Ux16, OpRsh16Ux16, OpRsh32Ux16, OpRsh64Ux16,
OpRsh8Ux32, OpRsh16Ux32, OpRsh32Ux32, OpRsh64Ux32,
OpRsh8Ux64, OpRsh16Ux64, OpRsh32Ux64, OpRsh64Ux64:
return kb.computeKnownBitsForRshU(v)
default:
return 0, 0
}
@ -287,3 +292,42 @@ func (kb *knownBitsState) computeKnownBitsForLsh(v *Value) (value, known int64)
return value & known, known
}
// computeKnownBitsForRshU is the same as computeKnownBitsForLsh but for unsigned right shifts.
func (kb *knownBitsState) computeKnownBitsForRshU(v *Value) (value, known int64) {
xSize := v.Args[0].Type.Size() * 8
x, xk := kb.fold(v.Args[0])
y, yk := kb.fold(v.Args[1])
if uint64(y) >= uint64(xSize) {
return 0, -1
}
set := false
if v.AuxInt == 0 && uint64(^yk) >= uint64(xSize) {
// this implement the default case of the equivalent switch.
// if the shift isn't bounded and there are unknown bits above the shift size we might completely stomp all bits.
value = 0
known = -1
set = true
}
xk |= -1 << xSize
x &= (1<<xSize - 1)
yk &= xSize - 1
for i := range xSize {
if i&yk != y {
continue
}
a, k := uint64(x)>>i, uint64(xk)>>i|(^uint64(0)<<(64-i))
if !set {
value, known = int64(a), int64(k)
set = true
} else {
known &^= value ^ int64(a)
known &= int64(k)
}
continue
}
return value & known, known
}

View file

@ -294,3 +294,48 @@ func unknownBitsLshRightSide(x uint32, y uint32) uint32 {
return (x << y) & 0b11000
}
func knownBitsRshU(x, y uint32) uint32 {
x |= 0b11110
x &^= 0b100000
y &= 2
// ?01111?
// ???0111
// -------
// ????11?
return (x >> y) & 0b110 // ERROR "known value of v[0-9]+ \(And32\): 6$"
}
func knownBitsRshUZero(x, y uint64) uint64 {
x &^= 4
y &^= 2
y |= 128
return (x >> y) & 1 // ERROR "known value of v[0-9]+ \(And64\): 0$" "known value of v[0-9]+ \(Rsh64Ux[0-9]+\): 0$"
}
func unknownBitsRshULeftSideMsb(x uint32, y uint32) uint32 {
x |= 0b11110
x &^= 0b100000
y &= 2
return (x >> y) & 0b1110
}
func unknownBitsRshULeftSideLsb(x uint32, y uint32) uint32 {
x |= 0b11110
x &^= 0b100000
y &= 2
return (x >> y) & 0b111
}
func unknownBitsRshURightSide(x uint32, y uint32) uint32 {
x |= 0b11110
x &^= 0b100000
y &= 6
return (x >> y) & 0b110
}