Auto merge of #82562 - llogiq:one-up-82248, r=oli-obk
Optimize counting digits in line numbers during error reporting further This one-ups #82248 by switching the strategy: Instead of dividing the value by 10 repeatedly, we compare with a limit that we multiply by 10 repeatedly. In my benchmarks, this took between 50% and 25% of the original time. The reasons for being faster are: 1. While LLVM is able to replace a division by constant with a multiply + shift, a plain multiplication is still faster. However, this doesn't even factor, because 2. Multiplication, unlike division, is const. We also use a simple for-loop instead of a more complex loop + break, which allows 3. rustc to const-fold the whole loop, and indeed the assembly output simply shows a series of comparisons.
This commit is contained in:
commit
35dbef2350
|
@ -1713,18 +1713,8 @@ impl EmitterWriter {
|
|||
let max_line_num_len = if self.ui_testing {
|
||||
ANONYMIZED_LINE_NUM.len()
|
||||
} else {
|
||||
// Instead of using .to_string().len(), we iteratively count the
|
||||
// number of digits to avoid allocation. This strategy has sizable
|
||||
// performance gains over the old string strategy.
|
||||
let mut n = self.get_max_line_num(span, children);
|
||||
let mut num_digits = 0;
|
||||
loop {
|
||||
num_digits += 1;
|
||||
n /= 10;
|
||||
if n == 0 {
|
||||
break num_digits;
|
||||
}
|
||||
}
|
||||
let n = self.get_max_line_num(span, children);
|
||||
num_decimal_digits(n)
|
||||
};
|
||||
|
||||
match self.emit_message_default(span, message, code, level, max_line_num_len, false) {
|
||||
|
@ -1952,6 +1942,30 @@ impl FileWithAnnotatedLines {
|
|||
}
|
||||
}
|
||||
|
||||
// instead of taking the String length or dividing by 10 while > 0, we multiply a limit by 10 until
|
||||
// we're higher. If the loop isn't exited by the `return`, the last multiplication will wrap, which
|
||||
// is OK, because while we cannot fit a higher power of 10 in a usize, the loop will end anyway.
|
||||
// This is also why we need the max number of decimal digits within a `usize`.
|
||||
fn num_decimal_digits(num: usize) -> usize {
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
const MAX_DIGITS: usize = 20;
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
const MAX_DIGITS: usize = 10;
|
||||
|
||||
#[cfg(target_pointer_width = "16")]
|
||||
const MAX_DIGITS: usize = 5;
|
||||
|
||||
let mut lim = 10;
|
||||
for num_digits in 1..MAX_DIGITS {
|
||||
if num < lim {
|
||||
return num_digits;
|
||||
}
|
||||
lim = lim.wrapping_mul(10);
|
||||
}
|
||||
MAX_DIGITS
|
||||
}
|
||||
|
||||
fn replace_tabs(str: &str) -> String {
|
||||
str.replace('\t', " ")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue