]> git.lizzy.rs Git - rust.git/commitdiff
Split Call into Call and DivergingCall
authorSimonas Kazlauskas <git@kazlauskas.me>
Mon, 14 Dec 2015 21:27:58 +0000 (23:27 +0200)
committerSimonas Kazlauskas <git@kazlauskas.me>
Wed, 6 Jan 2016 11:40:57 +0000 (13:40 +0200)
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
src/librustc/mir/visit.rs
src/librustc_mir/build/expr/into.rs
src/librustc_mir/transform/erase_regions.rs
src/librustc_trans/trans/mir/block.rs

index 75a588d424ebbb7b56ff7cb099f9ad06ac7581a7..42c9b7b0f39abd112554f9b14ba7518dc095112a 100644 (file)
@@ -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<Operand<'tcx>>,
+        /// 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<Operand<'tcx>>,
+        /// Some, if there’s any cleanup to be done when function unwinds
+        cleanup: Option<BasicBlock>,
+    }
+}
+
+#[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 @@ pub fn successors(&self) -> &[BasicBlock] {
         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 @@ pub fn successors_mut(&mut self) -> &mut [BasicBlock] {
         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<Operand<'tcx>>,
-}
-
 impl<'tcx> BasicBlockData<'tcx> {
     pub fn new(terminator: Terminator<'tcx>) -> BasicBlockData<'tcx> {
         BasicBlockData {
@@ -357,15 +393,13 @@ pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> fmt::Result {
             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 @@ pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
             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()
index 00d21d3c16e1faeb84a6b60d65721fa4847f3d75..c3a335fdfaac3781c60778167c159383df91431b 100644 (file)
@@ -137,16 +137,26 @@ fn super_terminator(&mut self, block: BasicBlock, terminator: &Terminator<'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 @@ fn super_terminator(&mut self,
             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);
+                }
+            }
         }
     }
 
index 802c55ce7647a0f53bdd731ba5f8eaab99ee3d9c..4a262196d367049fb264ade77e5e8ea695b60402 100644 (file)
@@ -218,14 +218,13 @@ pub fn into_expr(&mut self,
                         .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()
             }
index 1eb3bfd7e02299daeebdf575b1419adebd493c4e..1e7bb305cdbd2e2f79a7d803b61cd6afebd4b8db 100644 (file)
@@ -90,28 +90,23 @@ fn erase_regions_terminator(&mut self,
             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);
+                }
+            }
         }
     }
 
index 265969c52b39d3608b2078658272f3f2bd8b8d32..00508ed21e58e768b53a5b12ce0df4f94352f0e1 100644 (file)
@@ -164,6 +164,10 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                 }
 
                 build::Br(bcx, self.llblock(targets.0), DebugLoc::None)
+            },
+
+            mir::Terminator::DivergingCall { .. } => {
+                unimplemented!()
             }
         }
     }