Skip to content

Commit c4e8ab9

Browse files
committed
MultipleReturnTerminators + SingleReturnTerminator
MultipleReturnTerminators is maybe good for us but bad for LLVM. So this enables MultipleReturnTerminators and runs a SingleReturnTerminator pass at the end of optimizations.
1 parent 61a415b commit c4e8ab9

8 files changed

+88
-16
lines changed

compiler/rustc_mir_transform/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ mod required_consts;
8686
mod reveal_all;
8787
mod separate_const_switch;
8888
mod shim;
89+
mod single_return_terminator;
8990
// This pass is public to allow external drivers to perform MIR cleanup
9091
pub mod simplify;
9192
mod simplify_branches;
@@ -577,7 +578,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
577578
&o1(simplify::SimplifyCfg::new("final")),
578579
&nrvo::RenameReturnPlace,
579580
&simplify::SimplifyLocals::new("final"),
580-
&multiple_return_terminators::MultipleReturnTerminators,
581+
&single_return_terminator::SingleReturnTerminator,
581582
&deduplicate_blocks::DeduplicateBlocks,
582583
// Some cleanup necessary at least for LLVM and potentially other codegen backends.
583584
&add_call_guards::CriticalCallEdges,

compiler/rustc_mir_transform/src/multiple_return_terminators.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pub struct MultipleReturnTerminators;
1010

1111
impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators {
1212
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
13-
sess.mir_opt_level() >= 4
13+
sess.mir_opt_level() >= 1
1414
}
1515

1616
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
@@ -26,14 +26,15 @@ impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators {
2626
}
2727
}
2828

29-
for bb in bbs {
29+
for bb in 0..bbs.len() {
30+
let bb = bb.into();
3031
if !tcx.consider_optimizing(|| format!("MultipleReturnTerminators {:?} ", def_id)) {
3132
break;
3233
}
3334

34-
if let TerminatorKind::Goto { target } = bb.terminator().kind {
35+
if let TerminatorKind::Goto { target } = bbs[bb].terminator().kind {
3536
if bbs_simple_returns.contains(target) {
36-
bb.terminator_mut().kind = TerminatorKind::Return;
37+
*bbs[bb].terminator_mut() = bbs[target].terminator().clone();
3738
}
3839
}
3940
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
use crate::MirPass;
2+
use rustc_middle::mir::*;
3+
use rustc_middle::ty::TyCtxt;
4+
5+
use super::simplify::simplify_cfg;
6+
7+
pub struct SingleReturnTerminator;
8+
9+
impl<'tcx> MirPass<'tcx> for SingleReturnTerminator {
10+
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
11+
sess.mir_opt_level() >= 1
12+
}
13+
14+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
15+
let mut returns = 0;
16+
let mut return_terminator = None;
17+
let mut return_block = None;
18+
let mut has_extra_return_blocks = false;
19+
20+
for (block, block_data) in body.basic_blocks.iter_enumerated() {
21+
let terminator = block_data.terminator();
22+
if let TerminatorKind::Return = terminator.kind {
23+
return_terminator = Some(terminator.clone());
24+
returns += 1;
25+
if block_data.statements.is_empty() {
26+
if return_block.is_some() {
27+
has_extra_return_blocks = true;
28+
} else {
29+
return_block = Some(block);
30+
}
31+
}
32+
}
33+
}
34+
35+
if returns < 2 {
36+
return;
37+
}
38+
assert!(return_terminator.is_some());
39+
40+
let return_block = return_block.unwrap_or_else(|| {
41+
body.basic_blocks_mut().push(BasicBlockData::new(return_terminator))
42+
});
43+
44+
for (bb, block) in body.basic_blocks_mut().iter_enumerated_mut() {
45+
if bb == return_block {
46+
continue;
47+
}
48+
let terminator = block.terminator_mut();
49+
if let TerminatorKind::Return = terminator.kind {
50+
terminator.kind = TerminatorKind::Goto { target: return_block };
51+
}
52+
}
53+
54+
if has_extra_return_blocks {
55+
simplify_cfg(tcx, body);
56+
}
57+
}
58+
}

tests/mir-opt/76803_regression.encode.SimplifyBranchSame.diff

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,12 @@
1313

1414
bb1: {
1515
_0 = move _1; // scope 0 at $DIR/76803_regression.rs:+3:14: +3:15
16-
goto -> bb3; // scope 0 at $DIR/76803_regression.rs:+3:14: +3:15
16+
return; // scope 0 at $DIR/76803_regression.rs:+5:2: +5:2
1717
}
1818

1919
bb2: {
2020
Deinit(_0); // scope 0 at $DIR/76803_regression.rs:+2:20: +2:27
2121
discriminant(_0) = 1; // scope 0 at $DIR/76803_regression.rs:+2:20: +2:27
22-
goto -> bb3; // scope 0 at $DIR/76803_regression.rs:+2:20: +2:27
23-
}
24-
25-
bb3: {
2622
return; // scope 0 at $DIR/76803_regression.rs:+5:2: +5:2
2723
}
2824
}

