Skip to content

Commit e481662

Browse files
committed
Optimize pow when self is a power of two
if base == 2 ** k, then (2 ** k) ** n == 2 ** (k * n) == 1 << (k * n)
1 parent ee9dd66 commit e481662

File tree

3 files changed

+54
-0
lines changed

3 files changed

+54
-0
lines changed

library/core/src/num/uint_macros.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3318,6 +3318,18 @@ macro_rules! uint_impl {
33183318
let mut base = self;
33193319
let mut acc = 1;
33203320

3321+
if intrinsics::is_val_statically_known(base) {
3322+
// change of base:
3323+
// if base == 2 ** k, then
3324+
// (2 ** k) ** n
3325+
// == 2 ** (k * n)
3326+
// == 1 << (k * n)
3327+
if base.is_power_of_two() {
3328+
let k = base.ilog2();
3329+
return 1 << (k * exp)
3330+
}
3331+
}
3332+
33213333
if intrinsics::is_val_statically_known(exp) {
33223334
while exp > 1 {
33233335
if (exp & 1) == 1 {

library/coretests/tests/num/uint_macros.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,12 @@ macro_rules! uint_module {
310310
assert_eq_const_safe!(($T, bool): R.overflowing_pow(2), (1 as $T, true));
311311
assert_eq_const_safe!($T: R.saturating_pow(2), MAX);
312312
}
313+
314+
#[test]
315+
#[should_panic]
316+
fn test_pow_overflow() {
317+
let _ = <$T>::pow(2, 129);
318+
}
313319
}
314320

315321
fn test_isqrt() {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//@ compile-flags: -Copt-level=3
2+
// Test that `pow` can use a faster implementation when `base` is a
3+
// known power of two
4+
5+
#![crate_type = "lib"]
6+
7+
// CHECK-LABEL: @pow2
8+
#[no_mangle]
9+
pub fn pow2(exp: u32) -> u32 {
10+
// CHECK: %[[SHIFT_AMOUNT:.+]] = and i32 %exp, 31
11+
// CHECK: %[[POW2:.+]] = shl nuw i32 1, %[[SHIFT_AMOUNT]]
12+
// CHECK: ret i32 %[[POW2]]
13+
2u32.pow(exp)
14+
}
15+
16+
// 4 ** n == 2 ** (2 * n) == 1 << (2 * n)
17+
// CHECK-LABEL: @pow4
18+
#[no_mangle]
19+
pub fn pow4(exp: u32) -> u32 {
20+
// CHECK: %[[EXP2:.+]] = shl i32 %exp, 1
21+
// CHECK: %[[SHIFT_AMOUNT:.+]] = and i32 %[[EXP2]], 30
22+
// CHECK: %[[POW4:.+]] = shl nuw nsw i32 1, %[[SHIFT_AMOUNT]]
23+
// CHECK: ret i32 %[[POW4]]
24+
4u32.pow(exp)
25+
}
26+
27+
// 16 ** n == 2 ** (4 * n) == 1 << (4 * n)
28+
// CHECK-LABEL: @pow16
29+
#[no_mangle]
30+
pub fn pow16(exp: u32) -> u32 {
31+
// CHECK: %[[EXP2:.+]] = shl i32 %exp, 2
32+
// CHECK: %[[SHIFT_AMOUNT:.+]] = and i32 %[[EXP2]], 28
33+
// CHECK: %[[POW16:.+]] = shl nuw nsw i32 1, %[[SHIFT_AMOUNT]]
34+
// CHECK: ret i32 %[[POW16]]
35+
16u32.pow(exp)
36+
}

0 commit comments

Comments
 (0)