Skip to content

Commit 98d2324

Browse files
committed
Avoid cloning place in LocalAnalyzer visitor
1 parent d0accad commit 98d2324

File tree

2 files changed

+91
-56
lines changed

2 files changed

+91
-56
lines changed

src/librustc/mir/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1826,6 +1826,12 @@ newtype_index! {
18261826
}
18271827
}
18281828

1829+
#[derive(Debug)]
1830+
pub struct PlaceRef<'a, 'tcx> {
1831+
pub base: &'a PlaceBase<'tcx>,
1832+
pub projection: &'a Option<Box<Projection<'tcx>>>,
1833+
}
1834+
18291835
impl<'tcx> Place<'tcx> {
18301836
pub const RETURN_PLACE: Place<'tcx> = Place {
18311837
base: PlaceBase::Local(RETURN_PLACE),

src/librustc_codegen_ssa/mir/analyze.rs

Lines changed: 85 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,86 @@ impl<Bx: BuilderMethods<'a, 'tcx>> LocalAnalyzer<'mir, 'a, 'tcx, Bx> {
9292
self.first_assignment[local] = location;
9393
}
9494
}
95+
96+
fn process_place(&mut self,
97+
place_ref: &mir::PlaceRef<'_, 'tcx>,
98+
context: PlaceContext,
99+
location: Location) {
100+
let cx = self.fx.cx;
101+
102+
if let Some(proj) = place_ref.projection {
103+
// Allow uses of projections that are ZSTs or from scalar fields.
104+
let is_consume = match context {
105+
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
106+
PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => true,
107+
_ => false
108+
};
109+
if is_consume {
110+
let base_ty =
111+
mir::Place::ty_from(place_ref.base, &proj.base, self.fx.mir, cx.tcx());
112+
let base_ty = self.fx.monomorphize(&base_ty);
113+
114+
// ZSTs don't require any actual memory access.
115+
let elem_ty = base_ty
116+
.projection_ty(cx.tcx(), &proj.elem)
117+
.ty;
118+
let elem_ty = self.fx.monomorphize(&elem_ty);
119+
if cx.layout_of(elem_ty).is_zst() {
120+
return;
121+
}
122+
123+
if let mir::ProjectionElem::Field(..) = proj.elem {
124+
let layout = cx.layout_of(base_ty.ty);
125+
if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) {
126+
// Recurse with the same context, instead of `Projection`,
127+
// potentially stopping at non-operand projections,
128+
// which would trigger `not_ssa` on locals.
129+
self.process_place(
130+
&mir::PlaceRef {
131+
base: place_ref.base,
132+
projection: &proj.base,
133+
},
134+
context,
135+
location,
136+
);
137+
return;
138+
}
139+
}
140+
}
141+
142+
// A deref projection only reads the pointer, never needs the place.
143+
if let mir::ProjectionElem::Deref = proj.elem {
144+
self.process_place(
145+
&mir::PlaceRef {
146+
base: place_ref.base,
147+
projection: &proj.base,
148+
},
149+
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
150+
location
151+
);
152+
return;
153+
}
154+
}
155+
156+
// FIXME this is super_place code, is repeated here to avoid cloning place or changing
157+
// visit_place API
158+
let mut context = context;
159+
160+
if place_ref.projection.is_some() {
161+
context = if context.is_mutating_use() {
162+
PlaceContext::MutatingUse(MutatingUseContext::Projection)
163+
} else {
164+
PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
165+
};
166+
}
167+
168+
self.visit_place_base(place_ref.base, context, location);
169+
170+
if let Some(box proj) = place_ref.projection {
171+
self.visit_projection(place_ref.base, proj, context, location);
172+
}
173+
}
174+
95175
}
96176

97177
impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
@@ -158,63 +238,12 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
158238
context: PlaceContext,
159239
location: Location) {
160240
debug!("visit_place(place={:?}, context={:?})", place, context);
161-
let cx = self.fx.cx;
162-
163-
if let Some(proj) = &place.projection {
164-
// Allow uses of projections that are ZSTs or from scalar fields.
165-
let is_consume = match context {
166-
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
167-
PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => true,
168-
_ => false
169-
};
170-
if is_consume {
171-
let base_ty = mir::Place::ty_from(&place.base, &proj.base, self.fx.mir, cx.tcx());
172-
let base_ty = self.fx.monomorphize(&base_ty);
173-
174-
// ZSTs don't require any actual memory access.
175-
let elem_ty = base_ty
176-
.projection_ty(cx.tcx(), &proj.elem)
177-
.ty;
178-
let elem_ty = self.fx.monomorphize(&elem_ty);
179-
if cx.layout_of(elem_ty).is_zst() {
180-
return;
181-
}
182-
183-
if let mir::ProjectionElem::Field(..) = proj.elem {
184-
let layout = cx.layout_of(base_ty.ty);
185-
if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) {
186-
// Recurse with the same context, instead of `Projection`,
187-
// potentially stopping at non-operand projections,
188-
// which would trigger `not_ssa` on locals.
189-
self.visit_place(
190-
// FIXME do not clone
191-
&mir::Place {
192-
base: place.base.clone(),
193-
projection: proj.base.clone(),
194-
},
195-
context,
196-
location,
197-
);
198-
return;
199-
}
200-
}
201-
}
202-
203-
// A deref projection only reads the pointer, never needs the place.
204-
if let mir::ProjectionElem::Deref = proj.elem {
205-
return self.visit_place(
206-
// FIXME do not clone
207-
&mir::Place {
208-
base: place.base.clone(),
209-
projection: proj.base.clone(),
210-
},
211-
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
212-
location
213-
);
214-
}
215-
}
216241

217-
self.super_place(place, context, location);
242+
let place_ref = mir::PlaceRef {
243+
base: &place.base,
244+
projection: &place.projection,
245+
};
246+
self.process_place(&place_ref, context, location);
218247
}
219248

220249
fn visit_local(&mut self,

0 commit comments

Comments
 (0)