Skip to content

Commit d5ac1a1

Browse files
committed
Auto merge of #30481 - nagisa:mir-calls-2, r=nikomatsakis
r? @nikomatsakis This is a pretty big PR conflating changes to a few different block terminators (Call, DivergingCall, Panic, Resume, Diverge), because they are somewhat closely related. Each commit has a pretty good description on what is being changed in each commit. The end result is greatly simplified CFG and translation for calls (no success branch if the function is diverging, no cleanup branch if there’s nothing to cleanup etc). Fixes #30480 Fixes #29767 Partialy solves #29575 Fixes #29573
2 parents 7312e0a + 36b3951 commit d5ac1a1

31 files changed

+887
-260
lines changed

Diff for: src/librustc/mir/repr.rs

+102-51
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,6 @@ pub const START_BLOCK: BasicBlock = BasicBlock(0);
5151
/// where execution ends, on normal return
5252
pub const END_BLOCK: BasicBlock = BasicBlock(1);
5353

54-
/// where execution ends, on panic
55-
pub const DIVERGE_BLOCK: BasicBlock = BasicBlock(2);
56-
5754
impl<'tcx> Mir<'tcx> {
5855
pub fn all_basic_blocks(&self) -> Vec<BasicBlock> {
5956
(0..self.basic_blocks.len())
@@ -194,7 +191,8 @@ impl Debug for BasicBlock {
194191
#[derive(Debug, RustcEncodable, RustcDecodable)]
195192
pub struct BasicBlockData<'tcx> {
196193
pub statements: Vec<Statement<'tcx>>,
197-
pub terminator: Terminator<'tcx>,
194+
pub terminator: Option<Terminator<'tcx>>,
195+
pub is_cleanup: bool,
198196
}
199197

200198
#[derive(RustcEncodable, RustcDecodable)]
@@ -204,12 +202,6 @@ pub enum Terminator<'tcx> {
204202
target: BasicBlock,
205203
},
206204

207-
/// block should initiate unwinding; should be one successor
208-
/// that does cleanup and branches to DIVERGE_BLOCK
209-
Panic {
210-
target: BasicBlock,
211-
},
212-
213205
/// jump to branch 0 if this lvalue evaluates to true
214206
If {
215207
cond: Operand<'tcx>,
@@ -243,77 +235,125 @@ pub enum Terminator<'tcx> {
243235
targets: Vec<BasicBlock>,
244236
},
245237

246-
/// Indicates that the last statement in the block panics, aborts,
247-
/// etc. No successors. This terminator appears on exactly one
248-
/// basic block which we create in advance. However, during
249-
/// construction, we use this value as a sentinel for "terminator
250-
/// not yet assigned", and assert at the end that only the
251-
/// well-known diverging block actually diverges.
252-
Diverge,
238+
/// Indicates that the landing pad is finished and unwinding should
239+
/// continue. Emitted by build::scope::diverge_cleanup.
240+
Resume,
253241

254242
/// Indicates a normal return. The ReturnPointer lvalue should
255243
/// have been filled in by now. This should only occur in the
256244
/// `END_BLOCK`.
257245
Return,
258246

259-
/// block ends with a call; it should have two successors. The
260-
/// first successor indicates normal return. The second indicates
261-
/// unwinding.
247+
/// Block ends with a call of a converging function
262248
Call {
263-
data: CallData<'tcx>,
264-
targets: (BasicBlock, BasicBlock),
249+
/// The function that’s being called
250+
func: Operand<'tcx>,
251+
/// Arguments the function is called with
252+
args: Vec<Operand<'tcx>>,
253+
/// The kind of call with associated information
254+
kind: CallKind<'tcx>,
265255
},
266256
}
267257

