Skip to content

Commit 87b8256

Browse files
committed
Auto merge of #122884 - mzabaluev:pow-remove-exit-branch, r=Amanieu
Optimize integer `pow` by removing the exit branch The branch at the end of the `pow` implementations is redundant with multiplication code already present in the loop. By rotating the exit check, this branch can be largely removed, improving code size and reducing instruction cache misses. Testing on my machine (`x86_64`, 11th Gen Intel Core i5-1135G7 @ 2.40GHz), the `num::int_pow` benchmarks improve by some 40% for the unchecked operations and show some slight improvement for the checked operations as well.
2 parents 6475796 + 76d2530 commit 87b8256

File tree

2 files changed

+52
-73
lines changed

2 files changed

+52
-73
lines changed

library/core/src/num/int_macros.rs

+26-35
Original file line numberDiff line numberDiff line change
@@ -1418,18 +1418,17 @@ macro_rules! int_impl {
14181418
let mut base = self;
14191419
let mut acc: Self = 1;
14201420

1421-
while exp > 1 {
1421+
loop {
14221422
if (exp & 1) == 1 {
14231423
acc = try_opt!(acc.checked_mul(base));
1424+
// since exp!=0, finally the exp must be 1.
1425+
if exp == 1 {
1426+
return Some(acc);
1427+
}
14241428
}
14251429
exp /= 2;
14261430
base = try_opt!(base.checked_mul(base));
14271431
}
1428-
// since exp!=0, finally the exp must be 1.
1429-
// Deal with the final bit of the exponent separately, since
1430-
// squaring the base afterwards is not necessary and may cause a
1431-
// needless overflow.
1432-
acc.checked_mul(base)
14331432
}
14341433

14351434
/// Strict exponentiation. Computes `self.pow(exp)`, panicking if
@@ -1469,18 +1468,17 @@ macro_rules! int_impl {
14691468
let mut base = self;
14701469
let mut acc: Self = 1;
14711470

1472-
while exp > 1 {
1471+
loop {
14731472
if (exp & 1) == 1 {
14741473
acc = acc.strict_mul(base);
1474+
// since exp!=0, finally the exp must be 1.
1475+
if exp == 1 {
1476+
return acc;
1477+
}
14751478
}
14761479
exp /= 2;
14771480
base = base.strict_mul(base);
14781481
}
1479-
// since exp!=0, finally the exp must be 1.
1480-
// Deal with the final bit of the exponent separately, since
1481-
// squaring the base afterwards is not necessary and may cause a
1482-
// needless overflow.
1483-
acc.strict_mul(base)
14841482
}
14851483

14861484
/// Returns the square root of the number, rounded down.
@@ -2104,19 +2102,17 @@ macro_rules! int_impl {
21042102
let mut base = self;
21052103
let mut acc: Self = 1;
21062104

2107-
while exp > 1 {
2105+
loop {
21082106
if (exp & 1) == 1 {
21092107
acc = acc.wrapping_mul(base);
2108+
// since exp!=0, finally the exp must be 1.
2109+
if exp == 1 {
2110+
return acc;
2111+
}
21102112
}
21112113
exp /= 2;
21122114
base = base.wrapping_mul(base);
21132115
}
2114-
2115-
// since exp!=0, finally the exp must be 1.
2116-
// Deal with the final bit of the exponent separately, since
2117-
// squaring the base afterwards is not necessary and may cause a
2118-
// needless overflow.
2119-
acc.wrapping_mul(base)
21202116
}
21212117

21222118
/// Calculates `self` + `rhs`
@@ -2610,9 +2606,14 @@ macro_rules! int_impl {
26102606
// Scratch space for storing results of overflowing_mul.
26112607
let mut r;
26122608

2613-
while exp > 1 {
2609+
loop {
26142610
if (exp & 1) == 1 {
26152611
r = acc.overflowing_mul(base);
2612+
// since exp!=0, finally the exp must be 1.
2613+
if exp == 1 {
2614+
r.1 |= overflown;
2615+
return r;
2616+
}
26162617
acc = r.0;
26172618
overflown |= r.1;
26182619
}
@@ -2621,14 +2622,6 @@ macro_rules! int_impl {
26212622
base = r.0;
26222623
overflown |= r.1;
26232624
}
2624-
2625-
// since exp!=0, finally the exp must be 1.
2626-
// Deal with the final bit of the exponent separately, since
2627-
// squaring the base afterwards is not necessary and may cause a
2628-
// needless overflow.
2629-
r = acc.overflowing_mul(base);
2630-
r.1 |= overflown;
2631-
r
26322625
}
26332626

26342627
/// Raises self to the power of `exp`, using exponentiation by squaring.
@@ -2655,19 +2648,17 @@ macro_rules! int_impl {
26552648
let mut base = self;
26562649
let mut acc = 1;
26572650

2658-
while exp > 1 {
2651+
loop {
26592652
if (exp & 1) == 1 {
26602653
acc = acc * base;
2654+
// since exp!=0, finally the exp must be 1.
2655+
if exp == 1 {
2656+
return acc;
2657+
}
26612658
}
26622659
exp /= 2;
26632660
base = base * base;
26642661
}
2665-
2666-
// since exp!=0, finally the exp must be 1.
2667-
// Deal with the final bit of the exponent separately, since
2668-
// squaring the base afterwards is not necessary and may cause a
2669-
// needless overflow.
2670-
acc * base
26712662
}
26722663

26732664
/// Returns the square root of the number, rounded down.

library/core/src/num/uint_macros.rs

+26-38
Original file line numberDiff line numberDiff line change
@@ -1414,20 +1414,17 @@ macro_rules! uint_impl {
14141414
let mut base = self;
14151415
let mut acc: Self = 1;
14161416

1417-
while exp > 1 {
1417+
loop {
14181418
if (exp & 1) == 1 {
14191419
acc = try_opt!(acc.checked_mul(base));
1420+
// since exp!=0, finally the exp must be 1.
1421+
if exp == 1 {
1422+
return Some(acc);
1423+
}
14201424
}
14211425
exp /= 2;
14221426
base = try_opt!(base.checked_mul(base));
14231427
}
1424-
1425-
// since exp!=0, finally the exp must be 1.
1426-
// Deal with the final bit of the exponent separately, since
1427-
// squaring the base afterwards is not necessary and may cause a
1428-
// needless overflow.
1429-
1430-
acc.checked_mul(base)
14311428
}
14321429

14331430
/// Strict exponentiation. Computes `self.pow(exp)`, panicking if
@@ -1467,18 +1464,17 @@ macro_rules! uint_impl {
14671464
let mut base = self;
14681465
let mut acc: Self = 1;
14691466

1470-
while exp > 1 {
1467+
loop {
14711468
if (exp & 1) == 1 {
14721469
acc = acc.strict_mul(base);
1470+
// since exp!=0, finally the exp must be 1.
1471+
if exp == 1 {
1472+
return acc;
1473+
}
14731474
}
14741475
exp /= 2;
14751476
base = base.strict_mul(base);
14761477
}
1477-
// since exp!=0, finally the exp must be 1.
1478-
// Deal with the final bit of the exponent separately, since
1479-
// squaring the base afterwards is not necessary and may cause a
1480-
// needless overflow.
1481-
acc.strict_mul(base)
14821478
}
14831479

14841480
/// Saturating integer addition. Computes `self + rhs`, saturating at
@@ -1939,19 +1935,17 @@ macro_rules! uint_impl {
19391935
let mut base = self;
19401936
let mut acc: Self = 1;
19411937

1942-
while exp > 1 {
1938+
loop {
19431939
if (exp & 1) == 1 {
19441940
acc = acc.wrapping_mul(base);
1941+
// since exp!=0, finally the exp must be 1.
1942+
if exp == 1 {
1943+
return acc;
1944+
}
19451945
}
19461946
exp /= 2;
19471947
base = base.wrapping_mul(base);
19481948
}
1949-
1950-
// since exp!=0, finally the exp must be 1.
1951-
// Deal with the final bit of the exponent separately, since
1952-
// squaring the base afterwards is not necessary and may cause a
1953-
// needless overflow.
1954-
acc.wrapping_mul(base)
19551949
}
19561950

19571951
/// Calculates `self` + `rhs`
@@ -2396,9 +2390,14 @@ macro_rules! uint_impl {
23962390
// Scratch space for storing results of overflowing_mul.
23972391
let mut r;
23982392

2399-
while exp > 1 {
2393+
loop {
24002394
if (exp & 1) == 1 {
24012395
r = acc.overflowing_mul(base);
2396+
// since exp!=0, finally the exp must be 1.
2397+
if exp == 1 {
2398+
r.1 |= overflown;
2399+
return r;
2400+
}
24022401
acc = r.0;
24032402
overflown |= r.1;
24042403
}
@@ -2407,15 +2406,6 @@ macro_rules! uint_impl {
24072406
base = r.0;
24082407
overflown |= r.1;
24092408
}
2410-
2411-
// since exp!=0, finally the exp must be 1.
2412-
// Deal with the final bit of the exponent separately, since
2413-
// squaring the base afterwards is not necessary and may cause a
2414-
// needless overflow.
2415-
r = acc.overflowing_mul(base);
2416-
r.1 |= overflown;
2417-
2418-
r
24192409
}
24202410

24212411
/// Raises self to the power of `exp`, using exponentiation by squaring.
@@ -2440,19 +2430,17 @@ macro_rules! uint_impl {
24402430
let mut base = self;
24412431
let mut acc = 1;
24422432

2443-
while exp > 1 {
2433+
loop {
24442434
if (exp & 1) == 1 {
24452435
acc = acc * base;
2436+
// since exp!=0, finally the exp must be 1.
2437+
if exp == 1 {
2438+
return acc;
2439+
}
24462440
}
24472441
exp /= 2;
24482442
base = base * base;
24492443
}
2450-
2451-
// since exp!=0, finally the exp must be 1.
2452-
// Deal with the final bit of the exponent separately, since
2453-
// squaring the base afterwards is not necessary and may cause a
2454-
// needless overflow.
2455-
acc * base
24562444
}
24572445

24582446
/// Returns the square root of the number, rounded down.

0 commit comments

Comments
 (0)