Skip to content

Commit 12b5d3c

Browse files
committed
Auto merge of #124294 - tspiteri:ilog-first-iter, r=the8472
Unroll first iteration of checked_ilog loop This follows the optimization of #115913. As shown in #115913 (comment), the performance was improved in all important cases, but some regressions were introduced for the benchmarks `u32_log_random_small`, `u8_log_random` and `u8_log_random_small`. Basically, #115913 changed the implementation from one division per iteration to one multiplication per iteration plus one division. When there are zero iterations, this is a regression from zero divisions to one division. This PR avoids this by avoiding the division if we need zero iterations by returning `Some(0)` early. It also reduces the number of multiplications by one in all other cases.
2 parents f67a1ac + 245cc23 commit 12b5d3c

File tree

2 files changed

+25
-2
lines changed

2 files changed

+25
-2
lines changed

library/core/src/num/uint_macros.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -1148,9 +1148,12 @@ macro_rules! uint_impl {
11481148
pub const fn checked_ilog(self, base: Self) -> Option<u32> {
11491149
if self <= 0 || base <= 1 {
11501150
None
1151+
} else if self < base {
1152+
Some(0)
11511153
} else {
1152-
let mut n = 0;
1153-
let mut r = 1;
1154+
// Since base >= self, n >= 1
1155+
let mut n = 1;
1156+
let mut r = base;
11541157

11551158
// Optimization for 128 bit wide integers.
11561159
if Self::BITS == 128 {

tests/codegen/checked_ilog.rs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//@ compile-flags: -O
2+
3+
#![crate_type = "lib"]
4+
5+
// Ensure that when val < base, we do not divide or multiply.
6+
7+
// CHECK-LABEL: @checked_ilog
8+
// CHECK-SAME: (i16 noundef %val, i16 noundef %base)
9+
#[no_mangle]
10+
pub fn checked_ilog(val: u16, base: u16) -> Option<u32> {
11+
// CHECK-NOT: udiv
12+
// CHECK-NOT: mul
13+
// CHECK: %[[IS_LESS:.+]] = icmp ult i16 %val, %base
14+
// CHECK-NEXT: br i1 %[[IS_LESS]], label %[[TRUE:.+]], label %[[FALSE:.+]]
15+
// CHECK: [[TRUE]]:
16+
// CHECK-NOT: udiv
17+
// CHECK-NOT: mul
18+
// CHECK: ret { i32, i32 }
19+
val.checked_ilog(base)
20+
}

0 commit comments

Comments
 (0)