258+
#[derive(Clone, RustcEncodable, RustcDecodable)]
259+
pub enum CallKind<'tcx> {
260+
/// Diverging function without associated cleanup
261+
Diverging,
262+
/// Diverging function with associated cleanup
263+
DivergingCleanup(BasicBlock),
264+
/// Converging function without associated cleanup
265+
Converging {
266+
/// Destination where the call result is written
267+
destination: Lvalue<'tcx>,
268+
/// Block to branch into on successful return
269+
target: BasicBlock,
270+
},
271+
ConvergingCleanup {
272+
/// Destination where the call result is written
273+
destination: Lvalue<'tcx>,
274+
/// First target is branched to on successful return.
275+
/// Second block contains the cleanups to do on unwind.
276+
targets: (BasicBlock, BasicBlock)
277+
}
278+
}
279+
280+
impl<'tcx> CallKind<'tcx> {
281+
pub fn successors(&self) -> &[BasicBlock] {
282+
match *self {
283+
CallKind::Diverging => &[],
284+
CallKind::DivergingCleanup(ref b) |
285+
CallKind::Converging { target: ref b, .. } => slice::ref_slice(b),
286+
CallKind::ConvergingCleanup { ref targets, .. } => targets.as_slice(),
287+
}
288+
}
289+
290+
pub fn successors_mut(&mut self) -> &mut [BasicBlock] {
291+
match *self {
292+
CallKind::Diverging => &mut [],
293+
CallKind::DivergingCleanup(ref mut b) |
294+
CallKind::Converging { target: ref mut b, .. } => slice::mut_ref_slice(b),
295+
CallKind::ConvergingCleanup { ref mut targets, .. } => targets.as_mut_slice(),
296+
}
297+
}
298+
299+
pub fn destination(&self) -> Option<Lvalue<'tcx>> {
300+
match *self {
301+
CallKind::Converging { ref destination, .. } |
302+
CallKind::ConvergingCleanup { ref destination, .. } => Some(destination.clone()),
303+
CallKind::Diverging |
304+
CallKind::DivergingCleanup(_) => None
305+
}
306+
}
307+
}
308+
268309
impl<'tcx> Terminator<'tcx> {
269310
pub fn successors(&self) -> &[BasicBlock] {
270311
use self::Terminator::*;
271312
match *self {
272313
Goto { target: ref b } => slice::ref_slice(b),
273-
Panic { target: ref b } => slice::ref_slice(b),
274-
If { cond: _, targets: ref b } => b.as_slice(),
314+
If { targets: ref b, .. } => b.as_slice(),
275315
Switch { targets: ref b, .. } => b,
276316
SwitchInt { targets: ref b, .. } => b,
277-
Diverge => &[],
317+
Resume => &[],
278318
Return => &[],
279-
Call { data: _, targets: ref b } => b.as_slice(),
319+
Call { ref kind, .. } => kind.successors(),
280320
}
281321
}
282322

283323
pub fn successors_mut(&mut self) -> &mut [BasicBlock] {
284324
use self::Terminator::*;
285325
match *self {
286326
Goto { target: ref mut b } => slice::mut_ref_slice(b),
287-
Panic { target: ref mut b } => slice::mut_ref_slice(b),
288-
If { cond: _, targets: ref mut b } => b.as_mut_slice(),
327+
If { targets: ref mut b, .. } => b.as_mut_slice(),
289328
Switch { targets: ref mut b, .. } => b,
290329
SwitchInt { targets: ref mut b, .. } => b,
291-
Diverge => &mut [],
330+
Resume => &mut [],
292331
Return => &mut [],
293-
Call { data: _, targets: ref mut b } => b.as_mut_slice(),
332+
Call { ref mut kind, .. } => kind.successors_mut(),
294333
}
295334
}
296335
}
297336

