about summary refs log tree commit diff
path: root/compiler/rustc_target
diff options
context:
space:
mode:
authorYuki Okushi <huyuumi.dev@gmail.com>2021-01-12 07:59:08 +0900
committerGitHub <noreply@github.com>2021-01-12 07:59:08 +0900
commit56504a00f2ea183653beb0a06393343c99cdf6e2 (patch)
tree039356279174b4cc8a439391c93563ec66d346cb /compiler/rustc_target
parentedcfe7b6296aff0cf5c52f0c8bc972b0b156616d (diff)
parent4721b6518ce9c8e3a452af07c6dd178fbb83ab16 (diff)
downloadrust-56504a00f2ea183653beb0a06393343c99cdf6e2.tar.gz
rust-56504a00f2ea183653beb0a06393343c99cdf6e2.zip
Rollup merge of #80042 - sivadeilra:cold_bits, r=oli-obk
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. Not much, but it's something.
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.
Diffstat (limited to 'compiler/rustc_target')
-rw-r--r--compiler/rustc_target/src/abi/mod.rs26
1 files changed, 20 insertions, 6 deletions
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index 61bfd58533a..93868bed9b9 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -271,22 +271,38 @@ impl ToJson for 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]
@@ -301,9 +317,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]