Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 69665ae

Browse files
committedMar 6, 2020
Auto merge of #69756 - wesleywiser:simplify_try, r=<try>
[WIP] Modify SimplifyArmIdentity so it can trigger on mir-opt-level=1 r? @ghost
2 parents b818ccc + b5238fb commit 69665ae

File tree

4 files changed

+299
-80
lines changed

4 files changed

+299
-80
lines changed
 

‎src/librustc_mir/transform/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,12 +311,12 @@ fn run_optimization_passes<'tcx>(
311311
&const_prop::ConstProp,
312312
&simplify_branches::SimplifyBranches::new("after-const-prop"),
313313
&deaggregator::Deaggregator,
314+
&simplify_try::SimplifyArmIdentity,
315+
&simplify_try::SimplifyBranchSame,
314316
&copy_prop::CopyPropagation,
315317
&simplify_branches::SimplifyBranches::new("after-copy-prop"),
316318
&remove_noop_landing_pads::RemoveNoopLandingPads,
317319
&simplify::SimplifyCfg::new("after-remove-noop-landing-pads"),
318-
&simplify_try::SimplifyArmIdentity,
319-
&simplify_try::SimplifyBranchSame,
320320
&simplify::SimplifyCfg::new("final"),
321321
&simplify::SimplifyLocals,
322322
&add_call_guards::CriticalCallEdges,

‎src/librustc_mir/transform/simplify_try.rs

Lines changed: 204 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::transform::{simplify, MirPass, MirSource};
1313
use itertools::Itertools as _;
1414
use rustc::mir::*;
1515
use rustc::ty::{Ty, TyCtxt};
16+
use rustc_index::vec::IndexVec;
1617
use rustc_target::abi::VariantIdx;
1718

1819
/// Simplifies arms of form `Variant(x) => Variant(x)` to just a move.
@@ -21,7 +22,8 @@ use rustc_target::abi::VariantIdx;
2122
///
2223
/// ```rust
2324
/// _LOCAL_TMP = ((_LOCAL_1 as Variant ).FIELD: TY );
24-
/// ((_LOCAL_0 as Variant).FIELD: TY) = move _LOCAL_TMP;
25+
/// _TMP_2 = _LOCAL_TMP;
26+
/// ((_LOCAL_0 as Variant).FIELD: TY) = move _TMP_2;
2527
/// discriminant(_LOCAL_0) = VAR_IDX;
2628
/// ```
2729
///
@@ -32,50 +34,213 @@ use rustc_target::abi::VariantIdx;
3234
/// ```
3335
pub struct SimplifyArmIdentity;
3436

