Skip to content

Commit 6d800ae

Browse files
committed
Renumber locals after state transform.
1 parent 1ad657e commit 6d800ae

File tree

3 files changed

+75
-65
lines changed

3 files changed

+75
-65
lines changed

compiler/rustc_mir_transform/src/coroutine.rs

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ use rustc_hir::lang_items::LangItem;
6868
use rustc_hir::{CoroutineDesugaring, CoroutineKind};
6969
use rustc_index::bit_set::{BitMatrix, DenseBitSet, GrowableBitSet};
7070
use rustc_index::{Idx, IndexVec};
71-
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
71+
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
7272
use rustc_middle::mir::*;
7373
use rustc_middle::ty::util::Discr;
7474
use rustc_middle::ty::{
@@ -110,6 +110,8 @@ impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor<'tcx> {
110110
fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) {
111111
if *local == self.from {
112112
*local = self.to;
113+
} else if *local == self.to {
114+
*local = self.from;
113115
}
114116
}
115117

@@ -206,8 +208,8 @@ struct TransformVisitor<'tcx> {
206208
// The set of locals that have no `StorageLive`/`StorageDead` annotations.
207209
always_live_locals: DenseBitSet<Local>,
208210

209-
// The original RETURN_PLACE local
210-
old_ret_local: Local,
211+
// New local we just create to hold the `CoroutineState` value.
212+
new_ret_local: Local,
211213

212214
old_yield_ty: Ty<'tcx>,
213215

@@ -344,9 +346,10 @@ impl<'tcx> TransformVisitor<'tcx> {
344346
}
345347
};
346348

349+
// Assign to `new_ret_local`, which will be replaced by `RETURN_PLACE` later.
347350
statements.push(Statement::new(
348351
source_info,
349-
StatementKind::Assign(Box::new((Place::return_place(), rvalue))),
352+
StatementKind::Assign(Box::new((self.new_ret_local.into(), rvalue))),
350353
));
351354
}
352355

@@ -388,6 +391,20 @@ impl<'tcx> TransformVisitor<'tcx> {
388391
);
389392
(assign, temp)
390393
}
394+
395+
/// Swaps all references of `old_local` and `new_local`.
396+
#[tracing::instrument(level = "trace", skip(self, body))]
397+
fn replace_local(&mut self, old_local: Local, new_local: Local, body: &mut Body<'tcx>) {
398+
body.local_decls.swap(old_local, new_local);
399+
400+
let mut visitor = RenameLocalVisitor { from: old_local, to: new_local, tcx: self.tcx };
401+
visitor.visit_body(body);
402+
for suspension in &mut self.suspension_points {
403+
let ctxt = PlaceContext::MutatingUse(MutatingUseContext::Yield);
404+
let location = Location { block: START_BLOCK, statement_index: 0 };
405+
visitor.visit_place(&mut suspension.resume_arg, ctxt, location);
406+
}
407+
}
391408
}
392409

393410
impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
@@ -419,14 +436,24 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
419436
self.super_statement(stmt, location);
420437
}
421438

439+
#[tracing::instrument(level = "trace", skip(self, term), ret)]
440+
fn visit_terminator(&mut self, term: &mut Terminator<'tcx>, location: Location) {
441+
if let TerminatorKind::Return = term.kind {
442+
// `visit_basic_block_data` introduces `Return` terminators which read `RETURN_PLACE`.
443+
// But this `RETURN_PLACE` is already remapped, so we should not touch it again.
444+
return;
445+
}
446+
self.super_terminator(term, location);
447+
}
448+
422449
#[tracing::instrument(level = "trace", skip(self, data), ret)]
423450
fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
424451
match data.terminator().kind {
425452
TerminatorKind::Return => {
426453
let source_info = data.terminator().source_info;
427454
// We must assign the value first in case it gets declared dead below
428455
self.make_state(
429-
Operand::Move(Place::from(self.old_ret_local)),
456+
Operand::Move(Place::return_place()),
430457
source_info,
431458
true,
432459
&mut data.statements,
@@ -521,27 +548,6 @@ fn make_coroutine_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body
521548
.visit_body(body);
522549
}
523550

524-
/// Allocates a new local and replaces all references of `local` with it. Returns the new local.
525-
///
526-
/// `local` will be changed to a new local decl with type `ty`.
527-
///
528-
/// Note that the new local will be uninitialized. It is the caller's responsibility to assign some
529-
/// valid value to it before its first use.
530-
fn replace_local<'tcx>(
531-
local: Local,
532-
ty: Ty<'tcx>,
533-
body: &mut Body<'tcx>,
534-
tcx: TyCtxt<'tcx>,
535-
) -> Local {
536-
let new_decl = LocalDecl::new(ty, body.span);
537-
let new_local = body.local_decls.push(new_decl);
538-
body.local_decls.swap(local, new_local);
539-
540-
RenameLocalVisitor { from: local, to: new_local, tcx }.visit_body(body);
541-
542-
new_local
543-
}
544-
545551
/// Transforms the `body` of the coroutine applying the following transforms:
546552
///
547553
/// - Eliminates all the `get_context` calls that async lowering created.
@@ -1511,10 +1517,6 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
15111517
}
15121518
};
15131519

