Skip to content

Commit aa91716

Browse files
committed
add new rval, pull deref early
1 parent a25b131 commit aa91716

38 files changed

+251
-101
lines changed

Diff for: compiler/rustc_borrowck/src/invalidation.rs

+4
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,10 @@ impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
289289
| Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => {
290290
self.consume_operand(location, operand)
291291
}
292+
Rvalue::VirtualRef(ref place) => {
293+
let op = &Operand::Copy(*place);
294+
self.consume_operand(location, op);
295+
}
292296

293297
Rvalue::Len(place) | Rvalue::Discriminant(place) => {
294298
let af = match *rvalue {

Diff for: compiler/rustc_borrowck/src/lib.rs

+17
Original file line numberDiff line numberDiff line change
@@ -1224,6 +1224,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
12241224
| Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => {
12251225
self.consume_operand(location, (operand, span), flow_state)
12261226
}
1227+
Rvalue::VirtualRef(place) => {
1228+
self.access_place(
1229+
location,
1230+
(place, span),
1231+
(Deep, Read(ReadKind::Copy)),
1232+
LocalMutationIsAllowed::No,
1233+
flow_state,
1234+
);
1235+
1236+
// Finally, check if path was already moved.
1237+
self.check_if_path_or_subpath_is_moved(
1238+
location,
1239+
InitializationRequiringAction::Use,
1240+
(place.as_ref(), span),
1241+
flow_state,
1242+
);
1243+
}
12271244

12281245
Rvalue::Len(place) | Rvalue::Discriminant(place) => {
12291246
let af = match *rvalue {

Diff for: compiler/rustc_borrowck/src/type_check/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -2274,6 +2274,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
22742274
Rvalue::Use(operand) | Rvalue::UnaryOp(_, operand) => {
22752275
self.check_operand(operand, location);
22762276
}
2277+
Rvalue::VirtualRef(place) => {
2278+
let op = &Operand::Copy(*place);
2279+
self.check_operand(op, location);
2280+
}
22772281

22782282
Rvalue::BinaryOp(_, box (left, right))
22792283
| Rvalue::CheckedBinaryOp(_, box (left, right)) => {
@@ -2304,6 +2308,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
23042308
| Rvalue::BinaryOp(..)
23052309
| Rvalue::CheckedBinaryOp(..)
23062310
| Rvalue::NullaryOp(..)
2311+
| Rvalue::VirtualRef(..)
23072312
| Rvalue::UnaryOp(..)
23082313
| Rvalue::Discriminant(..) => None,
23092314

Diff for: compiler/rustc_codegen_cranelift/src/base.rs

+5
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,11 @@ fn codegen_stmt<'tcx>(
503503
let val = codegen_operand(fx, operand);
504504
lval.write_cvalue(fx, val);
505505
}
506+
Rvalue::VirtualRef(place) => {
507+
let cplace = codegen_place(fx, place);
508+
let val = cplace.to_cvalue(fx);
509+
lval.write_cvalue(fx, val)
510+
}
506511
Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
507512
let place = codegen_place(fx, place);
508513
let ref_ = place.place_ref(fx, lval.layout());

Diff for: compiler/rustc_codegen_ssa/src/mir/rvalue.rs

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::traits::*;
88
use crate::MemFlags;
99

1010
use rustc_middle::mir;
11+
use rustc_middle::mir::Operand;
1112
use rustc_middle::ty::cast::{CastTy, IntTy};
1213
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
1314
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt};
@@ -401,6 +402,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
401402
self.codegen_place_to_pointer(bx, place, mk_ref)
402403
}
403404

405+
mir::Rvalue::VirtualRef(place) => {
406+
let operand = self.codegen_operand(&mut bx, &Operand::Copy(place));
407+
(bx, operand)
408+
}
404409
mir::Rvalue::AddressOf(mutability, place) => {
405410
let mk_ptr = move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| {
406411
tcx.mk_ptr(ty::TypeAndMut { ty, mutbl: mutability })
@@ -755,6 +760,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
755760
pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) -> bool {
756761
match *rvalue {
757762
mir::Rvalue::Ref(..) |
763+
mir::Rvalue::VirtualRef(..) |
758764
mir::Rvalue::AddressOf(..) |
759765
mir::Rvalue::Len(..) |
760766
mir::Rvalue::Cast(..) | // (*)

Diff for: compiler/rustc_const_eval/src/interpret/step.rs

+5
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
172172
self.copy_op(&op, &dest)?;
173173
}
174174

175+
VirtualRef(ref place) => {
176+
let op = self.eval_place_to_op(*place, Some(dest.layout))?;
177+
self.copy_op(&op, &dest)?;
178+
}
179+
175180
BinaryOp(bin_op, box (ref left, ref right)) => {
176181
let layout = binop_left_homogeneous(bin_op).then_some(dest.layout);
177182
let left = self.read_immediate(&self.eval_operand(left, layout)?)?;

Diff for: compiler/rustc_const_eval/src/transform/check_consts/check.rs

+1
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
445445
Rvalue::ThreadLocalRef(_) => self.check_op(ops::ThreadLocalAccess),
446446

447447
Rvalue::Use(_)
448+
| Rvalue::VirtualRef(..)
448449
| Rvalue::Repeat(..)
449450
| Rvalue::Discriminant(..)
450451
| Rvalue::Len(_)

Diff for: compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs

+2
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,8 @@ where
260260
in_place::<Q, _>(cx, in_local, place.as_ref())
261261
}
262262

263+
Rvalue::VirtualRef(place) => in_place::<Q, _>(cx, in_local, place.as_ref()),
264+
263265
Rvalue::Use(operand)
264266
| Rvalue::Repeat(operand, _)
265267
| Rvalue::UnaryOp(_, operand)

Diff for: compiler/rustc_const_eval/src/transform/check_consts/resolver.rs

+1
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ where
199199
mir::Rvalue::Cast(..)
200200
| mir::Rvalue::ShallowInitBox(..)
201201
| mir::Rvalue::Use(..)
202+
| mir::Rvalue::VirtualRef(..)
202203
| mir::Rvalue::ThreadLocalRef(..)
203204
| mir::Rvalue::Repeat(..)
204205
| mir::Rvalue::Len(..)

Diff for: compiler/rustc_const_eval/src/transform/promote_consts.rs

+4
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,10 @@ impl<'tcx> Validator<'_, 'tcx> {
494494
Rvalue::Use(operand) | Rvalue::Repeat(operand, _) => {
495495
self.validate_operand(operand)?;
496496
}
497+
Rvalue::VirtualRef(place) => {
498+
let op = &Operand::Copy(*place);
499+
self.validate_operand(op)?
500+
}
497501

498502
Rvalue::Discriminant(place) | Rvalue::Len(place) => {
499503
self.validate_place(place.as_ref())?

Diff for: compiler/rustc_middle/src/mir/mod.rs

+23-3
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ pub enum MirPhase {
159159
/// of the `mir_promoted` query), these promoted elements are available in the `promoted_mir`
160160
/// query.
161161
ConstsPromoted = 2,
162+
/// After this projections may only contain deref projections as the first element.
163+
Derefered = 3,
162164
/// Beginning with this phase, the following variants are disallowed:
163165
/// * [`TerminatorKind::DropAndReplace`](terminator::TerminatorKind::DropAndReplace)
164166
/// * [`TerminatorKind::FalseUnwind`](terminator::TerminatorKind::FalseUnwind)
@@ -173,9 +175,7 @@ pub enum MirPhase {
173175
/// Furthermore, `Drop` now uses explicit drop flags visible in the MIR and reaching a `Drop`
174176
/// terminator means that the auto-generated drop glue will be invoked. Also, `Copy` operands
175177
/// are allowed for non-`Copy` types.
176-
DropsLowered = 3,
177-
/// After this projections may only contain deref projections as the first element.
178-
Derefered = 4,
178+
DropsLowered = 4,
179179
/// Beginning with this phase, the following variant is disallowed:
180180
/// * [`Rvalue::Aggregate`] for any `AggregateKind` except `Array`
181181
///
@@ -1174,6 +1174,15 @@ impl<'tcx> LocalDecl<'tcx> {
11741174
}
11751175
}
11761176

1177+
/// Returns `true` if this is a DerefTemp
1178+
pub fn is_deref_temp(&self) -> bool {
1179+
match self.local_info {
1180+
Some(box LocalInfo::DerefTemp) => return true,
1181+
_ => (),
1182+
}
1183+
return false;
1184+
}
1185+
11771186
/// Returns `true` is the local is from a compiler desugaring, e.g.,
11781187
/// `__next` from a `for` loop.
11791188
#[inline]
@@ -2602,6 +2611,15 @@ pub enum Rvalue<'tcx> {
26022611
/// initialized but its content as uninitialized. Like other pointer casts, this in general
26032612
/// affects alias analysis.
26042613
ShallowInitBox(Operand<'tcx>, Ty<'tcx>),
2614+
2615+
/// A virtual ref is equivalent to a read from a reference/pointer at the
2616+
/// codegen level, but is treated specially by drop elaboration. When such a read happens, it
2617+
/// is guaranteed that the only use of the returned value is a deref operation, immediately
2618+
/// followed by one or more projections. Drop elaboration treats this virtual ref as if the
2619+
/// read never happened and just projects further. This allows simplifying various MIR
2620+
/// optimizations and codegen backends that previously had to handle deref operations anywhere
2621+
/// in a place.
2622+
VirtualRef(Place<'tcx>),
26052623
}
26062624

26072625
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
@@ -2618,6 +2636,7 @@ impl<'tcx> Rvalue<'tcx> {
26182636
Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false,
26192637

26202638
Rvalue::Use(_)
2639+
| Rvalue::VirtualRef(_)
26212640
| Rvalue::Repeat(_, _)
26222641
| Rvalue::Ref(_, _, _)
26232642
| Rvalue::ThreadLocalRef(_)
@@ -2795,6 +2814,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
27952814
};
27962815
write!(fmt, "&{}{}{:?}", region, kind_str, place)
27972816
}
2817+
VirtualRef(ref place) => write!(fmt, "virt {:#?}", place),
27982818

27992819
AddressOf(mutability, ref place) => {
28002820
let kind_str = match mutability {

Diff for: compiler/rustc_middle/src/mir/tcx.rs

+1
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,7 @@ impl<'tcx> Rvalue<'tcx> {
211211
}
212212
},
213213
Rvalue::ShallowInitBox(_, ty) => tcx.mk_box(ty),
214+
Rvalue::VirtualRef(ref place) => place.ty(local_decls, tcx).ty,
214215
}
215216
}
216217

Diff for: compiler/rustc_middle/src/mir/type_foldable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
184184
Ref(region, bk, place) => {
185185
Ref(region.try_fold_with(folder)?, bk, place.try_fold_with(folder)?)
186186
}
187+
VirtualRef(place) => VirtualRef(place.try_fold_with(folder)?),
187188
AddressOf(mutability, place) => AddressOf(mutability, place.try_fold_with(folder)?),
188189
Len(place) => Len(place.try_fold_with(folder)?),
189190
Cast(kind, op, ty) => Cast(kind, op.try_fold_with(folder)?, ty.try_fold_with(folder)?),
@@ -235,6 +236,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
235236
region.visit_with(visitor)?;
236237
place.visit_with(visitor)
237238
}
239+
VirtualRef(ref place) => place.visit_with(visitor),
238240
AddressOf(_, ref place) => place.visit_with(visitor),
239241
Len(ref place) => place.visit_with(visitor),
240242
Cast(_, ref op, ty) => {

Diff for: compiler/rustc_middle/src/mir/visit.rs

+7
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,13 @@ macro_rules! make_mir_visitor {
670670
};
671671
self.visit_place(path, ctx, location);
672672
}
673+
Rvalue::VirtualRef(place) => {
674+
self.visit_place(
675+
place,
676+
PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
677+
location
678+
);
679+
}
673680

674681
Rvalue::AddressOf(m, path) => {
675682
let ctx = match m {

Diff for: compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ where
102102
| mir::Rvalue::NullaryOp(..)
103103
| mir::Rvalue::UnaryOp(..)
104104
| mir::Rvalue::Discriminant(..)
105-
| mir::Rvalue::Aggregate(..) => {}
105+
| mir::Rvalue::Aggregate(..)
106+
| mir::Rvalue::VirtualRef(..) => {}
106107
}
107108
}
108109

Diff for: compiler/rustc_mir_dataflow/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ pub mod impls;
3838
pub mod move_paths;
3939
pub mod rustc_peek;
4040
pub mod storage;
41+
pub mod un_derefer;
4142

4243
pub(crate) mod indexes {
4344
pub(crate) use super::move_paths::MovePathIndex;

Diff for: compiler/rustc_mir_dataflow/src/move_paths/builder.rs

+27-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::un_derefer::UnDerefer;
12
use rustc_index::vec::IndexVec;
23
use rustc_middle::mir::tcx::RvalueInitializationState;
34
use rustc_middle::mir::*;
@@ -19,6 +20,7 @@ struct MoveDataBuilder<'a, 'tcx> {
1920
param_env: ty::ParamEnv<'tcx>,
2021
data: MoveData<'tcx>,
2122
errors: Vec<(Place<'tcx>, MoveError<'tcx>)>,
23+
un_derefer: UnDerefer<'tcx>,
2224
}
2325

2426
impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
@@ -32,6 +34,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
3234
tcx,
3335
param_env,
3436
errors: Vec::new(),
37+
un_derefer: UnDerefer { tcx: tcx, derefer_sidetable: Default::default() },
3538
data: MoveData {
3639
moves: IndexVec::new(),
3740
loc_map: LocationMap::new(body),
@@ -94,6 +97,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
9497
///
9598
/// Maybe we should have separate "borrowck" and "moveck" modes.
9699
fn move_path_for(&mut self, place: Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
100+
if let Some(new_place) = self.builder.un_derefer.derefer(place.as_ref()) {
101+
return self.move_path_for(new_place);
102+
}
103+
97104
debug!("lookup({:?})", place);
98105
let mut base = self.builder.data.rev_lookup.locals[place.local];
99106

@@ -224,6 +231,8 @@ pub(super) fn gather_moves<'tcx>(
224231
param_env: ty::ParamEnv<'tcx>,
225232
) -> Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> {
226233
let mut builder = MoveDataBuilder::new(body, tcx, param_env);
234+
let mut un_derefer = UnDerefer { tcx: tcx, derefer_sidetable: Default::default() };
235+
un_derefer.ref_finder(body);
227236

228237
builder.gather_args();
229238

@@ -276,6 +285,10 @@ struct Gatherer<'b, 'a, 'tcx> {
276285
impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
277286
fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
278287
match &stmt.kind {
288+
StatementKind::Assign(box (place, Rvalue::VirtualRef(reffed))) => {
289+
assert!(place.projection.is_empty());
290+
self.builder.un_derefer.derefer_sidetable.insert(place.local, *reffed);
291+
}
279292
StatementKind::Assign(box (place, rval)) => {
280293
self.create_move_path(*place);
281294
if let RvalueInitializationState::Shallow = rval.initialization_state() {
@@ -294,7 +307,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
294307
}
295308
StatementKind::StorageLive(_) => {}
296309
StatementKind::StorageDead(local) => {
297-
self.gather_move(Place::from(*local));
310+
// DerefTemp locals (results of VirtualRef) don't actually move anything.
311+
if !self.builder.un_derefer.derefer_sidetable.contains_key(&local) {
312+
self.gather_move(Place::from(*local));
313+
}
298314
}
299315
StatementKind::SetDiscriminant { .. } | StatementKind::Deinit(..) => {
300316
span_bug!(
@@ -328,6 +344,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
328344
self.gather_operand(operand);
329345
}
330346
}
347+
Rvalue::VirtualRef(..) => unreachable!(),
331348
Rvalue::Ref(..)
332349
| Rvalue::AddressOf(..)
333350
| Rvalue::Discriminant(..)
@@ -439,6 +456,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
439456

440457
fn gather_move(&mut self, place: Place<'tcx>) {
441458
debug!("gather_move({:?}, {:?})", self.loc, place);
459+
if let Some(new_place) = self.builder.un_derefer.derefer(place.as_ref()) {
460+
self.gather_move(new_place);
461+
return;
462+
}
442463

443464
if let [ref base @ .., ProjectionElem::Subslice { from, to, from_end: false }] =
444465
**place.projection
@@ -494,6 +515,11 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
494515
fn gather_init(&mut self, place: PlaceRef<'tcx>, kind: InitKind) {
495516
debug!("gather_init({:?}, {:?})", self.loc, place);
496517

518+
if let Some(new_place) = self.builder.un_derefer.derefer(place) {
519+
self.gather_init(new_place.as_ref(), kind);
520+
return;
521+
}
522+
497523
let mut place = place;
498524

499525
// Check if we are assigning into a field of a union, if so, lookup the place

Diff for: compiler/rustc_mir_dataflow/src/un_derefer.rs

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use rustc_data_structures::stable_map::FxHashMap;
2+
use rustc_middle::mir::*;
3+
use rustc_middle::ty::TyCtxt;
4+
5+
/// Used for reverting changes made by `DerefSeparator`
6+
pub struct UnDerefer<'tcx> {
7+
pub tcx: TyCtxt<'tcx>,
8+
pub derefer_sidetable: FxHashMap<Local, Place<'tcx>>,
9+
}
10+
11+
impl<'tcx> UnDerefer<'tcx> {
12+
pub fn derefer(&self, place: PlaceRef<'tcx>) -> Option<Place<'tcx>> {
13+
let reffed = self.derefer_sidetable.get(&place.local)?;
14+
15+
let new_place = reffed.project_deeper(place.projection, self.tcx);
16+
Some(new_place)
17+
}
18+
19+
pub fn ref_finder(&mut self, body: &Body<'tcx>) {
20+
for (_bb, data) in body.basic_blocks().iter_enumerated() {
21+
for stmt in data.statements.iter() {
22+
match stmt.kind {
23+
StatementKind::Assign(box (place, Rvalue::VirtualRef(reffed))) => {
24+
self.derefer_sidetable.insert(place.local, reffed);
25+
}
26+
_ => (),
27+
}
28+
}
29+
}
30+
}
31+
}

0 commit comments

Comments
 (0)