37+
#[derive(Debug)]
38+
struct ArmIdentityInfo<'tcx> {
39+
/// Storage location for the variant's field
40+
local_temp_0: Local,
41+
/// Storage location holding the varient being read from
42+
local_1: Local,
43+
/// The varient field being read from
44+
vf_s0: VarField<'tcx>,
45+
46+
/// Tracks each assignment to a temporary of the varient's field
47+
field_tmp_assignments: Vec<(Local, Local)>,
48+
49+
/// Storage location holding the variant's field that was read from
50+
local_tmp_s1: Local,
51+
/// Storage location holding the enum that we are writing to
52+
local_0: Local,
53+
/// The varient field being written to
54+
vf_s1: VarField<'tcx>,
55+
56+
/// Storage location that the discrimentant is being set to
57+
set_discr_local: Local,
58+
/// The variant being written
59+
set_discr_var_idx: VariantIdx,
60+
61+
/// Index of the statement that should be overwritten as a move
62+
stmt_to_overwrite: usize,
63+
/// SourceInfo for the new move
64+
source_info: SourceInfo,
65+
66+
/// Indexes of matching Storage{Live,Dead} statements encountered.
67+
/// (StorageLive index,, StorageDead index, Local)
68+
storage_stmts: Vec<(usize, usize, Local)>,
69+
70+
/// The statements that should be removed (turned into nops)
71+
stmts_to_remove: Vec<usize>,
72+
}
73+
74+
fn get_arm_identity_info(stmts: &[Statement<'tcx>]) -> Option<ArmIdentityInfo<'tcx>> {
75+
let (mut local_tmp_s0, mut local_1, mut vf_s0) = (None, None, None);
76+
let mut tmp_assigns = Vec::new();
77+
let (mut local_tmp_s1, mut local_0, mut vf_s1) = (None, None, None);
78+
let (mut set_discr_local, mut set_discr_var_idx) = (None, None);
79+
let mut starting_stmt = None;
80+
let mut discr_stmt = None;
81+
let mut nop_stmts = Vec::new();
82+
let mut storage_stmts = Vec::new();
83+
let mut storage_live_stmts = Vec::new();
84+
let mut storage_dead_stmts = Vec::new();
85+
86+
for (stmt_idx, stmt) in stmts.iter().enumerate() {
87+
if let StatementKind::StorageLive(l) = stmt.kind {
88+
storage_live_stmts.push((stmt_idx, l));
89+
continue;
90+
} else if let StatementKind::StorageDead(l) = stmt.kind {
91+
storage_dead_stmts.push((stmt_idx, l));
92+
continue;
93+
}
94+
95+
if local_tmp_s0 == None && local_1 == None && vf_s0 == None {
96+
let result = match_get_variant_field(stmt)?;
97+
local_tmp_s0 = Some(result.0);
98+
local_1 = Some(result.1);
99+
vf_s0 = Some(result.2);
100+
starting_stmt = Some(stmt_idx);
101+
} else if let StatementKind::Assign(box (place, Rvalue::Use(op))) = &stmt.kind {
102+
if let Some(local) = place.as_local() {
103+
if let Operand::Copy(p) | Operand::Move(p) = op {
104+
tmp_assigns.push((local, p.as_local()?));
105+
nop_stmts.push(stmt_idx);
106+
} else {
107+
return None;
108+
}
109+
} else if local_tmp_s1 == None && local_0 == None && vf_s1 == None {
110+
let result = match_set_variant_field(stmt)?;
111+
local_tmp_s1 = Some(result.0);
112+
local_0 = Some(result.1);
113+
vf_s1 = Some(result.2);
114+
nop_stmts.push(stmt_idx);
115+
}
116+
} else if set_discr_local == None && set_discr_var_idx == None {
117+
let result = match_set_discr(stmt)?;
118+
set_discr_local = Some(result.0);
119+
set_discr_var_idx = Some(result.1);
120+
discr_stmt = Some(stmt);
121+
nop_stmts.push(stmt_idx);
122+
}
123+
}
124+
125+
for (live_idx, live_local) in storage_live_stmts {
126+
if let Some(i) = storage_dead_stmts.iter().rposition(|(_, l)| *l == live_local) {
127+
let (dead_idx, _) = storage_dead_stmts.swap_remove(i);
128+
storage_stmts.push((live_idx, dead_idx, live_local));
129+
}
130+
}
131+
132+
Some(ArmIdentityInfo {
133+
local_temp_0: local_tmp_s0?,
134+
local_1: local_1?,
135+
vf_s0: vf_s0?,
136+
field_tmp_assignments: tmp_assigns,
137+
local_tmp_s1: local_tmp_s1?,
138+
local_0: local_0?,
139+
vf_s1: vf_s1?,
140+
set_discr_local: set_discr_local?,
141+
set_discr_var_idx: set_discr_var_idx?,
142+
stmt_to_overwrite: starting_stmt?,
143+
source_info: discr_stmt?.source_info,
144+
storage_stmts: storage_stmts,
145+
stmts_to_remove: nop_stmts,
146+
})
147+
}
148+
149+
fn optimization_applies<'tcx>(opt_info: &ArmIdentityInfo<'tcx>, local_decls: &IndexVec<Local, LocalDecl<'tcx>>) -> bool {
150+
trace!("testing if optimization applies...");
151+
152+
if opt_info.local_0 == opt_info.local_1 {
153+
trace!("NO: moving into ourselves");
154+
return false;
155+
} else if opt_info.vf_s0 != opt_info.vf_s1 {
156+
trace!("NO: the field-and-variant information do not match");
157+
return false;
158+
} else if local_decls[opt_info.local_0].ty != local_decls[opt_info.local_1].ty {
159+
// FIXME(Centril,oli-obk): possibly relax ot same layout?
160+
trace!("NO: source and target locals have different types");
161+
return false;
162+
} else if (opt_info.local_0, opt_info.vf_s0.var_idx) != (opt_info.set_discr_local, opt_info.set_discr_var_idx) {
163+
trace!("NO: the discriminants do not match");
164+
return false;
165+
}
166+
167+
// Verify the assigment chain consists of the form b = a; c = b; d = c; etc...
168+
if opt_info.field_tmp_assignments.len() == 0 {
169+
trace!("NO: no assignments found");
170+
}
171+
let mut last_assigned_to = opt_info.field_tmp_assignments[0].1;
172+
let source_local = last_assigned_to;
173+
for (l, r) in &opt_info.field_tmp_assignments {
174+
if *r != last_assigned_to {
175+
trace!("NO: found unexpected assignment {:?} = {:?}", l, r);
176+
return false;
177+
}
178+
179+
last_assigned_to = *l;
180+
}
181+
182+
if source_local != opt_info.local_temp_0 {
183+
trace!("NO: start of assignment chain does not match enum variant temp: {:?} != {:?}", source_local, opt_info.local_temp_0);
184+
return false;
185+
} else if last_assigned_to != opt_info.local_tmp_s1 {
186+
trace!("NO: end of assignemnt chain does not match written enum temp: {:?} != {:?}", last_assigned_to, opt_info.local_tmp_s1);
187+
return false;
188+
}
189+
190+
trace!("SUCCESS: optimization applies!");
191+
return true;
192+
}
193+
35194
impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
36-
fn run_pass(&self, _: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
195+
fn run_pass(&self, _: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>) {
196+
trace!("running SimplifyArmIdentity on {:?}", source);
37197
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
38198
for bb in basic_blocks {
39-
// Need 3 statements:
40-
let (s0, s1, s2) = match &mut *bb.statements {
41-
[s0, s1, s2] => (s0, s1, s2),
42-
_ => continue,
43-
};
199+
trace!("bb.len() = {:?}", bb.statements.len());
44200

45-
// Pattern match on the form we want:
46-
let (local_tmp_s0, local_1, vf_s0) = match match_get_variant_field(s0) {
47-
None => continue,
48-
Some(x) => x,
49-
};
50-
let (local_tmp_s1, local_0, vf_s1) = match match_set_variant_field(s1) {
51-
None => continue,
52-
Some(x) => x,
53-
};
54-
if local_tmp_s0 != local_tmp_s1
55-
// Avoid moving into ourselves.
56-
|| local_0 == local_1
57-
// The field-and-variant information match up.
58-
|| vf_s0 != vf_s1
59-
// Source and target locals have the same type.
60-
// FIXME(Centril | oli-obk): possibly relax to same layout?
61-
|| local_decls[local_0].ty != local_decls[local_1].ty
62-
// We're setting the discriminant of `local_0` to this variant.
63-
|| Some((local_0, vf_s0.var_idx)) != match_set_discr(s2)
64-
{
65-
continue;
66-
}
201+
if let Some(mut opt_info) = get_arm_identity_info(&bb.statements) {
202+
trace!("got opt_info = {:#?}", opt_info);
203+
if !optimization_applies(&opt_info, local_decls) {
204+
debug!("skipping simplification!!!!!!!!!!!");
205+
continue;
206+
}
207+
208+
trace!("proceeding...");
209+
210+
//if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 {
211+
// continue;
212+
//}
67213

68-
// Right shape; transform!
69-
s0.source_info = s2.source_info;
70-
match &mut s0.kind {
71-
StatementKind::Assign(box (place, rvalue)) => {
72-
*place = local_0.into();
73-
*rvalue = Rvalue::Use(Operand::Move(local_1.into()));
214+
// Also remove unused Storage{Live,Dead} statements which correspond
215+
// to temps used previously.
216+
for (left, right) in opt_info.field_tmp_assignments {
217+
for (live_idx, dead_idx, local) in &opt_info.storage_stmts {
218+
if *local == left || *local == right {
219+
opt_info.stmts_to_remove.push(*live_idx);
220+
opt_info.stmts_to_remove.push(*dead_idx);
221+
}
222+
}
74223
}
75-
_ => unreachable!(),
224+
225+
// Right shape; transform!
226+
let stmt = &mut bb.statements[opt_info.stmt_to_overwrite];
227+
stmt.source_info = opt_info.source_info;
228+
match &mut stmt.kind {
229+
StatementKind::Assign(box (place, rvalue)) => {
230+
*place = opt_info.local_0.into();
231+
*rvalue = Rvalue::Use(Operand::Move(opt_info.local_1.into()));
232+
}
233+
_ => unreachable!(),
234+
}
235+
236+
for stmt_idx in opt_info.stmts_to_remove {
237+
bb.statements[stmt_idx].make_nop();
238+
}
239+
240+
bb.statements.retain(|stmt| stmt.kind != StatementKind::Nop);
241+
242+
trace!("block is now {:?}", bb.statements);
76243
}
77-
s1.make_nop();
78-
s2.make_nop();
79244
}
80245
}
81246
}
@@ -129,7 +294,7 @@ fn match_set_discr<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, VariantIdx)>
129294
}
130295
}
131296

