Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 548d2f0

Browse files
committed
Auto merge of rust-lang#15575 - HKalbasi:mir, r=HKalbasi
Intern projections in mir place I hope this reduces mir memory usage.
2 parents 829e777 + 9708a29 commit 548d2f0

File tree

7 files changed

+253
-157
lines changed

7 files changed

+253
-157
lines changed

crates/hir-ty/src/mir.rs

Lines changed: 103 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! MIR definitions and implementation
22
3-
use std::{fmt::Display, iter};
3+
use std::{collections::hash_map::Entry, fmt::Display, iter};
44

55
use crate::{
66
consteval::usize_const,
@@ -37,6 +37,7 @@ pub use monomorphization::{
3737
monomorphize_mir_body_bad, monomorphized_mir_body_for_closure_query,
3838
monomorphized_mir_body_query, monomorphized_mir_body_recover,
3939
};
40+
use rustc_hash::FxHashMap;
4041
use smallvec::{smallvec, SmallVec};
4142
use stdx::{impl_from, never};
4243
use triomphe::Arc;
@@ -223,35 +224,93 @@ impl<V, T> ProjectionElem<V, T> {
223224

224225
type PlaceElem = ProjectionElem<LocalId, Ty>;
225226

227+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
228+
pub struct ProjectionId(u32);
229+
230+
#[derive(Debug, Clone, PartialEq, Eq)]
231+
pub struct ProjectionStore {
232+
id_to_proj: FxHashMap<ProjectionId, Box<[PlaceElem]>>,
233+
proj_to_id: FxHashMap<Box<[PlaceElem]>, ProjectionId>,
234+
}
235+
236+
impl Default for ProjectionStore {
237+
fn default() -> Self {
238+
let mut this = Self { id_to_proj: Default::default(), proj_to_id: Default::default() };
239+
// Ensure that [] will get the id 0 which is used in `ProjectionId::Empty`
240+
this.intern(Box::new([]));
241+
this
242+
}
243+
}
244+
245+
impl ProjectionStore {
246+
fn shrink_to_fit(&mut self) {
247+
self.id_to_proj.shrink_to_fit();
248+
self.proj_to_id.shrink_to_fit();
249+
}
250+
251+
fn intern_if_exist(&self, projection: &[PlaceElem]) -> Option<ProjectionId> {
252+
self.proj_to_id.get(projection).copied()
253+
}
254+
255+
fn intern(&mut self, projection: Box<[PlaceElem]>) -> ProjectionId {
256+
let new_id = ProjectionId(self.proj_to_id.len() as u32);
257+
match self.proj_to_id.entry(projection) {
258+
Entry::Occupied(id) => *id.get(),
259+
Entry::Vacant(e) => {
260+
let key_clone = e.key().clone();
261+
e.insert(new_id);
262+
self.id_to_proj.insert(new_id, key_clone);
263+
new_id
264+
}
265+
}
266+
}
267+
}
268+
269+
impl ProjectionId {
270+
const EMPTY: ProjectionId = ProjectionId(0);
271+
272+
fn lookup(self, store: &ProjectionStore) -> &[PlaceElem] {
273+
store.id_to_proj.get(&self).unwrap()
274+
}
275+
276+
fn project(self, projection: PlaceElem, store: &mut ProjectionStore) -> ProjectionId {
277+
let mut current = self.lookup(store).to_vec();
278+
current.push(projection);
279+
store.intern(current.into())
280+
}
281+
}
282+
226283
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
227284
pub struct Place {
228285
pub local: LocalId,
229-
pub projection: Box<[PlaceElem]>,
286+
pub projection: ProjectionId,
230287
}
231288

232289
impl Place {
233-
fn is_parent(&self, child: &Place) -> bool {
234-
self.local == child.local && child.projection.starts_with(&self.projection)
290+
fn is_parent(&self, child: &Place, store: &ProjectionStore) -> bool {
291+
self.local == child.local
292+
&& child.projection.lookup(store).starts_with(&self.projection.lookup(store))
235293
}
236294

237295
/// The place itself is not included
238-
fn iterate_over_parents(&self) -> impl Iterator<Item = Place> + '_ {
239-
(0..self.projection.len())
240-
.map(|x| &self.projection[0..x])
241-
.map(|x| Place { local: self.local, projection: x.to_vec().into() })
296+
fn iterate_over_parents<'a>(
297+
&'a self,
298+
store: &'a ProjectionStore,
299+
) -> impl Iterator<Item = Place> + 'a {
300+
let projection = self.projection.lookup(store);
301+
(0..projection.len()).map(|x| &projection[0..x]).filter_map(move |x| {
302+
Some(Place { local: self.local, projection: store.intern_if_exist(x)? })
303+
})
242304
}
243305

244-
fn project(&self, projection: PlaceElem) -> Place {
245-
Place {
246-
local: self.local,
247-
projection: self.projection.iter().cloned().chain([projection]).collect(),
248-
}
306+
fn project(&self, projection: PlaceElem, store: &mut ProjectionStore) -> Place {
307+
Place { local: self.local, projection: self.projection.project(projection, store) }
249308
}
250309
}
251310

252311
impl From<LocalId> for Place {
253312
fn from(local: LocalId) -> Self {
254-
Self { local, projection: vec![].into() }
313+
Self { local, projection: ProjectionId::EMPTY }
255314
}
256315
}
257316

@@ -997,6 +1056,7 @@ pub struct BasicBlock {
9971056

9981057
#[derive(Debug, Clone, PartialEq, Eq)]
9991058
pub struct MirBody {
1059+
pub projection_store: ProjectionStore,
10001060
pub basic_blocks: Arena<BasicBlock>,
10011061
pub locals: Arena<Local>,
10021062
pub start_block: BasicBlockId,
@@ -1009,11 +1069,15 @@ pub struct MirBody {
10091069
}
10101070

10111071
impl MirBody {
1012-
fn walk_places(&mut self, mut f: impl FnMut(&mut Place)) {
1013-
fn for_operand(op: &mut Operand, f: &mut impl FnMut(&mut Place)) {
1072+
fn walk_places(&mut self, mut f: impl FnMut(&mut Place, &mut ProjectionStore)) {
1073+
fn for_operand(
1074+
op: &mut Operand,
1075+
f: &mut impl FnMut(&mut Place, &mut ProjectionStore),
1076+
store: &mut ProjectionStore,
1077+
) {
10141078
match op {
10151079
Operand::Copy(p) | Operand::Move(p) => {
1016-
f(p);
1080+
f(p, store);
10171081
}
10181082
Operand::Constant(_) | Operand::Static(_) => (),
10191083
}
@@ -1022,38 +1086,40 @@ impl MirBody {
10221086
for statement in &mut block.statements {
10231087
match &mut statement.kind {
10241088
StatementKind::Assign(p, r) => {
1025-
f(p);
1089+
f(p, &mut self.projection_store);
10261090
match r {
10271091
Rvalue::ShallowInitBoxWithAlloc(_) => (),
10281092
Rvalue::ShallowInitBox(o, _)
10291093
| Rvalue::UnaryOp(_, o)
10301094
| Rvalue::Cast(_, o, _)
10311095
| Rvalue::Repeat(o, _)
1032-
| Rvalue::Use(o) => for_operand(o, &mut f),
1096+
| Rvalue::Use(o) => for_operand(o, &mut f, &mut self.projection_store),
10331097
Rvalue::CopyForDeref(p)
10341098
| Rvalue::Discriminant(p)
10351099
| Rvalue::Len(p)
1036-
| Rvalue::Ref(_, p) => f(p),
1100+
| Rvalue::Ref(_, p) => f(p, &mut self.projection_store),
10371101
Rvalue::CheckedBinaryOp(_, o1, o2) => {
1038-
for_operand(o1, &mut f);
1039-
for_operand(o2, &mut f);
1102+
for_operand(o1, &mut f, &mut self.projection_store);
1103+
for_operand(o2, &mut f, &mut self.projection_store);
10401104
}
10411105
Rvalue::Aggregate(_, ops) => {
10421106
for op in ops.iter_mut() {
1043-
for_operand(op, &mut f);
1107+
for_operand(op, &mut f, &mut self.projection_store);
10441108
}
10451109
}
10461110
}
10471111
}
1048-
StatementKind::Deinit(p) => f(p),
1112+
StatementKind::Deinit(p) => f(p, &mut self.projection_store),
10491113
StatementKind::StorageLive(_)
10501114
| StatementKind::StorageDead(_)
10511115
| StatementKind::Nop => (),
10521116
}
10531117
}
10541118
match &mut block.terminator {
10551119
Some(x) => match &mut x.kind {
1056-
TerminatorKind::SwitchInt { discr, .. } => for_operand(discr, &mut f),
1120+
TerminatorKind::SwitchInt { discr, .. } => {
1121+
for_operand(discr, &mut f, &mut self.projection_store)
1122+
}
10571123
TerminatorKind::FalseEdge { .. }
10581124
| TerminatorKind::FalseUnwind { .. }
10591125
| TerminatorKind::Goto { .. }
@@ -1063,23 +1129,24 @@ impl MirBody {
10631129
| TerminatorKind::Return
10641130
| TerminatorKind::Unreachable => (),
10651131
TerminatorKind::Drop { place, .. } => {
1066-
f(place);
1132+
f(place, &mut self.projection_store);
10671133
}
10681134
TerminatorKind::DropAndReplace { place, value, .. } => {
1069-
f(place);
1070-
for_operand(value, &mut f);
1135+
f(place, &mut self.projection_store);
1136+
for_operand(value, &mut f, &mut self.projection_store);
10711137
}
10721138
TerminatorKind::Call { func, args, destination, .. } => {
1073-
for_operand(func, &mut f);
1074-
args.iter_mut().for_each(|x| for_operand(x, &mut f));
1075-
f(destination);
1139+
for_operand(func, &mut f, &mut self.projection_store);
1140+
args.iter_mut()
1141+
.for_each(|x| for_operand(x, &mut f, &mut self.projection_store));
1142+
f(destination, &mut self.projection_store);
10761143
}
10771144
TerminatorKind::Assert { cond, .. } => {
1078-
for_operand(cond, &mut f);
1145+
for_operand(cond, &mut f, &mut self.projection_store);
10791146
}
10801147
TerminatorKind::Yield { value, resume_arg, .. } => {
1081-
for_operand(value, &mut f);
1082-
f(resume_arg);
1148+
for_operand(value, &mut f, &mut self.projection_store);
1149+
f(resume_arg, &mut self.projection_store);
10831150
}
10841151
},
10851152
None => (),
@@ -1096,7 +1163,9 @@ impl MirBody {
10961163
binding_locals,
10971164
param_locals,
10981165
closures,
1166+
projection_store,
10991167
} = self;
1168+
projection_store.shrink_to_fit();
11001169
basic_blocks.shrink_to_fit();
11011170
locals.shrink_to_fit();
11021171
binding_locals.shrink_to_fit();

crates/hir-ty/src/mir/borrowck.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
8888
Operand::Copy(p) | Operand::Move(p) => {
8989
let mut ty: Ty = body.locals[p.local].ty.clone();
9090
let mut is_dereference_of_ref = false;
91-
for proj in &*p.projection {
91+
for proj in p.projection.lookup(&body.projection_store) {
9292
if *proj == ProjectionElem::Deref && ty.as_reference().is_some() {
9393
is_dereference_of_ref = true;
9494
}
@@ -195,7 +195,7 @@ enum ProjectionCase {
195195
fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> ProjectionCase {
196196
let mut is_part_of = false;
197197
let mut ty = body.locals[lvalue.local].ty.clone();
198-
for proj in lvalue.projection.iter() {
198+
for proj in lvalue.projection.lookup(&body.projection_store).iter() {
199199
match proj {
200200
ProjectionElem::Deref if ty.as_adt().is_none() => return ProjectionCase::Indirect, // It's indirect in case of reference and raw
201201
ProjectionElem::Deref // It's direct in case of `Box<T>`
@@ -254,7 +254,7 @@ fn ever_initialized_map(
254254
for statement in &block.statements {
255255
match &statement.kind {
256256
StatementKind::Assign(p, _) => {
257-
if p.projection.len() == 0 && p.local == l {
257+
if p.projection.lookup(&body.projection_store).len() == 0 && p.local == l {
258258
is_ever_initialized = true;
259259
}
260260
}
@@ -289,7 +289,9 @@ fn ever_initialized_map(
289289
| TerminatorKind::Return
290290
| TerminatorKind::Unreachable => (),
291291
TerminatorKind::Call { target, cleanup, destination, .. } => {
292-
if destination.projection.len() == 0 && destination.local == l {
292+
if destination.projection.lookup(&body.projection_store).len() == 0
293+
&& destination.local == l
294+
{
293295
is_ever_initialized = true;
294296
}
295297
target
@@ -389,7 +391,7 @@ fn mutability_of_locals(
389391
| TerminatorKind::Assert { .. }
390392
| TerminatorKind::Yield { .. } => (),
391393
TerminatorKind::Call { destination, .. } => {
392-
if destination.projection.len() == 0 {
394+
if destination.projection.lookup(&body.projection_store).len() == 0 {
393395
if ever_init_map.get(destination.local).copied().unwrap_or_default() {
394396
push_mut_span(destination.local, MirSpan::Unknown);
395397
} else {

crates/hir-ty/src/mir/eval.rs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ use crate::{
4646

4747
use super::{
4848
return_slot, AggregateKind, BasicBlockId, BinOp, CastKind, LocalId, MirBody, MirLowerError,
49-
MirSpan, Operand, Place, PlaceElem, ProjectionElem, Rvalue, StatementKind, TerminatorKind,
50-
UnOp,
49+
MirSpan, Operand, Place, PlaceElem, ProjectionElem, ProjectionStore, Rvalue, StatementKind,
50+
TerminatorKind, UnOp,
5151
};
5252

5353
mod shim;
@@ -483,17 +483,18 @@ struct DropFlags {
483483
}
484484

485485
impl DropFlags {
486-
fn add_place(&mut self, p: Place) {
487-
if p.iterate_over_parents().any(|it| self.need_drop.contains(&it)) {
486+
fn add_place(&mut self, p: Place, store: &ProjectionStore) {
487+
if p.iterate_over_parents(store).any(|it| self.need_drop.contains(&it)) {
488488
return;
489489
}
490-
self.need_drop.retain(|it| !p.is_parent(it));
490+
self.need_drop.retain(|it| !p.is_parent(it, store));
491491
self.need_drop.insert(p);
492492
}
493493

494-
fn remove_place(&mut self, p: &Place) -> bool {
494+
fn remove_place(&mut self, p: &Place, store: &ProjectionStore) -> bool {
495495
// FIXME: replace parents with parts
496-
if let Some(parent) = p.iterate_over_parents().find(|it| self.need_drop.contains(&it)) {
496+
if let Some(parent) = p.iterate_over_parents(store).find(|it| self.need_drop.contains(&it))
497+
{
497498
self.need_drop.remove(&parent);
498499
return true;
499500
}
@@ -654,7 +655,7 @@ impl Evaluator<'_> {
654655
let mut addr = locals.ptr[p.local].addr;
655656
let mut ty: Ty = locals.body.locals[p.local].ty.clone();
656657
let mut metadata: Option<IntervalOrOwned> = None; // locals are always sized
657-
for proj in &*p.projection {
658+
for proj in p.projection.lookup(&locals.body.projection_store) {
658659
let prev_ty = ty.clone();
659660
ty = self.projected_ty(ty, proj.clone());
660661
match proj {
@@ -835,7 +836,9 @@ impl Evaluator<'_> {
835836
let addr = self.place_addr(l, &locals)?;
836837
let result = self.eval_rvalue(r, &mut locals)?.to_vec(&self)?;
837838
self.write_memory(addr, &result)?;
838-
locals.drop_flags.add_place(l.clone());
839+
locals
840+
.drop_flags
841+
.add_place(l.clone(), &locals.body.projection_store);
839842
}
840843
StatementKind::Deinit(_) => not_supported!("de-init statement"),
841844
StatementKind::StorageLive(_)
@@ -887,7 +890,9 @@ impl Evaluator<'_> {
887890
)?,
888891
it => not_supported!("unknown function type {it:?}"),
889892
};
890-
locals.drop_flags.add_place(destination.clone());
893+
locals
894+
.drop_flags
895+
.add_place(destination.clone(), &locals.body.projection_store);
891896
if let Some(stack_frame) = stack_frame {
892897
self.code_stack.push(my_stack_frame);
893898
current_block_idx = stack_frame.locals.body.start_block;
@@ -968,7 +973,7 @@ impl Evaluator<'_> {
968973
) -> Result<()> {
969974
let mut remain_args = body.param_locals.len();
970975
for ((l, interval), value) in locals.ptr.iter().skip(1).zip(args) {
971-
locals.drop_flags.add_place(l.into());
976+
locals.drop_flags.add_place(l.into(), &locals.body.projection_store);
972977
match value {
973978
IntervalOrOwned::Owned(value) => interval.write_from_bytes(self, &value)?,
974979
IntervalOrOwned::Borrowed(value) => interval.write_from_interval(self, value)?,
@@ -1644,7 +1649,7 @@ impl Evaluator<'_> {
16441649
fn eval_operand(&mut self, it: &Operand, locals: &mut Locals) -> Result<Interval> {
16451650
Ok(match it {
16461651
Operand::Copy(p) | Operand::Move(p) => {
1647-
locals.drop_flags.remove_place(p);
1652+
locals.drop_flags.remove_place(p, &locals.body.projection_store);
16481653
self.eval_place(p, locals)?
16491654
}
16501655
Operand::Static(st) => {
@@ -2508,7 +2513,7 @@ impl Evaluator<'_> {
25082513

25092514
fn drop_place(&mut self, place: &Place, locals: &mut Locals, span: MirSpan) -> Result<()> {
25102515
let (addr, ty, metadata) = self.place_addr_and_ty_and_metadata(place, locals)?;
2511-
if !locals.drop_flags.remove_place(place) {
2516+
if !locals.drop_flags.remove_place(place, &locals.body.projection_store) {
25122517
return Ok(());
25132518
}
25142519
let metadata = match metadata {

0 commit comments

Comments
 (0)