From 4721b6518ce9c8e3a452af07c6dd178fbb83ab16 Mon Sep 17 00:00:00 2001 From: Arlie Davis Date: Mon, 14 Dec 2020 15:45:19 -0800 Subject: [PATCH] Split a func into cold/hot parts, reducing binary size 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. --- compiler/rustc_target/src/abi/mod.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index a43080b09e9a1..31ceb0a389076 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -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) -> 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) -> Size { - Size { raw: bytes.try_into().ok().unwrap() } + let bytes: u64 = bytes.try_into().ok().unwrap(); + Size { raw: bytes } } #[inline] @@ -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]