From 69f33e52b70e44d20ff8a91f62b38d2102885da4 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 2 Apr 2023 17:35:34 -0400 Subject: [PATCH 1/2] Optimize integer decoding a bit --- compiler/rustc_serialize/src/leb128.rs | 45 +++++++++++++++----------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_serialize/src/leb128.rs b/compiler/rustc_serialize/src/leb128.rs index 7dad9aa01fafd..9841edca012cf 100644 --- a/compiler/rustc_serialize/src/leb128.rs +++ b/compiler/rustc_serialize/src/leb128.rs @@ -51,28 +51,35 @@ macro_rules! impl_read_unsigned_leb128 { ($fn_name:ident, $int_ty:ty) => { #[inline] pub fn $fn_name(slice: &[u8], position: &mut usize) -> $int_ty { - // The first iteration of this loop is unpeeled. This is a - // performance win because this code is hot and integer values less - // than 128 are very common, typically occurring 50-80% or more of - // the time, even for u64 and u128. - let byte = slice[*position]; - *position += 1; - if (byte & 0x80) == 0 { - return byte as $int_ty; - } - let mut result = (byte & 0x7F) as $int_ty; - let mut shift = 7; - loop { - let byte = slice[*position]; - *position += 1; + #[inline] + fn inner(slice: &[u8], position: &mut usize) -> Option<$int_ty> { + let mut pos = *position; + // The first iteration of this loop is unpeeled. This is a + // performance win because this code is hot and integer values less + // than 128 are very common, typically occurring 50-80% or more of + // the time, even for u64 and u128. + let byte = *slice.get(pos)?; + pos += 1; if (byte & 0x80) == 0 { - result |= (byte as $int_ty) << shift; - return result; - } else { - result |= ((byte & 0x7F) as $int_ty) << shift; + *position = pos; + return Some(byte as $int_ty); + } + let mut result = (byte & 0x7F) as $int_ty; + let mut shift = 7; + loop { + let byte = *slice.get(pos)?; + pos += 1; + if (byte & 0x80) == 0 { + result |= (byte as $int_ty) << shift; + *position = pos; + return Some(result); + } else { + result |= ((byte & 0x7F) as $int_ty) << shift; + } + shift += 7; } - shift += 7; } + inner(slice, position).unwrap() } }; } From d8877cdeeee9b8c4446bd4e981e28df94ebaa3f3 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 3 Apr 2023 20:12:24 -0400 Subject: [PATCH 2/2] Peel the first two iterations, outline the rest --- compiler/rustc_serialize/src/leb128.rs | 51 +++++++++++++++----------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_serialize/src/leb128.rs b/compiler/rustc_serialize/src/leb128.rs index 9841edca012cf..4adab50344df0 100644 --- a/compiler/rustc_serialize/src/leb128.rs +++ b/compiler/rustc_serialize/src/leb128.rs @@ -51,35 +51,42 @@ macro_rules! impl_read_unsigned_leb128 { ($fn_name:ident, $int_ty:ty) => { #[inline] pub fn $fn_name(slice: &[u8], position: &mut usize) -> $int_ty { + #[inline(never)] + fn slow_path(slice: &[u8], position: &mut usize) -> Option<$int_ty> { + let mut result = 0; + let mut shift = 0; + for consumed in 0..20 { + let byte = slice[*position + consumed]; + result |= ((byte & 0x7F) as $int_ty) << shift; + if (byte & 0x80) == 0 { + *position += consumed + 1; + return Some(result); + } + shift += 7; + } + None + } + #[inline] - fn inner(slice: &[u8], position: &mut usize) -> Option<$int_ty> { - let mut pos = *position; + fn fast_path(slice: &[u8], position: &mut usize) -> Option<$int_ty> { + let pos = *position; // The first iteration of this loop is unpeeled. This is a // performance win because this code is hot and integer values less // than 128 are very common, typically occurring 50-80% or more of // the time, even for u64 and u128. - let byte = *slice.get(pos)?; - pos += 1; - if (byte & 0x80) == 0 { - *position = pos; - return Some(byte as $int_ty); - } - let mut result = (byte & 0x7F) as $int_ty; - let mut shift = 7; - loop { - let byte = *slice.get(pos)?; - pos += 1; - if (byte & 0x80) == 0 { - result |= (byte as $int_ty) << shift; - *position = pos; - return Some(result); - } else { - result |= ((byte & 0x7F) as $int_ty) << shift; - } - shift += 7; + if *slice.get(pos)? & 0x80 == 0 { + *position += 1; + Some(slice[pos] as $int_ty) + } else if *slice.get(pos + 1)? & 0x80 == 0 { + *position += 2; + Some(((slice[pos] & 0x7F) as $int_ty) | (slice[pos + 1] as $int_ty << 7)) + + } else { + slow_path(slice, position) } } - inner(slice, position).unwrap() + + fast_path(slice, position).unwrap() } }; }