Skip to content

Commit cc93132

Browse files
committed
simplifycfg: Preserve debuginfos when merging bbs
1 parent 571412f commit cc93132

8 files changed

+322
-3
lines changed

compiler/rustc_middle/src/mir/terminator.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,14 @@ impl<'tcx> Terminator<'tcx> {
444444
self.kind.successors()
445445
}
446446

447+
/// Return `Some` if all successors are identical.
448+
#[inline]
449+
pub fn identical_successor(&self) -> Option<BasicBlock> {
450+
let mut successors = self.successors();
451+
let first_succ = successors.next()?;
452+
if successors.all(|succ| first_succ == succ) { Some(first_succ) } else { None }
453+
}
454+
447455
#[inline]
448456
pub fn successors_mut<'a>(&'a mut self, f: impl FnMut(&'a mut BasicBlock)) {
449457
self.kind.successors_mut(f)

compiler/rustc_mir_transform/src/simplify.rs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
144144
// statements itself to avoid moving the (relatively) large statements twice.
145145
// We do not push the statements directly into the target block (`bb`) as that is slower
146146
// due to additional reallocations
147-
let mut merged_blocks = Vec::new();
147+
let mut merged_blocks: Vec<BasicBlock> = Vec::new();
148148
let mut outer_changed = false;
149149
loop {
150150
let mut changed = false;
@@ -159,8 +159,9 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
159159
let mut terminator =
160160
self.basic_blocks[bb].terminator.take().expect("invalid terminator state");
161161

162-
terminator
163-
.successors_mut(|successor| self.collapse_goto_chain(successor, &mut changed));
162+
terminator.successors_mut(|successor| {
163+
self.collapse_goto_chain(successor, &mut changed);
164+
});
164165

165166
let mut inner_changed = true;
166167
merged_blocks.clear();
@@ -177,10 +178,18 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
177178
if statements_to_merge > 0 {
178179
let mut statements = std::mem::take(&mut self.basic_blocks[bb].statements);
179180
statements.reserve(statements_to_merge);
181+
let mut parent_bb_last_debuginfos =
182+
std::mem::take(&mut self.basic_blocks[bb].after_last_stmt_debuginfos);
180183
for &from in &merged_blocks {
184+
if let Some(stmt) = self.basic_blocks[from].statements.first_mut() {
185+
stmt.debuginfos.prepend(&mut parent_bb_last_debuginfos);
186+
}
181187
statements.append(&mut self.basic_blocks[from].statements);
188+
parent_bb_last_debuginfos =
189+
std::mem::take(&mut self.basic_blocks[from].after_last_stmt_debuginfos);
182190
}
183191
self.basic_blocks[bb].statements = statements;
192+
self.basic_blocks[bb].after_last_stmt_debuginfos = parent_bb_last_debuginfos;
184193
}
185194

186195
self.basic_blocks[bb].terminator = Some(terminator);
@@ -220,10 +229,14 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
220229
// goto chains. We should probably benchmark different sizes.
221230
let mut terminators: SmallVec<[_; 1]> = Default::default();
222231
let mut current = *start;
232+
// If each successor has only one predecessor, it's a trivial goto chain.
233+
// We can move all debuginfos to the last basic block.
234+
let mut trivial_goto_chain = true;
223235
while let Some(terminator) = self.take_terminator_if_simple_goto(current) {
224236
let Terminator { kind: TerminatorKind::Goto { target }, .. } = terminator else {
225237
unreachable!();
226238
};
239+
trivial_goto_chain &= self.pred_count[target] == 1;
227240
terminators.push((current, terminator));
228241
current = target;
229242
}
@@ -235,6 +248,17 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
235248
else {
236249
unreachable!();
237250
};
251+
if trivial_goto_chain {
252+
let mut pred_debuginfos =
253+
std::mem::take(&mut self.basic_blocks[current].after_last_stmt_debuginfos);
254+
let debuginfos = if let Some(stmt) = self.basic_blocks[last].statements.first_mut()
255+
{
256+
&mut stmt.debuginfos
257+
} else {
258+
&mut self.basic_blocks[last].after_last_stmt_debuginfos
259+
};
260+
debuginfos.prepend(&mut pred_debuginfos);
261+
}
238262
*changed |= *target != last;
239263
*target = last;
240264
debug!("collapsing goto chain from {:?} to {:?}", current, target);

tests/mir-opt/debuginfo/simplifycfg.drop_debuginfo.SimplifyCfg-final.diff

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414
-
1515
- bb1: {
1616
- // DBG: _3 = &((*_1).0: i32);
17+
- nop;
1718
- goto -> bb2;
1819
- }
1920
-
2021
- bb2: {
2122
// DBG: _4 = &((*_1).1: i64);
23+
- nop;
2224
_0 = copy ((*_1).2: i32);
2325
return;
2426
}

tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_1.SimplifyCfg-final.diff

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@
1717
- bb1: {
1818
(*_2) = const true;
1919
// DBG: _3 = &((*_1).0: i32);
20+
- nop;
2021
- goto -> bb2;
2122
- }
2223
-
2324
- bb2: {
2425
// DBG: _4 = &((*_1).1: i64);
26+
- nop;
2527
_0 = copy ((*_1).2: i32);
2628
// DBG: _5 = &((*_1).2: i32);
29+
- nop;
2730
return;
2831
}
2932
}

tests/mir-opt/debuginfo/simplifycfg.preserve_debuginfo_2.SimplifyCfg-final.diff

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@
1616
-
1717
- bb1: {
1818
// DBG: _2 = &((*_1).0: i32);
19+
- nop;
1920
- goto -> bb2;
2021
- }
2122
-
2223
- bb2: {
2324
// DBG: _3 = &((*_1).1: i64);
25+
- nop;
2426
_0 = copy ((*_1).2: i32);
2527
// DBG: _4 = &((*_1).2: i32);
28+
- nop;
2629
return;
2730
}
2831
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
- // MIR for `preserve_debuginfo_3` before SimplifyCfg-final
2+
+ // MIR for `preserve_debuginfo_3` after SimplifyCfg-final
3+
4+
fn preserve_debuginfo_3(_1: &Foo, _2: bool) -> i32 {
5+
debug foo_a => _3;
6+
debug foo_b => _4;
7+
debug foo_c => _5;
8+
let mut _0: i32;
9+
let mut _3: &i32;
10+
let mut _4: &i64;
11+
let mut _5: &i32;
12+
13+
bb0: {
14+
- switchInt(copy _2) -> [1: bb1, otherwise: bb2];
15+
+ switchInt(copy _2) -> [1: bb2, otherwise: bb1];
16+
}
17+
18+
bb1: {
19+
- // DBG: _3 = &((*_1).0: i32);
20+
- nop;
21+
- goto -> bb3;
22+
- }
23+
-
24+
- bb2: {
25+
// DBG: _4 = &((*_1).1: i64);
26+
- nop;
27+
_0 = copy ((*_1).2: i32);
28+
return;
29+
}
30+
31+
- bb3: {
32+
+ bb2: {
33+
+ // DBG: _3 = &((*_1).0: i32);
34+
// DBG: _5 = &((*_1).2: i32);
35+
- nop;
36+
_0 = copy ((*_1).0: i32);
37+
return;
38+
}
39+
}
40+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
- // MIR for `preserve_debuginfo_identical_succs` before SimplifyCfg-final
2+
+ // MIR for `preserve_debuginfo_identical_succs` after SimplifyCfg-final
3+
4+
fn preserve_debuginfo_identical_succs(_1: &Foo, _2: bool) -> i32 {
5+
debug foo_a => _3;
6+
debug foo_b => _4;
7+
debug foo_c => _5;
8+
let mut _0: i32;
9+
let mut _3: &i32;
10+
let mut _4: &i64;
11+
let mut _5: &i32;
12+
13+
bb0: {
14+
- switchInt(copy _2) -> [1: bb1, otherwise: bb1];
15+
- }
16+
-
17+
- bb1: {
18+
// DBG: _3 = &((*_1).0: i32);
19+
- nop;
20+
- goto -> bb2;
21+
- }
22+
-
23+
- bb2: {
24+
// DBG: _4 = &((*_1).1: i64);
25+
- nop;
26+
_0 = copy ((*_1).2: i32);
27+
// DBG: _5 = &((*_1).2: i32);
28+
- nop;
29+
return;
30+
}
31+
}
32+

0 commit comments

Comments
 (0)