From 29f1d95077dce09bea2ea46ed4919dd76f18db6e Mon Sep 17 00:00:00 2001 From: panstromek Date: Fri, 12 Jun 2026 09:06:32 +0200 Subject: [PATCH 01/27] wip: try to shrink IndexVec to 16 bytes when possible --- compiler/rustc_abi/src/layout/coroutine.rs | 4 +- compiler/rustc_data_structures/src/marker.rs | 2 + compiler/rustc_hir_id/src/lib.rs | 3 + compiler/rustc_index/src/lib.rs | 1 + compiler/rustc_index/src/slice.rs | 5 +- compiler/rustc_index/src/vec.rs | 97 ++++++++++++------- compiler/rustc_middle/src/hir/mod.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 4 +- .../src/cleanup_post_borrowck.rs | 2 +- compiler/rustc_mir_transform/src/gvn.rs | 2 +- .../src/impossible_predicates.rs | 4 +- compiler/rustc_mir_transform/src/inline.rs | 2 +- compiler/rustc_mir_transform/src/simplify.rs | 4 +- compiler/rustc_mir_transform/src/validate.rs | 4 +- compiler/rustc_type_ir/src/fold.rs | 4 +- 15 files changed, 87 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_abi/src/layout/coroutine.rs b/compiler/rustc_abi/src/layout/coroutine.rs index fd68d06c93829..151abb21e04e5 100644 --- a/compiler/rustc_abi/src/layout/coroutine.rs +++ b/compiler/rustc_abi/src/layout/coroutine.rs @@ -186,7 +186,7 @@ pub(super) fn layout< // "a" (`0..b_start`) and "b" (`b_start..`) correspond to // "outer" and "promoted" fields respectively. let b_start = tag_index.plus(1); - let offsets_b = IndexVec::from_raw(offsets.raw.split_off(b_start.index())); + let offsets_b = IndexVec::from_raw(offsets.mutate(|raw| raw.split_off(b_start.index()))); let offsets_a = offsets; // Disentangle the "a" and "b" components of `in_memory_order` @@ -271,7 +271,7 @@ pub(super) fn layout< // Remove the unused slots to obtain the combined `in_memory_order` // (also see previous comment). - combined_in_memory_order.raw.retain(|&i| i.index() != invalid_field_idx); + combined_in_memory_order.mutate(|raw| raw.retain(|&i| i.index() != invalid_field_idx)); variant.fields = FieldsShape::Arbitrary { offsets: combined_offsets, diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index 2fe2a30c36751..31c854fdcc23c 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -95,6 +95,7 @@ impl_dyn_send!( [indexmap::IndexSet where V: DynSend, S: DynSend] [indexmap::IndexMap where K: DynSend, V: DynSend, S: DynSend] [thin_vec::ThinVec where T: DynSend] + [rustc_index::IndexVec where I: rustc_index::Idx, T: DynSend] [smallvec::SmallVec where A: smallvec::Array + DynSend] ); @@ -182,6 +183,7 @@ impl_dyn_sync!( [indexmap::IndexMap where K: DynSync, V: DynSync, S: DynSync] [smallvec::SmallVec where A: smallvec::Array + DynSync] [thin_vec::ThinVec where T: DynSync] + [rustc_index::IndexVec where I: rustc_index::Idx, T: DynSync] ); pub fn assert_dyn_sync() {} diff --git a/compiler/rustc_hir_id/src/lib.rs b/compiler/rustc_hir_id/src/lib.rs index 07b1cceebaf76..f0b00179f5073 100644 --- a/compiler/rustc_hir_id/src/lib.rs +++ b/compiler/rustc_hir_id/src/lib.rs @@ -9,6 +9,7 @@ use std::fmt::{self, Debug}; use rustc_data_structures::stable_hash::{ StableHash, StableHashCtxt, StableHasher, StableOrd, ToStableHashKey, }; +use rustc_index::static_assert_size; use rustc_macros::{Decodable, Encodable, StableHash}; use rustc_span::def_id::{CRATE_DEF_ID, DefId, DefIndex, DefPathHash, LocalDefId}; @@ -158,6 +159,8 @@ rustc_index::newtype_index! { pub struct ItemLocalId {} } +static_assert_size!(rustc_index::IndexVec, 16); + impl ItemLocalId { /// Signal local id which should never be used. pub const INVALID: ItemLocalId = ItemLocalId::MAX; diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index c84b06769e081..2b59ff33a5829 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -2,6 +2,7 @@ #![cfg_attr(all(feature = "nightly", test), feature(stmt_expr_attributes))] #![cfg_attr(all(feature = "nightly", test), feature(test))] #![cfg_attr(feature = "nightly", feature(extend_one, step_trait))] +#![cfg_attr(feature = "nightly", feature(dropck_eyepatch))] // tidy-alphabetical-end pub mod bit_set; diff --git a/compiler/rustc_index/src/slice.rs b/compiler/rustc_index/src/slice.rs index 415fe370b702c..a5c9da386fee5 100644 --- a/compiler/rustc_index/src/slice.rs +++ b/compiler/rustc_index/src/slice.rs @@ -254,7 +254,10 @@ impl ToOwned for IndexSlice { } fn clone_into(&self, target: &mut IndexVec) { - self.raw.clone_into(&mut target.raw) + target.mutate(|v| { + // todo this coerces to a slice now, is that correct? + self.raw.clone_into(v) + }); } } diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 13f0dda180be9..c312ff8918c86 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -3,11 +3,11 @@ use std::hash::Hash; use std::marker::PhantomData; use std::ops::{Deref, DerefMut, RangeBounds}; use std::{fmt, slice, vec}; - +use std::mem::ManuallyDrop; #[cfg(feature = "nightly")] use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; -use crate::{Idx, IndexSlice}; +use crate::{static_assert_size, Idx, IndexSlice}; /// An owned contiguous collection of `T`s, indexed by `I` rather than by `usize`. /// @@ -36,23 +36,47 @@ use crate::{Idx, IndexSlice}; /// /// [`newtype_index!`]: ../macro.newtype_index.html #[derive(Clone, PartialEq, Eq, Hash)] -#[repr(transparent)] pub struct IndexVec { - pub raw: Vec, + data: *mut T, + len: I, + capacity: I, + _marker: PhantomData, + _marker2: PhantomData, +} + +unsafe impl Drop for IndexVec { + fn drop(&mut self) { + std::mem::take(self).into_vec(); + } } impl IndexVec { /// Constructs a new, empty `IndexVec`. #[inline] - pub const fn new() -> Self { + pub fn new() -> Self { IndexVec::from_raw(Vec::new()) } /// Constructs a new `IndexVec` from a `Vec`. #[inline] - pub const fn from_raw(raw: Vec) -> Self { - IndexVec { raw, _marker: PhantomData } + pub fn from_raw(raw: Vec) -> Self { + let (data, len, capacity) = raw.into_raw_parts(); + + IndexVec { + data, + len: I::new(len), + capacity: I::new(capacity), + + _marker: PhantomData, + _marker2: PhantomData, + } + } + + pub fn into_vec(self) -> Vec { + let me = ManuallyDrop::new(self); + // fixme this is unsound because we rely on correct Idx trait impls + unsafe { Vec::from_raw_parts(me.data, me.len.index(), me.capacity.index()) } } #[inline] @@ -100,30 +124,30 @@ impl IndexVec { #[inline] pub fn as_slice(&self) -> &IndexSlice { - IndexSlice::from_raw(&self.raw) + IndexSlice::from_raw(unsafe { std::slice::from_raw_parts(self.data, self.len.index()) }) } #[inline] pub fn as_mut_slice(&mut self) -> &mut IndexSlice { - IndexSlice::from_raw_mut(&mut self.raw) + IndexSlice::from_raw_mut(unsafe { std::slice::from_raw_parts_mut(self.data, self.len.index()) }) } /// Pushes an element to the array returning the index where it was pushed to. #[inline] pub fn push(&mut self, d: T) -> I { let idx = self.next_index(); - self.raw.push(d); + self.mutate(|vec| vec.push(d)); idx } #[inline] pub fn pop(&mut self) -> Option { - self.raw.pop() + self.mutate(|raw| raw.pop()) } #[inline] pub fn into_iter(self) -> vec::IntoIter { - self.raw.into_iter() + self.into_vec().into_iter() } #[inline] @@ -132,35 +156,29 @@ impl IndexVec { ) -> impl DoubleEndedIterator + ExactSizeIterator { // Allow the optimizer to elide the bounds checking when creating each index. let _ = I::new(self.len()); - self.raw.into_iter().enumerate().map(|(n, t)| (I::new(n), t)) + self.into_iter().enumerate().map(|(n, t)| (I::new(n), t)) } #[inline] - pub fn drain>(&mut self, range: R) -> impl Iterator { - self.raw.drain(range) + pub fn drain_into>(&mut self, range: R, target: &mut IndexVec) { + self.mutate(|raw| target.extend(raw.drain(range))) } - #[inline] - pub fn drain_enumerated>( - &mut self, - range: R, - ) -> impl Iterator { - let begin = match range.start_bound() { - std::ops::Bound::Included(i) => *i, - std::ops::Bound::Excluded(i) => i.checked_add(1).unwrap(), - std::ops::Bound::Unbounded => 0, - }; - self.raw.drain(range).enumerate().map(move |(n, t)| (I::new(begin + n), t)) + pub fn mutate) -> U>(&mut self, f: F) -> U { + let mut vec = std::mem::take(self).into_vec(); + let v = f(&mut vec); + let _ = std::mem::replace(self, IndexVec::from_raw(vec)); + v } #[inline] pub fn shrink_to_fit(&mut self) { - self.raw.shrink_to_fit() + self.mutate(|vec| vec.shrink_to_fit()); } #[inline] pub fn truncate(&mut self, a: usize) { - self.raw.truncate(a) + self.mutate(|vec| vec.truncate(a)) } /// Grows the index vector so that it contains an entry for @@ -173,7 +191,7 @@ impl IndexVec { pub fn ensure_contains_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) -> &mut T { let min_new_len = elem.index() + 1; if self.len() < min_new_len { - self.raw.resize_with(min_new_len, fill_value); + self.mutate(|vec| vec.resize_with(min_new_len, fill_value)); } &mut self[elem] @@ -184,18 +202,22 @@ impl IndexVec { where T: Clone, { - self.raw.resize(new_len, value) + self.mutate(|vec| vec.resize(new_len, value)) } #[inline] pub fn resize_to_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) { let min_new_len = elem.index() + 1; - self.raw.resize_with(min_new_len, fill_value); + self.mutate(|vec| vec.resize_with(min_new_len, fill_value)); } #[inline] pub fn append(&mut self, other: &mut Self) { - self.raw.append(&mut other.raw); + self.mutate(|vec| { + other.mutate(|other| { + vec.append(other) + }) + }); } } @@ -259,19 +281,19 @@ impl BorrowMut> for IndexVec { impl Extend for IndexVec { #[inline] fn extend>(&mut self, iter: J) { - self.raw.extend(iter); + self.mutate(|vec| vec.extend(iter)); } #[inline] #[cfg(feature = "nightly")] fn extend_one(&mut self, item: T) { - self.raw.push(item); + self.mutate(|vec| vec.push(item)); } #[inline] #[cfg(feature = "nightly")] fn extend_reserve(&mut self, additional: usize) { - self.raw.reserve(additional); + self.mutate(|vec| vec.reserve(additional)); } } @@ -291,7 +313,7 @@ impl IntoIterator for IndexVec { #[inline] fn into_iter(self) -> vec::IntoIter { - self.raw.into_iter() + self.into_vec().into_iter() } } @@ -347,5 +369,8 @@ impl> Decodable for IndexVec { // not the phantom data. unsafe impl Send for IndexVec where T: Send {} +static_assert_size!(IndexVec, 16); +static_assert_size!(IndexVec, 24); + #[cfg(test)] mod tests; diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index e0c1482af72ba..92e104c8b275e 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -444,7 +444,7 @@ impl<'tcx> ProjectedMaybeOwner<'tcx> { } } - pub fn unwrap(&'tcx self) -> &'tcx ProjectedOwnerInfo<'tcx> { + pub fn unwrap<'a>(&'a self) -> &'a ProjectedOwnerInfo<'tcx> { self.as_owner().unwrap_or_else(|| panic!("Not a HIR owner")) } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 1d809a2c84ca0..4874cc777d5a5 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -505,8 +505,8 @@ impl<'tcx> Body<'tcx> { } #[inline] - pub fn drain_vars_and_temps(&mut self) -> impl Iterator> { - self.local_decls.drain(self.arg_count + 1..) + pub fn drain_vars_and_temps_into(&mut self, target: &mut IndexVec>) { + self.local_decls.drain_into(self.arg_count + 1.., target) } /// Returns the source info associated with `location`. diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs index 1f2ce9e5dc10d..440a9c991c9f2 100644 --- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs +++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs @@ -78,7 +78,7 @@ impl<'tcx> crate::MirPass<'tcx> for CleanupPostBorrowck { body.basic_blocks.invalidate_cfg_cache(); } - body.user_type_annotations.raw.clear(); + body.user_type_annotations.mutate(|raw| raw.clear()); for decl in &mut body.local_decls { decl.user_ty = None; diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index b30d2bd135546..bf8366e528425 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1831,7 +1831,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { } else if let ty::Adt(adt, args) = ty.kind() && adt.is_struct() && adt.repr().transparent() - && let [single_field] = adt.non_enum_variant().fields.raw.as_slice() + && let [single_field] = &adt.non_enum_variant().fields.as_slice().raw { Some((FieldIdx::ZERO, single_field.ty(self.tcx, args).skip_norm_wip())) } else { diff --git a/compiler/rustc_mir_transform/src/impossible_predicates.rs b/compiler/rustc_mir_transform/src/impossible_predicates.rs index cc216c39b8599..1e9fc5be8ecdb 100644 --- a/compiler/rustc_mir_transform/src/impossible_predicates.rs +++ b/compiler/rustc_mir_transform/src/impossible_predicates.rs @@ -63,11 +63,11 @@ impl<'tcx> MirPass<'tcx> for ImpossiblePredicates { trace!("found unsatisfiable predicates"); // Clear the body to only contain a single `unreachable` statement. let bbs = body.basic_blocks.as_mut(); - bbs.raw.truncate(1); + bbs.truncate(1); bbs[START_BLOCK].statements.clear(); bbs[START_BLOCK].terminator_mut().kind = TerminatorKind::Unreachable; body.var_debug_info.clear(); - body.local_decls.raw.truncate(body.arg_count + 1); + body.local_decls.truncate(body.arg_count + 1); } } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index c36b687111c01..2395c2692ee4b 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -997,7 +997,7 @@ fn inline_call<'tcx, I: Inliner<'tcx>>( } // Insert all of the (mapped) parts of the callee body into the caller. - caller_body.local_decls.extend(callee_body.drain_vars_and_temps()); + callee_body.drain_vars_and_temps_into(&mut caller_body.local_decls); caller_body.source_scopes.append(&mut callee_body.source_scopes); // only "full" debug promises any variable-level information diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 14ab4fb0e74eb..90641e9030e81 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -375,7 +375,7 @@ pub(super) fn remove_dead_blocks(body: &mut Body<'_>) { let mut used_index = 0; let mut kept_unreachable = None; let mut deduplicated_unreachable = false; - basic_blocks.raw.retain(|bbdata| { + basic_blocks.mutate(|raw| raw.retain(|bbdata| { let orig_bb = BasicBlock::new(orig_index); if !reachable.contains(orig_bb) { orig_index += 1; @@ -397,7 +397,7 @@ pub(super) fn remove_dead_blocks(body: &mut Body<'_>) { used_index += 1; orig_index += 1; true - }); + })); // If we deduplicated unreachable blocks we erase their source_info as we // can no longer attribute their code to a particular location in the diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index bbbae98cd49d0..bcb69be785e32 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1035,7 +1035,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.typing_env, adt_def.non_enum_variant().fields[field].ty(self.tcx, args), ); - if let [field] = fields.raw.as_slice() { + if let [field] = &fields.as_slice().raw { let src_ty = field.ty(self.body, self.tcx); if !self.mir_assign_valid_types(src_ty, dest_ty) { self.fail(location, "union field has the wrong type"); @@ -1108,7 +1108,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.fail(location, "RawPtr should be in runtime MIR only"); } - if let [data_ptr, metadata] = fields.raw.as_slice() { + if let [data_ptr, metadata] = &fields.as_slice().raw { let data_ptr_ty = data_ptr.ty(self.body, self.tcx); let metadata_ty = metadata.ty(self.body, self.tcx); if let ty::RawPtr(in_pointee, in_mut) = data_ptr_ty.kind() { diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index 8b1401c0609f9..d46eefe3f52ae 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -351,11 +351,11 @@ impl> TypeFoldable for Box<[T]> { impl, Ix: Idx> TypeFoldable for IndexVec { fn try_fold_with>(self, folder: &mut F) -> Result { - self.raw.try_fold_with(folder).map(IndexVec::from_raw) + self.into_vec().try_fold_with(folder).map(IndexVec::from_raw) } fn fold_with>(self, folder: &mut F) -> Self { - IndexVec::from_raw(self.raw.fold_with(folder)) + IndexVec::from_raw(self.into_vec().fold_with(folder)) } } From 00e6f1e2106ce3b110d50bf6bbd9c62cff599360 Mon Sep 17 00:00:00 2001 From: panstromek Date: Fri, 12 Jun 2026 09:09:08 +0200 Subject: [PATCH 02/27] wip: fmt --- compiler/rustc_abi/src/layout/coroutine.rs | 3 +- compiler/rustc_index/src/vec.rs | 15 ++++---- compiler/rustc_mir_transform/src/simplify.rs | 40 ++++++++++---------- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_abi/src/layout/coroutine.rs b/compiler/rustc_abi/src/layout/coroutine.rs index 151abb21e04e5..44b4664101bc0 100644 --- a/compiler/rustc_abi/src/layout/coroutine.rs +++ b/compiler/rustc_abi/src/layout/coroutine.rs @@ -186,7 +186,8 @@ pub(super) fn layout< // "a" (`0..b_start`) and "b" (`b_start..`) correspond to // "outer" and "promoted" fields respectively. let b_start = tag_index.plus(1); - let offsets_b = IndexVec::from_raw(offsets.mutate(|raw| raw.split_off(b_start.index()))); + let offsets_b = + IndexVec::from_raw(offsets.mutate(|raw| raw.split_off(b_start.index()))); let offsets_a = offsets; // Disentangle the "a" and "b" components of `in_memory_order` diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index c312ff8918c86..4ac0941bd3dc9 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -1,13 +1,14 @@ use std::borrow::{Borrow, BorrowMut}; use std::hash::Hash; use std::marker::PhantomData; +use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut, RangeBounds}; use std::{fmt, slice, vec}; -use std::mem::ManuallyDrop; + #[cfg(feature = "nightly")] use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; -use crate::{static_assert_size, Idx, IndexSlice}; +use crate::{Idx, IndexSlice, static_assert_size}; /// An owned contiguous collection of `T`s, indexed by `I` rather than by `usize`. /// @@ -129,7 +130,9 @@ impl IndexVec { #[inline] pub fn as_mut_slice(&mut self) -> &mut IndexSlice { - IndexSlice::from_raw_mut(unsafe { std::slice::from_raw_parts_mut(self.data, self.len.index()) }) + IndexSlice::from_raw_mut(unsafe { + std::slice::from_raw_parts_mut(self.data, self.len.index()) + }) } /// Pushes an element to the array returning the index where it was pushed to. @@ -213,11 +216,7 @@ impl IndexVec { #[inline] pub fn append(&mut self, other: &mut Self) { - self.mutate(|vec| { - other.mutate(|other| { - vec.append(other) - }) - }); + self.mutate(|vec| other.mutate(|other| vec.append(other))); } } diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 90641e9030e81..4a67766f75847 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -375,29 +375,31 @@ pub(super) fn remove_dead_blocks(body: &mut Body<'_>) { let mut used_index = 0; let mut kept_unreachable = None; let mut deduplicated_unreachable = false; - basic_blocks.mutate(|raw| raw.retain(|bbdata| { - let orig_bb = BasicBlock::new(orig_index); - if !reachable.contains(orig_bb) { - orig_index += 1; - return false; - } - - let used_bb = BasicBlock::new(used_index); - if should_deduplicate_unreachable(bbdata) { - let kept_unreachable = *kept_unreachable.get_or_insert(used_bb); - if kept_unreachable != used_bb { - replacements[orig_index] = kept_unreachable; - deduplicated_unreachable = true; + basic_blocks.mutate(|raw| { + raw.retain(|bbdata| { + let orig_bb = BasicBlock::new(orig_index); + if !reachable.contains(orig_bb) { orig_index += 1; return false; } - } - replacements[orig_index] = used_bb; - used_index += 1; - orig_index += 1; - true - })); + let used_bb = BasicBlock::new(used_index); + if should_deduplicate_unreachable(bbdata) { + let kept_unreachable = *kept_unreachable.get_or_insert(used_bb); + if kept_unreachable != used_bb { + replacements[orig_index] = kept_unreachable; + deduplicated_unreachable = true; + orig_index += 1; + return false; + } + } + + replacements[orig_index] = used_bb; + used_index += 1; + orig_index += 1; + true + }) + }); // If we deduplicated unreachable blocks we erase their source_info as we // can no longer attribute their code to a particular location in the From 17b9f63fd688161b290ae5dea463809e2718fb8c Mon Sep 17 00:00:00 2001 From: panstromek Date: Fri, 12 Jun 2026 09:13:53 +0200 Subject: [PATCH 03/27] wip: fix cranelift --- compiler/rustc_codegen_cranelift/src/base.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 467eceea221c8..10583d65163f7 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -862,7 +862,7 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: { let ty = to_place_and_rval.1.ty(&fx.mir.local_decls, fx.tcx); let layout = fx.layout_of(fx.monomorphize(ty)); - let [data, meta] = &*operands.raw else { + let [data, meta] = &operands.as_slice().raw else { bug!("RawPtr fields: {operands:?}"); }; let data = codegen_operand(fx, data); From e549dc6e61991e98fb6ddf5f8b17b1295ec252c1 Mon Sep 17 00:00:00 2001 From: panstromek Date: Fri, 12 Jun 2026 09:24:15 +0200 Subject: [PATCH 04/27] wip: fix tidy --- compiler/rustc_index/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index 2b59ff33a5829..af110a6f53256 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -1,8 +1,8 @@ // tidy-alphabetical-start #![cfg_attr(all(feature = "nightly", test), feature(stmt_expr_attributes))] #![cfg_attr(all(feature = "nightly", test), feature(test))] -#![cfg_attr(feature = "nightly", feature(extend_one, step_trait))] #![cfg_attr(feature = "nightly", feature(dropck_eyepatch))] +#![cfg_attr(feature = "nightly", feature(extend_one, step_trait))] // tidy-alphabetical-end pub mod bit_set; From 4deff26166c64c6ca8c47522c1920911bfaf8a11 Mon Sep 17 00:00:00 2001 From: panstromek Date: Fri, 12 Jun 2026 10:38:26 +0200 Subject: [PATCH 05/27] fix: implement derives manually --- compiler/rustc_index/src/vec.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 4ac0941bd3dc9..875627416f25c 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -1,5 +1,5 @@ use std::borrow::{Borrow, BorrowMut}; -use std::hash::Hash; +use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut, RangeBounds}; @@ -36,7 +36,6 @@ use crate::{Idx, IndexSlice, static_assert_size}; /// This allows to index the IndexVec with the new index type. /// /// [`newtype_index!`]: ../macro.newtype_index.html -#[derive(Clone, PartialEq, Eq, Hash)] pub struct IndexVec { data: *mut T, len: I, @@ -46,6 +45,27 @@ pub struct IndexVec { _marker2: PhantomData, } +impl Clone for IndexVec { + fn clone(&self) -> Self { + IndexVec::from_raw(self.as_slice().raw.to_vec()) + } +} + +impl PartialEq for IndexVec { + fn eq(&self, other: &Self<>) -> bool{ + self.as_slice().eq(other.as_slice()) + } +} + +impl Eq for IndexVec {} + +impl Hash for IndexVec { + fn hash(&self, state: &mut H) { + self.as_slice().hash(state); + } +} + + unsafe impl Drop for IndexVec { fn drop(&mut self) { std::mem::take(self).into_vec(); From e7d6ba2910c6b21729232cbb889cc5d8e9c60387 Mon Sep 17 00:00:00 2001 From: panstromek Date: Fri, 12 Jun 2026 11:05:35 +0200 Subject: [PATCH 06/27] fix: tidy --- compiler/rustc_index/src/vec.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 875627416f25c..819c5aa517d42 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -52,7 +52,7 @@ impl Clone for IndexVec { } impl PartialEq for IndexVec { - fn eq(&self, other: &Self<>) -> bool{ + fn eq(&self, other: &Self) -> bool { self.as_slice().eq(other.as_slice()) } } @@ -65,7 +65,6 @@ impl Hash for IndexVec { } } - unsafe impl Drop for IndexVec { fn drop(&mut self) { std::mem::take(self).into_vec(); From 4650137f938fecf1671ec7776d35d5b9f4757ea1 Mon Sep 17 00:00:00 2001 From: panstromek Date: Fri, 12 Jun 2026 11:55:08 +0200 Subject: [PATCH 07/27] fix: platform specific size assertions --- compiler/rustc_hir_id/src/lib.rs | 3 --- compiler/rustc_index/src/vec.rs | 8 ++++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir_id/src/lib.rs b/compiler/rustc_hir_id/src/lib.rs index f0b00179f5073..07b1cceebaf76 100644 --- a/compiler/rustc_hir_id/src/lib.rs +++ b/compiler/rustc_hir_id/src/lib.rs @@ -9,7 +9,6 @@ use std::fmt::{self, Debug}; use rustc_data_structures::stable_hash::{ StableHash, StableHashCtxt, StableHasher, StableOrd, ToStableHashKey, }; -use rustc_index::static_assert_size; use rustc_macros::{Decodable, Encodable, StableHash}; use rustc_span::def_id::{CRATE_DEF_ID, DefId, DefIndex, DefPathHash, LocalDefId}; @@ -159,8 +158,6 @@ rustc_index::newtype_index! { pub struct ItemLocalId {} } -static_assert_size!(rustc_index::IndexVec, 16); - impl ItemLocalId { /// Signal local id which should never be used. pub const INVALID: ItemLocalId = ItemLocalId::MAX; diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 819c5aa517d42..a39a3595f70a7 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -387,8 +387,12 @@ impl> Decodable for IndexVec { // not the phantom data. unsafe impl Send for IndexVec where T: Send {} -static_assert_size!(IndexVec, 16); -static_assert_size!(IndexVec, 24); +#[cfg(target_pointer_width = "64")] +mod size_asserts { + use super::*; + static_assert_size!(IndexVec, 16); + static_assert_size!(IndexVec, 24); +} #[cfg(test)] mod tests; From f8fab8480e0a4bd90655ff46c966ddcf59d231f2 Mon Sep 17 00:00:00 2001 From: panstromek Date: Fri, 12 Jun 2026 13:31:19 +0200 Subject: [PATCH 08/27] fix: unused warning on non-64 bit pointer width --- compiler/rustc_index/src/vec.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index a39a3595f70a7..902a354a9b737 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -8,7 +8,7 @@ use std::{fmt, slice, vec}; #[cfg(feature = "nightly")] use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; -use crate::{Idx, IndexSlice, static_assert_size}; +use crate::{Idx, IndexSlice}; /// An owned contiguous collection of `T`s, indexed by `I` rather than by `usize`. /// @@ -389,7 +389,8 @@ unsafe impl Send for IndexVec where T: Send {} #[cfg(target_pointer_width = "64")] mod size_asserts { - use super::*; + use super::IndexVec; + use crate::static_assert_size; static_assert_size!(IndexVec, 16); static_assert_size!(IndexVec, 24); } From f55d0f11b75e02b35387dc890edefdb6af7a8038 Mon Sep 17 00:00:00 2001 From: panstromek Date: Fri, 12 Jun 2026 15:19:35 +0200 Subject: [PATCH 09/27] fix: make IndexVec compile on stable --- compiler/rustc_index/src/vec.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 902a354a9b737..43662a5e6b269 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -65,12 +65,20 @@ impl Hash for IndexVec { } } +#[cfg(feature = "nightly")] unsafe impl Drop for IndexVec { fn drop(&mut self) { std::mem::take(self).into_vec(); } } +#[cfg(not(feature = "nightly"))] +impl Drop for IndexVec { + fn drop(&mut self) { + std::mem::take(self).into_vec(); + } +} + impl IndexVec { /// Constructs a new, empty `IndexVec`. #[inline] From 24e187c780d4e76211c024dcdd0eeb7b3d82a3b5 Mon Sep 17 00:00:00 2001 From: panstromek Date: Sun, 14 Jun 2026 06:25:10 +0200 Subject: [PATCH 10/27] try to force inline mutate fn to avoid the vec roundtrip overhead --- compiler/rustc_index/src/vec.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 43662a5e6b269..75297480ecfba 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -194,6 +194,7 @@ impl IndexVec { self.mutate(|raw| target.extend(raw.drain(range))) } + #[inline(always)] pub fn mutate) -> U>(&mut self, f: F) -> U { let mut vec = std::mem::take(self).into_vec(); let v = f(&mut vec); From 13cec9bd2babf7bb0cac8050d814b0a2a1a7af75 Mon Sep 17 00:00:00 2001 From: panstromek Date: Mon, 15 Jun 2026 16:40:24 +0200 Subject: [PATCH 11/27] add drop fast to (hopefully) reduce the cost of mutate fn --- compiler/rustc_index/src/vec.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 75297480ecfba..a39ae217e70a5 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -68,6 +68,9 @@ impl Hash for IndexVec { #[cfg(feature = "nightly")] unsafe impl Drop for IndexVec { fn drop(&mut self) { + if self.capacity.index() == 0 { + return; + } std::mem::take(self).into_vec(); } } From 16593e4a511b63858a4889d5dc159e1cd36f71b7 Mon Sep 17 00:00:00 2001 From: panstromek Date: Mon, 15 Jun 2026 16:47:26 +0200 Subject: [PATCH 12/27] add more inline hints and inline into_raw_parts (It wasn't inline) --- compiler/rustc_index/src/vec.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index a39ae217e70a5..d9549637e3ac1 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -67,6 +67,7 @@ impl Hash for IndexVec { #[cfg(feature = "nightly")] unsafe impl Drop for IndexVec { + #[inline] fn drop(&mut self) { if self.capacity.index() == 0 { return; @@ -92,18 +93,19 @@ impl IndexVec { /// Constructs a new `IndexVec` from a `Vec`. #[inline] pub fn from_raw(raw: Vec) -> Self { - let (data, len, capacity) = raw.into_raw_parts(); + let mut me = ManuallyDrop::new(raw); IndexVec { - data, - len: I::new(len), - capacity: I::new(capacity), + data: me.as_mut_ptr(), + len: I::new(me.len()), + capacity: I::new(me.capacity()), _marker: PhantomData, _marker2: PhantomData, } } + #[inline] pub fn into_vec(self) -> Vec { let me = ManuallyDrop::new(self); // fixme this is unsound because we rely on correct Idx trait impls From 7ff17d4e8a78fda0c09e82800514f244b77dfa00 Mon Sep 17 00:00:00 2001 From: panstromek Date: Tue, 16 Jun 2026 16:40:22 +0200 Subject: [PATCH 13/27] copy the fast path for Vec::push_mut to avoid round tripping overhead --- compiler/rustc_index/src/vec.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index d9549637e3ac1..9f83255a29d79 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -3,7 +3,7 @@ use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut, RangeBounds}; -use std::{fmt, slice, vec}; +use std::{fmt, ptr, slice, vec}; #[cfg(feature = "nightly")] use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -171,7 +171,18 @@ impl IndexVec { #[inline] pub fn push(&mut self, d: T) -> I { let idx = self.next_index(); - self.mutate(|vec| vec.push(d)); + let len = self.len.index(); + + if len < self.capacity.index() { + unsafe { + // todo copy pasta from Vec::push_mut + let end = self.data.add(len); + ptr::write(end, d); + self.len = I::new(len + 1); + } + } else { + self.mutate(|vec| vec.push(d)); + } idx } From 0d8b5b5c1c743839e24000a18b4298900f2af367 Mon Sep 17 00:00:00 2001 From: panstromek Date: Tue, 16 Jun 2026 20:10:27 +0200 Subject: [PATCH 14/27] restore niche optimization on IndexVec --- compiler/rustc_index/src/vec.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 9f83255a29d79..5fdee3af31d12 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -3,6 +3,7 @@ use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut, RangeBounds}; +use std::ptr::NonNull; use std::{fmt, ptr, slice, vec}; #[cfg(feature = "nightly")] @@ -37,7 +38,7 @@ use crate::{Idx, IndexSlice}; /// /// [`newtype_index!`]: ../macro.newtype_index.html pub struct IndexVec { - data: *mut T, + data: NonNull, len: I, capacity: I, @@ -96,7 +97,7 @@ impl IndexVec { let mut me = ManuallyDrop::new(raw); IndexVec { - data: me.as_mut_ptr(), + data: unsafe { NonNull::new_unchecked(me.as_mut_ptr()) }, len: I::new(me.len()), capacity: I::new(me.capacity()), @@ -109,7 +110,7 @@ impl IndexVec { pub fn into_vec(self) -> Vec { let me = ManuallyDrop::new(self); // fixme this is unsound because we rely on correct Idx trait impls - unsafe { Vec::from_raw_parts(me.data, me.len.index(), me.capacity.index()) } + unsafe { Vec::from_raw_parts(me.data.as_ptr(), me.len.index(), me.capacity.index()) } } #[inline] @@ -157,13 +158,15 @@ impl IndexVec { #[inline] pub fn as_slice(&self) -> &IndexSlice { - IndexSlice::from_raw(unsafe { std::slice::from_raw_parts(self.data, self.len.index()) }) + IndexSlice::from_raw(unsafe { + std::slice::from_raw_parts(self.data.as_ptr(), self.len.index()) + }) } #[inline] pub fn as_mut_slice(&mut self) -> &mut IndexSlice { IndexSlice::from_raw_mut(unsafe { - std::slice::from_raw_parts_mut(self.data, self.len.index()) + std::slice::from_raw_parts_mut(self.data.as_ptr(), self.len.index()) }) } @@ -177,7 +180,7 @@ impl IndexVec { unsafe { // todo copy pasta from Vec::push_mut let end = self.data.add(len); - ptr::write(end, d); + ptr::write(end.as_ptr(), d); self.len = I::new(len + 1); } } else { @@ -418,6 +421,8 @@ mod size_asserts { use crate::static_assert_size; static_assert_size!(IndexVec, 16); static_assert_size!(IndexVec, 24); + static_assert_size!(Option>, 16); + static_assert_size!(Option>, 24); } #[cfg(test)] From e0a9e147f5ceffb64b0057d340c079ff31a33619 Mon Sep 17 00:00:00 2001 From: panstromek Date: Wed, 1 Jul 2026 11:55:07 +0200 Subject: [PATCH 15/27] add missing inlines on Idx impls --- compiler/rustc_data_structures/src/graph/linked_graph/mod.rs | 2 ++ compiler/rustc_monomorphize/src/graph_checks/statics.rs | 2 ++ src/tools/miri/src/concurrency/thread.rs | 2 ++ 3 files changed, 6 insertions(+) diff --git a/compiler/rustc_data_structures/src/graph/linked_graph/mod.rs b/compiler/rustc_data_structures/src/graph/linked_graph/mod.rs index cecb051172598..dd796cf6bb558 100644 --- a/compiler/rustc_data_structures/src/graph/linked_graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/linked_graph/mod.rs @@ -91,10 +91,12 @@ impl NodeIndex { } impl Idx for NodeIndex { + #[inline] fn new(idx: usize) -> NodeIndex { NodeIndex(idx) } + #[inline] fn index(self) -> usize { self.0 } diff --git a/compiler/rustc_monomorphize/src/graph_checks/statics.rs b/compiler/rustc_monomorphize/src/graph_checks/statics.rs index 4a6416843fded..145d49a96b0db 100644 --- a/compiler/rustc_monomorphize/src/graph_checks/statics.rs +++ b/compiler/rustc_monomorphize/src/graph_checks/statics.rs @@ -14,10 +14,12 @@ use crate::diagnostics; struct StaticNodeIdx(usize); impl Idx for StaticNodeIdx { + #[inline] fn new(idx: usize) -> Self { Self(idx) } + #[inline] fn index(self) -> usize { self.0 } diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 7d9001e73b30d..bf429a2268be7 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -74,10 +74,12 @@ impl ThreadId { } impl Idx for ThreadId { + #[inline] fn new(idx: usize) -> Self { ThreadId(u32::try_from(idx).unwrap()) } + #[inline] fn index(self) -> usize { usize::try_from(self.0).unwrap() } From 996c2bb6077aaf1b25c12b3fea97a1df6503254e Mon Sep 17 00:00:00 2001 From: panstromek Date: Wed, 1 Jul 2026 12:55:19 +0200 Subject: [PATCH 16/27] add explicit len impl to avoid slice roundtrip --- compiler/rustc_index/src/vec.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 5fdee3af31d12..0b6a43d24ca8a 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -156,6 +156,11 @@ impl IndexVec { IndexVec::from_raw((0..n).map(I::new).map(func).collect()) } + #[inline] + pub fn len(&self) -> usize { + self.len.index() + } + #[inline] pub fn as_slice(&self) -> &IndexSlice { IndexSlice::from_raw(unsafe { From 438231098b37053ed50f1582f8a15be78a245fe6 Mon Sep 17 00:00:00 2001 From: panstromek Date: Wed, 1 Jul 2026 18:15:06 +0200 Subject: [PATCH 17/27] use custom sentinel to avoid vec roundtrip in vec::mutate --- compiler/rustc_index/src/vec.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 0b6a43d24ca8a..a9a8e40a7f86a 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -220,7 +220,16 @@ impl IndexVec { #[inline(always)] pub fn mutate) -> U>(&mut self, f: F) -> U { - let mut vec = std::mem::take(self).into_vec(); + let sentinel = IndexVec { + data: NonNull::dangling(), + len: I::new(0), + capacity: I::new(0), + _marker: PhantomData, + _marker2: PhantomData, + }; + let mut vec = std::mem::replace(self, sentinel).into_vec(); + + // let mut vec = std::mem::take(self).into_vec(); let v = f(&mut vec); let _ = std::mem::replace(self, IndexVec::from_raw(vec)); v From 315479191fc0c73d67dc1c48702788cff2efbf38 Mon Sep 17 00:00:00 2001 From: panstromek Date: Wed, 1 Jul 2026 19:53:43 +0200 Subject: [PATCH 18/27] avoid ub_checks overhead by using core::ptr methods instead of std::slice --- compiler/rustc_index/src/vec.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index a9a8e40a7f86a..d46c296ebd2ef 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -164,14 +164,14 @@ impl IndexVec { #[inline] pub fn as_slice(&self) -> &IndexSlice { IndexSlice::from_raw(unsafe { - std::slice::from_raw_parts(self.data.as_ptr(), self.len.index()) + &*std::ptr::slice_from_raw_parts(self.data.as_ptr(), self.len.index()) }) } #[inline] pub fn as_mut_slice(&mut self) -> &mut IndexSlice { IndexSlice::from_raw_mut(unsafe { - std::slice::from_raw_parts_mut(self.data.as_ptr(), self.len.index()) + &mut *ptr::slice_from_raw_parts_mut(self.data.as_ptr(), self.len.index()) }) } From a6bf0d5dbcd3cd11de9e3f6e9e8a97f28f8ca244 Mon Sep 17 00:00:00 2001 From: panstromek Date: Wed, 1 Jul 2026 20:27:48 +0200 Subject: [PATCH 19/27] add assume to avoid ub check overhead in from_raw_parts --- compiler/rustc_index/src/vec.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index d46c296ebd2ef..45efe1041b32c 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -110,7 +110,10 @@ impl IndexVec { pub fn into_vec(self) -> Vec { let me = ManuallyDrop::new(self); // fixme this is unsound because we rely on correct Idx trait impls - unsafe { Vec::from_raw_parts(me.data.as_ptr(), me.len.index(), me.capacity.index()) } + let len = me.len.index(); + let cap = me.capacity.index(); + unsafe { core::hint::assert_unchecked(len <= cap); } + unsafe { Vec::from_raw_parts(me.data.as_ptr(), len, cap) } } #[inline] From af46c3f965c5bf894760cefe4a101305458a385a Mon Sep 17 00:00:00 2001 From: panstromek Date: Thu, 2 Jul 2026 08:49:28 +0200 Subject: [PATCH 20/27] perf: avoid indexing again in Indexer::insert to avoid one more bound check --- compiler/rustc_ast_lowering/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 35e16ce78a8a8..f6838d409c42b 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -494,8 +494,8 @@ fn index_ast<'tcx>( impl Indexer<'_, '_> { fn insert(&mut self, id: NodeId, node: AstOwner) { let def_id = self.owners[&id].def_id; - self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner); - self.index[def_id] = node; + let elem = self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner); + *elem = node; } fn make_dummy( From 002f27f08caa7093d51b7f2a6f4dd99b3a53e4b9 Mon Sep 17 00:00:00 2001 From: panstromek Date: Thu, 2 Jul 2026 14:54:59 +0200 Subject: [PATCH 21/27] tidy --- compiler/rustc_index/src/vec.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 45efe1041b32c..7d745c8ce5e6d 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -112,7 +112,9 @@ impl IndexVec { // fixme this is unsound because we rely on correct Idx trait impls let len = me.len.index(); let cap = me.capacity.index(); - unsafe { core::hint::assert_unchecked(len <= cap); } + unsafe { + core::hint::assert_unchecked(len <= cap); + } unsafe { Vec::from_raw_parts(me.data.as_ptr(), len, cap) } } From 60e4c711daf5205e4912a374bfe7741a78a19a96 Mon Sep 17 00:00:00 2001 From: panstromek Date: Thu, 2 Jul 2026 14:56:02 +0200 Subject: [PATCH 22/27] try to avoid unpacking indexvec into indexslice on each iteration when loading dep graph --- compiler/rustc_middle/src/dep_graph/serialized.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_middle/src/dep_graph/serialized.rs b/compiler/rustc_middle/src/dep_graph/serialized.rs index dbaf29745a8bc..1b4b707485edf 100644 --- a/compiler/rustc_middle/src/dep_graph/serialized.rs +++ b/compiler/rustc_middle/src/dep_graph/serialized.rs @@ -340,6 +340,10 @@ impl SerializedDepGraph { let mut edge_list_data = Vec::with_capacity(graph_bytes - node_count * size_of::()); + let node_slice = nodes.as_mut_slice(); + let value_fingerprints_slice = value_fingerprints.as_mut_slice(); + let edge_list_indices_slice = edge_list_indices.as_mut_slice(); + for _ in 0..node_count { // Decode the header for this edge; the header packs together as many of the fixed-size // fields as possible to limit the number of times we update decoder state. @@ -347,12 +351,12 @@ impl SerializedDepGraph { let index = node_header.index(); - let node = &mut nodes[index]; + let node = &mut node_slice[index]; // Make sure there's no duplicate indices in the dep graph. assert!(node_header.node().kind != DepKind::Null && node.kind == DepKind::Null); *node = node_header.node(); - value_fingerprints[index] = node_header.value_fingerprint(); + value_fingerprints_slice[index] = node_header.value_fingerprint(); // If the length of this node's edge list is small, the length is stored in the header. // If it is not, we fall back to another decoder call. @@ -368,7 +372,7 @@ impl SerializedDepGraph { edge_list_data.extend(d.read_raw_bytes(edges_len_bytes)); - edge_list_indices[index] = edges_header; + edge_list_indices_slice[index] = edges_header; } // When we access the edge list data, we do a fixed-size read from the edge list data then From 3542ec4955eeebd8486762e4bfa5ca3091a8fc0e Mon Sep 17 00:00:00 2001 From: panstromek Date: Fri, 3 Jul 2026 12:17:36 +0200 Subject: [PATCH 23/27] extract function --- compiler/rustc_middle/src/dep_graph/graph.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/dep_graph/graph.rs b/compiler/rustc_middle/src/dep_graph/graph.rs index f3666d5f30817..f58de0b71daf5 100644 --- a/compiler/rustc_middle/src/dep_graph/graph.rs +++ b/compiler/rustc_middle/src/dep_graph/graph.rs @@ -13,7 +13,7 @@ use rustc_data_structures::stable_hash::{StableHash, StableHasher}; use rustc_data_structures::sync::{AtomicU64, Lock, WorkerLocal}; use rustc_data_structures::unord::UnordMap; use rustc_errors::DiagInner; -use rustc_index::IndexVec; +use rustc_index::{IndexSlice, IndexVec}; use rustc_macros::{Decodable, Encodable}; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_session::Session; @@ -1370,7 +1370,15 @@ impl DepNodeColorMap { #[inline] pub(super) fn get(&self, index: SerializedDepNodeIndex) -> DepNodeColor { - let value = self.values[index].load(Ordering::Acquire); + Self::get_from_slice(self.values.as_slice(), index) + } + + #[inline] + pub(super) fn get_from_slice( + values: &IndexSlice, + index: SerializedDepNodeIndex, + ) -> DepNodeColor { + let value = values[index].load(Ordering::Acquire); // Green is by far the most common case. Check for that first so we can succeed with a // single comparison. if value < COMPRESSED_RED { From f59e82d455da7aa458e684737bc46227661289ec Mon Sep 17 00:00:00 2001 From: panstromek Date: Fri, 3 Jul 2026 12:22:57 +0200 Subject: [PATCH 24/27] avoid unpacking indexvec into indexslice on each iteration in exec_cache_promotions --- compiler/rustc_middle/src/dep_graph/graph.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/dep_graph/graph.rs b/compiler/rustc_middle/src/dep_graph/graph.rs index f58de0b71daf5..457cf89fa25ee 100644 --- a/compiler/rustc_middle/src/dep_graph/graph.rs +++ b/compiler/rustc_middle/src/dep_graph/graph.rs @@ -1061,8 +1061,9 @@ impl DepGraph { let _prof_timer = tcx.prof.generic_activity("incr_comp_query_cache_promotion"); let data = self.data.as_ref().unwrap(); - for prev_index in data.colors.values.indices() { - match data.colors.get(prev_index) { + let colors = data.colors.values.as_slice(); + for prev_index in colors.indices() { + match DepNodeColorMap::get_from_slice(colors, prev_index) { DepNodeColor::Green(_) => { let dep_node = data.previous.index_to_node(prev_index); if let Some(promote_fn) = From 42dccf2c7c9ea41d3381bbbd0552605462ff41fe Mon Sep 17 00:00:00 2001 From: panstromek Date: Fri, 3 Jul 2026 12:30:37 +0200 Subject: [PATCH 25/27] avoid unpacking indexvec into indexslice on each iteration in exec_cache_promotions also for the nodes IndexVec --- compiler/rustc_middle/src/dep_graph/graph.rs | 4 +++- compiler/rustc_middle/src/dep_graph/serialized.rs | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_middle/src/dep_graph/graph.rs b/compiler/rustc_middle/src/dep_graph/graph.rs index 457cf89fa25ee..196ab3a6228ea 100644 --- a/compiler/rustc_middle/src/dep_graph/graph.rs +++ b/compiler/rustc_middle/src/dep_graph/graph.rs @@ -1061,11 +1061,13 @@ impl DepGraph { let _prof_timer = tcx.prof.generic_activity("incr_comp_query_cache_promotion"); let data = self.data.as_ref().unwrap(); + let nodes = data.previous.nodes(); let colors = data.colors.values.as_slice(); + for prev_index in colors.indices() { match DepNodeColorMap::get_from_slice(colors, prev_index) { DepNodeColor::Green(_) => { - let dep_node = data.previous.index_to_node(prev_index); + let dep_node = &nodes[prev_index]; if let Some(promote_fn) = tcx.dep_kind_vtable(dep_node.kind).promote_from_disk_fn { diff --git a/compiler/rustc_middle/src/dep_graph/serialized.rs b/compiler/rustc_middle/src/dep_graph/serialized.rs index 1b4b707485edf..06e91375e1e91 100644 --- a/compiler/rustc_middle/src/dep_graph/serialized.rs +++ b/compiler/rustc_middle/src/dep_graph/serialized.rs @@ -232,6 +232,11 @@ impl SerializedDepGraph { &self.nodes[dep_node_index] } + #[inline] + pub fn nodes(&self) -> &IndexSlice { + self.nodes.as_slice() + } + #[inline] pub fn node_to_index_opt(&self, dep_node: &DepNode) -> Option { let kind = self.reverse_index.kinds.get(dep_node.kind.as_usize())?; From c89fc829de3c9054578ca6f4803c19e736cbaf9f Mon Sep 17 00:00:00 2001 From: panstromek Date: Mon, 6 Jul 2026 22:07:56 +0200 Subject: [PATCH 26/27] avoid converting color map into slice in each iteration in try_mark_previous green This lookup is the most common operation in try_mark_green --- compiler/rustc_middle/src/dep_graph/graph.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/dep_graph/graph.rs b/compiler/rustc_middle/src/dep_graph/graph.rs index 196ab3a6228ea..5357b838625d0 100644 --- a/compiler/rustc_middle/src/dep_graph/graph.rs +++ b/compiler/rustc_middle/src/dep_graph/graph.rs @@ -944,8 +944,10 @@ impl DepGraphData { // We never try to mark eval_always nodes as green debug_assert!(!tcx.is_eval_always(self.previous.index_to_node(prev_dep_node_index).kind)); + let colors = self.colors.values.as_slice(); + for parent_dep_node_index in self.previous.edge_targets_from(prev_dep_node_index) { - match self.colors.get(parent_dep_node_index) { + match DepNodeColorMap::get_from_slice(colors, parent_dep_node_index) { // This dependency has been marked as green before, we are still ok and can // continue checking the remaining dependencies. DepNodeColor::Green(parent_index) => { @@ -983,7 +985,7 @@ impl DepGraphData { return None; } - match self.colors.get(parent_dep_node_index) { + match DepNodeColorMap::get_from_slice(colors, parent_dep_node_index) { DepNodeColor::Green(parent_index) => { edges.push(parent_index); continue; From 559426c720a8e3a6621946d6a130aaa77b653fad Mon Sep 17 00:00:00 2001 From: panstromek Date: Tue, 7 Jul 2026 08:21:27 +0200 Subject: [PATCH 27/27] Revert "avoid converting color map into slice in each iteration in try_mark_previous green" This reverts commit c89fc829de3c9054578ca6f4803c19e736cbaf9f. --- compiler/rustc_middle/src/dep_graph/graph.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/dep_graph/graph.rs b/compiler/rustc_middle/src/dep_graph/graph.rs index 5357b838625d0..196ab3a6228ea 100644 --- a/compiler/rustc_middle/src/dep_graph/graph.rs +++ b/compiler/rustc_middle/src/dep_graph/graph.rs @@ -944,10 +944,8 @@ impl DepGraphData { // We never try to mark eval_always nodes as green debug_assert!(!tcx.is_eval_always(self.previous.index_to_node(prev_dep_node_index).kind)); - let colors = self.colors.values.as_slice(); - for parent_dep_node_index in self.previous.edge_targets_from(prev_dep_node_index) { - match DepNodeColorMap::get_from_slice(colors, parent_dep_node_index) { + match self.colors.get(parent_dep_node_index) { // This dependency has been marked as green before, we are still ok and can // continue checking the remaining dependencies. DepNodeColor::Green(parent_index) => { @@ -985,7 +983,7 @@ impl DepGraphData { return None; } - match DepNodeColorMap::get_from_slice(colors, parent_dep_node_index) { + match self.colors.get(parent_dep_node_index) { DepNodeColor::Green(parent_index) => { edges.push(parent_index); continue;