1514-
// We rename RETURN_PLACE which has type mir.return_ty to old_ret_local
1515-
// RETURN_PLACE then is a fresh unused local with type ret_ty.
1516-
let old_ret_local = replace_local(RETURN_PLACE, new_ret_ty, body, tcx);
1517-
15181520
// We need to insert clean drop for unresumed state and perform drop elaboration
15191521
// (finally in open_drop_for_tuple) before async drop expansion.
15201522
// Async drops, produced by this drop elaboration, will be expanded,
@@ -1561,6 +1563,11 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
15611563

15621564
let can_return = can_return(tcx, body, body.typing_env(tcx));
15631565

1566+
// We rename RETURN_PLACE which has type mir.return_ty to new_ret_local
1567+
// RETURN_PLACE then is a fresh unused local with type ret_ty.
1568+
let new_ret_local = body.local_decls.push(LocalDecl::new(new_ret_ty, body.span));
1569+
tracing::trace!(?new_ret_local);
1570+
15641571
// Run the transformation which converts Places from Local to coroutine struct
15651572
// accesses for locals in `remap`.
15661573
// It also rewrites `return x` and `yield y` as writing a new coroutine state and returning
@@ -1573,13 +1580,16 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
15731580
storage_liveness,
15741581
always_live_locals,
15751582
suspension_points: Vec::new(),
1576-
old_ret_local,
15771583
discr_ty,
1584+
new_ret_local,
15781585
old_ret_ty,
15791586
old_yield_ty,
15801587
};
15811588
transform.visit_body(body);
15821589

1590+
// Swap the actual `RETURN_PLACE` and the provisional `new_ret_local`.
1591+
transform.replace_local(RETURN_PLACE, new_ret_local, body);
1592+
15831593
// MIR parameters are not explicitly assigned-to when entering the MIR body.
15841594
// If we want to save their values inside the coroutine state, we need to do so explicitly.
15851595
let source_info = SourceInfo::outermost(body.span);

tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-abort.mir

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a<T>()}>, _2: &mut Context<'_>)
1010
let mut _6: std::pin::Pin<&mut T>;
1111
let mut _7: &mut T;
1212
let mut _8: *mut T;
13-
let mut _9: ();
14-
let mut _10: std::task::Poll<()>;
15-
let mut _11: &mut std::task::Context<'_>;
16-
let mut _12: &mut impl std::future::Future<Output = ()>;
17-
let mut _13: std::pin::Pin<&mut impl std::future::Future<Output = ()>>;
18-
let mut _14: isize;
19-
let mut _15: &mut std::task::Context<'_>;
20-
let mut _16: &mut impl std::future::Future<Output = ()>;
21-
let mut _17: std::pin::Pin<&mut impl std::future::Future<Output = ()>>;
22-
let mut _18: isize;
13+
let mut _9: std::task::Poll<()>;
14+
let mut _10: &mut std::task::Context<'_>;
15+
let mut _11: &mut impl std::future::Future<Output = ()>;
16+
let mut _12: std::pin::Pin<&mut impl std::future::Future<Output = ()>>;
17+
let mut _13: isize;
18+
let mut _14: &mut std::task::Context<'_>;
19+
let mut _15: &mut impl std::future::Future<Output = ()>;
20+
let mut _16: std::pin::Pin<&mut impl std::future::Future<Output = ()>>;
21+
let mut _17: isize;
22+
let mut _18: ();
2323
let mut _19: u32;
2424
scope 1 {
2525
debug x => (((*(_1.0: &mut {async fn body of a<T>()})) as variant#4).0: T);
@@ -48,23 +48,23 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a<T>()}>, _2: &mut Context<'_>)
4848
}
4949

5050
bb4: {
51-
StorageLive(_17);
52-
_16 = &mut (((*(_1.0: &mut {async fn body of a<T>()})) as variant#4).1: impl std::future::Future<Output = ()>);
53-
_17 = Pin::<&mut impl Future<Output = ()>>::new_unchecked(move _16) -> [return: bb7, unwind unreachable];
51+
StorageLive(_16);
52+
_15 = &mut (((*(_1.0: &mut {async fn body of a<T>()})) as variant#4).1: impl std::future::Future<Output = ()>);
53+
_16 = Pin::<&mut impl Future<Output = ()>>::new_unchecked(move _15) -> [return: bb7, unwind unreachable];
5454
}
5555

5656
bb5: {
5757
unreachable;
5858
}
5959

6060
bb6: {
61-
StorageDead(_17);
62-
_18 = discriminant(_10);
63-
switchInt(move _18) -> [0: bb1, 1: bb3, otherwise: bb5];
61+
StorageDead(_16);
62+
_17 = discriminant(_9);
63+
switchInt(move _17) -> [0: bb1, 1: bb3, otherwise: bb5];
6464
}
6565

6666
bb7: {
67-
_10 = <impl Future<Output = ()> as Future>::poll(move _17, move _15) -> [return: bb6, unwind unreachable];
67+
_9 = <impl Future<Output = ()> as Future>::poll(move _16, move _14) -> [return: bb6, unwind unreachable];
6868
}
6969

7070
bb8: {

tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-unwind.mir

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a<T>()}>, _2: &mut Context<'_>)
1010
let mut _6: std::pin::Pin<&mut T>;
1111
let mut _7: &mut T;
1212
let mut _8: *mut T;
13-
let mut _9: ();
14-
let mut _10: std::task::Poll<()>;
15-
let mut _11: &mut std::task::Context<'_>;
16-
let mut _12: &mut impl std::future::Future<Output = ()>;
17-
let mut _13: std::pin::Pin<&mut impl std::future::Future<Output = ()>>;
18-
let mut _14: isize;
19-
let mut _15: &mut std::task::Context<'_>;
20-
let mut _16: &mut impl std::future::Future<Output = ()>;
21-
let mut _17: std::pin::Pin<&mut impl std::future::Future<Output = ()>>;
22-
let mut _18: isize;
13+
let mut _9: std::task::Poll<()>;
14+
let mut _10: &mut std::task::Context<'_>;
15+
let mut _11: &mut impl std::future::Future<Output = ()>;
16+
let mut _12: std::pin::Pin<&mut impl std::future::Future<Output = ()>>;
17+
let mut _13: isize;
18+
let mut _14: &mut std::task::Context<'_>;
19+
let mut _15: &mut impl std::future::Future<Output = ()>;
20+
let mut _16: std::pin::Pin<&mut impl std::future::Future<Output = ()>>;
21+
let mut _17: isize;
22+
let mut _18: ();
2323
let mut _19: u32;
2424
scope 1 {
2525
debug x => (((*(_1.0: &mut {async fn body of a<T>()})) as variant#4).0: T);
@@ -62,23 +62,23 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a<T>()}>, _2: &mut Context<'_>)
6262
}
6363

6464
bb7: {
65-
StorageLive(_17);
66-
_16 = &mut (((*(_1.0: &mut {async fn body of a<T>()})) as variant#4).1: impl std::future::Future<Output = ()>);
67-
_17 = Pin::<&mut impl Future<Output = ()>>::new_unchecked(move _16) -> [return: bb10, unwind: bb15];
65+
StorageLive(_16);
66+
_15 = &mut (((*(_1.0: &mut {async fn body of a<T>()})) as variant#4).1: impl std::future::Future<Output = ()>);
67+
_16 = Pin::<&mut impl Future<Output = ()>>::new_unchecked(move _15) -> [return: bb10, unwind: bb15];
6868
}
6969

7070
bb8: {
7171
unreachable;
7272
}
7373

7474
bb9: {
75-
StorageDead(_17);
76-
_18 = discriminant(_10);
77-
switchInt(move _18) -> [0: bb1, 1: bb6, otherwise: bb8];
75+
StorageDead(_16);
76+
_17 = discriminant(_9);
77+
switchInt(move _17) -> [0: bb1, 1: bb6, otherwise: bb8];
7878
}
7979

8080
bb10: {
81-
_10 = <impl Future<Output = ()> as Future>::poll(move _17, move _15) -> [return: bb9, unwind: bb3];
81+
_9 = <impl Future<Output = ()> as Future>::poll(move _16, move _14) -> [return: bb9, unwind: bb3];
8282
}
8383

8484
bb11: {

0 commit comments

Comments
 (0)