132-
#[derive(PartialEq)]
297+
#[derive(PartialEq, Debug)]
133298
struct VarField<'tcx> {
134299
field: Field,
135300
field_ty: Ty<'tcx>,

‎src/test/mir-opt/simplify-arm-identity.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,14 @@ fn main() {
3939
// }
4040
// ...
4141
// bb3: {
42+
// StorageLive(_4);
4243
// _4 = ((_1 as Foo).0: u8);
43-
// ((_2 as Foo).0: u8) = move _4;
44+
// StorageLive(_5);
45+
// _5 = _4;
46+
// ((_2 as Foo).0: u8) = move _5;
4447
// discriminant(_2) = 0;
48+
// StorageDead(_5);
49+
// StorageDead(_4);
4550
// goto -> bb4;
4651
// }
4752
// ...
@@ -65,9 +70,14 @@ fn main() {
6570
// }
6671
// ...
6772
// bb3: {
73+
// StorageLive(_4);
6874
// _4 = ((_1 as Foo).0: u8);
69-
// ((_2 as Foo).0: u8) = move _4;
75+
// StorageLive(_5);
76+
// _5 = _4;
77+
// ((_2 as Foo).0: u8) = move _5;
7078
// discriminant(_2) = 0;
79+
// StorageDead(_5);
80+
// StorageDead(_4);
7181
// goto -> bb4;
7282
// }
7383
// ...

‎src/test/mir-opt/simplify_try.rs

Lines changed: 81 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,16 @@ fn main() {
2323
// let _10: u32;
2424
// let mut _11: u32;
2525
// scope 1 {
26-
// debug y => _10;
26+
// debug y => _2;
2727
// }
2828
// scope 2 {
2929
// debug err => _6;
3030
// scope 3 {
3131
// scope 7 {
32-
// debug t => _6;
32+
// debug t => _9;
3333
// }
3434
// scope 8 {
35-
// debug v => _6;
35+
// debug v => _8;
3636
// let mut _12: i32;
3737
// }
3838
// }
@@ -43,22 +43,49 @@ fn main() {
4343
// }
4444
// }
4545
// scope 6 {
46-
// debug self => _1;
46+
// debug self => _4;
4747
// }
4848
// bb0: {
49-
// _5 = discriminant(_1);
49+
// StorageLive(_2);
50+
// StorageLive(_3);
51+
// StorageLive(_4);
52+
// _4 = _1;
53+
// _3 = move _4;
54+
// StorageDead(_4);
55+
// _5 = discriminant(_3);
5056
// switchInt(move _5) -> [0isize: bb1, otherwise: bb2];
5157
// }
5258
// bb1: {
53-
// _10 = ((_1 as Ok).0: u32);
54-
// ((_0 as Ok).0: u32) = move _10;
59+
// StorageLive(_10);
60+
// _10 = ((_3 as Ok).0: u32);
61+
// _2 = _10;
62+
// StorageDead(_10);
63+
// StorageDead(_3);
64+
// StorageLive(_11);
65+
// _11 = _2;
66+
// ((_0 as Ok).0: u32) = move _11;
5567
// discriminant(_0) = 0;
68+
// StorageDead(_11);
69+
// StorageDead(_2);
5670
// goto -> bb3;
5771
// }
5872
// bb2: {
59-
// _6 = ((_1 as Err).0: i32);
60-
// ((_0 as Err).0: i32) = move _6;
73+
// StorageLive(_6);
74+
// _6 = ((_3 as Err).0: i32);
75+
// StorageLive(_8);
76+
// StorageLive(_9);
77+
// _9 = _6;
78+
// _8 = move _9;
79+
// StorageDead(_9);
80+
// StorageLive(_12);
81+
// _12 = move _8;
82+
// ((_0 as Err).0: i32) = move _12;
6183
// discriminant(_0) = 1;
84+
// StorageDead(_12);
85+
// StorageDead(_8);
86+
// StorageDead(_6);
87+
// StorageDead(_3);
88+
// StorageDead(_2);
6289
// goto -> bb3;
6390
// }
6491
// bb3: {
@@ -82,16 +109,16 @@ fn main() {
82109
// let _10: u32;
83110
// let mut _11: u32;
84111
// scope 1 {
85-
// debug y => _10;
112+
// debug y => _2;
86113
// }
87114
// scope 2 {
88115
// debug err => _6;
89116
// scope 3 {
90117
// scope 7 {
91-
// debug t => _6;
118+
// debug t => _9;
92119
// }
93120
// scope 8 {
94-
// debug v => _6;
121+
// debug v => _8;
95122
// let mut _12: i32;
96123
// }
97124
// }
@@ -102,22 +129,28 @@ fn main() {
102129
// }
103130
// }
104131
// scope 6 {
105-
// debug self => _1;
132+
// debug self => _4;
106133
// }
107134
// bb0: {
108-
// _5 = discriminant(_1);
135+
// StorageLive(_2);
136+
// StorageLive(_3);
137+
// StorageLive(_4);
138+
// _4 = _1;
139+
// _3 = move _4;
140+
// StorageDead(_4);
141+
// _5 = discriminant(_3);
109142
// switchInt(move _5) -> [0isize: bb1, otherwise: bb2];
110143
// }
111144
// bb1: {
112-
// _0 = move _1;
113-
// nop;
114-
// nop;
145+
// _0 = move _3;
146+
// StorageDead(_3);
147+
// StorageDead(_2);
115148
// goto -> bb3;
116149
// }
117150
// bb2: {
118-
// _0 = move _1;
119-
// nop;
120-
// nop;
151+
// _0 = move _3;
152+
// StorageDead(_3);
153+
// StorageDead(_2);
121154
// goto -> bb3;
122155
// }
123156
// bb3: {
@@ -141,16 +174,16 @@ fn main() {
141174
// let _10: u32;
142175
// let mut _11: u32;
143176
// scope 1 {
144-
// debug y => _10;
177+
// debug y => _2;
145178
// }
146179
// scope 2 {
147180
// debug err => _6;
148181
// scope 3 {
149182
// scope 7 {
150-
// debug t => _6;
183+
// debug t => _9;
151184
// }
152185
// scope 8 {
153-
// debug v => _6;
186+
// debug v => _8;
154187
// let mut _12: i32;
155188
// }
156189
// }
@@ -161,16 +194,22 @@ fn main() {
161194
// }
162195
// }
163196
// scope 6 {
164-
// debug self => _1;
197+
// debug self => _4;
165198
// }
166199
// bb0: {
167-
// _5 = discriminant(_1);
200+
// StorageLive(_2);
201+
// StorageLive(_3);
202+
// StorageLive(_4);
203+
// _4 = _1;
204+
// _3 = move _4;
205+
// StorageDead(_4);
206+
// _5 = discriminant(_3);
168207
// goto -> bb1;
169208
// }
170209
// bb1: {
171-
// _0 = move _1;
172-
// nop;
173-
// nop;
210+
// _0 = move _3;
211+
// StorageDead(_3);
212+
// StorageDead(_2);
174213
// goto -> bb2;
175214
// }
176215
// bb2: {
@@ -183,34 +222,39 @@ fn main() {
183222
// fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
184223
// debug x => _1;
185224
// let mut _0: std::result::Result<u32, i32>;
186-
// let mut _2: isize;
187-
// let _3: i32;
188-
// let _4: u32;
225+
// let _2: u32;
226+
// let mut _3: isize;
227+
// let _4: i32;
228+
// let mut _5: i32;
229+
// let mut _6: i32;
230+
// let _7: u32;
189231
// scope 1 {
190-
// debug y => _4;
232+
// debug y => _2;
191233
// }
192234
// scope 2 {
193-
// debug err => _3;
235+
// debug err => _4;
194236
// scope 3 {
195237
// scope 7 {
196-
// debug t => _3;
238+
// debug t => _6;
197239
// }
198240
// scope 8 {
199-
// debug v => _3;
241+
// debug v => _5;
200242
// }
201243
// }
202244
// }
203245
// scope 4 {
204-
// debug val => _4;
246+
// debug val => _7;
205247
// scope 5 {
206248
// }
207249
// }
208250
// scope 6 {
209251
// debug self => _1;
210252
// }
211253
// bb0: {
212-
// _2 = discriminant(_1);
254+
// StorageLive(_2);
255+
// _3 = discriminant(_1);
213256
// _0 = move _1;
257+
// StorageDead(_2);
214258
// return;
215259
// }
216260
// }

0 commit comments

Comments
 (0)
Please sign in to comment.