Rollup merge of #125606 - diondokter:opt-size-int-fmt, r=cuviper
Size optimize int formatting Let's use the new feature flag! This uses a simpler algorithm to format integers. It is slower, but also smaller. It also saves having to import the 200 byte rodata lookup table. In a test of mine this saves ~300 bytes total of a cortex-m binary that does integer formatting. For a 16KB device, that's almost 2%. Note though that for opt-level 3 the text size actually grows by 116 bytes. Still a win in total. I'm not sure why the generated code is bigger than the more fancy algo. Maybe the smaller algo lends itself more to inlining and duplicating?
This commit is contained in:
commit
c6cdd457eb
@ -212,6 +212,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
||||
macro_rules! impl_Display {
|
||||
($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => {
|
||||
#[cfg(not(feature = "optimize_for_size"))]
|
||||
fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// 2^128 is about 3*10^38, so 39 gives an extra byte of space
|
||||
let mut buf = [MaybeUninit::<u8>::uninit(); 39];
|
||||
@ -277,6 +278,38 @@ fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Re
|
||||
f.pad_integral(is_nonnegative, "", buf_slice)
|
||||
}
|
||||
|
||||
#[cfg(feature = "optimize_for_size")]
|
||||
fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// 2^128 is about 3*10^38, so 39 gives an extra byte of space
|
||||
let mut buf = [MaybeUninit::<u8>::uninit(); 39];
|
||||
let mut curr = buf.len();
|
||||
let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
|
||||
|
||||
// SAFETY: To show that it's OK to copy into `buf_ptr`, notice that at the beginning
|
||||
// `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at
|
||||
// each step this is kept the same as `n` is divided. Since `n` is always
|
||||
// non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]`
|
||||
// is safe to access.
|
||||
unsafe {
|
||||
loop {
|
||||
curr -= 1;
|
||||
buf_ptr.add(curr).write((n % 10) as u8 + b'0');
|
||||
n /= 10;
|
||||
|
||||
if n == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid UTF-8
|
||||
let buf_slice = unsafe {
|
||||
str::from_utf8_unchecked(
|
||||
slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr))
|
||||
};
|
||||
f.pad_integral(is_nonnegative, "", buf_slice)
|
||||
}
|
||||
|
||||
$(#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl fmt::Display for $t {
|
||||
#[allow(unused_comparisons)]
|
||||
|
Loading…
Reference in New Issue
Block a user