Skip to content

Commit 55e1407

Browse files
committed
optimize: pow if exp is statically known
Copy the optimization that unrolls the loop from `pow` to `checked_pow` and `overflowing_pow`.
1 parent c52c2ee commit 55e1407

2 files changed

Lines changed: 72 additions & 0 deletions

File tree

library/core/src/num/int_macros.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1767,6 +1767,22 @@ macro_rules! int_impl {
17671767
let mut base = self;
17681768
let mut acc: Self = 1;
17691769

1770+
if intrinsics::is_val_statically_known(exp) {
1771+
while exp > 1 {
1772+
if (exp & 1) == 1 {
1773+
acc = try_opt!(acc.checked_mul(base));
1774+
}
1775+
exp /= 2;
1776+
base = try_opt!(base.checked_mul(base));
1777+
}
1778+
1779+
// since exp!=0, finally the exp must be 1.
1780+
// Deal with the final bit of the exponent separately, since
1781+
// squaring the base afterwards is not necessary and may cause a
1782+
// needless overflow.
1783+
return acc.checked_mul(base);
1784+
}
1785+
17701786
loop {
17711787
if (exp & 1) == 1 {
17721788
acc = try_opt!(acc.checked_mul(base));
@@ -3001,6 +3017,26 @@ macro_rules! int_impl {
30013017
let mut overflow = false;
30023018
let mut tmp_overflow;
30033019

3020+
if intrinsics::is_val_statically_known(exp) {
3021+
while exp > 1 {
3022+
if (exp & 1) == 1 {
3023+
(acc, tmp_overflow) = acc.overflowing_mul(base);
3024+
overflow |= tmp_overflow;
3025+
}
3026+
exp /= 2;
3027+
(base, tmp_overflow) = base.overflowing_mul(base);
3028+
overflow |= tmp_overflow;
3029+
}
3030+
3031+
// since exp!=0, finally the exp must be 1.
3032+
// Deal with the final bit of the exponent separately, since
3033+
// squaring the base afterwards is not necessary and may cause a
3034+
// needless overflow.
3035+
(acc, tmp_overflow) = acc.overflowing_mul(base);
3036+
overflow |= tmp_overflow;
3037+
return (acc, overflow);
3038+
}
3039+
30043040
loop {
30053041
if (exp & 1) == 1 {
30063042
(acc, tmp_overflow) = acc.overflowing_mul(base);

library/core/src/num/uint_macros.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2232,6 +2232,22 @@ macro_rules! uint_impl {
22322232
let mut base = self;
22332233
let mut acc: Self = 1;
22342234

2235+
if intrinsics::is_val_statically_known(exp) {
2236+
while exp > 1 {
2237+
if (exp & 1) == 1 {
2238+
acc = try_opt!(acc.checked_mul(base));
2239+
}
2240+
exp /= 2;
2241+
base = try_opt!(base.checked_mul(base));
2242+
}
2243+
2244+
// since exp!=0, finally the exp must be 1.
2245+
// Deal with the final bit of the exponent separately, since
2246+
// squaring the base afterwards is not necessary and may cause a
2247+
// needless overflow.
2248+
return acc.checked_mul(base);
2249+
}
2250+
22352251
loop {
22362252
if (exp & 1) == 1 {
22372253
acc = try_opt!(acc.checked_mul(base));
@@ -3417,6 +3433,26 @@ macro_rules! uint_impl {
34173433
let mut overflow = false;
34183434
let mut tmp_overflow;
34193435

3436+
if intrinsics::is_val_statically_known(exp) {
3437+
while exp > 1 {
3438+
if (exp & 1) == 1 {
3439+
(acc, tmp_overflow) = acc.overflowing_mul(base);
3440+
overflow |= tmp_overflow;
3441+
}
3442+
exp /= 2;
3443+
(base, tmp_overflow) = base.overflowing_mul(base);
3444+
overflow |= tmp_overflow;
3445+
}
3446+
3447+
// since exp!=0, finally the exp must be 1.
3448+
// Deal with the final bit of the exponent separately, since
3449+
// squaring the base afterwards is not necessary and may cause a
3450+
// needless overflow.
3451+
(acc, tmp_overflow) = acc.overflowing_mul(base);
3452+
overflow |= tmp_overflow;
3453+
return (acc, overflow);
3454+
}
3455+
34203456
loop {
34213457
if (exp & 1) == 1 {
34223458
(acc, tmp_overflow) = acc.overflowing_mul(base);

0 commit comments

Comments
 (0)