Skip to content

Commit 4721b65

Browse files
committed
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.
1 parent 3b63e16 commit 4721b65

File tree

1 file changed

+20
-6
lines changed
  • compiler/rustc_target/src/abi

1 file changed

+20
-6
lines changed

compiler/rustc_target/src/abi/mod.rs

+20-6
Original file line numberDiff line numberDiff line change
@@ -238,22 +238,38 @@ pub enum Endian {
238238
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)]
239239
#[derive(HashStable_Generic)]
240240
pub struct Size {
241+
// The top 3 bits are ALWAYS zero.
241242
raw: u64,
242243
}
243244

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

247-
#[inline]
248+
/// Rounds `bits` up to the next-higher byte boundary, if `bits` is
249+
/// is not aligned.
248250
pub fn from_bits(bits: impl TryInto<u64>) -> Size {
249251
let bits = bits.try_into().ok().unwrap();
252+
253+
#[cold]
254+
fn overflow(bits: u64) -> ! {
255+
panic!("Size::from_bits({}) has overflowed", bits);
256+
}
257+
258+
// This is the largest value of `bits` that does not cause overflow
259+
// during rounding, and guarantees that the resulting number of bytes
260+
// cannot cause overflow when multiplied by 8.
261+
if bits > 0xffff_ffff_ffff_fff8 {
262+
overflow(bits);
263+
}
264+
250265
// Avoid potential overflow from `bits + 7`.
251-
Size::from_bytes(bits / 8 + ((bits % 8) + 7) / 8)
266+
Size { raw: bits / 8 + ((bits % 8) + 7) / 8 }
252267
}
253268

254269
#[inline]
255270
pub fn from_bytes(bytes: impl TryInto<u64>) -> Size {
256-
Size { raw: bytes.try_into().ok().unwrap() }
271+
let bytes: u64 = bytes.try_into().ok().unwrap();
272+
Size { raw: bytes }
257273
}
258274

259275
#[inline]
@@ -268,9 +284,7 @@ impl Size {
268284

269285
#[inline]
270286
pub fn bits(self) -> u64 {
271-
self.bytes().checked_mul(8).unwrap_or_else(|| {
272-
panic!("Size::bits: {} bytes in bits doesn't fit in u64", self.bytes())
273-
})
287+
self.raw << 3
274288
}
275289

276290
#[inline]

0 commit comments

Comments
 (0)