From 893a66d7a11150615c385a190d0140f0b8549409 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Mon, 14 Dec 2015 23:27:58 +0200 Subject: [PATCH] Split Call into Call and DivergingCall DivergingCall is different enough from the regular converging Call to warrant the split. This also inlines CallData struct and creates a new CallTargets enum in order to have a way to differentiate between calls that do not have an associated cleanup block. Note, that this patch still does not produce DivergingCall terminator anywhere. Look for that in the next patches. --- src/librustc/mir/repr.rs | 95 ++++++++++++++------- src/librustc/mir/visit.rs | 39 +++++++-- src/librustc_mir/build/expr/into.rs | 11 ++- src/librustc_mir/transform/erase_regions.rs | 21 ++--- src/librustc_trans/trans/mir/block.rs | 4 + 5 files changed, 113 insertions(+), 57 deletions(-) diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 75a588d424e..42c9b7b0f39 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -256,13 +256,51 @@ pub enum Terminator<'tcx> { /// `END_BLOCK`. Return, - /// block ends with a call; it should have two successors. The - /// first successor indicates normal return. The second indicates - /// unwinding. + /// Block ends with a call of a converging function Call { - data: CallData<'tcx>, - targets: (BasicBlock, BasicBlock), + /// The function that’s being called + func: Operand<'tcx>, + /// Arguments the function is called with + args: Vec>, + /// Location to write the return value into + destination: Lvalue<'tcx>, + targets: CallTargets, }, + + /// Block ends with a call of a diverging function. + DivergingCall { + /// The function that’s being called + func: Operand<'tcx>, + /// Arguments the function is called with + args: Vec>, + /// Some, if there’s any cleanup to be done when function unwinds + cleanup: Option, + } +} + +#[derive(RustcEncodable, RustcDecodable)] +pub enum CallTargets { + /// The only target that should be entered when function returns normally. + Return(BasicBlock), + /// In addition to the normal-return block, function has associated cleanup that should be done + /// when function unwinds. + WithCleanup((BasicBlock, BasicBlock)) +} + +impl CallTargets { + pub fn as_slice(&self) -> &[BasicBlock] { + match *self { + CallTargets::Return(ref b) => slice::ref_slice(b), + CallTargets::WithCleanup(ref bs) => bs.as_slice() + } + } + + pub fn as_mut_slice(&mut self) -> &mut [BasicBlock] { + match *self { + CallTargets::Return(ref mut b) => slice::mut_ref_slice(b), + CallTargets::WithCleanup(ref mut bs) => bs.as_mut_slice() + } + } } impl<'tcx> Terminator<'tcx> { @@ -271,12 +309,17 @@ impl<'tcx> Terminator<'tcx> { match *self { Goto { target: ref b } => slice::ref_slice(b), Panic { target: ref b } => slice::ref_slice(b), - If { cond: _, targets: ref b } => b.as_slice(), + If { targets: ref b, .. } => b.as_slice(), Switch { targets: ref b, .. } => b, SwitchInt { targets: ref b, .. } => b, Diverge => &[], Return => &[], - Call { data: _, targets: ref b } => b.as_slice(), + Call { targets: ref b, .. } => b.as_slice(), + DivergingCall { cleanup: ref b, .. } => if let Some(b) = b.as_ref() { + slice::ref_slice(b) + } else { + &mut [] + }, } } @@ -285,28 +328,21 @@ impl<'tcx> Terminator<'tcx> { match *self { Goto { target: ref mut b } => slice::mut_ref_slice(b), Panic { target: ref mut b } => slice::mut_ref_slice(b), - If { cond: _, targets: ref mut b } => b.as_mut_slice(), + If { targets: ref mut b, .. } => b.as_mut_slice(), Switch { targets: ref mut b, .. } => b, SwitchInt { targets: ref mut b, .. } => b, Diverge => &mut [], Return => &mut [], - Call { data: _, targets: ref mut b } => b.as_mut_slice(), + Call { targets: ref mut b, .. } => b.as_mut_slice(), + DivergingCall { cleanup: ref mut b, .. } => if let Some(b) = b.as_mut() { + slice::mut_ref_slice(b) + } else { + &mut [] + }, } } } -#[derive(Debug, RustcEncodable, RustcDecodable)] -pub struct CallData<'tcx> { - /// where the return value is written to - pub destination: Lvalue<'tcx>, - - /// the fn being called - pub func: Operand<'tcx>, - - /// the arguments - pub args: Vec>, -} - impl<'tcx> BasicBlockData<'tcx> { pub fn new(terminator: Terminator<'tcx>) -> BasicBlockData<'tcx> { BasicBlockData { @@ -357,15 +393,13 @@ impl<'tcx> Terminator<'tcx> { SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv), Diverge => write!(fmt, "diverge"), Return => write!(fmt, "return"), - Call { data: ref c, .. } => { - try!(write!(fmt, "{:?} = {:?}(", c.destination, c.func)); - for (index, arg) in c.args.iter().enumerate() { - if index > 0 { - try!(write!(fmt, ", ")); - } - try!(write!(fmt, "{:?}", arg)); - } - write!(fmt, ")") + Call { .. } => { + // the author didn’t bother rebasing this + unimplemented!() + }, + DivergingCall { .. } => { + // the author didn’t bother rebasing this + unimplemented!() } } } @@ -378,6 +412,7 @@ impl<'tcx> Terminator<'tcx> { Goto { .. } | Panic { .. } => vec!["".into_cow()], If { .. } => vec!["true".into_cow(), "false".into_cow()], Call { .. } => vec!["return".into_cow(), "unwind".into_cow()], + DivergingCall { .. } => vec!["unwind".into_cow()], Switch { ref adt_def, .. } => { adt_def.variants .iter() diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 00d21d3c16e..c3a335fdfaa 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -137,16 +137,26 @@ pub trait Visitor<'tcx> { Terminator::Return => { } - Terminator::Call { ref data, ref targets } => { - self.visit_lvalue(&data.destination, LvalueContext::Store); - self.visit_operand(&data.func); - for arg in &data.args { + Terminator::Call { ref func, ref args, ref destination, ref targets } => { + self.visit_lvalue(destination, LvalueContext::Store); + self.visit_operand(func); + for arg in args { self.visit_operand(arg); } for &target in targets.as_slice() { self.visit_branch(block, target); } } + + Terminator::DivergingCall { ref func, ref args, ref cleanup } => { + self.visit_operand(func); + for arg in args { + self.visit_operand(arg); + } + for &target in cleanup.as_ref() { + self.visit_branch(block, target); + } + } } } @@ -424,16 +434,29 @@ pub trait MutVisitor<'tcx> { Terminator::Return => { } - Terminator::Call { ref mut data, ref mut targets } => { - self.visit_lvalue(&mut data.destination, LvalueContext::Store); - self.visit_operand(&mut data.func); - for arg in &mut data.args { + Terminator::Call { ref mut func, + ref mut args, + ref mut destination, + ref mut targets } => { + self.visit_lvalue(destination, LvalueContext::Store); + self.visit_operand(func); + for arg in args { self.visit_operand(arg); } for &target in targets.as_slice() { self.visit_branch(block, target); } } + + Terminator::DivergingCall { ref mut func, ref mut args, ref mut cleanup } => { + self.visit_operand(func); + for arg in args { + self.visit_operand(arg); + } + for &target in cleanup.as_ref() { + self.visit_branch(block, target); + } + } } } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 802c55ce764..4a262196d36 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -218,14 +218,13 @@ impl<'a,'tcx> Builder<'a,'tcx> { .collect(); let success = this.cfg.start_new_block(); let panic = this.diverge_cleanup(); + let targets = CallTargets::WithCleanup((success, panic)); this.cfg.terminate(block, Terminator::Call { - data: CallData { - destination: destination.clone(), - func: fun, - args: args, - }, - targets: (success, panic), + func: fun, + args: args, + destination: destination.clone(), + targets: targets }); success.unit() } diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 1eb3bfd7e02..1e7bb305cdb 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -90,28 +90,23 @@ impl<'a, 'tcx> EraseRegions<'a, 'tcx> { Terminator::Switch { ref mut discr, .. } => { self.erase_regions_lvalue(discr); } - Terminator::SwitchInt { - ref mut discr, - ref mut switch_ty, - .. - } => { + Terminator::SwitchInt { ref mut discr, ref mut switch_ty, .. } => { self.erase_regions_lvalue(discr); *switch_ty = self.tcx.erase_regions(switch_ty); }, - Terminator::Call { - data: CallData { - ref mut destination, - ref mut func, - ref mut args - }, - .. - } => { + Terminator::Call { ref mut destination, ref mut func, ref mut args, .. } => { self.erase_regions_lvalue(destination); self.erase_regions_operand(func); for arg in &mut *args { self.erase_regions_operand(arg); } } + Terminator::DivergingCall { ref mut func, ref mut args, .. } => { + self.erase_regions_operand(func); + for arg in &mut *args { + self.erase_regions_operand(arg); + } + } } } diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs index 265969c52b3..00508ed21e5 100644 --- a/src/librustc_trans/trans/mir/block.rs +++ b/src/librustc_trans/trans/mir/block.rs @@ -164,6 +164,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } build::Br(bcx, self.llblock(targets.0), DebugLoc::None) + }, + + mir::Terminator::DivergingCall { .. } => { + unimplemented!() } } }