Skip to content

Commit 9e5c064

Browse files
committed
Put entry block at the end instead of shifting everything.
1 parent 3b77583 commit 9e5c064

23 files changed

Lines changed: 1964 additions & 1465 deletions

compiler/rustc_mir_transform/src/coroutine.rs

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,31 +1077,42 @@ fn compute_layout<'tcx>(
10771077
/// Replaces the entry point of `body` with a block that switches on the coroutine discriminant and
10781078
/// dispatches to blocks according to `cases`.
10791079
///
1080-
/// After this function, the former entry point of the function will be bb1.
1080+
/// After this function, the former entry point of the function will be the last block.
10811081
fn insert_switch<'tcx>(
10821082
body: &mut Body<'tcx>,
10831083
cases: Vec<(usize, BasicBlock)>,
10841084
transform: &TransformVisitor<'tcx>,
10851085
default_block: BasicBlock,
10861086
) {
10871087
let (assign, discr) = transform.get_discr(body);
1088-
let switch_targets =
1089-
SwitchTargets::new(cases.iter().map(|(i, bb)| ((*i) as u128, *bb)), default_block);
1090-
let switch = TerminatorKind::SwitchInt { discr: Operand::Move(discr), targets: switch_targets };
10911088

1092-
let source_info = SourceInfo::outermost(body.span);
1093-
body.basic_blocks_mut().raw.insert(
1094-
0,
1095-
BasicBlockData::new_stmts(
1096-
vec![assign],
1097-
Some(Terminator { source_info, kind: switch }),
1098-
false,
1099-
),
1089+
// MIR validation ensures that no block targets `ENTRY_BLOCK`.
1090+
#[cfg(debug_assertions)]
1091+
for bb in body.basic_blocks.iter() {
1092+
for target in bb.terminator().successors() {
1093+
assert_ne!(target, START_BLOCK);
1094+
}
1095+
}
1096+
1097+
// Add the switch as entry block, and put the former entry block at the end.
1098+
let former_entry = std::mem::replace(
1099+
&mut body.basic_blocks_mut()[START_BLOCK],
1100+
BasicBlockData::new_stmts(vec![assign], None, false),
11001101
);
1102+
let former_entry = body.basic_blocks_mut().push(former_entry);
11011103

1102-
for b in body.basic_blocks_mut().iter_mut() {
1103-
b.terminator_mut().successors_mut(|target| *target += 1);
1104+
// We may point to `START_BLOCK` in our `cases`, replace it with `former_entry`.
1105+
let mut switch_targets =
1106+
SwitchTargets::new(cases.iter().map(|(i, bb)| ((*i) as u128, *bb)), default_block);
1107+
for bb in switch_targets.all_targets_mut() {
1108+
if *bb == START_BLOCK {
1109+
*bb = former_entry;
1110+
}
11041111
}
1112+
1113+
let switch = TerminatorKind::SwitchInt { discr: Operand::Move(discr), targets: switch_targets };
1114+
body.basic_blocks_mut()[START_BLOCK].terminator =
1115+
Some(Terminator { source_info: SourceInfo::outermost(body.span), kind: switch });
11051116
}
11061117

11071118
fn insert_term_block<'tcx>(body: &mut Body<'tcx>, kind: TerminatorKind<'tcx>) -> BasicBlock {
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
- // MIR for `a::{closure#0}` before StateTransform
2+
+ // MIR for `a::{closure#0}` after StateTransform
3+
4+
- fn a::{closure#0}(_1: {async fn body of a()}, _2: std::future::ResumeTy) -> ()
5+
- yields ()
6+
- {
7+
+ fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>) -> Poll<()> {
8+
+ coroutine layout {
9+
+ variant_fields = {
10+
+ Unresumed(0): [],
11+
+ Returned (1): [],
12+
+ Panicked (2): [],
13+
+ }
14+
+ storage_conflicts = BitMatrix(0x0) {}
15+
+ }
16+
debug _task_context => _2;
17+
- let mut _0: ();
18+
+ let mut _0: std::task::Poll<()>;
19+
+ let mut _3: ();
20+
+ let mut _4: u32;
21+
+ let mut _5: &mut {async fn body of a()};
22+
23+
bb0: {
24+
- _0 = const ();
25+
- drop(_1) -> [return: bb1, unwind: bb2];
26+
+ _5 = copy (_1.0: &mut {async fn body of a()});
27+
+ _4 = discriminant((*_5));
28+
+ switchInt(move _4) -> [0: bb5, 1: bb3, otherwise: bb4];
29+
}
30+
31+
bb1: {
32+
+ _0 = Poll::<()>::Ready(move _3);
33+
+ discriminant((*_5)) = 1;
34+
return;
35+
}
36+
37+
- bb2 (cleanup): {
38+
- resume;
39+
+ bb2: {
40+
+ goto -> bb1;
41+
+ }
42+
+
43+
+ bb3: {
44+
+ assert(const false, "`async fn` resumed after completion") -> [success: bb3, unwind continue];
45+
+ }
46+
+
47+
+ bb4: {
48+
+ unreachable;
49+
+ }
50+
+
51+
+ bb5: {
52+
+ _3 = const ();
53+
+ goto -> bb2;
54+
}
55+
}
56+

tests/mir-opt/coroutine/async_await.a-{closure#0}.coroutine_resume.0.mir

Lines changed: 0 additions & 46 deletions
This file was deleted.

0 commit comments

Comments
 (0)