298-
#[derive(Debug, RustcEncodable, RustcDecodable)]
299-
pub struct CallData<'tcx> {
300-
/// where the return value is written to
301-
pub destination: Lvalue<'tcx>,
302-
303-
/// the fn being called
304-
pub func: Operand<'tcx>,
305-
306-
/// the arguments
307-
pub args: Vec<Operand<'tcx>>,
308-
}
309-
310337
impl<'tcx> BasicBlockData<'tcx> {
311-
pub fn new(terminator: Terminator<'tcx>) -> BasicBlockData<'tcx> {
338+
pub fn new(terminator: Option<Terminator<'tcx>>) -> BasicBlockData<'tcx> {
312339
BasicBlockData {
313340
statements: vec![],
314341
terminator: terminator,
342+
is_cleanup: false,
315343
}
316344
}
345+
346+
/// Accessor for terminator.
347+
///
348+
/// Terminator may not be None after construction of the basic block is complete. This accessor
349+
/// provides a convenience way to reach the terminator.
350+
pub fn terminator(&self) -> &Terminator<'tcx> {
351+
self.terminator.as_ref().expect("invalid terminator state")
352+
}
353+
354+
pub fn terminator_mut(&mut self) -> &mut Terminator<'tcx> {
355+
self.terminator.as_mut().expect("invalid terminator state")
356+
}
317357
}
318358

319359
impl<'tcx> Debug for Terminator<'tcx> {
@@ -351,15 +391,17 @@ impl<'tcx> Terminator<'tcx> {
351391
use self::Terminator::*;
352392
match *self {
353393
Goto { .. } => write!(fmt, "goto"),
354-
Panic { .. } => write!(fmt, "panic"),
355394
If { cond: ref lv, .. } => write!(fmt, "if({:?})", lv),
356395
Switch { discr: ref lv, .. } => write!(fmt, "switch({:?})", lv),
357396
SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv),
358-
Diverge => write!(fmt, "diverge"),
359397
Return => write!(fmt, "return"),
360-
Call { data: ref c, .. } => {
361-
try!(write!(fmt, "{:?} = {:?}(", c.destination, c.func));
362-
for (index, arg) in c.args.iter().enumerate() {
398+
Resume => write!(fmt, "resume"),
399+
Call { ref kind, ref func, ref args } => {
400+
if let Some(destination) = kind.destination() {
401+
try!(write!(fmt, "{:?} = ", destination));
402+
}
403+
try!(write!(fmt, "{:?}(", func));
404+
for (index, arg) in args.iter().enumerate() {
363405
if index > 0 {
364406
try!(write!(fmt, ", "));
365407
}
@@ -374,10 +416,9 @@ impl<'tcx> Terminator<'tcx> {
374416
pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
375417
use self::Terminator::*;
376418
match *self {
377-
Diverge | Return => vec![],
378-
Goto { .. } | Panic { .. } => vec!["".into_cow()],
419+
Return | Resume => vec![],
420+
Goto { .. } => vec!["".into_cow()],
379421
If { .. } => vec!["true".into_cow(), "false".into_cow()],
380-
Call { .. } => vec!["return".into_cow(), "unwind".into_cow()],
381422
Switch { ref adt_def, .. } => {
382423
adt_def.variants
383424
.iter()
@@ -394,6 +435,16 @@ impl<'tcx> Terminator<'tcx> {
394435
.chain(iter::once(String::from("otherwise").into_cow()))
395436
.collect()
396437
}
438+
Call { ref kind, .. } => match *kind {
439+
CallKind::Diverging =>
440+
vec![],
441+
CallKind::DivergingCleanup(..) =>
442+
vec!["unwind".into_cow()],
443+
CallKind::Converging { .. } =>
444+
vec!["return".into_cow()],
445+
CallKind::ConvergingCleanup { .. } =>
446+
vec!["return".into_cow(), "unwind".into_cow()],
447+
},
397448
}
398449
}
399450
}

Diff for: src/librustc/mir/visit.rs

+20-18
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ pub trait Visitor<'tcx> {
8484
for statement in &data.statements {
8585
self.visit_statement(block, statement);
8686
}
87-
self.visit_terminator(block, &data.terminator);
87+
data.terminator.as_ref().map(|r| self.visit_terminator(block, r));
8888
}
8989

9090
fn super_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) {
@@ -107,8 +107,7 @@ pub trait Visitor<'tcx> {
107107

108108
fn super_terminator(&mut self, block: BasicBlock, terminator: &Terminator<'tcx>) {
109109
match *terminator {
110-
Terminator::Goto { target } |
111-
Terminator::Panic { target } => {
110+
Terminator::Goto { target } => {
112111
self.visit_branch(block, target);
113112
}
114113

@@ -133,17 +132,19 @@ pub trait Visitor<'tcx> {
133132
}
134133
}
135134

136-
Terminator::Diverge |
135+
Terminator::Resume |
137136
Terminator::Return => {
138137
}
139138

140-
Terminator::Call { ref data, ref targets } => {
141-
self.visit_lvalue(&data.destination, LvalueContext::Store);
142-
self.visit_operand(&data.func);
143-
for arg in &data.args {
139+
Terminator::Call { ref func, ref args, ref kind } => {
140+
if let Some(ref destination) = kind.destination() {
141+
self.visit_lvalue(destination, LvalueContext::Store);
142+
}
143+
self.visit_operand(func);
144+
for arg in args {
144145
self.visit_operand(arg);
145146
}
146-
for &target in targets.as_slice() {
147+
for &target in kind.successors() {
147148
self.visit_branch(block, target);
148149
}
149150
}
@@ -364,7 +365,7 @@ pub trait MutVisitor<'tcx> {
364365
for statement in &mut data.statements {
365366
self.visit_statement(block, statement);
366367
}
367-
self.visit_terminator(block, &mut data.terminator);
368+
data.terminator.as_mut().map(|r| self.visit_terminator(block, r));
368369
}
369370

370371
fn super_statement(&mut self,
@@ -394,8 +395,7 @@ pub trait MutVisitor<'tcx> {
394395
block: BasicBlock,
395396
terminator: &mut Terminator<'tcx>) {
396397
match *terminator {
397-
Terminator::Goto { target } |
398-
Terminator::Panic { target } => {
398+
Terminator::Goto { target } => {
399399
self.visit_branch(block, target);
400400
}
401401

@@ -420,17 +420,19 @@ pub trait MutVisitor<'tcx> {
420420
}
421421
}
422422

423-
Terminator::Diverge |
423+
Terminator::Resume |
424424
Terminator::Return => {
425425
}
426426

427-
Terminator::Call { ref mut data, ref mut targets } => {
428-
self.visit_lvalue(&mut data.destination, LvalueContext::Store);
429-
self.visit_operand(&mut data.func);
430-
for arg in &mut data.args {
427+
Terminator::Call { ref mut func, ref mut args, ref mut kind } => {
428+
if let Some(ref mut destination) = kind.destination() {
429+
self.visit_lvalue(destination, LvalueContext::Store);
430+
}
431+
self.visit_operand(func);
432+
for arg in args {
431433
self.visit_operand(arg);
432434
}
433-
for &target in targets.as_slice() {
435+
for &target in kind.successors() {
434436
self.visit_branch(block, target);
435437
}
436438
}

Diff for: src/librustc_mir/build/cfg.rs

+3-9
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ impl<'tcx> CFG<'tcx> {
2828

2929
pub fn start_new_block(&mut self) -> BasicBlock {
3030
let node_index = self.basic_blocks.len();
31-
self.basic_blocks.push(BasicBlockData::new(Terminator::Diverge));
31+
self.basic_blocks.push(BasicBlockData::new(None));
3232
BasicBlock::new(node_index)
3333
}
3434

@@ -67,15 +67,9 @@ impl<'tcx> CFG<'tcx> {
6767
pub fn terminate(&mut self,
6868
block: BasicBlock,
6969
terminator: Terminator<'tcx>) {
70-
// Check whether this block has already been terminated. For
71-
// this, we rely on the fact that the initial state is to have
72-
// a Diverge terminator and an empty list of targets (which
73-
// is not a valid state).
74-
debug_assert!(match self.block_data(block).terminator { Terminator::Diverge => true,
75-
_ => false },
70+
debug_assert!(self.block_data(block).terminator.is_none(),
7671
"terminate: block {:?} already has a terminator set", block);
77-
78-
self.block_data_mut(block).terminator = terminator;
72+
self.block_data_mut(block).terminator = Some(terminator);
7973
}
8074
}
8175

Diff for: src/librustc_mir/build/expr/as_lvalue.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,15 @@ impl<'a,'tcx> Builder<'a,'tcx> {
6363
this.cfg.push_assign(block, expr_span, // lt = idx < len
6464
&lt, Rvalue::BinaryOp(BinOp::Lt,
6565
idx.clone(),
66-
Operand::Consume(len)));
66+
Operand::Consume(len.clone())));
6767

6868
let (success, failure) = (this.cfg.start_new_block(), this.cfg.start_new_block());
6969
this.cfg.terminate(block,
7070
Terminator::If {
7171
cond: Operand::Consume(lt),
7272
targets: (success, failure),
7373
});
74-
this.panic(failure);
74+
this.panic_bounds_check(failure, idx.clone(), Operand::Consume(len), expr_span);
7575
success.and(slice.index(idx))
7676
}
7777
ExprKind::SelfRef => {

0 commit comments

Comments
 (0)