// See ../magic.go for a detailed description of these algorithms.
// Unsigned divide by power of 2. Strength reduce to a shift.
-(Div8u n (Const8 [c])) && isPowerOfTwo(c) => (Rsh8Ux64 n (Const64 <typ.UInt64> [log8(c)]))
-(Div16u n (Const16 [c])) && isPowerOfTwo(c) => (Rsh16Ux64 n (Const64 <typ.UInt64> [log16(c)]))
-(Div32u n (Const32 [c])) && isPowerOfTwo(c) => (Rsh32Ux64 n (Const64 <typ.UInt64> [log32(c)]))
-(Div64u n (Const64 [c])) && isPowerOfTwo(c) => (Rsh64Ux64 n (Const64 <typ.UInt64> [log64(c)]))
-(Div64u n (Const64 [-1<<63])) => (Rsh64Ux64 n (Const64 <typ.UInt64> [63]))
+(Div8u n (Const8 [c])) && isUnsignedPowerOfTwo(uint8(c)) => (Rsh8Ux64 n (Const64 <typ.UInt64> [log8u(uint8(c))]))
+(Div16u n (Const16 [c])) && isUnsignedPowerOfTwo(uint16(c)) => (Rsh16Ux64 n (Const64 <typ.UInt64> [log16u(uint16(c))]))
+(Div32u n (Const32 [c])) && isUnsignedPowerOfTwo(uint32(c)) => (Rsh32Ux64 n (Const64 <typ.UInt64> [log32u(uint32(c))]))
+(Div64u n (Const64 [c])) && isUnsignedPowerOfTwo(uint64(c)) => (Rsh64Ux64 n (Const64 <typ.UInt64> [log64u(uint64(c))]))
// Signed non-negative divide by power of 2.
(Div8 n (Const8 [c])) && isNonNegative(n) && isPowerOfTwo(c) => (Rsh8Ux64 n (Const64 <typ.UInt64> [log8(c)]))
return int64(bits.Len64(uint64(n))) - 1
}
+// logXu returns the logarithm of n base 2.
+// n must be a power of 2 (isUnsignedPowerOfTwo returns true)
+func log8u(n uint8) int64 { return int64(bits.Len8(n)) - 1 }
+func log16u(n uint16) int64 { return int64(bits.Len16(n)) - 1 }
+func log32u(n uint32) int64 { return int64(bits.Len32(n)) - 1 }
+func log64u(n uint64) int64 { return int64(bits.Len64(n)) - 1 }
+
// log2uint32 returns logarithm in base 2 of uint32(n), with log2(0) = -1.
// Rounds down.
func log2uint32(n int64) int64 {
return n > 0 && n&(n-1) == 0
}
+// isUnsignedPowerOfTwo reports whether n is an unsigned power of 2.
+func isUnsignedPowerOfTwo[T uint8 | uint16 | uint32 | uint64](n T) bool {
+ return n != 0 && n&(n-1) == 0
+}
+
// isUint64PowerOfTwo reports whether uint64(n) is a power of 2.
func isUint64PowerOfTwo(in int64) bool {
n := uint64(in)
return true
}
// match: (Div16u n (Const16 [c]))
- // cond: isPowerOfTwo(c)
- // result: (Rsh16Ux64 n (Const64 <typ.UInt64> [log16(c)]))
+ // cond: isUnsignedPowerOfTwo(uint16(c))
+ // result: (Rsh16Ux64 n (Const64 <typ.UInt64> [log16u(uint16(c))]))
for {
n := v_0
if v_1.Op != OpConst16 {
break
}
c := auxIntToInt16(v_1.AuxInt)
- if !(isPowerOfTwo(c)) {
+ if !(isUnsignedPowerOfTwo(uint16(c))) {
break
}
v.reset(OpRsh16Ux64)
v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
- v0.AuxInt = int64ToAuxInt(log16(c))
+ v0.AuxInt = int64ToAuxInt(log16u(uint16(c)))
v.AddArg2(n, v0)
return true
}
return true
}
// match: (Div32u n (Const32 [c]))
- // cond: isPowerOfTwo(c)
- // result: (Rsh32Ux64 n (Const64 <typ.UInt64> [log32(c)]))
+ // cond: isUnsignedPowerOfTwo(uint32(c))
+ // result: (Rsh32Ux64 n (Const64 <typ.UInt64> [log32u(uint32(c))]))
for {
n := v_0
if v_1.Op != OpConst32 {
break
}
c := auxIntToInt32(v_1.AuxInt)
- if !(isPowerOfTwo(c)) {
+ if !(isUnsignedPowerOfTwo(uint32(c))) {
break
}
v.reset(OpRsh32Ux64)
v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
- v0.AuxInt = int64ToAuxInt(log32(c))
+ v0.AuxInt = int64ToAuxInt(log32u(uint32(c)))
v.AddArg2(n, v0)
return true
}
return true
}
// match: (Div64u n (Const64 [c]))
- // cond: isPowerOfTwo(c)
- // result: (Rsh64Ux64 n (Const64 <typ.UInt64> [log64(c)]))
+ // cond: isUnsignedPowerOfTwo(uint64(c))
+ // result: (Rsh64Ux64 n (Const64 <typ.UInt64> [log64u(uint64(c))]))
for {
n := v_0
if v_1.Op != OpConst64 {
break
}
c := auxIntToInt64(v_1.AuxInt)
- if !(isPowerOfTwo(c)) {
+ if !(isUnsignedPowerOfTwo(uint64(c))) {
break
}
v.reset(OpRsh64Ux64)
v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
- v0.AuxInt = int64ToAuxInt(log64(c))
- v.AddArg2(n, v0)
- return true
- }
- // match: (Div64u n (Const64 [-1<<63]))
- // result: (Rsh64Ux64 n (Const64 <typ.UInt64> [63]))
- for {
- n := v_0
- if v_1.Op != OpConst64 || auxIntToInt64(v_1.AuxInt) != -1<<63 {
- break
- }
- v.reset(OpRsh64Ux64)
- v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
- v0.AuxInt = int64ToAuxInt(63)
+ v0.AuxInt = int64ToAuxInt(log64u(uint64(c)))
v.AddArg2(n, v0)
return true
}
return true
}
// match: (Div8u n (Const8 [c]))
- // cond: isPowerOfTwo(c)
- // result: (Rsh8Ux64 n (Const64 <typ.UInt64> [log8(c)]))
+ // cond: isUnsignedPowerOfTwo(uint8(c))
+ // result: (Rsh8Ux64 n (Const64 <typ.UInt64> [log8u(uint8(c))]))
for {
n := v_0
if v_1.Op != OpConst8 {
break
}
c := auxIntToInt8(v_1.AuxInt)
- if !(isPowerOfTwo(c)) {
+ if !(isUnsignedPowerOfTwo(uint8(c))) {
break
}
v.reset(OpRsh8Ux64)
v0 := b.NewValue0(v.Pos, OpConst64, typ.UInt64)
- v0.AuxInt = int64ToAuxInt(log8(c))
+ v0.AuxInt = int64ToAuxInt(log8u(uint8(c)))
v.AddArg2(n, v0)
return true
}
--- /dev/null
+// asmcheck
+
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package codegen
+
+func divUint64(b uint64) uint64 {
+ // amd64:"SHRQ [$]63, AX"
+ return b / 9223372036854775808
+}
+
+func divUint32(b uint32) uint32 {
+ // amd64:"SHRL [$]31, AX"
+ return b / 2147483648
+}
+
+func divUint16(b uint16) uint16 {
+ // amd64:"SHRW [$]15, AX"
+ return b / 32768
+}
+
+func divUint8(b uint8) uint8 {
+ // amd64:"SHRB [$]7, AL"
+ return b / 128
+}