Skip to content

Commit

Permalink
Split a func into cold/hot parts, reducing binary size
Browse files Browse the repository at this point in the history
I noticed that the Size::bits function is called in many places,
and is inlined into them. On x86_64-pc-windows-msvc, this function
is inlined 527 times, and compiled separately (non-inlined) 3 times.

Each of those inlined calls contains code that panics. This commit
moves the `panic!` call into a separate function and marks that
function with `#[cold]`.

This reduces binary size by 24 KB. By itself, that's not a substantial
reduction. However, changes like this often reduce pressure on
instruction-caches, since it reduces the amount of code that is inlined
into hot code paths. Or more precisely, it removes cold code from hot
cache lines. It also removes all conditionals from Size::bits(),
which is called in many places.
  • Loading branch information
Arlie Davis committed Jan 5, 2021
1 parent 3b63e16 commit 4721b65
Showing 1 changed file with 20 additions and 6 deletions.
26 changes: 20 additions & 6 deletions compiler/rustc_target/src/abi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,22 +238,38 @@ pub enum Endian {
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)]
#[derive(HashStable_Generic)]
pub struct Size {
// The top 3 bits are ALWAYS zero.
raw: u64,
}

impl Size {
pub const ZERO: Size = Size { raw: 0 };

#[inline]
/// Rounds `bits` up to the next-higher byte boundary, if `bits` is
/// is not aligned.
pub fn from_bits(bits: impl TryInto<u64>) -> Size {
let bits = bits.try_into().ok().unwrap();

#[cold]
fn overflow(bits: u64) -> ! {
panic!("Size::from_bits({}) has overflowed", bits);
}

// This is the largest value of `bits` that does not cause overflow
// during rounding, and guarantees that the resulting number of bytes
// cannot cause overflow when multiplied by 8.
if bits > 0xffff_ffff_ffff_fff8 {
overflow(bits);
}

// Avoid potential overflow from `bits + 7`.
Size::from_bytes(bits / 8 + ((bits % 8) + 7) / 8)
Size { raw: bits / 8 + ((bits % 8) + 7) / 8 }
}

#[inline]
pub fn from_bytes(bytes: impl TryInto<u64>) -> Size {
Size { raw: bytes.try_into().ok().unwrap() }
let bytes: u64 = bytes.try_into().ok().unwrap();
Size { raw: bytes }
}

#[inline]
Expand All @@ -268,9 +284,7 @@ impl Size {

#[inline]
pub fn bits(self) -> u64 {
self.bytes().checked_mul(8).unwrap_or_else(|| {
panic!("Size::bits: {} bytes in bits doesn't fit in u64", self.bytes())
})
self.raw << 3
}

#[inline]
Expand Down

0 comments on commit 4721b65

Please sign in to comment.