From 23ce228d545aef4ad7933e69ff9d68961f407605 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Fri, 19 May 2023 00:16:52 +0330 Subject: [PATCH] Reduce MIR memory usage --- crates/hir-ty/src/mir.rs | 40 ++++++++++++++++--- crates/hir-ty/src/mir/borrowck.rs | 4 +- crates/hir-ty/src/mir/eval.rs | 2 +- crates/hir-ty/src/mir/lower.rs | 40 +++++++++---------- crates/hir-ty/src/mir/lower/as_place.rs | 19 +++++---- .../hir-ty/src/mir/lower/pattern_matching.rs | 33 ++++++++------- 6 files changed, 83 insertions(+), 55 deletions(-) diff --git a/crates/hir-ty/src/mir.rs b/crates/hir-ty/src/mir.rs index 11c35dfb8a8..f8451f28d73 100644 --- a/crates/hir-ty/src/mir.rs +++ b/crates/hir-ty/src/mir.rs @@ -205,7 +205,7 @@ type PlaceElem = ProjectionElem; #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Place { pub local: LocalId, - pub projection: Vec, + pub projection: Box<[PlaceElem]>, } impl Place { @@ -216,13 +216,20 @@ impl Place { fn iterate_over_parents(&self) -> impl Iterator + '_ { (0..self.projection.len()) .map(|x| &self.projection[0..x]) - .map(|x| Place { local: self.local, projection: x.to_vec() }) + .map(|x| Place { local: self.local, projection: x.to_vec().into() }) + } + + fn project(&self, projection: PlaceElem) -> Place { + Place { + local: self.local, + projection: self.projection.iter().cloned().chain([projection]).collect(), + } } } impl From for Place { fn from(local: LocalId) -> Self { - Self { local, projection: vec![] } + Self { local, projection: vec![].into() } } } @@ -437,7 +444,7 @@ pub enum TerminatorKind { /// These are owned by the callee, which is free to modify them. /// This allows the memory occupied by "by-value" arguments to be /// reused across function calls without duplicating the contents. - args: Vec, + args: Box<[Operand]>, /// Where the returned value will be written destination: Place, /// Where to go after this call returns. If none, the call necessarily diverges. @@ -894,7 +901,7 @@ pub enum Rvalue { /// /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Generator`. After /// generator lowering, `Generator` aggregate kinds are disallowed too. - Aggregate(AggregateKind, Vec), + Aggregate(AggregateKind, Box<[Operand]>), /// Transmutes a `*mut u8` into shallow-initialized `Box`. /// @@ -1011,7 +1018,7 @@ impl MirBody { for_operand(o2, &mut f); } Rvalue::Aggregate(_, ops) => { - for op in ops { + for op in ops.iter_mut() { for_operand(op, &mut f); } } @@ -1058,6 +1065,27 @@ impl MirBody { } } } + + fn shrink_to_fit(&mut self) { + let MirBody { + basic_blocks, + locals, + start_block: _, + owner: _, + binding_locals, + param_locals, + closures, + } = self; + basic_blocks.shrink_to_fit(); + locals.shrink_to_fit(); + binding_locals.shrink_to_fit(); + param_locals.shrink_to_fit(); + closures.shrink_to_fit(); + for (_, b) in basic_blocks.iter_mut() { + let BasicBlock { statements, terminator: _, is_cleanup: _ } = b; + statements.shrink_to_fit(); + } + } } #[derive(Debug, PartialEq, Eq, Clone, Copy)] diff --git a/crates/hir-ty/src/mir/borrowck.rs b/crates/hir-ty/src/mir/borrowck.rs index 412390d3fa1..66af6658e81 100644 --- a/crates/hir-ty/src/mir/borrowck.rs +++ b/crates/hir-ty/src/mir/borrowck.rs @@ -93,7 +93,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec Operand::Copy(p) | Operand::Move(p) => { let mut ty: Ty = body.locals[p.local].ty.clone(); let mut is_dereference_of_ref = false; - for proj in &p.projection { + for proj in &*p.projection { if *proj == ProjectionElem::Deref && ty.as_reference().is_some() { is_dereference_of_ref = true; } @@ -143,7 +143,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec for_operand(o2, statement.span); } Rvalue::Aggregate(_, ops) => { - for op in ops { + for op in ops.iter() { for_operand(op, statement.span); } } diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 327161b99eb..e4acd10aa9b 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -562,7 +562,7 @@ impl Evaluator<'_> { let mut ty: Ty = self.ty_filler(&locals.body.locals[p.local].ty, locals.subst, locals.body.owner)?; let mut metadata: Option = None; // locals are always sized - for proj in &p.projection { + for proj in &*p.projection { let prev_ty = ty.clone(); ty = proj.projected_ty( ty, diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 292a771baf9..f73b25d83f4 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -387,7 +387,7 @@ impl<'ctx> MirLowerCtx<'ctx> { current, place, ty, - vec![], + Box::new([]), expr_id.into(), )?; } @@ -561,7 +561,7 @@ impl<'ctx> MirLowerCtx<'ctx> { }; self.push_assignment(current, ref_mut_iterator_place.clone(), Rvalue::Ref(BorrowKind::Mut { allow_two_phase_borrow: false }, iterator_place), expr_id.into()); self.lower_loop(current, place, label, expr_id.into(), |this, begin| { - let Some(current) = this.lower_call(iter_next_fn_op, vec![Operand::Copy(ref_mut_iterator_place)], option_item_place.clone(), begin, false, expr_id.into())? + let Some(current) = this.lower_call(iter_next_fn_op, Box::new([Operand::Copy(ref_mut_iterator_place)]), option_item_place.clone(), begin, false, expr_id.into())? else { return Ok(()); }; @@ -758,8 +758,7 @@ impl<'ctx> MirLowerCtx<'ctx> { match x { Some(x) => x, None => { - let mut p = sp.clone(); - p.projection.push(ProjectionElem::Field(FieldId { + let p = sp.project(ProjectionElem::Field(FieldId { parent: variant_id, local_id: LocalFieldId::from_raw(RawIdx::from(i as u32)), })); @@ -782,10 +781,7 @@ impl<'ctx> MirLowerCtx<'ctx> { }; let local_id = variant_data.field(name).ok_or(MirLowerError::UnresolvedField)?; - let mut place = place; - place - .projection - .push(PlaceElem::Field(FieldId { parent: union_id.into(), local_id })); + let place = place.project(PlaceElem::Field(FieldId { parent: union_id.into(), local_id })); self.lower_expr_to_place(*expr, place, current) } } @@ -826,8 +822,7 @@ impl<'ctx> MirLowerCtx<'ctx> { let Some((operand, current)) = self.lower_expr_to_some_operand(*expr, current)? else { return Ok(None); }; - let mut p = place; - p.projection.push(ProjectionElem::Deref); + let p = place.project(ProjectionElem::Deref); self.push_assignment(current, p, operand.into(), expr_id.into()); Ok(Some(current)) }, @@ -1031,7 +1026,7 @@ impl<'ctx> MirLowerCtx<'ctx> { self.push_assignment( current, place, - Rvalue::Aggregate(AggregateKind::Closure(ty), operands), + Rvalue::Aggregate(AggregateKind::Closure(ty), operands.into()), expr_id.into(), ); Ok(Some(current)) @@ -1128,11 +1123,11 @@ impl<'ctx> MirLowerCtx<'ctx> { let index = name .as_tuple_index() .ok_or(MirLowerError::TypeError("named field on tuple"))?; - place.projection.push(ProjectionElem::TupleOrClosureField(index)) + *place = place.project(ProjectionElem::TupleOrClosureField(index)) } else { let field = self.infer.field_resolution(expr_id).ok_or(MirLowerError::UnresolvedField)?; - place.projection.push(ProjectionElem::Field(field)); + *place = place.project(ProjectionElem::Field(field)); } } else { not_supported!("") @@ -1242,7 +1237,7 @@ impl<'ctx> MirLowerCtx<'ctx> { prev_block: BasicBlockId, place: Place, ty: Ty, - fields: Vec, + fields: Box<[Operand]>, span: MirSpan, ) -> Result { let subst = match ty.kind(Interner) { @@ -1280,13 +1275,13 @@ impl<'ctx> MirLowerCtx<'ctx> { else { return Ok(None); }; - self.lower_call(func, args, place, current, is_uninhabited, span) + self.lower_call(func, args.into(), place, current, is_uninhabited, span) } fn lower_call( &mut self, func: Operand, - args: Vec, + args: Box<[Operand]>, place: Place, current: BasicBlockId, is_uninhabited: bool, @@ -1744,12 +1739,13 @@ pub fn mir_body_for_closure_query( match r { Some(x) => { p.local = closure_local; - let prev_projs = - mem::replace(&mut p.projection, vec![PlaceElem::TupleOrClosureField(x.1)]); + let mut next_projs = vec![PlaceElem::TupleOrClosureField(x.1)]; + let prev_projs = mem::take(&mut p.projection); if x.0.kind != CaptureKind::ByValue { - p.projection.push(ProjectionElem::Deref); + next_projs.push(ProjectionElem::Deref); } - p.projection.extend(prev_projs.into_iter().skip(x.0.place.projections.len())); + next_projs.extend(prev_projs.iter().cloned().skip(x.0.place.projections.len())); + p.projection = next_projs.into(); } None => err = Some(p.clone()), } @@ -1764,6 +1760,7 @@ pub fn mir_body_for_closure_query( if let Some(err) = err { return Err(MirLowerError::UnresolvedUpvar(err)); } + ctx.result.shrink_to_fit(); Ok(Arc::new(ctx.result)) } @@ -1780,7 +1777,8 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result { )? else { return Ok(None); }; - x.0.projection.push(ProjectionElem::Deref); + x.0 = x.0.project(ProjectionElem::Deref); Ok(Some(x)) } Adjust::Deref(Some(od)) => { @@ -139,15 +139,14 @@ impl MirLowerCtx<'_> { let ty = self.expr_ty_without_adjust(expr_id); let ref_ty = TyKind::Ref(Mutability::Not, static_lifetime(), ty).intern(Interner); - let mut temp: Place = self.temp(ref_ty, current, expr_id.into())?.into(); + let temp: Place = self.temp(ref_ty, current, expr_id.into())?.into(); self.push_assignment( current, temp.clone(), Operand::Static(s).into(), expr_id.into(), ); - temp.projection.push(ProjectionElem::Deref); - Ok(Some((temp, current))) + Ok(Some((temp.project(ProjectionElem::Deref), current))) } _ => try_rvalue(self), } @@ -196,7 +195,7 @@ impl MirLowerCtx<'_> { let Some((mut r, current)) = self.lower_expr_as_place(current, *expr, true)? else { return Ok(None); }; - r.projection.push(ProjectionElem::Deref); + r = r.project(ProjectionElem::Deref); Ok(Some((r, current))) } _ => try_rvalue(self), @@ -253,7 +252,7 @@ impl MirLowerCtx<'_> { let Some(current) = self.lower_expr_to_place(*index, l_index.into(), current)? else { return Ok(None); }; - p_base.projection.push(ProjectionElem::Index(l_index)); + p_base = p_base.project(ProjectionElem::Index(l_index)); Ok(Some((p_base, current))) } _ => try_rvalue(self), @@ -283,10 +282,10 @@ impl MirLowerCtx<'_> { ) .intern(Interner), ); - let Some(current) = self.lower_call(index_fn_op, vec![Operand::Copy(place), index_operand], result.clone(), current, false, span)? else { + let Some(current) = self.lower_call(index_fn_op, Box::new([Operand::Copy(place), index_operand]), result.clone(), current, false, span)? else { return Ok(None); }; - result.projection.push(ProjectionElem::Deref); + result = result.project(ProjectionElem::Deref); Ok(Some((result, current))) } @@ -330,10 +329,10 @@ impl MirLowerCtx<'_> { .intern(Interner), ); let mut result: Place = self.temp(target_ty_ref, current, span)?.into(); - let Some(current) = self.lower_call(deref_fn_op, vec![Operand::Copy(ref_place)], result.clone(), current, false, span)? else { + let Some(current) = self.lower_call(deref_fn_op, Box::new([Operand::Copy(ref_place)]), result.clone(), current, false, span)? else { return Ok(None); }; - result.projection.push(ProjectionElem::Deref); + result = result.project(ProjectionElem::Deref); Ok(Some((result, current))) } } diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs index 45c245e281b..00864907ac8 100644 --- a/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -110,10 +110,10 @@ impl MirLowerCtx<'_> { Pat::Slice { prefix, slice, suffix } => { pattern_matching_dereference(&mut cond_ty, &mut binding_mode, &mut cond_place); for (i, &pat) in prefix.iter().enumerate() { - let mut next_place = cond_place.clone(); - next_place - .projection - .push(ProjectionElem::ConstantIndex { offset: i as u64, from_end: false }); + let next_place = cond_place.project(ProjectionElem::ConstantIndex { + offset: i as u64, + from_end: false, + }); let cond_ty = self.infer[pat].clone(); (current, current_else) = self.pattern_match( current, @@ -126,8 +126,7 @@ impl MirLowerCtx<'_> { } if let Some(slice) = slice { if let Pat::Bind { id, subpat: _ } = self.body[*slice] { - let mut next_place = cond_place.clone(); - next_place.projection.push(ProjectionElem::Subslice { + let next_place = cond_place.project(ProjectionElem::Subslice { from: prefix.len() as u64, to: suffix.len() as u64, }); @@ -142,10 +141,10 @@ impl MirLowerCtx<'_> { } } for (i, &pat) in suffix.iter().enumerate() { - let mut next_place = cond_place.clone(); - next_place - .projection - .push(ProjectionElem::ConstantIndex { offset: i as u64, from_end: true }); + let next_place = cond_place.project(ProjectionElem::ConstantIndex { + offset: i as u64, + from_end: true, + }); let cond_ty = self.infer[pat].clone(); (current, current_else) = self.pattern_match( current, @@ -269,11 +268,10 @@ impl MirLowerCtx<'_> { Pat::Ref { pat, mutability: _ } => { if let Some((ty, _, _)) = cond_ty.as_reference() { cond_ty = ty.clone(); - cond_place.projection.push(ProjectionElem::Deref); self.pattern_match( current, current_else, - cond_place, + cond_place.project(ProjectionElem::Deref), cond_ty, *pat, binding_mode, @@ -479,8 +477,7 @@ impl MirLowerCtx<'_> { binding_mode: BindingAnnotation, ) -> Result<(BasicBlockId, Option)> { for (proj, arg, ty) in args { - let mut cond_place = cond_place.clone(); - cond_place.projection.push(proj); + let cond_place = cond_place.project(proj); (current, current_else) = self.pattern_match(current, current_else, cond_place, ty, arg, binding_mode)?; } @@ -513,5 +510,11 @@ fn pattern_matching_dereference( cond_place: &mut Place, ) { let cnt = pattern_matching_dereference_count(cond_ty, binding_mode); - cond_place.projection.extend((0..cnt).map(|_| ProjectionElem::Deref)); + cond_place.projection = cond_place + .projection + .iter() + .cloned() + .chain((0..cnt).map(|_| ProjectionElem::Deref)) + .collect::>() + .into(); }