diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index ce30b3fae47ae..1f9c5a8eecad0 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1730,10 +1730,10 @@ mod size_asserts { use super::*; // tidy-alphabetical-start - static_assert_size!(BasicBlockData<'_>, 160); + static_assert_size!(BasicBlockData<'_>, 144); static_assert_size!(LocalDecl<'_>, 40); static_assert_size!(SourceScopeData<'_>, 64); - static_assert_size!(Statement<'_>, 56); + static_assert_size!(Statement<'_>, 40); static_assert_size!(Terminator<'_>, 104); static_assert_size!(VarDebugInfo<'_>, 88); // tidy-alphabetical-end diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index f25eaf3c6d32e..8e1479d284fd8 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -2,6 +2,7 @@ use std::ops; +use rustc_data_structures::outline; use tracing::{debug, instrument}; use super::interpret::GlobalAlloc; @@ -1034,66 +1035,107 @@ impl RawPtrKind { } } +// FIXME(panstromek) +// I'd like to use real ThinVec here, but it fails to borrow check, +// probably because ThinVec doesn't have #[may_dangle] on Drop impl? +type ThinVec = Option>>; + +// This collection is almost always empty, so we +// use thin representation and optimize all methods +// for that by inlining the empty check +// and outlining the rest. #[derive(Default, Debug, Clone, TyEncodable, TyDecodable, StableHash, TypeFoldable, TypeVisitable)] -pub struct StmtDebugInfos<'tcx>(Vec>); +pub struct StmtDebugInfos<'tcx>(ThinVec>); impl<'tcx> StmtDebugInfos<'tcx> { pub fn push(&mut self, debuginfo: StmtDebugInfo<'tcx>) { - self.0.push(debuginfo); + self.0.get_or_insert_default().push(debuginfo); } - + #[inline] pub fn drop_debuginfo(&mut self) { - self.0.clear(); + match &mut self.0 { + None => (), + Some(v) => outline(move || v.clear()), + } } + #[inline] pub fn is_empty(&self) -> bool { - self.0.is_empty() + match &self.0 { + None => true, + Some(v) => outline(move || v.is_empty()), + } } - + #[inline] pub fn prepend(&mut self, debuginfos: &mut Self) { if debuginfos.is_empty() { return; }; - debuginfos.0.append(self); - std::mem::swap(debuginfos, self); + outline(move || { + debuginfos.append(self); + std::mem::swap(debuginfos, self); + }) } - + #[inline] pub fn append(&mut self, debuginfos: &mut Self) { if debuginfos.is_empty() { return; }; - self.0.append(debuginfos); + outline(move || { + self.0.get_or_insert_default().append(debuginfos.0.as_mut().unwrap().as_mut()) + }); } - + #[inline] pub fn extend(&mut self, debuginfos: &Self) { if debuginfos.is_empty() { return; }; - self.0.extend_from_slice(debuginfos); + outline(move || self.0.get_or_insert_default().extend_from_slice(debuginfos.as_slice())) } + #[inline] + pub fn as_slice(&self) -> &[StmtDebugInfo<'tcx>] { + match &self.0 { + None => &[], + Some(items) => outline(move || items.as_slice()), + } + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [StmtDebugInfo<'tcx>] { + match &mut self.0 { + None => &mut [], + Some(items) => outline(move || items.as_mut_slice()), + } + } + #[inline] pub fn retain_locals(&mut self, locals: &DenseBitSet) { - self.retain(|debuginfo| match debuginfo { - StmtDebugInfo::AssignRef(local, _) | StmtDebugInfo::InvalidAssign(local) => { - locals.contains(*local) - } - }); + match &mut self.0 { + None => (), + Some(items) => outline(move || { + items.retain(|debuginfo| match debuginfo { + StmtDebugInfo::AssignRef(local, _) | StmtDebugInfo::InvalidAssign(local) => { + locals.contains(*local) + } + }) + }), + } } } impl<'tcx> ops::Deref for StmtDebugInfos<'tcx> { - type Target = Vec>; + type Target = [StmtDebugInfo<'tcx>]; #[inline] - fn deref(&self) -> &Vec> { - &self.0 + fn deref(&self) -> &Self::Target { + self.as_slice() } } impl<'tcx> ops::DerefMut for StmtDebugInfos<'tcx> { #[inline] - fn deref_mut(&mut self) -> &mut Vec> { - &mut self.0 + fn deref_mut(&mut self) -> &mut Self::Target { + self.as_mut_slice() } }