tests/mir-opt/inline/inline_generator.main.Inline.diff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@
111111
+ discriminant(_1) = 0; // scope 6 at $DIR/inline_generator.rs:15:11: 15:39
112112
+ _11 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:11: 15:39
113113
+ discriminant((*_11)) = 3; // scope 6 at $DIR/inline_generator.rs:15:11: 15:39
114-
+ goto -> bb1; // scope 0 at $DIR/inline_generator.rs:15:11: 15:39
114+
+ goto -> bb1; // scope 6 at $DIR/inline_generator.rs:15:11: 15:39
115115
+ }
116116
+
117117
+ bb7: {
@@ -122,7 +122,7 @@
122122
+ discriminant(_1) = 1; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
123123
+ _12 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
124124
+ discriminant((*_12)) = 1; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
125-
+ goto -> bb1; // scope 0 at $DIR/inline_generator.rs:15:41: 15:41
125+
+ goto -> bb1; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
126126
+ }
127127
+
128128
+ bb8: {

tests/mir-opt/multiple_return_terminators.test.MultipleReturnTerminators.diff

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,16 @@
44
fn test(_1: bool) -> () {
55
debug x => _1; // in scope 0 at $DIR/multiple_return_terminators.rs:+0:9: +0:10
66
let mut _0: (); // return place in scope 0 at $DIR/multiple_return_terminators.rs:+0:18: +0:18
7+
let mut _2: bool; // in scope 0 at $DIR/multiple_return_terminators.rs:+1:8: +1:9
8+
let mut _3: bool; // in scope 0 at $DIR/multiple_return_terminators.rs:+1:8: +1:9
79

810
bb0: {
11+
StorageLive(_2); // scope 0 at $DIR/multiple_return_terminators.rs:+1:8: +1:9
12+
_2 = _1; // scope 0 at $DIR/multiple_return_terminators.rs:+1:8: +1:9
13+
StorageLive(_3); // scope 0 at $DIR/multiple_return_terminators.rs:+1:8: +1:9
14+
_3 = move _2; // scope 0 at $DIR/multiple_return_terminators.rs:+1:8: +1:9
15+
StorageDead(_3); // scope 0 at $DIR/multiple_return_terminators.rs:+1:8: +1:9
16+
StorageDead(_2); // scope 0 at $DIR/multiple_return_terminators.rs:+5:5: +5:6
917
return; // scope 0 at $DIR/multiple_return_terminators.rs:+6:2: +6:2
1018
}
1119
}

tests/mir-opt/try_identity_e2e.new.PreCodegen.after.mir

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ fn new(_1: Result<T, E>) -> Result<T, E> {
5353
((_0 as Err).0: E) = move _8; // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51
5454
discriminant(_0) = 1; // scope 4 at $DIR/try_identity_e2e.rs:+9:45: +9:51
5555
StorageDead(_2); // scope 0 at $DIR/try_identity_e2e.rs:+12:1: +12:2
56-
return; // scope 0 at $DIR/try_identity_e2e.rs:+12:1: +12:2
56+
goto -> bb6; // scope 0 at $DIR/try_identity_e2e.rs:+12:2: +12:2
5757
}
5858

5959
bb4: {
@@ -66,6 +66,10 @@ fn new(_1: Result<T, E>) -> Result<T, E> {
6666
((_0 as Ok).0: T) = move _7; // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6
6767
discriminant(_0) = 0; // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +11:6
6868
StorageDead(_2); // scope 0 at $DIR/try_identity_e2e.rs:+12:1: +12:2
69-
return; // scope 0 at $DIR/try_identity_e2e.rs:+12:1: +12:2
69+
goto -> bb6; // scope 0 at $DIR/try_identity_e2e.rs:+12:2: +12:2
70+
}
71+
72+
bb6: {
73+
return; // scope 0 at $DIR/try_identity_e2e.rs:+12:2: +12:2
7074
}
7175
}

tests/mir-opt/try_identity_e2e.old.PreCodegen.after.mir

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ fn old(_1: Result<T, E>) -> Result<T, E> {
2323
Deinit(_0); // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36
2424
((_0 as Err).0: E) = move _4; // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36
2525
discriminant(_0) = 1; // scope 2 at $DIR/try_identity_e2e.rs:+4:30: +4:36
26-
return; // scope 0 at $DIR/try_identity_e2e.rs:+7:1: +7:2
26+
goto -> bb4; // scope 0 at $DIR/try_identity_e2e.rs:+7:2: +7:2
2727
}
2828

2929
bb2: {
@@ -35,6 +35,10 @@ fn old(_1: Result<T, E>) -> Result<T, E> {
3535
Deinit(_0); // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6
3636
((_0 as Ok).0: T) = move _3; // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6
3737
discriminant(_0) = 0; // scope 0 at $DIR/try_identity_e2e.rs:+1:5: +6:6
38-
return; // scope 0 at $DIR/try_identity_e2e.rs:+7:1: +7:2
38+
goto -> bb4; // scope 0 at $DIR/try_identity_e2e.rs:+7:2: +7:2
39+
}
40+
41+
bb4: {
42+
return; // scope 0 at $DIR/try_identity_e2e.rs:+7:2: +7:2
3943
}
4044
}

0 commit comments

Comments
 (0)