Skip to content

Commit 76d2530

Browse files
committed
Optimize integer pow by removing 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 instruction cache coherence.
1 parent eb80be2 commit 76d2530

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
@@ -1416,18 +1416,17 @@ macro_rules! int_impl {
14161416
let mut base = self;
14171417
let mut acc: Self = 1;
14181418

1419-
while exp > 1 {
1419+
loop {
14201420
if (exp & 1) == 1 {
14211421
acc = try_opt!(acc.checked_mul(base));
1422+
// since exp!=0, finally the exp must be 1.
1423+
if exp == 1 {
1424+
return Some(acc);
1425+
}
14221426
}
14231427
exp /= 2;
14241428
base = try_opt!(base.checked_mul(base));
14251429
}
1426-
// since exp!=0, finally the exp must be 1.
1427-
// Deal with the final bit of the exponent separately, since
1428-
// squaring the base afterwards is not necessary and may cause a
1429-
// needless overflow.
1430-
acc.checked_mul(base)
14311430
}
14321431

14331432
/// Strict exponentiation. Computes `self.pow(exp)`, panicking if
@@ -1467,18 +1466,17 @@ macro_rules! int_impl {
14671466
let mut base = self;
14681467
let mut acc: Self = 1;
14691468

1470-
while exp > 1 {
1469+
loop {
14711470
if (exp & 1) == 1 {
14721471
acc = acc.strict_mul(base);
1472+
// since exp!=0, finally the exp must be 1.
1473+
if exp == 1 {
1474+
return acc;
1475+
}
14731476
}
14741477
exp /= 2;
14751478
base = base.strict_mul(base);
14761479
}
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)
14821480
}
14831481

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

2105-
while exp > 1 {
2103+
loop {
21062104
if (exp & 1) == 1 {
21072105
acc = acc.wrapping_mul(base);
2106+
// since exp!=0, finally the exp must be 1.
2107+
if exp == 1 {
2108+
return acc;
2109+
}
21082110
}
21092111
exp /= 2;
21102112
base = base.wrapping_mul(base);
21112113
}
2112-
2113-
// since exp!=0, finally the exp must be 1.
2114-
// Deal with the final bit of the exponent separately, since
2115-
// squaring the base afterwards is not necessary and may cause a
2116-
// needless overflow.
2117-
acc.wrapping_mul(base)
21182114
}
21192115

21202116
/// Calculates `self` + `rhs`
@@ -2608,9 +2604,14 @@ macro_rules! int_impl {
26082604
// Scratch space for storing results of overflowing_mul.
26092605
let mut r;
26102606

2611-
while exp > 1 {
2607+
loop {
26122608
if (exp & 1) == 1 {
26132609
r = acc.overflowing_mul(base);
2610+
// since exp!=0, finally the exp must be 1.
2611+
if exp == 1 {
2612+
r.1 |= overflown;
2613+
return r;
2614+
}
26142615
acc = r.0;
26152616
overflown |= r.1;
26162617
}
@@ -2619,14 +2620,6 @@ macro_rules! int_impl {
26192620
base = r.0;
26202621
overflown |= r.1;
26212622
}
2622-
2623-
// since exp!=0, finally the exp must be 1.
2624-
// Deal with the final bit of the exponent separately, since
2625-
// squaring the base afterwards is not necessary and may cause a
2626-
// needless overflow.
2627-
r = acc.overflowing_mul(base);
2628-
r.1 |= overflown;
2629-
r
26302623
}
26312624

26322625
/// Raises self to the power of `exp`, using exponentiation by squaring.
@@ -2653,19 +2646,17 @@ macro_rules! int_impl {
26532646
let mut base = self;
26542647
let mut acc = 1;
26552648

2656-
while exp > 1 {
2649+
loop {
26572650
if (exp & 1) == 1 {
26582651
acc = acc * base;
2652+
// since exp!=0, finally the exp must be 1.
2653+
if exp == 1 {
2654+
return acc;
2655+
}
26592656
}
26602657
exp /= 2;
26612658
base = base * base;
26622659
}
2663-
2664-
// since exp!=0, finally the exp must be 1.
2665-
// Deal with the final bit of the exponent separately, since
2666-
// squaring the base afterwards is not necessary and may cause a
2667-
// needless overflow.
2668-
acc * base
26692660
}
26702661

26712662
/// 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
@@ -1413,20 +1413,17 @@ macro_rules! uint_impl {
14131413
let mut base = self;
14141414
let mut acc: Self = 1;
14151415

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

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

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

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

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

19561950
/// Calculates `self` + `rhs`
@@ -2395,9 +2389,14 @@ macro_rules! uint_impl {
23952389
// Scratch space for storing results of overflowing_mul.
23962390
let mut r;
23972391

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

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

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

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

0 commit comments

Comments
 (0)