Skip to content

Commit f3582fc

Browse files
cuonglmgopherbot
authored andcommitted
cmd/compile: add unsigned power-of-two detector
Fixes #74485 Change-Id: Ia22a58ac43bdc36c8414d555672a3a3eafc749ca Reviewed-on: https://go-review.googlesource.com/c/go/+/689815 Reviewed-by: Keith Randall <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: David Chase <[email protected]> Reviewed-by: Keith Randall <[email protected]> Auto-Submit: Cuong Manh Le <[email protected]>
1 parent f7d167f commit f3582fc

File tree

4 files changed

+59
-34
lines changed

4 files changed

+59
-34
lines changed

src/cmd/compile/internal/ssa/_gen/generic.rules

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,11 +1014,10 @@
10141014
// See ../magic.go for a detailed description of these algorithms.
10151015

10161016
// Unsigned divide by power of 2. Strength reduce to a shift.
1017-
(Div8u n (Const8 [c])) && isPowerOfTwo(c) => (Rsh8Ux64 n (Const64 <typ.UInt64> [log8(c)]))
1018-
(Div16u n (Const16 [c])) && isPowerOfTwo(c) => (Rsh16Ux64 n (Const64 <typ.UInt64> [log16(c)]))
1019-
(Div32u n (Const32 [c])) && isPowerOfTwo(c) => (Rsh32Ux64 n (Const64 <typ.UInt64> [log32(c)]))
1020-
(Div64u n (Const64 [c])) && isPowerOfTwo(c) => (Rsh64Ux64 n (Const64 <typ.UInt64> [log64(c)]))
1021-
(Div64u n (Const64 [-1<<63])) => (Rsh64Ux64 n (Const64 <typ.UInt64> [63]))
1017+
(Div8u n (Const8 [c])) && isUnsignedPowerOfTwo(uint8(c)) => (Rsh8Ux64 n (Const64 <typ.UInt64> [log8u(uint8(c))]))
1018+
(Div16u n (Const16 [c])) && isUnsignedPowerOfTwo(uint16(c)) => (Rsh16Ux64 n (Const64 <typ.UInt64> [log16u(uint16(c))]))
1019+
(Div32u n (Const32 [c])) && isUnsignedPowerOfTwo(uint32(c)) => (Rsh32Ux64 n (Const64 <typ.UInt64> [log32u(uint32(c))]))
1020+
(Div64u n (Const64 [c])) && isUnsignedPowerOfTwo(uint64(c)) => (Rsh64Ux64 n (Const64 <typ.UInt64> [log64u(uint64(c))]))
10221021

10231022
// Signed non-negative divide by power of 2.
10241023
(Div8 n (Const8 [c])) && isNonNegative(n) && isPowerOfTwo(c) => (Rsh8Ux64 n (Const64 <typ.UInt64> [log8(c)]))

src/cmd/compile/internal/ssa/rewrite.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,13 @@ func log64(n int64) int64 {
493493
return int64(bits.Len64(uint64(n))) - 1
494494
}
495495

496+
// logXu returns the logarithm of n base 2.
497+
// n must be a power of 2 (isUnsignedPowerOfTwo returns true)
498+
func log8u(n uint8) int64 { return int64(bits.Len8(n)) - 1 }
499+
func log16u(n uint16) int64 { return int64(bits.Len16(n)) - 1 }
500+
func log32u(n uint32) int64 { return int64(bits.Len32(n)) - 1 }
501+
func log64u(n uint64) int64 { return int64(bits.Len64(n)) - 1 }
502+
496503
// log2uint32 returns logarithm in base 2 of uint32(n), with log2(0) = -1.
497504
// Rounds down.
498505
func log2uint32(n int64) int64 {
@@ -504,6 +511,11 @@ func isPowerOfTwo[T int8 | int16 | int32 | int64](n T) bool {
504511
return n > 0 && n&(n-1) == 0
505512
}
506513

514+
// isUnsignedPowerOfTwo reports whether n is an unsigned power of 2.
515+
func isUnsignedPowerOfTwo[T uint8 | uint16 | uint32 | uint64](n T) bool {
516+
return n != 0 && n&(n-1) == 0
517+
}
518+
507519
// isUint64PowerOfTwo reports whether uint64(n) is a power of 2.
508520
func isUint64PowerOfTwo(in int64) bool {
509521
n := uint64(in)

src/cmd/compile/internal/ssa/rewritegeneric.go

Lines changed: 16 additions & 29 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/codegen/issue74485.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// asmcheck
2+
3+
// Copyright 2025 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package codegen
8+
9+
func divUint64(b uint64) uint64 {
10+
// amd64:"SHRQ [$]63, AX"
11+
return b / 9223372036854775808
12+
}
13+
14+
func divUint32(b uint32) uint32 {
15+
// amd64:"SHRL [$]31, AX"
16+
return b / 2147483648
17+
}
18+
19+
func divUint16(b uint16) uint16 {
20+
// amd64:"SHRW [$]15, AX"
21+
return b / 32768
22+
}
23+
24+
func divUint8(b uint8) uint8 {
25+
// amd64:"SHRB [$]7, AL"
26+
return b / 128
27+
}

0 commit comments

Comments
 (0)